Try the new plugin

This commit is contained in:
dvirlabs 2025-06-18 06:21:45 +03:00
parent fdb03f983c
commit cec81e48c9
11 changed files with 116 additions and 96 deletions

View File

@ -1,72 +1,38 @@
when:
event:
- push
- pull_request
branch:
- master
steps: steps:
- name: tag build-frontend:
image: alpine name: Build & Push Frontend with wp-kaniko-sync
commands: image: harbor.dvirlabs.com/devtools/wp-kaniko-sync:latest
- export TAG_DATE=$(date +%Y%m%d) settings:
- export SHORT_SHA=${CI_COMMIT_SHA:0:7} PLUGIN_CONTEXT: frontend
- echo "TAGS=latest,$TAG_DATE-$SHORT_SHA" > .tags.env 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 build-backend:
image: alpine name: Build & Push Backend with wp-kaniko-sync
commands: image: harbor.dvirlabs.com/devtools/wp-kaniko-sync:latest
- mkdir -p /kaniko/.docker settings:
- | PLUGIN_CONTEXT: backend
cat <<EOF > /kaniko/.docker/config.json PLUGIN_DOCKERFILE: backend/Dockerfile
{ PLUGIN_REPO: my-apps/labmap-backend
"auths": { PLUGIN_REGISTRY: harbor.dvirlabs.com
"harbor.dvirlabs.com": { PLUGIN_NAME: backend
"auth": "ZHZpcmxhYnM6S1loaHBlMUhwNk5DR2IxWDJVQ0VDRUtjS25mSFhodEY=" 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:
EOF from_secret: GIT_USERNAME
volumes: PLUGIN_GIT_TOKEN:
- name: docker-config from_secret: GIT_TOKEN
path: /kaniko/.docker/
- name: build-frontend when:
image: gcr.io/kaniko-project/executor:latest branch: [ master, develop ]
environment: event: [ push, tag ]
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: {}

View File

@ -1,4 +1,4 @@
from fastapi import FastAPI from fastapi import FastAPI, APIRouter
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
import os import os
@ -7,11 +7,10 @@ import yaml
from pathlib import Path from pathlib import Path
from pydantic import BaseModel from pydantic import BaseModel
from minio import Minio from minio import Minio
from datetime import timedelta
app = FastAPI() app = FastAPI()
# Allow CORS for all origins router = APIRouter()
app.add_middleware( app.add_middleware(
CORSMiddleware, CORSMiddleware,
allow_origins=["*"], allow_origins=["*"],
@ -22,13 +21,12 @@ app.add_middleware(
load_dotenv() load_dotenv()
# Load ENV variables # ENV
MINIO_ENDPOINT = os.getenv("MINIO_ENDPOINT") MINIO_ENDPOINT = os.getenv("MINIO_ENDPOINT")
MINIO_ACCESS_KEY = os.getenv("MINIO_ACCESS_KEY") MINIO_ACCESS_KEY = os.getenv("MINIO_ACCESS_KEY")
MINIO_SECRET_KEY = os.getenv("MINIO_SECRET_KEY") MINIO_SECRET_KEY = os.getenv("MINIO_SECRET_KEY")
MINIO_BUCKET = os.getenv("MINIO_BUCKET") MINIO_BUCKET = os.getenv("MINIO_BUCKET")
# MinIO connection with access and secret keys
minio_client = Minio( minio_client = Minio(
MINIO_ENDPOINT, MINIO_ENDPOINT,
access_key=MINIO_ACCESS_KEY, access_key=MINIO_ACCESS_KEY,
@ -36,16 +34,15 @@ minio_client = Minio(
secure=True secure=True
) )
BUCKET = "navix-icons" BUCKET = MINIO_BUCKET or "navix-icons"
@app.get("/") @router.get("/")
async def root(): def root():
return {"message": "Welcome to the FastAPI application!"} return {"message": "Welcome to the FastAPI application!"}
# Path to apps.yaml (relative to backend/)
APPS_FILE = Path(__file__).parent / "apps.yaml" APPS_FILE = Path(__file__).parent / "apps.yaml"
@app.get("/apps") @router.get("/apps")
def get_apps(): def get_apps():
if not APPS_FILE.exists(): if not APPS_FILE.exists():
return {"error": "apps.yaml not found"} return {"error": "apps.yaml not found"}
@ -62,7 +59,7 @@ class AppEntry(BaseModel):
section: str section: str
app: AppData app: AppData
@app.post("/add_app") @router.post("/add_app")
def add_app(entry: AppEntry): def add_app(entry: AppEntry):
if not APPS_FILE.exists(): if not APPS_FILE.exists():
current = {"sections": []} current = {"sections": []}
@ -70,7 +67,6 @@ def add_app(entry: AppEntry):
with open(APPS_FILE, "r") as f: with open(APPS_FILE, "r") as f:
current = yaml.safe_load(f) or {"sections": []} current = yaml.safe_load(f) or {"sections": []}
# Find or create section
for section in current["sections"]: for section in current["sections"]:
if section["name"] == entry.section: if section["name"] == entry.section:
section["apps"].append(entry.app.dict()) section["apps"].append(entry.app.dict())
@ -86,12 +82,12 @@ def add_app(entry: AppEntry):
return {"status": "added"} return {"status": "added"}
@app.get("/icon/{filename}") @router.get("/icon/{filename}")
def get_public_icon_url(filename: str): 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}) return JSONResponse(content={"url": url})
app.include_router(router, prefix="/api")
if __name__ == "__main__": if __name__ == "__main__":
import uvicorn import uvicorn

View File

@ -6,15 +6,24 @@ RUN npm install --legacy-peer-deps
COPY . . COPY . .
RUN npm run build RUN npm run build
# Stage 2: NGINX # Stage 2: Runtime (NGINX)
FROM nginx:alpine 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/* RUN rm -rf /usr/share/nginx/html/*
# Copy built frontend
COPY --from=builder /app/dist /usr/share/nginx/html 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 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 RUN echo "window.env = {}" > /usr/share/nginx/html/env.js
CMD ["/docker-entrypoint.sh"] # Set entrypoint
ENTRYPOINT ["/docker-entrypoint.sh"]

View File

@ -1,11 +1,11 @@
#!/bin/sh #!/bin/sh
set -e set -e
# Generate env.js at runtime # Generate env.js at runtime from env var
cat <<EOF > /usr/share/nginx/html/env.js cat <<EOF > /usr/share/nginx/html/env.js
window.env = { window.env = {
VITE_API_URL: "${VITE_API_URL}" VITE_API_URL: "${VITE_API_URL}"
} };
EOF EOF
exec nginx -g "daemon off;" exec nginx -g "daemon off;"

View File

@ -5,6 +5,7 @@
<link rel="icon" type="image/svg+xml" href="/navix-logo.svg" /> <link rel="icon" type="image/svg+xml" href="/navix-logo.svg" />
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@500&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@500&family=Rajdhani:wght@500&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@500&family=Rajdhani:wght@500&display=swap" rel="stylesheet">
<script src="/env.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Navix</title> <title>Navix</title>
</head> </head>

View File

@ -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() { export async function fetchSections() {
const res = await fetch(`${API_BASE}/apps`); const res = await fetch(`${API_BASE}/apps`);

View File

@ -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',
}
}
});

View File

@ -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 }}

View File

@ -5,5 +5,5 @@ metadata:
data: data:
env.js: | env.js: |
window.env = { window.env = {
VITE_API_URL: "http://navix-backend.{{ .Release.Namespace }}.svc.cluster.local:8000" VITE_API_URL: "{{ .Values.frontend.env.VITE_API_URL }}"
}; };

View File

@ -17,6 +17,8 @@ frontend:
paths: paths:
- path: / - path: /
pathType: Prefix pathType: Prefix
env:
VITE_API_URL: "/api"
backend: backend:
image: image:
@ -32,4 +34,13 @@ backend:
MINIO_ENDPOINT: "s3.dvirlabs.com" MINIO_ENDPOINT: "s3.dvirlabs.com"
MINIO_BUCKET: "navix-icons" MINIO_BUCKET: "navix-icons"
ingress: ingress:
enabled: false 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