mirror of
https://github.com/morten-olsen/homelab-operator.git
synced 2026-02-08 01:36:28 +01:00
simplify
This commit is contained in:
@@ -3,22 +3,21 @@ import type { V1Secret } from '@kubernetes/client-node';
|
||||
|
||||
import {
|
||||
CustomResource,
|
||||
type CustomResourceObject,
|
||||
type CustomResourceOptions,
|
||||
type SubresourceResult,
|
||||
} from '../../services/custom-resources/custom-resources.custom-resource.ts';
|
||||
import { PostgresService } from '../../services/postgres/postgres.service.ts';
|
||||
import {
|
||||
postgresConnectionSecretDataSchema,
|
||||
type postgresConnectionSpecSchema,
|
||||
} from '../postgres-connection/posgtres-connection.schemas.ts';
|
||||
import { ResourceReference } from '../../services/resources/resources.ref.ts';
|
||||
import { Resource, ResourceService } from '../../services/resources/resources.ts';
|
||||
import { getWithNamespace } from '../../utils/naming.ts';
|
||||
import { API_VERSION } from '../../utils/consts.ts';
|
||||
import { decodeSecret } from '../../utils/secrets.ts';
|
||||
import { decodeSecret, encodeSecret } from '../../utils/secrets.ts';
|
||||
import { isDeepSubset } from '../../utils/objects.ts';
|
||||
|
||||
import type { postgresDatabaseSpecSchema } from './portgres-database.schemas.ts';
|
||||
import {
|
||||
postgresDatabaseConnectionSecretSchema,
|
||||
postgresDatabaseSecretSchema,
|
||||
type postgresDatabaseSpecSchema,
|
||||
} from './portgres-database.schemas.ts';
|
||||
|
||||
const SECRET_READY_CONDITION = 'Secret';
|
||||
const DATABASE_READY_CONDITION = 'Database';
|
||||
@@ -32,31 +31,23 @@ const secretDataSchema = z.object({
|
||||
});
|
||||
|
||||
class PostgresDatabaseResource extends CustomResource<typeof postgresDatabaseSpecSchema> {
|
||||
#secret: Resource<V1Secret>;
|
||||
#secretName: string;
|
||||
#connection: ResourceReference<CustomResourceObject<typeof postgresConnectionSpecSchema>>;
|
||||
#connectionSecret: ResourceReference<V1Secret>;
|
||||
#serverSecret: ResourceReference<V1Secret>;
|
||||
#databaseSecret: Resource<V1Secret>;
|
||||
|
||||
constructor(options: CustomResourceOptions<typeof postgresDatabaseSpecSchema>) {
|
||||
super(options);
|
||||
const resouceService = this.services.get(ResourceService);
|
||||
this.#serverSecret = new ResourceReference();
|
||||
|
||||
this.#secretName = `postgres-database-${this.name}`;
|
||||
this.#secret = resouceService.get({
|
||||
const resourceService = this.services.get(ResourceService);
|
||||
this.#databaseSecret = resourceService.get({
|
||||
apiVersion: 'v1',
|
||||
kind: 'Secret',
|
||||
name: this.#secretName,
|
||||
name: `${this.name}-connection`,
|
||||
namespace: this.namespace,
|
||||
});
|
||||
|
||||
this.#connection = new ResourceReference();
|
||||
this.#connectionSecret = new ResourceReference();
|
||||
|
||||
this.#updateSecret();
|
||||
|
||||
this.#secret.on('changed', this.queueReconcile);
|
||||
this.#connection.on('changed', this.queueReconcile);
|
||||
this.#connectionSecret.on('changed', this.queueReconcile);
|
||||
this.#serverSecret.on('changed', this.queueReconcile);
|
||||
}
|
||||
|
||||
get #dbName() {
|
||||
@@ -68,68 +59,52 @@ class PostgresDatabaseResource extends CustomResource<typeof postgresDatabaseSpe
|
||||
}
|
||||
|
||||
#updateSecret = () => {
|
||||
const resouceService = this.services.get(ResourceService);
|
||||
const connectionNames = getWithNamespace(this.spec.connection, this.namespace);
|
||||
this.#connection.current = resouceService.get({
|
||||
apiVersion: API_VERSION,
|
||||
kind: 'PostgresConnection',
|
||||
name: connectionNames.name,
|
||||
namespace: connectionNames.namespace,
|
||||
const resourceService = this.services.get(ResourceService);
|
||||
const secretNames = getWithNamespace(this.spec.secretRef, this.namespace);
|
||||
this.#serverSecret.current = resourceService.get({
|
||||
apiVersion: 'v1',
|
||||
kind: 'Secret',
|
||||
name: secretNames.name,
|
||||
namespace: secretNames.namespace,
|
||||
});
|
||||
if (this.#connection.current?.exists && this.#connection.current.spec) {
|
||||
const connectionSecretNames = getWithNamespace(
|
||||
this.#connection.current.spec.secret,
|
||||
this.#connection.current.namespace,
|
||||
);
|
||||
this.#connectionSecret.current = resouceService.get({
|
||||
apiVersion: 'v1',
|
||||
kind: 'Secret',
|
||||
name: connectionSecretNames.name,
|
||||
namespace: connectionSecretNames.namespace,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
#reconcileSecret = async (): Promise<SubresourceResult> => {
|
||||
const connectionSecret = this.#connectionSecret.current;
|
||||
if (!connectionSecret?.exists || !connectionSecret.data) {
|
||||
const serverSecret = this.#serverSecret.current;
|
||||
const databaseSecret = this.#databaseSecret;
|
||||
|
||||
if (!serverSecret?.exists || !serverSecret.data) {
|
||||
return {
|
||||
ready: false,
|
||||
failed: true,
|
||||
reason: 'MissingConnectionSecret',
|
||||
};
|
||||
}
|
||||
|
||||
const connectionSecretData = decodeSecret(connectionSecret.data);
|
||||
|
||||
const secret = this.#secret;
|
||||
const parsed = secretDataSchema.safeParse(decodeSecret(secret.data));
|
||||
|
||||
if (!parsed.success) {
|
||||
this.#secret.patch({
|
||||
data: {
|
||||
host: Buffer.from(connectionSecretData?.host || '').toString('base64'),
|
||||
port: connectionSecretData?.port ? Buffer.from(connectionSecretData.port).toString('base64') : undefined,
|
||||
user: Buffer.from(this.#userName).toString('base64'),
|
||||
database: Buffer.from(this.#dbName).toString('base64'),
|
||||
password: Buffer.from(Buffer.from(crypto.randomUUID()).toString('hex')).toString('base64'),
|
||||
},
|
||||
});
|
||||
const serverSecretData = postgresDatabaseSecretSchema.safeParse(decodeSecret(serverSecret.data));
|
||||
if (!serverSecretData.success || !serverSecretData.data) {
|
||||
return {
|
||||
ready: false,
|
||||
syncing: true,
|
||||
reason: 'SecretMissing',
|
||||
};
|
||||
}
|
||||
if (parsed.data?.host !== connectionSecretData?.host || parsed.data?.port !== connectionSecretData?.port) {
|
||||
this.#secret.patch({
|
||||
data: {
|
||||
host: Buffer.from(connectionSecretData?.host || '').toString('base64'),
|
||||
port: connectionSecretData?.port ? Buffer.from(connectionSecretData.port).toString('base64') : undefined,
|
||||
},
|
||||
const databaseSecretData = postgresDatabaseConnectionSecretSchema.safeParse(decodeSecret(databaseSecret.data));
|
||||
const expectedSecret = {
|
||||
password: crypto.randomUUID(),
|
||||
host: serverSecretData.data.host,
|
||||
port: serverSecretData.data.port,
|
||||
user: this.#userName,
|
||||
database: this.#dbName,
|
||||
};
|
||||
|
||||
if (!isDeepSubset(databaseSecretData.data, expectedSecret)) {
|
||||
databaseSecret.patch({
|
||||
data: encodeSecret(expectedSecret),
|
||||
});
|
||||
return {
|
||||
ready: false,
|
||||
syncing: true,
|
||||
reason: 'SecretNotReady',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -139,7 +114,7 @@ class PostgresDatabaseResource extends CustomResource<typeof postgresDatabaseSpe
|
||||
};
|
||||
|
||||
#reconcileDatabase = async (): Promise<SubresourceResult> => {
|
||||
const connectionSecret = this.#connectionSecret.current;
|
||||
const connectionSecret = this.#serverSecret.current;
|
||||
if (!connectionSecret?.exists || !connectionSecret.data) {
|
||||
return {
|
||||
ready: false,
|
||||
@@ -148,21 +123,21 @@ class PostgresDatabaseResource extends CustomResource<typeof postgresDatabaseSpe
|
||||
};
|
||||
}
|
||||
|
||||
const connectionSecretData = postgresConnectionSecretDataSchema.safeParse(decodeSecret(connectionSecret.data));
|
||||
const connectionSecretData = postgresDatabaseSecretSchema.safeParse(decodeSecret(connectionSecret.data));
|
||||
if (!connectionSecretData.success || !connectionSecretData.data) {
|
||||
return {
|
||||
ready: false,
|
||||
syncing: true,
|
||||
reason: 'ConnectionSecretMissing',
|
||||
reason: 'SecretMissing',
|
||||
};
|
||||
}
|
||||
|
||||
const secretData = secretDataSchema.safeParse(decodeSecret(this.#secret.data));
|
||||
const secretData = postgresDatabaseConnectionSecretSchema.safeParse(decodeSecret(this.#serverSecret.current?.data));
|
||||
if (!secretData.success || !secretData.data) {
|
||||
return {
|
||||
ready: false,
|
||||
syncing: true,
|
||||
reason: 'SecretMissing',
|
||||
reason: 'ConnectionSecretMissing',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -186,7 +161,7 @@ class PostgresDatabaseResource extends CustomResource<typeof postgresDatabaseSpe
|
||||
};
|
||||
|
||||
public reconcile = async () => {
|
||||
if (!this.exists || this.metadata.deletionTimestamp) {
|
||||
if (!this.exists || this.metadata?.deletionTimestamp) {
|
||||
return;
|
||||
}
|
||||
this.#updateSecret();
|
||||
|
||||
Reference in New Issue
Block a user