This commit is contained in:
Morten Olsen
2025-08-12 22:32:09 +02:00
parent d4b56007f1
commit b8bb16ccbb
59 changed files with 1855 additions and 290 deletions

View File

@@ -5,8 +5,8 @@ import {
CustomObjectsApi,
EventsV1Api,
KubernetesObjectApi,
ApiException,
AppsV1Api,
StorageV1Api,
} from '@kubernetes/client-node';
class K8sService {
@@ -17,6 +17,7 @@ class K8sService {
#k8sEventsApi: EventsV1Api;
#k8sObjectsApi: KubernetesObjectApi;
#k8sAppsApi: AppsV1Api;
#k8sStorageApi: StorageV1Api;
constructor() {
this.#kc = new KubeConfig();
@@ -27,6 +28,7 @@ class K8sService {
this.#k8sEventsApi = this.#kc.makeApiClient(EventsV1Api);
this.#k8sObjectsApi = this.#kc.makeApiClient(KubernetesObjectApi);
this.#k8sAppsApi = this.#kc.makeApiClient(AppsV1Api);
this.#k8sStorageApi = this.#kc.makeApiClient(StorageV1Api);
}
public get config() {
@@ -56,6 +58,10 @@ class K8sService {
public get apps() {
return this.#k8sAppsApi;
}
public get storageApi() {
return this.#k8sStorageApi;
}
}
export { K8sService };

View File

@@ -8,7 +8,7 @@ type PostgresInstanceOptions = {
services: Services;
host: string;
port?: number;
user: string;
username: string;
password: string;
database?: string;
};
@@ -21,7 +21,7 @@ class PostgresInstance {
client: 'pg',
connection: {
host: process.env.FORCE_PG_HOST ?? options.host,
user: process.env.FORCE_PG_USER ?? options.user,
user: process.env.FORCE_PG_USER ?? options.username,
password: process.env.FORCE_PG_PASSWORD ?? options.password,
port: process.env.FORCE_PG_PORT ? parseInt(process.env.FORCE_PG_PORT) : options.port,
database: options.database,

View File

@@ -1,5 +1,7 @@
import type { KubernetesObject } from '@kubernetes/client-node';
import { isDeepSubset } from '../../utils/objects.ts';
import { ResourceReference } from './resources.ref.ts';
abstract class ResourceInstance<T extends KubernetesObject> extends ResourceReference<T> {
@@ -10,8 +12,12 @@ abstract class ResourceInstance<T extends KubernetesObject> extends ResourceRefe
return this.current;
}
public get exists() {
return this.resource.exists;
}
public get manifest() {
return this.resource.metadata;
return this.resource.manifest;
}
public get apiVersion() {
@@ -42,9 +48,32 @@ abstract class ResourceInstance<T extends KubernetesObject> extends ResourceRefe
return this.resource.data;
}
public get status() {
return this.resource.status;
}
public patch = this.resource.patch;
public reload = this.resource.load;
public delete = this.resource.delete;
public ensure = async (manifest: T) => {
if (isDeepSubset(this.manifest, manifest)) {
return false;
}
await this.patch(manifest);
return true;
};
public get ready() {
return this.exists;
}
public getCondition = (
condition: string,
): T extends { status?: { conditions?: (infer U)[] } } ? U | undefined : undefined => {
const status = this.status as ExpectedAny;
return status?.conditions?.find((c: ExpectedAny) => c?.type === condition);
};
}
export { ResourceInstance };

View File

@@ -163,6 +163,13 @@ class Resource<T extends KubernetesObject = UnknownResource> extends EventEmitte
return undefined as ExpectedAny;
}
public get status(): T extends { status?: infer K } ? K | undefined : never {
if (this.manifest && 'status' in this.manifest) {
return this.manifest.status as ExpectedAny;
}
return undefined as ExpectedAny;
}
public get owners() {
const { services } = this.#options;
const references = this.metadata?.ownerReferences || [];

View File

@@ -3,6 +3,7 @@ import type { KubernetesObject } from '@kubernetes/client-node';
import type { Services } from '../../utils/service.ts';
import { Resource } from './resources.resource.ts';
import type { ResourceInstance } from './resources.instance.ts';
type ResourceGetOptions = {
apiVersion: string;
@@ -19,6 +20,14 @@ class ResourceService {
this.#services = services;
}
public getInstance = <T extends KubernetesObject, I extends ResourceInstance<T>>(
options: ResourceGetOptions,
instance: new (resource: Resource<T>) => I,
) => {
const resource = this.get<T>(options);
return new instance(resource);
};
public get = <T extends KubernetesObject>(options: ResourceGetOptions) => {
const { apiVersion, kind, name, namespace } = options;
let resource = this.#cache.find(
@@ -40,5 +49,6 @@ class ResourceService {
};
}
export { ResourceInstance } from './resources.instance.ts';
export { ResourceReference } from './resources.ref.ts';
export { ResourceService, Resource };

View File

@@ -41,7 +41,7 @@ class EnsuredSecret<T extends ZodObject> {
return this.#options.namespace;
}
public get resouce() {
public get resource() {
return this.#resource;
}
@@ -62,7 +62,7 @@ class EnsuredSecret<T extends ZodObject> {
if (deepEqual(patched, this.value)) {
return;
}
await this.resouce.patch({
await this.resource.patch({
data: patched,
});
};