diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 7c3a63b..0000000 --- a/.flake8 +++ /dev/null @@ -1,8 +0,0 @@ -[flake8] -max-line-length = 120 -exclude = .venv, docs, .vscode, pychache, .git,__pycache__,__init__.py,.mypy_cache,.pytest_cache -ignore = E501, W503, E226, E203, W503, W293, I004, E266, W391, W292, I001 -# E501: Line too long -# W503: Line break occurred before binary operator -# E226: Missing white space around arithmetic operator -# I001: Import wrong positions diff --git a/.vscode/settings.json b/.vscode/settings.json index f47a7b9..51d0743 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,4 +3,5 @@ "python.linting.flake8Enabled": true, "python.linting.mypyEnabled": false, "python.linting.enabled": true, + "java.compile.nullAnalysis.mode": "automatic", } diff --git a/Dockerfile b/Dockerfile index 6c9f16d..ccbb560 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,55 @@ -FROM python:3.10-alpine +# Build stage +FROM golang:1.21-alpine AS builder +WORKDIR /build -WORKDIR /code +# Add necessary build tools +RUN apk add --no-cache make build-base -COPY ./requirements.txt /code/requirements.txt +# Install dependencies first (better layer caching) +COPY go.mod go.sum ./ +RUN echo "📦 Installing dependencies..." && \ + go mod download -RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt +# Copy source code +COPY . . -COPY ./app /code/app +# Build the application +RUN echo "🔨 Building application..." && \ + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \ + -ldflags='-w -s -extldflags "-static"' \ + -o status-service -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] +# Security scan (optional but recommended) +RUN echo "🔍 Running security checks..." && \ + go vet ./... + +# Final stage +FROM alpine:3.19 +WORKDIR /app + +# Add non-root user +RUN echo "🔒 Creating non-root user..." && \ + addgroup -S appgroup && \ + adduser -S appuser -G appgroup + +# Copy binary from builder +COPY --from=builder /build/status-service . + +# Set ownership +RUN chown -R appuser:appgroup /app + +# Use non-root user +USER appuser + +# Container configuration +EXPOSE 8000 +ENV TZ=Europe/Rome \ + APP_USER=appuser + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:8000/health || exit 1 + +# Run application +CMD echo "🚀 Starting status-service..." && \ + ./status-service diff --git a/app/main.py b/app/main.py deleted file mode 100644 index e1520e7..0000000 --- a/app/main.py +++ /dev/null @@ -1,25 +0,0 @@ -from fastapi import FastAPI, Response -from http import HTTPStatus - - -app = FastAPI() - - -@app.get("/") -async def home_root(): - return Response(status_code=HTTPStatus.OK) - - -@app.get("/status") -async def status(): - return Response(status_code=HTTPStatus.OK) - - -@app.get("/health") -async def health(): - return Response(status_code=HTTPStatus.OK) - - -@app.get("/healthz") -async def healthz(): - return Response(status_code=HTTPStatus.OK) diff --git a/docker-compose.yml b/docker-compose.yml index 000b07f..cb60fdd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,3 +8,16 @@ services: restart: always ports: - "8000:8000" + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:8080/"] + interval: 30s + timeout: 10s + retries: 3 + deploy: + resources: + limits: + cpus: '0.1' + memory: 6M + reservations: + cpus: '0.1' + memory: 6M diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d692032 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module status-service + +go 1.21 + +require github.com/gorilla/mux v1.8.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7128337 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= diff --git a/handlers/status.go b/handlers/status.go new file mode 100644 index 0000000..e60f8b9 --- /dev/null +++ b/handlers/status.go @@ -0,0 +1,34 @@ +package handlers + +import ( + "encoding/json" + "net/http" +) + +type Response struct { + Result string `json:"result"` +} + +func HomeHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(Response{Result: "ok"}) +} + +func StatusHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(Response{Result: "ok"}) +} + +func HealthHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(Response{Result: "ok"}) +} + +func HealthzHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(Response{Result: "ok"}) +} diff --git a/helm/devopslab/diego/.helmignore b/helm/devopslab/diego/.helmignore deleted file mode 100644 index 0e8a0eb..0000000 --- a/helm/devopslab/diego/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/helm/devopslab/diego/Chart.lock b/helm/devopslab/diego/Chart.lock deleted file mode 100644 index 66cca0c..0000000 --- a/helm/devopslab/diego/Chart.lock +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: -- name: microservice-chart - repository: https://pagopa.github.io/aks-microservice-chart-blueprint - version: 5.4.1 -digest: sha256:6c92f7bc29936b5600d1f6220b409d214f1b3c4fad5845f7d22aa2b1b05777fb -generated: "2024-02-19T17:48:38.125636+01:00" diff --git a/helm/devopslab/diego/Chart.yaml b/helm/devopslab/diego/Chart.yaml deleted file mode 100644 index 1927f39..0000000 --- a/helm/devopslab/diego/Chart.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: v2 -name: devops-app-status -description: App that allow to expose a simple health checks endpoints -type: application -version: 1.5.0 -appVersion: 1.5.0 -dependencies: -- name: microservice-chart - version: 5.4.1 - repository: "https://pagopa.github.io/aks-microservice-chart-blueprint" diff --git a/helm/devopslab/diego/values-dev.yaml b/helm/devopslab/diego/values-dev.yaml deleted file mode 100644 index f44dd3b..0000000 --- a/helm/devopslab/diego/values-dev.yaml +++ /dev/null @@ -1,96 +0,0 @@ -microservice-chart: - namespace: "diego" - nameOverride: "" - fullnameOverride: "" - -# -# Deploy -# - deployment: - create: true - # forceRedeploy: true - - image: - repository: ghcr.io/pagopa/devops-app-status - tag: v1.5.0 - pullPolicy: Always - - livenessProbe: - httpGet: - path: /status - port: 8000 - initialDelaySeconds: 10 - failureThreshold: 6 - periodSeconds: 10 - - readinessProbe: - httpGet: - path: /status - port: 8000 - initialDelaySeconds: 10 - failureThreshold: 6 - periodSeconds: 10 - - -# -# Network -# - service: - create: true - type: ClusterIP - ports: - - 8000 - - ingress: - create: true - host: "diego.itn.internal.devopslab.pagopa.it" - path: /status(/|$)(.*) - rewriteTarget: /$2 - servicePort: 8000 - # proxyBodySize: 2m - annotations: { - nginx.ingress.kubernetes.io/satisfy: "any" - } - - serviceAccount: - create: false - annotations: {} - name: "" - - podAnnotations: {} - - podSecurityContext: - seccompProfile: - type: RuntimeDefault - - securityContext: - allowPrivilegeEscalation: false - - resources: - requests: - memory: "128Mi" - cpu: "40m" - limits: - memory: "128Mi" - cpu: "40m" - - autoscaling: - enable: true - minReplica: 1 - maxReplica: 3 - pollingInterval: 30 # seconds - cooldownPeriod: 300 # seconds - triggers: - - type: cpu - metadata: - type: Utilization - value: "60" - - secretProviderClass: - create: false - - # nodeSelector: {} - - # tolerations: [] - - # affinity: {} diff --git a/launch-debug.sh b/launch-debug.sh deleted file mode 100644 index 0699eca..0000000 --- a/launch-debug.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -export PYTHONPATH=$(pwd) -export API_ENDPOINT_PORT=5000 -export VERBOSITY=DEBUG -export DEBUG_MODE=True -python3 app/main.py diff --git a/launch.sh b/launch.sh deleted file mode 100755 index 831b103..0000000 --- a/launch.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -#Launch the application using gunicorn backend -#gunicorn -w 4 -b 0.0.0.0:${APP_ENDPOINT_PORT:-8045} app.main:app -# gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:${APP_ENDPOINT_PORT:-8045} --preload --log-level ${VERBOSIT:-INFO} app.main:app -# python ./app/main.py -uvicorn app.main:app --host 0.0.0.0 --port ${APP_ENDPOINT_PORT:-8045} --log-level ${APP_VERBOSITY:-info} --reload diff --git a/main.go b/main.go new file mode 100644 index 0000000..2a360ba --- /dev/null +++ b/main.go @@ -0,0 +1,22 @@ +package main + +import ( + "log" + "net/http" + + "status-service/handlers" + + "github.com/gorilla/mux" +) + +func main() { + r := mux.NewRouter() + + r.HandleFunc("/", handlers.HomeHandler) + r.HandleFunc("/status", handlers.StatusHandler) + r.HandleFunc("/health", handlers.HealthHandler) + r.HandleFunc("/healthz", handlers.HealthzHandler) + + log.Printf("Server starting on port 8000") + log.Fatal(http.ListenAndServe(":8000", r)) +} diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 97dc7cd..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -fastapi -uvicorn diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..59d8105 --- /dev/null +++ b/run.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +echo "Building Go application..." +go build -o status-service + +echo "Starting server on port 8000..." +./status-service