Add a stateful Proxmox API console and broad handler coverage beyond the
initial QEMU slice, backed by imported contracts for majors 6–9. - Implement durable handlers for access/auth, cluster, LXC, storage, HA, firewall, Ceph, SDN, ACME, notifications, pools, mapping, and node ops - Serve an interactive Web UI with catalog browsing, demo seed controls, and OpenAPI/help surfaces - Bundle PVE 6.4-15, 7.4-16, and 8.4.5 contract revisions alongside 9.2.3 - Support in-memory runtime contract Apply (POST /ui/api/contract/apply) so /version and /api2 routes follow the selected major until restart - Expand seed profiles (including demo-cluster), migrations 007–008, TLS gateway config, Compose/Makefile tooling, and compatibility evidence - Tighten .gitignore for macOS, hidden directories (.*/), and local secrets
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
.DS_Store
|
||||
.git
|
||||
.gitignore
|
||||
*.md
|
||||
*.tgz
|
||||
charts/*.tgz
|
||||
values-ingress-example.yaml
|
||||
@@ -0,0 +1,16 @@
|
||||
apiVersion: v2
|
||||
name: proxmox-api-simulator
|
||||
description: Stateful Proxmox VE API simulator (PostgreSQL-backed) for labs and CI
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "0.1.0"
|
||||
home: https://github.com/inecs/proxmox-api-simulator
|
||||
keywords:
|
||||
- proxmox
|
||||
- pve
|
||||
- api
|
||||
- simulator
|
||||
maintainers:
|
||||
- name: inecs
|
||||
# Bundled PostgreSQL uses the official postgres image (see templates/postgresql-*.yaml).
|
||||
# No external chart dependency is required — run helm install directly.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Helm chart: proxmox-api-simulator
|
||||
|
||||
Deploys the published runtime image
|
||||
[`inecs/proxmox-api-simulator`](https://hub.docker.com/r/inecs/proxmox-api-simulator)
|
||||
with optional Bitnami PostgreSQL, migrations, seed Job, Ingress, and
|
||||
cert-manager Let's Encrypt `ClusterIssuer` resources.
|
||||
|
||||
Full guide: [docs/kubernetes.md](../../docs/kubernetes.md).
|
||||
|
||||
## Quick install
|
||||
|
||||
Prerequisites: Kubernetes, Helm 3, ingress-nginx (or compatible), cert-manager.
|
||||
|
||||
```bash
|
||||
helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
|
||||
-n proxmox-sim --create-namespace \
|
||||
-f ./helm/proxmox-api-simulator/values-ingress-example.yaml \
|
||||
--set certManager.email=you@example.com \
|
||||
--set ingress.hosts[0].host=pve-sim.example.com \
|
||||
--set ingress.tls[0].hosts[0]=pve-sim.example.com \
|
||||
--set secret.ticketSigningKey="$(openssl rand -hex 32)" \
|
||||
--set postgresql.auth.password="$(openssl rand -hex 16)"
|
||||
```
|
||||
|
||||
Point DNS for your host at the Ingress controller, wait for the Certificate to
|
||||
become Ready, then open `https://pve-sim.example.com/`.
|
||||
|
||||
## Values overview
|
||||
|
||||
| Key | Default | Meaning |
|
||||
|---|---|---|
|
||||
| `image.repository` | `inecs/proxmox-api-simulator` | Hub image |
|
||||
| `image.tag` | chart `appVersion` | Image tag |
|
||||
| `postgresql.enabled` | `true` | Bundle official PostgreSQL StatefulSet |
|
||||
| `secret.databaseUrl` / `externalDatabase.*` | | External DB when postgres disabled |
|
||||
| `ingress.enabled` | `false` | Expose via Ingress |
|
||||
| `certManager.enabled` | `false` | Annotate Ingress + optional ClusterIssuers |
|
||||
| `seed.enabled` | `false` | Post-install seed Job |
|
||||
|
||||
See [`values.yaml`](values.yaml) and [`values-ingress-example.yaml`](values-ingress-example.yaml).
|
||||
@@ -0,0 +1,32 @@
|
||||
proxmox-api-simulator {{ .Chart.AppVersion }} installed as release "{{ .Release.Name }}".
|
||||
|
||||
Image: {{ include "proxmox-api-simulator.image" . }}
|
||||
|
||||
1. Check readiness:
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} get pods -l "app.kubernetes.io/instance={{ .Release.Name }}"
|
||||
|
||||
2. Access the API / Web UI:
|
||||
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
https://{{ .host }}/
|
||||
{{- end }}
|
||||
{{- if .Values.certManager.enabled }}
|
||||
TLS certificate is requested via cert-manager ClusterIssuer
|
||||
"{{ include "proxmox-api-simulator.clusterIssuer" . }}".
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
kubectl -n {{ .Release.Namespace }} port-forward svc/{{ include "proxmox-api-simulator.fullname" . }} 8006:{{ .Values.service.port }}
|
||||
Then open http://127.0.0.1:8006/
|
||||
{{- end }}
|
||||
|
||||
3. Seed laboratory data (if seed.enabled was false):
|
||||
|
||||
kubectl -n {{ .Release.Namespace }} exec deploy/{{ include "proxmox-api-simulator.fullname" . }} -- \
|
||||
python -m app.simulation.seed_cli
|
||||
|
||||
Or upgrade with --set seed.enabled=true,seed.profile=small
|
||||
|
||||
Default lab login after seeding: root@pam / secret
|
||||
Change secret.ticketSigningKey before exposing the cluster publicly.
|
||||
@@ -0,0 +1,121 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.labels" -}}
|
||||
helm.sh/chart: {{ include "proxmox-api-simulator.chart" . }}
|
||||
{{ include "proxmox-api-simulator.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "proxmox-api-simulator.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Service account name
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "proxmox-api-simulator.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Image reference
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.image" -}}
|
||||
{{- $tag := .Values.image.tag | default .Chart.AppVersion }}
|
||||
{{- printf "%s:%s" .Values.image.repository $tag }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Secret name holding DATABASE_URL and TICKET_SIGNING_KEY
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.secretName" -}}
|
||||
{{- if .Values.secret.existingSecret }}
|
||||
{{- .Values.secret.existingSecret }}
|
||||
{{- else }}
|
||||
{{- include "proxmox-api-simulator.fullname" . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PostgreSQL hostname when bundled subchart is enabled
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.postgresqlHost" -}}
|
||||
{{- printf "%s-postgresql" .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Build DATABASE_URL when not supplied explicitly (bundled or external discrete fields).
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.databaseUrl" -}}
|
||||
{{- if .Values.secret.databaseUrl }}
|
||||
{{- .Values.secret.databaseUrl }}
|
||||
{{- else if .Values.postgresql.enabled }}
|
||||
{{- $user := .Values.postgresql.auth.username }}
|
||||
{{- $pass := .Values.postgresql.auth.password }}
|
||||
{{- $db := .Values.postgresql.auth.database }}
|
||||
{{- $host := include "proxmox-api-simulator.postgresqlHost" . }}
|
||||
{{- printf "postgresql://%s:%s@%s:5432/%s" $user $pass $host $db }}
|
||||
{{- else if .Values.externalDatabase.host }}
|
||||
{{- $user := .Values.externalDatabase.user }}
|
||||
{{- $pass := .Values.externalDatabase.password }}
|
||||
{{- $db := .Values.externalDatabase.database }}
|
||||
{{- $host := .Values.externalDatabase.host }}
|
||||
{{- $port := int .Values.externalDatabase.port }}
|
||||
{{- printf "postgresql://%s:%s@%s:%d/%s" $user $pass $host $port $db }}
|
||||
{{- else }}
|
||||
{{- fail "Set postgresql.enabled=true, or secret.databaseUrl / secret.existingSecret, or externalDatabase.host" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
cert-manager ClusterIssuer name used by Ingress
|
||||
*/}}
|
||||
{{- define "proxmox-api-simulator.clusterIssuer" -}}
|
||||
{{- if .Values.certManager.useStaging }}
|
||||
{{- .Values.certManager.stagingIssuerName }}
|
||||
{{- else }}
|
||||
{{- .Values.certManager.issuerName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,42 @@
|
||||
{{- if and .Values.certManager.enabled .Values.certManager.createClusterIssuer }}
|
||||
{{- $solverClass := .Values.certManager.solverIngressClassName | default .Values.ingress.className }}
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: {{ .Values.certManager.issuerName }}
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
spec:
|
||||
acme:
|
||||
email: {{ required "certManager.email is required when createClusterIssuer=true" .Values.certManager.email | quote }}
|
||||
server: {{ .Values.certManager.server | quote }}
|
||||
privateKeySecretRef:
|
||||
name: {{ printf "%s-account-key" .Values.certManager.issuerName }}
|
||||
solvers:
|
||||
- http01:
|
||||
ingress:
|
||||
{{- if $solverClass }}
|
||||
ingressClassName: {{ $solverClass }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- if .Values.certManager.createStagingIssuer }}
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: {{ .Values.certManager.stagingIssuerName }}
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
spec:
|
||||
acme:
|
||||
email: {{ .Values.certManager.email | quote }}
|
||||
server: {{ .Values.certManager.stagingServer | quote }}
|
||||
privateKeySecretRef:
|
||||
name: {{ printf "%s-account-key" .Values.certManager.stagingIssuerName }}
|
||||
solvers:
|
||||
- http01:
|
||||
ingress:
|
||||
{{- if $solverClass }}
|
||||
ingressClassName: {{ $solverClass }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,148 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "proxmox-api-simulator.fullname" . }}
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "proxmox-api-simulator.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "proxmox-api-simulator.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
{{- if and .Values.migrate.enabled (not .Values.migrate.asJob) }}
|
||||
initContainers:
|
||||
- name: migrate
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: {{ include "proxmox-api-simulator.image" . }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "proxmox-api-simulator.secretName" . }}
|
||||
key: DATABASE_URL
|
||||
- name: LOG_LEVEL
|
||||
value: {{ .Values.config.logLevel | quote }}
|
||||
command:
|
||||
- python
|
||||
- -c
|
||||
- |
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
import asyncpg
|
||||
|
||||
dsn = os.environ["DATABASE_URL"]
|
||||
deadline = time.time() + 300
|
||||
while True:
|
||||
try:
|
||||
async def ping() -> None:
|
||||
conn = await asyncpg.connect(dsn=dsn, timeout=5)
|
||||
await conn.close()
|
||||
|
||||
asyncio.run(ping())
|
||||
break
|
||||
except Exception as exc: # noqa: BLE001 - wait until Postgres accepts connections
|
||||
if time.time() >= deadline:
|
||||
print(f"database not ready: {exc}", file=sys.stderr)
|
||||
raise
|
||||
print(f"waiting for database: {exc}")
|
||||
time.sleep(3)
|
||||
|
||||
from app.db.migrate_cli import run
|
||||
|
||||
asyncio.run(run())
|
||||
resources:
|
||||
{{- toYaml .Values.migrate.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: simulator
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: {{ include "proxmox-api-simulator.image" . }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8006
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: APP_HOST
|
||||
value: "0.0.0.0"
|
||||
- name: APP_PORT
|
||||
value: "8006"
|
||||
- name: LOG_LEVEL
|
||||
value: {{ .Values.config.logLevel | quote }}
|
||||
- name: CONTRACT_SNAPSHOT
|
||||
value: {{ .Values.config.contractSnapshot | quote }}
|
||||
- name: COMPATIBILITY_EVIDENCE
|
||||
value: {{ .Values.config.compatibilityEvidence | quote }}
|
||||
- name: CONTRACT_FALLBACK
|
||||
value: {{ .Values.config.contractFallback | quote }}
|
||||
- name: TASK_WORKER_CONCURRENCY
|
||||
value: {{ .Values.config.taskWorkerConcurrency | quote }}
|
||||
- name: TASK_LEASE_SECONDS
|
||||
value: {{ .Values.config.taskLeaseSeconds | quote }}
|
||||
- name: SIMULATION_TIME_SCALE
|
||||
value: {{ .Values.config.simulationTimeScale | quote }}
|
||||
- name: REQUEST_ID_HEADER
|
||||
value: {{ .Values.config.requestIdHeader | quote }}
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "proxmox-api-simulator.secretName" . }}
|
||||
key: DATABASE_URL
|
||||
- name: TICKET_SIGNING_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "proxmox-api-simulator.secretName" . }}
|
||||
key: TICKET_SIGNING_KEY
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.livenessProbe | nindent 12 }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.readinessProbe | nindent 12 }}
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,46 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
{{- $fullName := include "proxmox-api-simulator.fullname" . -}}
|
||||
{{- $svcPort := .Values.service.port -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ $fullName }}
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
{{- if .Values.certManager.enabled }}
|
||||
cert-manager.io/cluster-issuer: {{ include "proxmox-api-simulator.clusterIssuer" . | quote }}
|
||||
{{- end }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.ingress.className }}
|
||||
ingressClassName: {{ . }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls }}
|
||||
tls:
|
||||
{{- range .Values.ingress.tls }}
|
||||
- hosts:
|
||||
{{- range .hosts }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
secretName: {{ .secretName }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- range .Values.ingress.hosts }}
|
||||
- host: {{ .host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ $fullName }}
|
||||
port:
|
||||
number: {{ $svcPort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,50 @@
|
||||
{{- /* Kept for optional standalone migrate Job when migrate.asJob=true */ -}}
|
||||
{{- if and .Values.migrate.enabled .Values.migrate.asJob }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ include "proxmox-api-simulator.fullname" . }}-migrate
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: migrate
|
||||
spec:
|
||||
backoffLimit: {{ .Values.migrate.backoffLimit }}
|
||||
activeDeadlineSeconds: {{ .Values.migrate.activeDeadlineSeconds }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: migrate
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "proxmox-api-simulator.serviceAccountName" . }}
|
||||
restartPolicy: OnFailure
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
- name: migrate
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: {{ include "proxmox-api-simulator.image" . }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "proxmox-api-simulator.secretName" . }}
|
||||
key: DATABASE_URL
|
||||
- name: LOG_LEVEL
|
||||
value: {{ .Values.config.logLevel | quote }}
|
||||
command: ["python", "-m", "app.db.migrate_cli"]
|
||||
resources:
|
||||
{{- toYaml .Values.migrate.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,19 @@
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "proxmox-api-simulator.postgresqlHost" . }}
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: postgresql
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: postgresql
|
||||
protocol: TCP
|
||||
name: postgresql
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "proxmox-api-simulator.name" . }}-postgresql
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,71 @@
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ include "proxmox-api-simulator.postgresqlHost" . }}
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: postgresql
|
||||
spec:
|
||||
serviceName: {{ include "proxmox-api-simulator.postgresqlHost" . }}
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "proxmox-api-simulator.name" . }}-postgresql
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "proxmox-api-simulator.name" . }}-postgresql
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: postgresql
|
||||
spec:
|
||||
containers:
|
||||
- name: postgresql
|
||||
image: {{ printf "%s:%s" .Values.postgresql.image.repository .Values.postgresql.image.tag | quote }}
|
||||
imagePullPolicy: {{ .Values.postgresql.image.pullPolicy }}
|
||||
ports:
|
||||
- name: postgresql
|
||||
containerPort: 5432
|
||||
env:
|
||||
- name: POSTGRES_DB
|
||||
value: {{ .Values.postgresql.auth.database | quote }}
|
||||
- name: POSTGRES_USER
|
||||
value: {{ .Values.postgresql.auth.username | quote }}
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: {{ .Values.postgresql.auth.password | quote }}
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
livenessProbe:
|
||||
exec:
|
||||
command: ["pg_isready", "-U", {{ .Values.postgresql.auth.username | quote }}]
|
||||
initialDelaySeconds: 20
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
exec:
|
||||
command: ["pg_isready", "-U", {{ .Values.postgresql.auth.username | quote }}]
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
{{- toYaml .Values.postgresql.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
{{- if .Values.postgresql.persistence.enabled }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
spec:
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
{{- with .Values.postgresql.persistence.storageClass }}
|
||||
storageClassName: {{ . | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.postgresql.persistence.size }}
|
||||
{{- else }}
|
||||
volumes:
|
||||
- name: data
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,12 @@
|
||||
{{- if and .Values.secret.create (not .Values.secret.existingSecret) }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "proxmox-api-simulator.fullname" . }}
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
DATABASE_URL: {{ include "proxmox-api-simulator.databaseUrl" . | quote }}
|
||||
TICKET_SIGNING_KEY: {{ required "secret.ticketSigningKey is required when secret.create=true" .Values.secret.ticketSigningKey | quote }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,54 @@
|
||||
{{- if .Values.seed.enabled }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ include "proxmox-api-simulator.fullname" . }}-seed
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: seed
|
||||
annotations:
|
||||
"helm.sh/hook": post-install,post-upgrade
|
||||
"helm.sh/hook-weight": "5"
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
spec:
|
||||
backoffLimit: {{ .Values.seed.backoffLimit }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: seed
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "proxmox-api-simulator.serviceAccountName" . }}
|
||||
restartPolicy: OnFailure
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
- name: seed
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: {{ include "proxmox-api-simulator.image" . }}
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "proxmox-api-simulator.secretName" . }}
|
||||
key: DATABASE_URL
|
||||
- name: SEED_PROFILE
|
||||
value: {{ .Values.seed.profile | quote }}
|
||||
- name: LOG_LEVEL
|
||||
value: {{ .Values.config.logLevel | quote }}
|
||||
command: ["python", "-m", "app.simulation.seed_cli"]
|
||||
resources:
|
||||
{{- toYaml .Values.seed.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,15 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "proxmox-api-simulator.fullname" . }}
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "proxmox-api-simulator.selectorLabels" . | nindent 4 }}
|
||||
@@ -0,0 +1,13 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "proxmox-api-simulator.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "proxmox-api-simulator.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: false
|
||||
{{- end }}
|
||||
@@ -0,0 +1,53 @@
|
||||
# Example: public Ingress + Let's Encrypt (cert-manager) + Hub image.
|
||||
#
|
||||
# helm upgrade --install pve-sim ./helm/proxmox-api-simulator \
|
||||
# -n proxmox-sim --create-namespace \
|
||||
# -f helm/proxmox-api-simulator/values-ingress-example.yaml \
|
||||
# --set certManager.email=you@example.com \
|
||||
# --set ingress.hosts[0].host=pve-sim.example.com \
|
||||
# --set ingress.tls[0].hosts[0]=pve-sim.example.com \
|
||||
# --set secret.ticketSigningKey="$(openssl rand -hex 32)"
|
||||
|
||||
image:
|
||||
repository: inecs/proxmox-api-simulator
|
||||
tag: "0.1.0"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
secret:
|
||||
create: true
|
||||
ticketSigningKey: "replace-me"
|
||||
|
||||
postgresql:
|
||||
enabled: true
|
||||
auth:
|
||||
username: proxmox
|
||||
password: "replace-me-db-password"
|
||||
database: proxmox_simulator
|
||||
|
||||
seed:
|
||||
enabled: true
|
||||
profile: small
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: nginx
|
||||
hosts:
|
||||
- host: pve-sim.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: proxmox-api-simulator-tls
|
||||
hosts:
|
||||
- pve-sim.example.com
|
||||
|
||||
certManager:
|
||||
enabled: true
|
||||
createClusterIssuer: true
|
||||
createStagingIssuer: true
|
||||
email: you@example.com
|
||||
issuerName: letsencrypt-prod
|
||||
stagingIssuerName: letsencrypt-staging
|
||||
# Set true first to validate HTTP-01 against Let's Encrypt staging.
|
||||
useStaging: false
|
||||
solverIngressClassName: nginx
|
||||
@@ -0,0 +1,177 @@
|
||||
## Default values for proxmox-api-simulator.
|
||||
## Image: https://hub.docker.com/r/inecs/proxmox-api-simulator
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: inecs/proxmox-api-simulator
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: ""
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
create: true
|
||||
annotations: {}
|
||||
name: ""
|
||||
|
||||
podAnnotations: {}
|
||||
podLabels: {}
|
||||
|
||||
podSecurityContext:
|
||||
fsGroup: 10001
|
||||
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 10001
|
||||
runAsGroup: 10001
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
readOnlyRootFilesystem: true
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8006
|
||||
|
||||
## Application environment (non-secret).
|
||||
config:
|
||||
logLevel: INFO
|
||||
contractSnapshot: /app/contracts/pve-9.2.3.json
|
||||
compatibilityEvidence: /app/evidence/pve-9.2.3.json
|
||||
contractFallback: error
|
||||
taskWorkerConcurrency: 2
|
||||
taskLeaseSeconds: "30"
|
||||
simulationTimeScale: "10"
|
||||
requestIdHeader: X-Request-ID
|
||||
|
||||
## Secrets. Prefer existingSecret in production.
|
||||
secret:
|
||||
# Create a Secret from the values below when existingSecret is empty.
|
||||
create: true
|
||||
existingSecret: ""
|
||||
# Keys expected in an existing secret (when existingSecret is set):
|
||||
# DATABASE_URL, TICKET_SIGNING_KEY
|
||||
ticketSigningKey: "change-me-to-a-long-random-secret"
|
||||
# Used only when postgresql.enabled=true and databaseUrl is empty.
|
||||
# The chart builds postgresql://USER:PASSWORD@HOST:5432/DB
|
||||
databaseUrl: ""
|
||||
|
||||
## Bundled PostgreSQL (official image — same major as docker-compose.release.yml).
|
||||
postgresql:
|
||||
enabled: true
|
||||
image:
|
||||
repository: postgres
|
||||
tag: "17.5-bookworm"
|
||||
pullPolicy: IfNotPresent
|
||||
auth:
|
||||
username: proxmox
|
||||
password: proxmox
|
||||
database: proxmox_simulator
|
||||
persistence:
|
||||
enabled: true
|
||||
size: 8Gi
|
||||
storageClass: ""
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
memory: 512Mi
|
||||
|
||||
## External database when postgresql.enabled=false.
|
||||
## Provide either full URL (secret.databaseUrl / existingSecret) or discrete fields.
|
||||
externalDatabase:
|
||||
host: ""
|
||||
port: 5432
|
||||
user: proxmox
|
||||
password: ""
|
||||
database: proxmox_simulator
|
||||
# Optional existing secret with key database-password (or set password above).
|
||||
existingSecret: ""
|
||||
existingSecretPasswordKey: database-password
|
||||
|
||||
## Database migrations.
|
||||
## Default: idempotent initContainer on the Deployment (recommended).
|
||||
## Set asJob=true to run a standalone Job instead.
|
||||
migrate:
|
||||
enabled: true
|
||||
asJob: false
|
||||
backoffLimit: 20
|
||||
activeDeadlineSeconds: 600
|
||||
resources: {}
|
||||
|
||||
## Optional post-install seed Job (lab data).
|
||||
seed:
|
||||
enabled: false
|
||||
profile: small
|
||||
backoffLimit: 3
|
||||
resources: {}
|
||||
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: "1"
|
||||
memory: 1Gi
|
||||
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health/live
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health/ready
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 8
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
## Ingress + TLS via cert-manager (Let's Encrypt).
|
||||
ingress:
|
||||
enabled: false
|
||||
className: nginx
|
||||
annotations: {}
|
||||
# Extra annotations merged after cert-manager ones when certManager.enabled.
|
||||
hosts:
|
||||
- host: pve-sim.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: proxmox-api-simulator-tls
|
||||
hosts:
|
||||
- pve-sim.example.com
|
||||
|
||||
## cert-manager ClusterIssuers for Let's Encrypt.
|
||||
## Requires cert-manager already installed in the cluster.
|
||||
certManager:
|
||||
enabled: false
|
||||
# Create ClusterIssuer resources from this chart.
|
||||
createClusterIssuer: true
|
||||
email: admin@example.com
|
||||
# Production issuer (used by Ingress by default).
|
||||
issuerName: letsencrypt-prod
|
||||
server: https://acme-v02.api.letsencrypt.org/directory
|
||||
# Staging issuer (optional; useful for dry-runs).
|
||||
createStagingIssuer: true
|
||||
stagingIssuerName: letsencrypt-staging
|
||||
stagingServer: https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
# Which issuer the Ingress annotation should reference.
|
||||
useStaging: false
|
||||
# ACME HTTP-01 solver ingress class (usually same as ingress.className).
|
||||
solverIngressClassName: ""
|
||||
Reference in New Issue
Block a user