mirror of
https://github.com/pacnpal/simpleguardhome.git
synced 2025-12-20 12:31:16 -05:00
feat(docker): enhance Dockerfile with debugging outputs and install tree utility; update .dockerignore and MANIFEST.in for better packaging
This commit is contained in:
@@ -42,6 +42,3 @@ htmlcov/
|
|||||||
|
|
||||||
# Project specific
|
# Project specific
|
||||||
rules_backup/
|
rules_backup/
|
||||||
|
|
||||||
# Documentation
|
|
||||||
*.md
|
|
||||||
39
Dockerfile
39
Dockerfile
@@ -12,6 +12,7 @@ RUN apt-get update && \
|
|||||||
libc6-dev \
|
libc6-dev \
|
||||||
python3-dev \
|
python3-dev \
|
||||||
python3-pip \
|
python3-pip \
|
||||||
|
tree \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
&& python3 -m pip install --no-cache-dir --upgrade "pip>=21.3" setuptools wheel
|
&& python3 -m pip install --no-cache-dir --upgrade "pip>=21.3" setuptools wheel
|
||||||
@@ -26,23 +27,27 @@ RUN mkdir -p /app/src/simpleguardhome && \
|
|||||||
# Copy source code, maintaining directory structure
|
# Copy source code, maintaining directory structure
|
||||||
COPY . /app/
|
COPY . /app/
|
||||||
|
|
||||||
# Set execute permission for entrypoint script
|
# Debug: Show the copied files and set execute permission for entrypoint script
|
||||||
RUN chmod +x /app/docker-entrypoint.sh && \
|
RUN echo "Project structure:" && \
|
||||||
|
tree /app && \
|
||||||
|
echo "Package directory contents:" && \
|
||||||
|
ls -la /app/src/simpleguardhome/ && \
|
||||||
|
chmod +x /app/docker-entrypoint.sh && \
|
||||||
cp /app/docker-entrypoint.sh /usr/local/bin/
|
cp /app/docker-entrypoint.sh /usr/local/bin/
|
||||||
|
|
||||||
# Set PYTHONPATH
|
# Set PYTHONPATH
|
||||||
ENV PYTHONPATH=/app/src
|
ENV PYTHONPATH=/app/src
|
||||||
|
|
||||||
# Install Python requirements
|
# Install Python requirements and verify the package
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt && \
|
||||||
|
set -e && \
|
||||||
# Install and verify the package
|
|
||||||
RUN set -e && \
|
|
||||||
echo "Installing package..." && \
|
echo "Installing package..." && \
|
||||||
pip uninstall -y simpleguardhome || true && \
|
pip uninstall -y simpleguardhome || true && \
|
||||||
# Verify source files exist
|
# Debug: Show package files
|
||||||
echo "Verifying source files..." && \
|
echo "Python path:" && \
|
||||||
ls -la /app/src/simpleguardhome/ && \
|
python3 -c "import sys; print('\n'.join(sys.path))" && \
|
||||||
|
echo "Source directory contents:" && \
|
||||||
|
ls -R /app/src && \
|
||||||
# Install package in editable mode with compatibility mode enabled
|
# Install package in editable mode with compatibility mode enabled
|
||||||
pip install --use-pep517 -e . --config-settings editable_mode=compat && \
|
pip install --use-pep517 -e . --config-settings editable_mode=compat && \
|
||||||
echo "Verifying installation..." && \
|
echo "Verifying installation..." && \
|
||||||
@@ -50,13 +55,15 @@ RUN set -e && \
|
|||||||
# List all package files
|
# List all package files
|
||||||
echo "Package contents:" && \
|
echo "Package contents:" && \
|
||||||
find /app/src/simpleguardhome -type f -ls && \
|
find /app/src/simpleguardhome -type f -ls && \
|
||||||
# Verify import works
|
# Verify package can be imported
|
||||||
echo "Testing import..." && \
|
echo "Testing import..." && \
|
||||||
python3 -c "import simpleguardhome; from simpleguardhome.main import app; print(f'Package found at: {simpleguardhome.__file__}')" && \
|
python3 -c "import simpleguardhome; print(f'Package found at: {simpleguardhome.__file__}')" && \
|
||||||
echo "Package installation successful"
|
# Verify app can be imported
|
||||||
|
echo "Testing app import..." && \
|
||||||
# Create rules backup directory with proper permissions
|
python3 -c "from simpleguardhome.main import app; print('App imported successfully')" && \
|
||||||
RUN mkdir -p /app/rules_backup && \
|
echo "Package installation successful" && \
|
||||||
|
# Create rules backup directory with proper permissions
|
||||||
|
mkdir -p /app/rules_backup && \
|
||||||
chmod 777 /app/rules_backup
|
chmod 777 /app/rules_backup
|
||||||
|
|
||||||
# Default environment variables
|
# Default environment variables
|
||||||
|
|||||||
19
MANIFEST.in
19
MANIFEST.in
@@ -1,3 +1,18 @@
|
|||||||
recursive-include src/simpleguardhome/templates *
|
# Include all package Python files
|
||||||
|
graft src/simpleguardhome
|
||||||
|
|
||||||
|
# Include package data files
|
||||||
include src/simpleguardhome/favicon.ico
|
include src/simpleguardhome/favicon.ico
|
||||||
recursive-include src/simpleguardhome *.py
|
include src/simpleguardhome/templates/*.html
|
||||||
|
|
||||||
|
# Include important project files
|
||||||
|
include README.md
|
||||||
|
include LICENSE
|
||||||
|
include requirements.txt
|
||||||
|
include pyproject.toml
|
||||||
|
include setup.py
|
||||||
|
|
||||||
|
# Exclude bytecode files
|
||||||
|
global-exclude *.py[cod]
|
||||||
|
global-exclude __pycache__
|
||||||
|
global-exclude *.so
|
||||||
@@ -22,9 +22,21 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[tool.setuptools]
|
[tool.setuptools]
|
||||||
|
# Using explicit package configuration
|
||||||
package-dir = {"" = "src"}
|
package-dir = {"" = "src"}
|
||||||
packages = ["simpleguardhome"]
|
packages = ["simpleguardhome"]
|
||||||
include-package-data = true
|
|
||||||
|
|
||||||
|
# Include all package data
|
||||||
[tool.setuptools.package-data]
|
[tool.setuptools.package-data]
|
||||||
simpleguardhome = ["templates/*", "favicon.ico"]
|
"*" = ["*.ico", "templates/*.html"]
|
||||||
|
|
||||||
|
# Explicitly include the package data
|
||||||
|
[options.package_data]
|
||||||
|
simpleguardhome = [
|
||||||
|
"templates/*",
|
||||||
|
"favicon.ico"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Make sure data files are included
|
||||||
|
[options]
|
||||||
|
include_package_data = true
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
from pydantic_settings import BaseSettings
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from pydantic_settings import BaseSettings # type: ignore
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
"""Application settings using environment variables."""
|
"""Application settings using environment variables."""
|
||||||
|
|||||||
@@ -1,25 +1,33 @@
|
|||||||
from fastapi import FastAPI, Request, Form, HTTPException, status
|
|
||||||
from fastapi.templating import Jinja2Templates
|
|
||||||
from fastapi.staticfiles import StaticFiles
|
|
||||||
from fastapi.responses import HTMLResponse, JSONResponse
|
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
|
||||||
from pathlib import Path
|
|
||||||
import httpx
|
|
||||||
import logging
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from . import adguard
|
|
||||||
from .config import settings
|
import httpx # noqa: F401
|
||||||
from .adguard import (
|
from fastapi import ( # type: ignore # noqa: F401
|
||||||
AdGuardError,
|
FastAPI,
|
||||||
AdGuardConnectionError,
|
Form,
|
||||||
AdGuardAPIError,
|
HTTPException,
|
||||||
AdGuardValidationError,
|
Request,
|
||||||
FilterStatus,
|
status,
|
||||||
FilterCheckHostResponse,
|
|
||||||
SetRulesRequest
|
|
||||||
)
|
)
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware # type: ignore
|
||||||
|
from fastapi.responses import HTMLResponse, JSONResponse # type: ignore
|
||||||
|
from fastapi.staticfiles import StaticFiles # type: ignore
|
||||||
|
from fastapi.templating import Jinja2Templates # type: ignore
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from . import adguard
|
||||||
|
from .adguard import (
|
||||||
|
AdGuardAPIError,
|
||||||
|
AdGuardConnectionError,
|
||||||
|
AdGuardError,
|
||||||
|
AdGuardValidationError,
|
||||||
|
FilterCheckHostResponse,
|
||||||
|
FilterStatus,
|
||||||
|
SetRulesRequest,
|
||||||
|
)
|
||||||
|
from .config import settings # noqa: F401
|
||||||
|
|
||||||
# Configure logging
|
# Configure logging
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -53,13 +61,17 @@ app.mount("/static", StaticFiles(directory=str(Path(__file__).parent)), name="st
|
|||||||
|
|
||||||
# Mount favicon.ico at root
|
# Mount favicon.ico at root
|
||||||
static_files_path = Path(__file__).parent
|
static_files_path = Path(__file__).parent
|
||||||
app.mount("/favicon.ico", StaticFiles(directory=str(static_files_path)), name="favicon")
|
app.mount("/favicon.ico",
|
||||||
|
StaticFiles(directory=str(static_files_path)), name="favicon")
|
||||||
|
|
||||||
# Response models matching AdGuard spec
|
# Response models matching AdGuard spec
|
||||||
|
|
||||||
|
|
||||||
class ErrorResponse(BaseModel):
|
class ErrorResponse(BaseModel):
|
||||||
"""Error response model according to AdGuard spec."""
|
"""Error response model according to AdGuard spec."""
|
||||||
message: str = Field(..., description="The error message")
|
message: str = Field(..., description="The error message")
|
||||||
|
|
||||||
|
|
||||||
@app.get("/", response_class=HTMLResponse)
|
@app.get("/", response_class=HTMLResponse)
|
||||||
async def home(request: Request):
|
async def home(request: Request):
|
||||||
"""Render the home page."""
|
"""Render the home page."""
|
||||||
@@ -68,6 +80,7 @@ async def home(request: Request):
|
|||||||
{"request": request}
|
{"request": request}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@app.get(
|
@app.get(
|
||||||
"/control/filtering/check_host",
|
"/control/filtering/check_host",
|
||||||
response_model=FilterCheckHostResponse,
|
response_model=FilterCheckHostResponse,
|
||||||
@@ -96,11 +109,12 @@ async def check_domain(name: str) -> FilterCheckHostResponse:
|
|||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
detail=str(e)
|
detail=str(e)
|
||||||
)
|
) from e
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error checking domain {name}: {str(e)}")
|
logger.error(f"Error checking domain {name}: {str(e)}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
@app.post(
|
@app.post(
|
||||||
"/control/filtering/set_rules",
|
"/control/filtering/set_rules",
|
||||||
response_model=Dict,
|
response_model=Dict,
|
||||||
@@ -144,11 +158,12 @@ async def add_to_whitelist(request: SetRulesRequest) -> Dict:
|
|||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
detail=str(e)
|
detail=str(e)
|
||||||
)
|
) from e
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error adding domain to whitelist: {str(e)}")
|
logger.error(f"Error adding domain to whitelist: {str(e)}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
@app.get(
|
@app.get(
|
||||||
"/control/filtering/status",
|
"/control/filtering/status",
|
||||||
response_model=FilterStatus,
|
response_model=FilterStatus,
|
||||||
@@ -167,8 +182,9 @@ async def get_filtering_status() -> FilterStatus:
|
|||||||
logger.error(f"Error getting filter status: {str(e)}")
|
logger.error(f"Error getting filter status: {str(e)}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
@app.exception_handler(AdGuardError)
|
@app.exception_handler(AdGuardError)
|
||||||
async def adguard_exception_handler(request: Request, exc: AdGuardError) -> JSONResponse:
|
async def adguard_exception_handler(_request: Request, exc: AdGuardError) -> JSONResponse:
|
||||||
"""Handle AdGuard-related exceptions according to spec."""
|
"""Handle AdGuard-related exceptions according to spec."""
|
||||||
if isinstance(exc, AdGuardConnectionError):
|
if isinstance(exc, AdGuardConnectionError):
|
||||||
status_code = status.HTTP_503_SERVICE_UNAVAILABLE
|
status_code = status.HTTP_503_SERVICE_UNAVAILABLE
|
||||||
@@ -184,9 +200,10 @@ async def adguard_exception_handler(request: Request, exc: AdGuardError) -> JSON
|
|||||||
content={"message": str(exc)}
|
content={"message": str(exc)}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
"""Start the application using uvicorn."""
|
"""Start the application using uvicorn."""
|
||||||
import uvicorn
|
import uvicorn # type: ignore
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
app,
|
app,
|
||||||
host="0.0.0.0",
|
host="0.0.0.0",
|
||||||
@@ -194,5 +211,6 @@ def start():
|
|||||||
reload=False # Disable reload in Docker
|
reload=False # Disable reload in Docker
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
start()
|
start()
|
||||||
Reference in New Issue
Block a user