diff --git a/.woodpecker.yaml b/.woodpecker.yaml index 56db5b5..d17cc99 100644 --- a/.woodpecker.yaml +++ b/.woodpecker.yaml @@ -1,72 +1,38 @@ -when: - event: - - push - - pull_request - branch: - - master - steps: - - name: tag - image: alpine - commands: - - export TAG_DATE=$(date +%Y%m%d) - - export SHORT_SHA=${CI_COMMIT_SHA:0:7} - - echo "TAGS=latest,$TAG_DATE-$SHORT_SHA" > .tags.env + build-frontend: + name: Build & Push Frontend with wp-kaniko-sync + image: harbor.dvirlabs.com/devtools/wp-kaniko-sync:latest + settings: + PLUGIN_CONTEXT: frontend + PLUGIN_DOCKERFILE: frontend/Dockerfile + PLUGIN_REPO: my-apps/labmap-frontend + PLUGIN_REGISTRY: harbor.dvirlabs.com + PLUGIN_NAME: frontend + PLUGIN_GIT_REPO: git.dvirlabs.com/dvirlabs/my-apps.git + PLUGIN_VALUES_FILE: manifests/labmap/values.yaml + PLUGIN_VALUES_PATH: frontend.tag + PLUGIN_GIT_USERNAME: + from_secret: GIT_USERNAME + PLUGIN_GIT_TOKEN: + from_secret: GIT_TOKEN - - name: setup-docker-config - image: alpine - commands: - - mkdir -p /kaniko/.docker - - | - cat < /kaniko/.docker/config.json - { - "auths": { - "harbor.dvirlabs.com": { - "auth": "ZHZpcmxhYnM6S1loaHBlMUhwNk5DR2IxWDJVQ0VDRUtjS25mSFhodEY=" - } - } - } - EOF - volumes: - - name: docker-config - path: /kaniko/.docker/ + build-backend: + name: Build & Push Backend with wp-kaniko-sync + image: harbor.dvirlabs.com/devtools/wp-kaniko-sync:latest + settings: + PLUGIN_CONTEXT: backend + PLUGIN_DOCKERFILE: backend/Dockerfile + PLUGIN_REPO: my-apps/labmap-backend + PLUGIN_REGISTRY: harbor.dvirlabs.com + PLUGIN_NAME: backend + PLUGIN_GIT_REPO: git.dvirlabs.com/dvirlabs/my-apps.git + PLUGIN_VALUES_FILE: manifests/labmap/values.yaml + PLUGIN_VALUES_PATH: backend.tag + PLUGIN_GIT_USERNAME: + from_secret: GIT_USERNAME + PLUGIN_GIT_TOKEN: + from_secret: GIT_TOKEN - - name: build-frontend - image: gcr.io/kaniko-project/executor:latest - environment: - DOCKER_CONFIG: /kaniko/.docker/ - volumes: - - name: docker-config - path: /kaniko/.docker/ - commands: - - | - for TAG in $(cut -d= -f2 .tags.env | tr ',' '\n'); do - /kaniko/executor \ - --dockerfile=frontend/Dockerfile \ - --context=frontend \ - --destination=harbor.dvirlabs.com/my-apps/navix-frontend:$TAG \ - --insecure \ - --skip-tls-verify - done - - - name: build-backend - image: gcr.io/kaniko-project/executor:latest - environment: - DOCKER_CONFIG: /kaniko/.docker/ - volumes: - - name: docker-config - path: /kaniko/.docker/ - commands: - - | - for TAG in $(cut -d= -f2 .tags.env | tr ',' '\n'); do - /kaniko/executor \ - --dockerfile=backend/Dockerfile \ - --context=backend \ - --destination=harbor.dvirlabs.com/my-apps/navix-backend:$TAG \ - --insecure \ - --skip-tls-verify - done - -volumes: - - name: docker-config - temp: {} +when: + branch: [ master, develop ] + event: [ push, tag ] diff --git a/backend/__pycache__/main.cpython-313.pyc b/backend/__pycache__/main.cpython-313.pyc index add390f..6f41891 100644 Binary files a/backend/__pycache__/main.cpython-313.pyc and b/backend/__pycache__/main.cpython-313.pyc differ diff --git a/backend/main.py b/backend/main.py index 7f6354f..8e41231 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,4 +1,4 @@ -from fastapi import FastAPI +from fastapi import FastAPI, APIRouter from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse import os @@ -7,11 +7,10 @@ import yaml from pathlib import Path from pydantic import BaseModel from minio import Minio -from datetime import timedelta - app = FastAPI() -# Allow CORS for all origins +router = APIRouter() + app.add_middleware( CORSMiddleware, allow_origins=["*"], @@ -22,13 +21,12 @@ app.add_middleware( load_dotenv() -# Load ENV variables +# ENV MINIO_ENDPOINT = os.getenv("MINIO_ENDPOINT") MINIO_ACCESS_KEY = os.getenv("MINIO_ACCESS_KEY") MINIO_SECRET_KEY = os.getenv("MINIO_SECRET_KEY") MINIO_BUCKET = os.getenv("MINIO_BUCKET") -# MinIO connection with access and secret keys minio_client = Minio( MINIO_ENDPOINT, access_key=MINIO_ACCESS_KEY, @@ -36,22 +34,21 @@ minio_client = Minio( secure=True ) -BUCKET = "navix-icons" +BUCKET = MINIO_BUCKET or "navix-icons" -@app.get("/") -async def root(): +@router.get("/") +def root(): return {"message": "Welcome to the FastAPI application!"} -# Path to apps.yaml (relative to backend/) APPS_FILE = Path(__file__).parent / "apps.yaml" -@app.get("/apps") +@router.get("/apps") def get_apps(): if not APPS_FILE.exists(): return {"error": "apps.yaml not found"} with open(APPS_FILE, "r") as f: return yaml.safe_load(f) - + class AppData(BaseModel): name: str icon: str @@ -62,7 +59,7 @@ class AppEntry(BaseModel): section: str app: AppData -@app.post("/add_app") +@router.post("/add_app") def add_app(entry: AppEntry): if not APPS_FILE.exists(): current = {"sections": []} @@ -70,7 +67,6 @@ def add_app(entry: AppEntry): with open(APPS_FILE, "r") as f: current = yaml.safe_load(f) or {"sections": []} - # Find or create section for section in current["sections"]: if section["name"] == entry.section: section["apps"].append(entry.app.dict()) @@ -86,13 +82,13 @@ def add_app(entry: AppEntry): return {"status": "added"} -@app.get("/icon/{filename}") +@router.get("/icon/{filename}") def get_public_icon_url(filename: str): - url = f"https://{MINIO_ENDPOINT}/{MINIO_BUCKET}/{filename}" + url = f"https://{MINIO_ENDPOINT}/{BUCKET}/{filename}" return JSONResponse(content={"url": url}) - +app.include_router(router, prefix="/api") if __name__ == "__main__": import uvicorn - uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) \ No newline at end of file + uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 1ada1cc..02ba70e 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -6,15 +6,24 @@ RUN npm install --legacy-peer-deps COPY . . RUN npm run build -# Stage 2: NGINX +# Stage 2: Runtime (NGINX) FROM nginx:alpine +# Install dos2unix to fix Windows line endings +RUN apk add --no-cache dos2unix + +# Clean default nginx html RUN rm -rf /usr/share/nginx/html/* + +# Copy built frontend COPY --from=builder /app/dist /usr/share/nginx/html -# Runtime env injection +# Copy entrypoint and normalize line endings COPY docker-entrypoint.sh /docker-entrypoint.sh -RUN chmod +x /docker-entrypoint.sh +RUN dos2unix /docker-entrypoint.sh && chmod +x /docker-entrypoint.sh + +# Fallback env.js (to avoid 404 before initContainer writes real one) RUN echo "window.env = {}" > /usr/share/nginx/html/env.js -CMD ["/docker-entrypoint.sh"] +# Set entrypoint +ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/frontend/docker-entrypoint.sh b/frontend/docker-entrypoint.sh index 09e117e..6fab1ad 100644 --- a/frontend/docker-entrypoint.sh +++ b/frontend/docker-entrypoint.sh @@ -1,11 +1,11 @@ #!/bin/sh set -e -# Generate env.js at runtime +# Generate env.js at runtime from env var cat < /usr/share/nginx/html/env.js window.env = { VITE_API_URL: "${VITE_API_URL}" -} +}; EOF exec nginx -g "daemon off;" diff --git a/frontend/index.html b/frontend/index.html index ca5b307..164436e 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -5,6 +5,7 @@ + Navix diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index 66bf39e..309ad6a 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -1,4 +1,4 @@ -const API_BASE = window?.env?.VITE_API_URL || ''; +const API_BASE = window?.env?.VITE_API_URL || '/api'; export async function fetchSections() { const res = await fetch(`${API_BASE}/apps`); diff --git a/frontend/vite-config.js-develop b/frontend/vite-config.js-develop new file mode 100644 index 0000000..ea8be0a --- /dev/null +++ b/frontend/vite-config.js-develop @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + server: { + proxy: { + '/apps': 'http://localhost:8000', + '/add_app': 'http://localhost:8000', + '/icon': 'http://localhost:8000', + } + } +}); diff --git a/navix-helm/templates/backend-ingress.yaml b/navix-helm/templates/backend-ingress.yaml new file mode 100644 index 0000000..02fa268 --- /dev/null +++ b/navix-helm/templates/backend-ingress.yaml @@ -0,0 +1,23 @@ +{{- if .Values.backend.ingress.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: navix-backend + annotations: + {{- range $key, $value := .Values.backend.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + ingressClassName: {{ .Values.backend.ingress.className }} + rules: + - host: {{ .Values.backend.ingress.hosts[0].host }} + http: + paths: + - path: /api + pathType: Prefix + backend: + service: + name: navix-backend + port: + number: {{ .Values.backend.service.port }} +{{- end }} diff --git a/navix-helm/templates/frontend-env-configmap.yaml b/navix-helm/templates/frontend-env-configmap.yaml index 75e69c9..a4faaf6 100644 --- a/navix-helm/templates/frontend-env-configmap.yaml +++ b/navix-helm/templates/frontend-env-configmap.yaml @@ -5,5 +5,5 @@ metadata: data: env.js: | window.env = { - VITE_API_URL: "http://navix-backend.{{ .Release.Namespace }}.svc.cluster.local:8000" + VITE_API_URL: "{{ .Values.frontend.env.VITE_API_URL }}" }; diff --git a/navix-helm/values.yaml b/navix-helm/values.yaml index a4f148e..f97bd25 100644 --- a/navix-helm/values.yaml +++ b/navix-helm/values.yaml @@ -17,6 +17,8 @@ frontend: paths: - path: / pathType: Prefix + env: + VITE_API_URL: "/api" backend: image: @@ -32,4 +34,13 @@ backend: MINIO_ENDPOINT: "s3.dvirlabs.com" MINIO_BUCKET: "navix-icons" ingress: - enabled: false \ No newline at end of file + enabled: true + className: traefik + annotations: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.tls: "true" + hosts: + - host: navix.dvirlabs.com + paths: + - path: /api + pathType: Prefix