Compare commits
11 Commits
4f16e001c6
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| a0f8bb8616 | |||
| 393fe985b8 | |||
| 3196d0d442 | |||
| aa4098cfbf | |||
| 0658c9e810 | |||
| d8f2e2dbb0 | |||
| d834c7b885 | |||
| 618db93105 | |||
| 840bb32a5d | |||
| 076e9a81db | |||
| d1a7aa3f74 |
@@ -6,18 +6,15 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: self-hosted
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- name: Checkout
|
||||||
|
run: git clone https://gitea.it-microevo.com/Dev/k8s-pilot.git .
|
||||||
|
|
||||||
- name: Login to Gitea Registry
|
- name: Login to Gitea Registry
|
||||||
run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login gitea.it-microevo.com -u "${{ secrets.REGISTRY_USER }}" --password-stdin
|
run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login gitea.it-microevo.com -u "${{ secrets.REGISTRY_USER }}" --password-stdin
|
||||||
|
|
||||||
- name: Build & Push
|
- name: Build & Push
|
||||||
run: |
|
run: |
|
||||||
docker build -t gitea.it-microevo.com/Dev/k8s-pilot:latest .
|
docker build -t gitea.it-microevo.com/dev/k8s-pilot:latest .
|
||||||
docker push gitea.it-microevo.com/Dev/k8s-pilot:latest
|
docker push gitea.it-microevo.com/dev/k8s-pilot:latest
|
||||||
|
|
||||||
- name: Rolling Restart
|
|
||||||
run: |
|
|
||||||
kubectl rollout restart deployment/k8s-pilot -n k8s-pilot
|
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ FROM node:20-alpine
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm ci --omit=dev
|
RUN npm install --omit=dev
|
||||||
|
|
||||||
COPY src/ ./src/
|
COPY src/ ./src/
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -51,7 +51,7 @@ spec:
|
|||||||
- name: k8s-pilot
|
- name: k8s-pilot
|
||||||
# Replace with your Gitea registry path:
|
# Replace with your Gitea registry path:
|
||||||
# image: git.it-microevo.com/<user>/k8s-pilot:latest
|
# image: git.it-microevo.com/<user>/k8s-pilot:latest
|
||||||
image: k8s-pilot:latest
|
image: gitea.it-microevo.com/dev/k8s-pilot:latest
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 3000
|
- containerPort: 3000
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ rules:
|
|||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["events"]
|
resources: ["events"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["secrets"]
|
||||||
|
verbs: ["get", "list"]
|
||||||
- apiGroups: ["apps"]
|
- apiGroups: ["apps"]
|
||||||
resources: ["deployments", "replicasets"]
|
resources: ["deployments", "replicasets"]
|
||||||
verbs: ["get", "list", "watch", "patch", "update"]
|
verbs: ["get", "list", "watch", "patch", "update"]
|
||||||
|
|||||||
+1004
-1057
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,9 @@ const { WebSocketServer } = require('ws');
|
|||||||
const http = require('http');
|
const http = require('http');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { PassThrough } = require('stream');
|
const { PassThrough } = require('stream');
|
||||||
|
const zlib = require('zlib');
|
||||||
|
const { promisify } = require('util');
|
||||||
|
const gunzip = promisify(zlib.gunzip);
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
@@ -361,6 +364,70 @@ app.get('/api/vulnerabilities', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Helm releases (reads helm.sh/release.v1 secrets)
|
||||||
|
app.get('/api/helm/releases', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await coreApi.listSecretForAllNamespaces();
|
||||||
|
const helmSecrets = result.body.items.filter(s => s.type === 'helm.sh/release.v1');
|
||||||
|
|
||||||
|
// Keep only latest revision per release
|
||||||
|
const latestMap = {};
|
||||||
|
for (const s of helmSecrets) {
|
||||||
|
const key = `${s.metadata.namespace}/${s.metadata.labels?.name}`;
|
||||||
|
const v = parseInt(s.metadata.labels?.version || '0');
|
||||||
|
if (!latestMap[key] || v > latestMap[key].v) latestMap[key] = { s, v };
|
||||||
|
}
|
||||||
|
|
||||||
|
const releases = [];
|
||||||
|
for (const { s } of Object.values(latestMap)) {
|
||||||
|
try {
|
||||||
|
const compressed = Buffer.from(s.data.release, 'base64');
|
||||||
|
const json = await gunzip(compressed);
|
||||||
|
const r = JSON.parse(json.toString());
|
||||||
|
releases.push({
|
||||||
|
name: r.name,
|
||||||
|
namespace: r.namespace,
|
||||||
|
status: r.info?.status,
|
||||||
|
chartName: r.chart?.metadata?.name,
|
||||||
|
chartVersion: r.chart?.metadata?.version,
|
||||||
|
appVersion: r.chart?.metadata?.appVersion,
|
||||||
|
description: r.chart?.metadata?.description,
|
||||||
|
deployedAt: r.info?.last_deployed,
|
||||||
|
revision: parseInt(s.metadata.labels?.version || '1'),
|
||||||
|
});
|
||||||
|
} catch (e) { console.error('[helm parse]', e.message); }
|
||||||
|
}
|
||||||
|
|
||||||
|
res.json(releases.sort((a, b) => a.name.localeCompare(b.name)));
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[helm]', err.message);
|
||||||
|
res.status(500).json({ error: err.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check Artifact Hub for latest chart version
|
||||||
|
app.get('/api/helm/check-update/:chart', async (req, res) => {
|
||||||
|
const { chart } = req.params;
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`https://artifacthub.io/api/v1/packages/search?ts_query_web=${encodeURIComponent(chart)}&kind=0&limit=10`
|
||||||
|
);
|
||||||
|
const data = await response.json();
|
||||||
|
const packages = data.packages || [];
|
||||||
|
const match = packages.find(p => p.name === chart) || packages[0];
|
||||||
|
if (!match) return res.json({ found: false });
|
||||||
|
res.json({
|
||||||
|
found: true,
|
||||||
|
latestVersion: match.version,
|
||||||
|
appVersion: match.app_version,
|
||||||
|
repoName: match.repository?.name,
|
||||||
|
artifactHubUrl: `https://artifacthub.io/packages/helm/${match.repository?.name}/${match.name}`,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500).json({ error: err.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ── SSE: Live log stream ──────────────────────────────────────────────────────
|
// ── SSE: Live log stream ──────────────────────────────────────────────────────
|
||||||
app.get('/api/logs/:namespace/:pod/:container', async (req, res) => {
|
app.get('/api/logs/:namespace/:pod/:container', async (req, res) => {
|
||||||
const { namespace, pod, container } = req.params;
|
const { namespace, pod, container } = req.params;
|
||||||
|
|||||||
Reference in New Issue
Block a user