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:
@@ -9,4 +9,6 @@ metadata:
|
|||||||
name: dev
|
name: dev
|
||||||
namespace: dev
|
namespace: dev
|
||||||
spec:
|
spec:
|
||||||
domain: dev.mortenolsen.pro
|
domain: one.dev.olsen.cloud
|
||||||
|
tls:
|
||||||
|
issuer: letsencrypt-prod
|
||||||
@@ -16,6 +16,8 @@ import { API_VERSION } from '../../utils/consts.ts';
|
|||||||
import { getWithNamespace } from '../../utils/naming.ts';
|
import { getWithNamespace } from '../../utils/naming.ts';
|
||||||
import { decodeSecret, encodeSecret } from '../../utils/secrets.ts';
|
import { decodeSecret, encodeSecret } from '../../utils/secrets.ts';
|
||||||
import type { environmentSpecSchema } from '../environment/environment.schemas.ts';
|
import type { environmentSpecSchema } from '../environment/environment.schemas.ts';
|
||||||
|
import { HttpServiceInstance } from '../../instances/http-service.ts';
|
||||||
|
import type { redisServerSpecSchema } from '../redis-server/redis-server.schemas.ts';
|
||||||
|
|
||||||
import { authentikServerInitSecretSchema, type authentikServerSpecSchema } from './authentik-server.schemas.ts';
|
import { authentikServerInitSecretSchema, type authentikServerSpecSchema } from './authentik-server.schemas.ts';
|
||||||
|
|
||||||
@@ -25,6 +27,8 @@ class AuthentikServerController extends CustomResource<typeof authentikServerSpe
|
|||||||
#authentikSecret: SecretInstance;
|
#authentikSecret: SecretInstance;
|
||||||
#authentikRelease: HelmReleaseInstance;
|
#authentikRelease: HelmReleaseInstance;
|
||||||
#postgresSecret: ResourceReference<V1Secret>;
|
#postgresSecret: ResourceReference<V1Secret>;
|
||||||
|
#httpService: HttpServiceInstance;
|
||||||
|
#redisServer: ResourceReference<CustomResourceObject<typeof redisServerSpecSchema>>;
|
||||||
|
|
||||||
constructor(options: CustomResourceOptions<typeof authentikServerSpecSchema>) {
|
constructor(options: CustomResourceOptions<typeof authentikServerSpecSchema>) {
|
||||||
super(options);
|
super(options);
|
||||||
@@ -62,12 +66,24 @@ class AuthentikServerController extends CustomResource<typeof authentikServerSpe
|
|||||||
},
|
},
|
||||||
HelmReleaseInstance,
|
HelmReleaseInstance,
|
||||||
);
|
);
|
||||||
|
this.#httpService = resourceService.getInstance(
|
||||||
|
{
|
||||||
|
apiVersion: API_VERSION,
|
||||||
|
kind: 'HttpService',
|
||||||
|
name: this.name,
|
||||||
|
namespace: this.namespace,
|
||||||
|
},
|
||||||
|
HttpServiceInstance,
|
||||||
|
);
|
||||||
|
this.#redisServer = new ResourceReference();
|
||||||
this.#postgresSecret = new ResourceReference();
|
this.#postgresSecret = new ResourceReference();
|
||||||
this.#authentikSecret.on('changed', this.queueReconcile);
|
this.#authentikSecret.on('changed', this.queueReconcile);
|
||||||
this.#authentikInitSecret.resource.on('deleted', this.queueReconcile);
|
this.#authentikInitSecret.resource.on('deleted', this.queueReconcile);
|
||||||
this.#environment.on('changed', this.queueReconcile);
|
this.#environment.on('changed', this.queueReconcile);
|
||||||
this.#authentikRelease.on('changed', this.queueReconcile);
|
this.#authentikRelease.on('changed', this.queueReconcile);
|
||||||
this.#postgresSecret.on('changed', this.queueReconcile);
|
this.#postgresSecret.on('changed', this.queueReconcile);
|
||||||
|
this.#httpService.on('changed', this.queueReconcile);
|
||||||
|
this.#redisServer.on('changed', this.queueReconcile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public reconcile = async () => {
|
public reconcile = async () => {
|
||||||
@@ -126,6 +142,9 @@ class AuthentikServerController extends CustomResource<typeof authentikServerSpe
|
|||||||
|
|
||||||
const repoService = this.services.get(RepoService);
|
const repoService = this.services.get(RepoService);
|
||||||
|
|
||||||
|
const redisNames = getWithNamespace(this.spec.redisServer, this.namespace);
|
||||||
|
const redisHost = `${redisNames.name}.${redisNames.namespace}.svc.cluster.local`;
|
||||||
|
|
||||||
await this.#authentikRelease.ensure({
|
await this.#authentikRelease.ensure({
|
||||||
metadata: {
|
metadata: {
|
||||||
ownerReferences: [this.ref],
|
ownerReferences: [this.ref],
|
||||||
@@ -165,7 +184,7 @@ class AuthentikServerController extends CustomResource<typeof authentikServerSpe
|
|||||||
password: 'file:///postgres-creds/password',
|
password: 'file:///postgres-creds/password',
|
||||||
},
|
},
|
||||||
redis: {
|
redis: {
|
||||||
host: `redis.${this.namespace}.svc.cluster.local`,
|
host: redisHost,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
@@ -205,6 +224,22 @@ class AuthentikServerController extends CustomResource<typeof authentikServerSpe
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await this.#httpService.ensure({
|
||||||
|
metadata: {
|
||||||
|
ownerReferences: [this.ref],
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
environment: this.spec.environment,
|
||||||
|
subdomain: this.spec.subdomain,
|
||||||
|
destination: {
|
||||||
|
host: `${this.name}-server.${this.namespace}.svc.cluster.local`,
|
||||||
|
port: {
|
||||||
|
number: 443,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
const authentikServerSpecSchema = z.object({
|
const authentikServerSpecSchema = z.object({
|
||||||
|
redisServer: z.string(),
|
||||||
postgresCluster: z.string(),
|
postgresCluster: z.string(),
|
||||||
environment: z.string(),
|
environment: z.string(),
|
||||||
subdomain: z.string(),
|
subdomain: z.string(),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { generateSecretDefinition } from './generate-secret/generate-secret.ts';
|
|||||||
import { httpServiceDefinition } from './http-service/http-service.ts';
|
import { httpServiceDefinition } from './http-service/http-service.ts';
|
||||||
import { postgresClusterDefinition } from './postgres-cluster/postgres-cluster.ts';
|
import { postgresClusterDefinition } from './postgres-cluster/postgres-cluster.ts';
|
||||||
import { postgresDatabaseDefinition } from './postgres-database/postgres-database.ts';
|
import { postgresDatabaseDefinition } from './postgres-database/postgres-database.ts';
|
||||||
|
import { redisServerDefinition } from './redis-server/redis-server.ts';
|
||||||
|
|
||||||
const customResources = [
|
const customResources = [
|
||||||
postgresDatabaseDefinition,
|
postgresDatabaseDefinition,
|
||||||
@@ -14,6 +15,7 @@ const customResources = [
|
|||||||
postgresClusterDefinition,
|
postgresClusterDefinition,
|
||||||
authentikServerDefinition,
|
authentikServerDefinition,
|
||||||
httpServiceDefinition,
|
httpServiceDefinition,
|
||||||
|
redisServerDefinition,
|
||||||
];
|
];
|
||||||
|
|
||||||
export { customResources };
|
export { customResources };
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import { API_VERSION } from '../../utils/consts.ts';
|
|||||||
import { AuthentikServerInstance } from '../../instances/authentik-server.ts';
|
import { AuthentikServerInstance } from '../../instances/authentik-server.ts';
|
||||||
import { StorageClassInstance } from '../../instances/storageclass.ts';
|
import { StorageClassInstance } from '../../instances/storageclass.ts';
|
||||||
import { PROVISIONER } from '../../storage-provider/storage-provider.ts';
|
import { PROVISIONER } from '../../storage-provider/storage-provider.ts';
|
||||||
|
import { RedisServerInstance } from '../../instances/redis-server.ts';
|
||||||
|
import { NamespaceService } from '../../bootstrap/namespaces/namespaces.ts';
|
||||||
|
|
||||||
import type { environmentSpecSchema } from './environment.schemas.ts';
|
import type { environmentSpecSchema } from './environment.schemas.ts';
|
||||||
|
|
||||||
@@ -24,10 +26,12 @@ class EnvironmentController extends CustomResource<typeof environmentSpecSchema>
|
|||||||
#storageClass: StorageClassInstance;
|
#storageClass: StorageClassInstance;
|
||||||
#postgresCluster: PostgresClusterInstance;
|
#postgresCluster: PostgresClusterInstance;
|
||||||
#authentikServer: AuthentikServerInstance;
|
#authentikServer: AuthentikServerInstance;
|
||||||
|
#redisServer: RedisServerInstance;
|
||||||
|
|
||||||
constructor(options: CustomResourceOptions<typeof environmentSpecSchema>) {
|
constructor(options: CustomResourceOptions<typeof environmentSpecSchema>) {
|
||||||
super(options);
|
super(options);
|
||||||
const resourceService = this.services.get(ResourceService);
|
const resourceService = this.services.get(ResourceService);
|
||||||
|
const namespaceService = this.services.get(NamespaceService);
|
||||||
this.#namespace = resourceService.getInstance(
|
this.#namespace = resourceService.getInstance(
|
||||||
{
|
{
|
||||||
apiVersion: 'v1',
|
apiVersion: 'v1',
|
||||||
@@ -48,8 +52,8 @@ class EnvironmentController extends CustomResource<typeof environmentSpecSchema>
|
|||||||
{
|
{
|
||||||
apiVersion: 'cert-manager.io/v1',
|
apiVersion: 'cert-manager.io/v1',
|
||||||
kind: 'Certificate',
|
kind: 'Certificate',
|
||||||
name: this.name,
|
name: `${this.name}-tls`,
|
||||||
namespace: this.namespace,
|
namespace: namespaceService.homelab.name,
|
||||||
},
|
},
|
||||||
CertificateInstance,
|
CertificateInstance,
|
||||||
);
|
);
|
||||||
@@ -96,6 +100,15 @@ class EnvironmentController extends CustomResource<typeof environmentSpecSchema>
|
|||||||
},
|
},
|
||||||
AuthentikServerInstance,
|
AuthentikServerInstance,
|
||||||
);
|
);
|
||||||
|
this.#redisServer = resourceService.getInstance(
|
||||||
|
{
|
||||||
|
apiVersion: API_VERSION,
|
||||||
|
kind: 'RedisServer',
|
||||||
|
name: `${this.name}-redis-server`,
|
||||||
|
namespace: this.namespace,
|
||||||
|
},
|
||||||
|
RedisServerInstance,
|
||||||
|
);
|
||||||
this.#gatewayCrd.on('changed', this.queueReconcile);
|
this.#gatewayCrd.on('changed', this.queueReconcile);
|
||||||
this.#gateway.on('changed', this.queueReconcile);
|
this.#gateway.on('changed', this.queueReconcile);
|
||||||
this.#certificateCrd.on('changed', this.queueReconcile);
|
this.#certificateCrd.on('changed', this.queueReconcile);
|
||||||
@@ -104,6 +117,7 @@ class EnvironmentController extends CustomResource<typeof environmentSpecSchema>
|
|||||||
this.#postgresCluster.on('changed', this.queueReconcile);
|
this.#postgresCluster.on('changed', this.queueReconcile);
|
||||||
this.#authentikServer.on('changed', this.queueReconcile);
|
this.#authentikServer.on('changed', this.queueReconcile);
|
||||||
this.#storageClass.on('changed', this.queueReconcile);
|
this.#storageClass.on('changed', this.queueReconcile);
|
||||||
|
this.#redisServer.on('changed', this.queueReconcile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public reconcile = async () => {
|
public reconcile = async () => {
|
||||||
@@ -120,13 +134,10 @@ class EnvironmentController extends CustomResource<typeof environmentSpecSchema>
|
|||||||
});
|
});
|
||||||
if (this.#certificateCrd.ready) {
|
if (this.#certificateCrd.ready) {
|
||||||
await this.#certificate.ensure({
|
await this.#certificate.ensure({
|
||||||
metadata: {
|
|
||||||
ownerReferences: [this.ref],
|
|
||||||
},
|
|
||||||
spec: {
|
spec: {
|
||||||
secretName: `${this.name}-tls`,
|
secretName: `${this.name}-tls`,
|
||||||
issuerRef: {
|
issuerRef: {
|
||||||
name: 'cluster-issuer',
|
name: this.spec.tls.issuer,
|
||||||
kind: 'ClusterIssuer',
|
kind: 'ClusterIssuer',
|
||||||
},
|
},
|
||||||
dnsNames: [`*.${this.spec.domain}`],
|
dnsNames: [`*.${this.spec.domain}`],
|
||||||
@@ -143,7 +154,7 @@ class EnvironmentController extends CustomResource<typeof environmentSpecSchema>
|
|||||||
},
|
},
|
||||||
spec: {
|
spec: {
|
||||||
selector: {
|
selector: {
|
||||||
istio: 'gateway',
|
istio: 'homelab-istio-gateway',
|
||||||
},
|
},
|
||||||
servers: [
|
servers: [
|
||||||
{
|
{
|
||||||
@@ -197,8 +208,15 @@ class EnvironmentController extends CustomResource<typeof environmentSpecSchema>
|
|||||||
environment: `${this.namespace}/${this.name}`,
|
environment: `${this.namespace}/${this.name}`,
|
||||||
subdomain: 'authentik',
|
subdomain: 'authentik',
|
||||||
postgresCluster: `${this.name}-postgres-cluster`,
|
postgresCluster: `${this.name}-postgres-cluster`,
|
||||||
|
redisServer: `${this.name}-redis-server`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
await this.#redisServer.ensure({
|
||||||
|
metadata: {
|
||||||
|
ownerReferences: [this.ref],
|
||||||
|
},
|
||||||
|
spec: {},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import { z } from 'zod';
|
|||||||
|
|
||||||
const environmentSpecSchema = z.object({
|
const environmentSpecSchema = z.object({
|
||||||
domain: z.string(),
|
domain: z.string(),
|
||||||
|
tls: z.object({
|
||||||
|
issuer: z.string(),
|
||||||
|
}),
|
||||||
storage: z
|
storage: z
|
||||||
.object({
|
.object({
|
||||||
location: z.string().optional(),
|
location: z.string().optional(),
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class HttpServiceController extends CustomResource<typeof httpServiceSpecSchema>
|
|||||||
},
|
},
|
||||||
spec: {
|
spec: {
|
||||||
hosts: [`${this.spec.subdomain}.${environment.spec?.domain}`],
|
hosts: [`${this.spec.subdomain}.${environment.spec?.domain}`],
|
||||||
gateways: [`${this.#environment.current.namespace}/gateway`],
|
gateways: [`${this.#environment.current.namespace}/${this.#environment.current.name}`],
|
||||||
http: [
|
http: [
|
||||||
{
|
{
|
||||||
route: [
|
route: [
|
||||||
|
|||||||
82
src/custom-resouces/redis-server/redis-server.controller.ts
Normal file
82
src/custom-resouces/redis-server/redis-server.controller.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { DeploymentInstance } from '../../instances/deployment.ts';
|
||||||
|
import { ServiceInstance } from '../../instances/service.ts';
|
||||||
|
import { CustomResource } from '../../services/custom-resources/custom-resources.custom-resource.ts';
|
||||||
|
import type { CustomResourceOptions } from '../../services/custom-resources/custom-resources.custom-resource.ts';
|
||||||
|
import { ResourceService } from '../../services/resources/resources.ts';
|
||||||
|
|
||||||
|
import type { redisServerSpecSchema } from './redis-server.schemas.ts';
|
||||||
|
|
||||||
|
class RedisServerController extends CustomResource<typeof redisServerSpecSchema> {
|
||||||
|
#deployment: DeploymentInstance;
|
||||||
|
#service: ServiceInstance;
|
||||||
|
|
||||||
|
constructor(options: CustomResourceOptions<typeof redisServerSpecSchema>) {
|
||||||
|
super(options);
|
||||||
|
const resourceService = this.services.get(ResourceService);
|
||||||
|
this.#deployment = resourceService.getInstance(
|
||||||
|
{
|
||||||
|
apiVersion: 'apps/v1',
|
||||||
|
kind: 'Deployment',
|
||||||
|
name: this.name,
|
||||||
|
namespace: this.namespace,
|
||||||
|
},
|
||||||
|
DeploymentInstance,
|
||||||
|
);
|
||||||
|
this.#service = resourceService.getInstance(
|
||||||
|
{
|
||||||
|
apiVersion: 'v1',
|
||||||
|
kind: 'Service',
|
||||||
|
name: this.name,
|
||||||
|
namespace: this.namespace,
|
||||||
|
},
|
||||||
|
ServiceInstance,
|
||||||
|
);
|
||||||
|
this.#deployment.on('changed', this.queueReconcile);
|
||||||
|
this.#service.on('changed', this.queueReconcile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public reconcile = async () => {
|
||||||
|
await this.#deployment.ensure({
|
||||||
|
metadata: {
|
||||||
|
ownerReferences: [this.ref],
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
replicas: 1,
|
||||||
|
selector: {
|
||||||
|
matchLabels: {
|
||||||
|
app: this.name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
template: {
|
||||||
|
metadata: {
|
||||||
|
labels: {
|
||||||
|
app: this.name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
containers: [
|
||||||
|
{
|
||||||
|
name: this.name,
|
||||||
|
image: 'redis:latest',
|
||||||
|
ports: [{ containerPort: 6379 }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await this.#service.ensure({
|
||||||
|
metadata: {
|
||||||
|
ownerReferences: [this.ref],
|
||||||
|
},
|
||||||
|
spec: {
|
||||||
|
selector: {
|
||||||
|
app: this.name,
|
||||||
|
},
|
||||||
|
ports: [{ port: 6379, targetPort: 6379 }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export { RedisServerController };
|
||||||
5
src/custom-resouces/redis-server/redis-server.schemas.ts
Normal file
5
src/custom-resouces/redis-server/redis-server.schemas.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
const redisServerSpecSchema = z.object({});
|
||||||
|
|
||||||
|
export { redisServerSpecSchema };
|
||||||
19
src/custom-resouces/redis-server/redis-server.ts
Normal file
19
src/custom-resouces/redis-server/redis-server.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import { createCustomResourceDefinition } from '../../services/custom-resources/custom-resources.ts';
|
||||||
|
import { GROUP } from '../../utils/consts.ts';
|
||||||
|
|
||||||
|
import { RedisServerController } from './redis-server.controller.ts';
|
||||||
|
import { redisServerSpecSchema } from './redis-server.schemas.ts';
|
||||||
|
|
||||||
|
const redisServerDefinition = createCustomResourceDefinition({
|
||||||
|
group: GROUP,
|
||||||
|
version: 'v1',
|
||||||
|
kind: 'RedisServer',
|
||||||
|
names: {
|
||||||
|
plural: 'redis-servers',
|
||||||
|
singular: 'redis-server',
|
||||||
|
},
|
||||||
|
spec: redisServerSpecSchema,
|
||||||
|
create: (options) => new RedisServerController(options),
|
||||||
|
});
|
||||||
|
|
||||||
|
export { redisServerDefinition };
|
||||||
7
src/instances/http-service.ts
Normal file
7
src/instances/http-service.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { httpServiceSpecSchema } from '../custom-resouces/http-service/http-service.schemas.ts';
|
||||||
|
import type { CustomResourceObject } from '../services/custom-resources/custom-resources.custom-resource.ts';
|
||||||
|
import { ResourceInstance } from '../services/resources/resources.instance.ts';
|
||||||
|
|
||||||
|
class HttpServiceInstance extends ResourceInstance<CustomResourceObject<typeof httpServiceSpecSchema>> {}
|
||||||
|
|
||||||
|
export { HttpServiceInstance };
|
||||||
7
src/instances/redis-server.ts
Normal file
7
src/instances/redis-server.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import type { CustomResourceObject } from '../services/custom-resources/custom-resources.custom-resource.ts';
|
||||||
|
import { ResourceInstance } from '../services/resources/resources.instance.ts';
|
||||||
|
import type { redisServerSpecSchema } from '../custom-resouces/redis-server/redis-server.schemas.ts';
|
||||||
|
|
||||||
|
class RedisServerInstance extends ResourceInstance<CustomResourceObject<typeof redisServerSpecSchema>> {}
|
||||||
|
|
||||||
|
export { RedisServerInstance };
|
||||||
Reference in New Issue
Block a user