mirror of
https://github.com/morten-olsen/homelab-operator.git
synced 2026-02-08 01:36:28 +01:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32576ad37d |
@@ -31,16 +31,69 @@ spec:
|
|||||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
env:
|
||||||
|
# PostgreSQL Host
|
||||||
|
- name: POSTGRES_HOST
|
||||||
|
{{- if .Values.config.postgres.host.fromSecret.enabled }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.config.postgres.host.fromSecret.secretName }}
|
||||||
|
key: {{ .Values.config.postgres.host.fromSecret.key }}
|
||||||
|
{{- else }}
|
||||||
|
value: {{ .Values.config.postgres.host.value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
# PostgreSQL Port
|
||||||
|
- name: POSTGRES_PORT
|
||||||
|
{{- if .Values.config.postgres.port.fromSecret.enabled }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.config.postgres.port.fromSecret.secretName }}
|
||||||
|
key: {{ .Values.config.postgres.port.fromSecret.key }}
|
||||||
|
{{- else }}
|
||||||
|
value: {{ .Values.config.postgres.port.value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
# PostgreSQL User
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
{{- if .Values.config.postgres.user.fromSecret.enabled }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.config.postgres.user.fromSecret.secretName }}
|
||||||
|
key: {{ .Values.config.postgres.user.fromSecret.key }}
|
||||||
|
{{- else }}
|
||||||
|
value: {{ .Values.config.postgres.user.value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
# PostgreSQL Password
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
{{- if .Values.config.postgres.password.fromSecret.enabled }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.config.postgres.password.fromSecret.secretName }}
|
||||||
|
key: {{ .Values.config.postgres.password.fromSecret.key }}
|
||||||
|
{{- else }}
|
||||||
|
value: {{ .Values.config.postgres.password.value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
# Certificate Manager
|
||||||
|
- name: CERT_MANAGER
|
||||||
|
{{- if .Values.config.certManager.fromSecret.enabled }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.config.certManager.fromSecret.secretName }}
|
||||||
|
key: {{ .Values.config.certManager.fromSecret.key }}
|
||||||
|
{{- else }}
|
||||||
|
value: {{ .Values.config.certManager.value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
# Istio Gateway
|
||||||
|
- name: ISTIO_GATEWAY
|
||||||
|
{{- if .Values.config.istioGateway.fromSecret.enabled }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ .Values.config.istioGateway.fromSecret.secretName }}
|
||||||
|
key: {{ .Values.config.istioGateway.fromSecret.key }}
|
||||||
|
{{- else }}
|
||||||
|
value: {{ .Values.config.istioGateway.value | quote }}
|
||||||
|
{{- end }}
|
||||||
resources:
|
resources:
|
||||||
{{- toYaml .Values.resources | nindent 12 }}
|
{{- toYaml .Values.resources | nindent 12 }}
|
||||||
volumeMounts:
|
|
||||||
- name: data-volumes
|
|
||||||
mountPath: {{ .Values.storage.path }}
|
|
||||||
volumes:
|
|
||||||
- name: data-volumes
|
|
||||||
hostPath:
|
|
||||||
path: {{ .Values.storage.path }}
|
|
||||||
type: DirectoryOrCreate
|
|
||||||
{{- with .Values.nodeSelector }}
|
{{- with .Values.nodeSelector }}
|
||||||
nodeSelector:
|
nodeSelector:
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
|
|||||||
@@ -9,11 +9,8 @@ image:
|
|||||||
tag: main
|
tag: main
|
||||||
|
|
||||||
imagePullSecrets: []
|
imagePullSecrets: []
|
||||||
nameOverride: ''
|
nameOverride: ""
|
||||||
fullnameOverride: ''
|
fullnameOverride: ""
|
||||||
|
|
||||||
storage:
|
|
||||||
path: /data/volumes
|
|
||||||
|
|
||||||
serviceAccount:
|
serviceAccount:
|
||||||
# Specifies whether a service account should be created
|
# Specifies whether a service account should be created
|
||||||
@@ -22,7 +19,7 @@ serviceAccount:
|
|||||||
annotations: {}
|
annotations: {}
|
||||||
# The name of the service account to use.
|
# The name of the service account to use.
|
||||||
# If not set and create is true, a name is generated using the fullname template
|
# If not set and create is true, a name is generated using the fullname template
|
||||||
name: ''
|
name: ""
|
||||||
|
|
||||||
podAnnotations: {}
|
podAnnotations: {}
|
||||||
|
|
||||||
@@ -54,3 +51,53 @@ nodeSelector: {}
|
|||||||
tolerations: []
|
tolerations: []
|
||||||
|
|
||||||
affinity: {}
|
affinity: {}
|
||||||
|
|
||||||
|
# Configuration for the homelab operator
|
||||||
|
config:
|
||||||
|
# PostgreSQL database configuration
|
||||||
|
postgres:
|
||||||
|
host:
|
||||||
|
# Direct value (used when fromSecret.enabled is false)
|
||||||
|
value: "127.0.0.1"
|
||||||
|
# Secret reference (used when fromSecret.enabled is true)
|
||||||
|
fromSecret:
|
||||||
|
enabled: false
|
||||||
|
secretName: ""
|
||||||
|
key: "POSTGRES_HOST"
|
||||||
|
|
||||||
|
port:
|
||||||
|
value: "5432"
|
||||||
|
fromSecret:
|
||||||
|
enabled: false
|
||||||
|
secretName: ""
|
||||||
|
key: "POSTGRES_PORT"
|
||||||
|
|
||||||
|
user:
|
||||||
|
value: "postgres"
|
||||||
|
fromSecret:
|
||||||
|
enabled: false
|
||||||
|
secretName: ""
|
||||||
|
key: "POSTGRES_USER"
|
||||||
|
|
||||||
|
password:
|
||||||
|
value: ""
|
||||||
|
fromSecret:
|
||||||
|
enabled: true # Default to secret for sensitive data
|
||||||
|
secretName: "postgres-secret"
|
||||||
|
key: "POSTGRES_PASSWORD"
|
||||||
|
|
||||||
|
# Certificate manager configuration
|
||||||
|
certManager:
|
||||||
|
value: "letsencrypt-prod"
|
||||||
|
fromSecret:
|
||||||
|
enabled: false
|
||||||
|
secretName: ""
|
||||||
|
key: "CERT_MANAGER"
|
||||||
|
|
||||||
|
# Istio gateway configuration
|
||||||
|
istioGateway:
|
||||||
|
value: "istio-ingress"
|
||||||
|
fromSecret:
|
||||||
|
enabled: false
|
||||||
|
secretName: ""
|
||||||
|
key: "ISTIO_GATEWAY"
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
import { K8sService } from '../src/services/k8s/k8s.ts';
|
|
||||||
import { Services } from '../src/utils/service.ts';
|
|
||||||
|
|
||||||
const services = new Services();
|
|
||||||
const k8s = services.get(K8sService);
|
|
||||||
|
|
||||||
const manifests = await k8s.extensionsApi.listCustomResourceDefinition();
|
|
||||||
|
|
||||||
for (const manifest of manifests.items) {
|
|
||||||
for (const version of manifest.spec.versions) {
|
|
||||||
console.log(`group: ${manifest.spec.group}, plural: ${manifest.spec.names.plural}, version: ${version.name}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,6 @@ import { Services } from './utils/service.ts';
|
|||||||
import { CustomResourceService } from './services/custom-resources/custom-resources.ts';
|
import { CustomResourceService } from './services/custom-resources/custom-resources.ts';
|
||||||
import { WatcherService } from './services/watchers/watchers.ts';
|
import { WatcherService } from './services/watchers/watchers.ts';
|
||||||
import { customResources } from './custom-resouces/custom-resources.ts';
|
import { customResources } from './custom-resouces/custom-resources.ts';
|
||||||
import { StorageProvider } from './storage-provider/storage-provider.ts';
|
|
||||||
|
|
||||||
process.on('uncaughtException', (error) => {
|
process.on('uncaughtException', (error) => {
|
||||||
console.log('UNCAUGHT EXCEPTION');
|
console.log('UNCAUGHT EXCEPTION');
|
||||||
@@ -30,8 +29,6 @@ process.on('unhandledRejection', (error) => {
|
|||||||
|
|
||||||
const services = new Services();
|
const services = new Services();
|
||||||
const watcherService = services.get(WatcherService);
|
const watcherService = services.get(WatcherService);
|
||||||
const storageProvider = services.get(StorageProvider);
|
|
||||||
await storageProvider.start();
|
|
||||||
await watcherService
|
await watcherService
|
||||||
.create({
|
.create({
|
||||||
path: '/apis/apiextensions.k8s.io/v1/customresourcedefinitions',
|
path: '/apis/apiextensions.k8s.io/v1/customresourcedefinitions',
|
||||||
@@ -79,4 +76,4 @@ const customResourceService = services.get(CustomResourceService);
|
|||||||
customResourceService.register(...customResources);
|
customResourceService.register(...customResources);
|
||||||
|
|
||||||
await customResourceService.install(true);
|
await customResourceService.install(true);
|
||||||
// await customResourceService.watch();
|
await customResourceService.watch();
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
import { mkdir } from 'fs/promises';
|
|
||||||
|
|
||||||
import { V1PersistentVolume, type V1PersistentVolumeClaim } from '@kubernetes/client-node';
|
|
||||||
|
|
||||||
import { Watcher, WatcherService } from '../services/watchers/watchers.ts';
|
|
||||||
import type { Services } from '../utils/service.ts';
|
|
||||||
import { ResourceService, type Resource } from '../services/resources/resources.ts';
|
|
||||||
|
|
||||||
const PROVISIONER = 'reuse-local-path-provisioner';
|
|
||||||
|
|
||||||
class StorageProvider {
|
|
||||||
#watcher: Watcher<V1PersistentVolumeClaim>;
|
|
||||||
#services: Services;
|
|
||||||
|
|
||||||
constructor(services: Services) {
|
|
||||||
this.#services = services;
|
|
||||||
const watchService = this.#services.get(WatcherService);
|
|
||||||
this.#watcher = watchService.create({
|
|
||||||
path: '/api/v1/persistentvolumeclaims',
|
|
||||||
transform: (manifest) => ({
|
|
||||||
apiVersion: 'v1',
|
|
||||||
kind: 'PersistentVolumeClaim',
|
|
||||||
...manifest,
|
|
||||||
}),
|
|
||||||
list: async (k8s) => {
|
|
||||||
const current = await k8s.api.listPersistentVolumeClaimForAllNamespaces();
|
|
||||||
return current;
|
|
||||||
},
|
|
||||||
verbs: ['add', 'update', 'delete'],
|
|
||||||
});
|
|
||||||
this.#watcher.on('changed', this.#handleChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
#handleChange = async (pvc: Resource<V1PersistentVolumeClaim>) => {
|
|
||||||
if (pvc.metadata?.annotations?.['volume.kubernetes.io/storage-provisioner'] !== PROVISIONER) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const target = `/data/volumes/${pvc.namespace}/${pvc.name}`;
|
|
||||||
try {
|
|
||||||
await mkdir(target, { recursive: true });
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
const resourceService = this.#services.get(ResourceService);
|
|
||||||
const pv = resourceService.get<V1PersistentVolume>({
|
|
||||||
apiVersion: 'v1',
|
|
||||||
kind: 'PersistentVolume',
|
|
||||||
name: `${pvc.namespace}-${pvc.name}`,
|
|
||||||
});
|
|
||||||
await pv.load();
|
|
||||||
await pv.patch({
|
|
||||||
metadata: {
|
|
||||||
labels: {
|
|
||||||
provisioner: PROVISIONER,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
spec: {
|
|
||||||
hostPath: {
|
|
||||||
path: target,
|
|
||||||
},
|
|
||||||
capacity: {
|
|
||||||
storage: pvc.spec?.resources?.requests?.storage ?? '1Gi',
|
|
||||||
},
|
|
||||||
persistentVolumeReclaimPolicy: 'Retain',
|
|
||||||
accessModes: pvc.spec?.accessModes,
|
|
||||||
claimRef: {
|
|
||||||
uid: pvc.metadata?.uid,
|
|
||||||
resourceVersion: pvc.metadata?.resourceVersion,
|
|
||||||
apiVersion: pvc.apiVersion,
|
|
||||||
name: pvc.name,
|
|
||||||
namespace: pvc.namespace,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
public start = async () => {
|
|
||||||
await this.#watcher.start();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export { StorageProvider };
|
|
||||||
Reference in New Issue
Block a user