mirror of
https://github.com/morten-olsen/homelab-operator.git
synced 2026-02-08 01:36:28 +01:00
updates
This commit is contained in:
206
src/custom-resouces/environment/environment.controller.ts
Normal file
206
src/custom-resouces/environment/environment.controller.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
import { CertificateInstance } from '../../instances/certificate.ts';
|
||||
import { CustomDefinitionInstance } from '../../instances/custom-resource-definition.ts';
|
||||
import { NamespaceInstance } from '../../instances/namespace.ts';
|
||||
import {
|
||||
CustomResource,
|
||||
type CustomResourceOptions,
|
||||
} from '../../services/custom-resources/custom-resources.custom-resource.ts';
|
||||
import { ResourceService } from '../../services/resources/resources.ts';
|
||||
import { GatewayInstance } from '../../instances/gateway.ts';
|
||||
import { PostgresClusterInstance } from '../../instances/postgres-cluster.ts';
|
||||
import { API_VERSION } from '../../utils/consts.ts';
|
||||
import { AuthentikServerInstance } from '../../instances/authentik-server.ts';
|
||||
import { StorageClassInstance } from '../../instances/storageclass.ts';
|
||||
import { PROVISIONER } from '../../storage-provider/storage-provider.ts';
|
||||
|
||||
import type { environmentSpecSchema } from './environment.schemas.ts';
|
||||
|
||||
class EnvironmentController extends CustomResource<typeof environmentSpecSchema> {
|
||||
#namespace: NamespaceInstance;
|
||||
#certificateCrd: CustomDefinitionInstance;
|
||||
#certificate: CertificateInstance;
|
||||
#gatewayCrd: CustomDefinitionInstance;
|
||||
#gateway: GatewayInstance;
|
||||
#storageClass: StorageClassInstance;
|
||||
#postgresCluster: PostgresClusterInstance;
|
||||
#authentikServer: AuthentikServerInstance;
|
||||
|
||||
constructor(options: CustomResourceOptions<typeof environmentSpecSchema>) {
|
||||
super(options);
|
||||
const resourceService = this.services.get(ResourceService);
|
||||
this.#namespace = resourceService.getInstance(
|
||||
{
|
||||
apiVersion: 'v1',
|
||||
kind: 'Namespace',
|
||||
name: this.namespace,
|
||||
},
|
||||
NamespaceInstance,
|
||||
);
|
||||
this.#certificateCrd = resourceService.getInstance(
|
||||
{
|
||||
apiVersion: 'apiextensions.k8s.io/v1',
|
||||
kind: 'CustomResourceDefinition',
|
||||
name: 'certificates.cert-manager.io',
|
||||
},
|
||||
CustomDefinitionInstance,
|
||||
);
|
||||
this.#certificate = resourceService.getInstance(
|
||||
{
|
||||
apiVersion: 'cert-manager.io/v1',
|
||||
kind: 'Certificate',
|
||||
name: this.name,
|
||||
namespace: this.namespace,
|
||||
},
|
||||
CertificateInstance,
|
||||
);
|
||||
this.#gatewayCrd = resourceService.getInstance(
|
||||
{
|
||||
apiVersion: 'apiextensions.k8s.io/v1',
|
||||
kind: 'CustomResourceDefinition',
|
||||
name: 'gateways.networking.istio.io',
|
||||
},
|
||||
CustomDefinitionInstance,
|
||||
);
|
||||
this.#gateway = resourceService.getInstance(
|
||||
{
|
||||
apiVersion: 'networking.istio.io/v1',
|
||||
kind: 'Gateway',
|
||||
name: this.name,
|
||||
namespace: this.namespace,
|
||||
},
|
||||
GatewayInstance,
|
||||
);
|
||||
this.#storageClass = resourceService.getInstance(
|
||||
{
|
||||
apiVersion: 'storage.k8s.io/v1',
|
||||
kind: 'StorageClass',
|
||||
name: `${this.name}-retain`,
|
||||
},
|
||||
StorageClassInstance,
|
||||
);
|
||||
this.#postgresCluster = resourceService.getInstance(
|
||||
{
|
||||
apiVersion: API_VERSION,
|
||||
kind: 'PostgresCluster',
|
||||
name: `${this.name}-postgres-cluster`,
|
||||
namespace: this.namespace,
|
||||
},
|
||||
PostgresClusterInstance,
|
||||
);
|
||||
this.#authentikServer = resourceService.getInstance(
|
||||
{
|
||||
apiVersion: API_VERSION,
|
||||
kind: 'AuthentikServer',
|
||||
name: `${this.name}-authentik-server`,
|
||||
namespace: this.namespace,
|
||||
},
|
||||
AuthentikServerInstance,
|
||||
);
|
||||
this.#gatewayCrd.on('changed', this.queueReconcile);
|
||||
this.#gateway.on('changed', this.queueReconcile);
|
||||
this.#certificateCrd.on('changed', this.queueReconcile);
|
||||
this.#namespace.on('changed', this.queueReconcile);
|
||||
this.#certificate.on('changed', this.queueReconcile);
|
||||
this.#postgresCluster.on('changed', this.queueReconcile);
|
||||
this.#authentikServer.on('changed', this.queueReconcile);
|
||||
this.#storageClass.on('changed', this.queueReconcile);
|
||||
}
|
||||
|
||||
public reconcile = async () => {
|
||||
if (!this.exists || this.metadata?.deletionTimestamp) {
|
||||
return;
|
||||
}
|
||||
await this.#namespace.ensure({
|
||||
metadata: {
|
||||
ownerReferences: [this.ref],
|
||||
labels: {
|
||||
'istio-injection': 'enabled',
|
||||
},
|
||||
},
|
||||
});
|
||||
if (this.#certificateCrd.ready) {
|
||||
await this.#certificate.ensure({
|
||||
metadata: {
|
||||
ownerReferences: [this.ref],
|
||||
},
|
||||
spec: {
|
||||
secretName: `${this.name}-tls`,
|
||||
issuerRef: {
|
||||
name: 'cluster-issuer',
|
||||
kind: 'ClusterIssuer',
|
||||
},
|
||||
dnsNames: [`*.${this.spec.domain}`],
|
||||
privateKey: {
|
||||
rotationPolicy: 'Always',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
if (this.#gatewayCrd.ready) {
|
||||
await this.#gateway.ensure({
|
||||
metadata: {
|
||||
ownerReferences: [this.ref],
|
||||
},
|
||||
spec: {
|
||||
selector: {
|
||||
istio: 'gateway',
|
||||
},
|
||||
servers: [
|
||||
{
|
||||
hosts: [`*.${this.spec.domain}`],
|
||||
port: {
|
||||
name: 'http',
|
||||
number: 80,
|
||||
protocol: 'HTTP',
|
||||
},
|
||||
tls: {
|
||||
httpsRedirect: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
hosts: [`*.${this.spec.domain}`],
|
||||
port: {
|
||||
name: 'https',
|
||||
number: 443,
|
||||
protocol: 'HTTPS',
|
||||
},
|
||||
tls: {
|
||||
mode: 'SIMPLE',
|
||||
credentialName: `${this.name}-tls`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
await this.#storageClass.ensure({
|
||||
provisioner: PROVISIONER,
|
||||
parameters: {
|
||||
storageLocation: this.spec.storage?.location || `/data/volumes/${this.name}`,
|
||||
reclaimPolicy: 'Retain',
|
||||
allowVolumeExpansion: 'true',
|
||||
volumeBindingMode: 'Immediate',
|
||||
},
|
||||
});
|
||||
await this.#postgresCluster.ensure({
|
||||
metadata: {
|
||||
ownerReferences: [this.ref],
|
||||
},
|
||||
spec: {
|
||||
environment: this.name,
|
||||
},
|
||||
});
|
||||
await this.#authentikServer.ensure({
|
||||
metadata: {
|
||||
ownerReferences: [this.ref],
|
||||
},
|
||||
spec: {
|
||||
environment: `${this.namespace}/${this.name}`,
|
||||
subdomain: 'authentik',
|
||||
postgresCluster: `${this.name}-postgres-cluster`,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export { EnvironmentController };
|
||||
14
src/custom-resouces/environment/environment.schemas.ts
Normal file
14
src/custom-resouces/environment/environment.schemas.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
const environmentSpecSchema = z.object({
|
||||
domain: z.string(),
|
||||
storage: z
|
||||
.object({
|
||||
location: z.string().optional(),
|
||||
})
|
||||
.optional(),
|
||||
});
|
||||
|
||||
type EnvironmentSpec = z.infer<typeof environmentSpecSchema>;
|
||||
|
||||
export { environmentSpecSchema, type EnvironmentSpec };
|
||||
19
src/custom-resouces/environment/environment.ts
Normal file
19
src/custom-resouces/environment/environment.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { createCustomResourceDefinition } from '../../services/custom-resources/custom-resources.ts';
|
||||
import { GROUP } from '../../utils/consts.ts';
|
||||
|
||||
import { EnvironmentController } from './environment.controller.ts';
|
||||
import { environmentSpecSchema } from './environment.schemas.ts';
|
||||
|
||||
const environmentDefinition = createCustomResourceDefinition({
|
||||
group: GROUP,
|
||||
version: 'v1',
|
||||
kind: 'Environment',
|
||||
names: {
|
||||
plural: 'environments',
|
||||
singular: 'environment',
|
||||
},
|
||||
spec: environmentSpecSchema,
|
||||
create: (options) => new EnvironmentController(options),
|
||||
});
|
||||
|
||||
export { environmentDefinition };
|
||||
Reference in New Issue
Block a user