Files
operator/src/custom-resource/custom-resource.base.ts
Morten Olsen 85d043aec3 more
2025-07-31 08:51:50 +02:00

132 lines
3.3 KiB
TypeScript

import { type Static, type TObject, type TSchema } from '@sinclair/typebox';
import { GROUP } from '../utils/consts.ts';
import type { Services } from '../utils/service.ts';
import { noopAsync } from '../utils/types.js';
import { customResourceStatusSchema, type CustomResourceRequest } from './custom-resource.request.ts';
type EnsureSecretOptions<T extends TObject> = {
schema: T;
name: string;
namespace: string;
generator: () => Promise<Static<T>>;
};
type CustomResourceHandlerOptions<TSpec extends TSchema> = {
request: CustomResourceRequest<TSpec>;
ensureSecret: <T extends TObject>(options: EnsureSecretOptions<T>) => Promise<Static<T>>;
services: Services;
};
type CustomResourceConstructor<TSpec extends TSchema> = {
kind: string;
spec: TSpec;
names: {
plural: string;
singular: string;
};
};
abstract class CustomResource<TSpec extends TSchema> {
#options: CustomResourceConstructor<TSpec>;
constructor(options: CustomResourceConstructor<TSpec>) {
this.#options = options;
}
public readonly version = 'v1';
public get name() {
return `${this.#options.names.plural}.${this.group}`;
}
public get group() {
return GROUP;
}
public get path() {
return `/apis/${this.group}/v1/${this.#options.names.plural}`;
}
public get kind() {
return this.#options.kind;
}
public get spec() {
return this.#options.spec;
}
public get names() {
return this.#options.names;
}
public abstract update(options: CustomResourceHandlerOptions<TSpec>): Promise<void>;
public create?(options: CustomResourceHandlerOptions<TSpec>): Promise<void>;
public delete?(options: CustomResourceHandlerOptions<TSpec>): Promise<void>;
public toManifest = () => {
return {
apiVersion: 'apiextensions.k8s.io/v1',
kind: 'CustomResourceDefinition',
metadata: {
name: this.name,
},
spec: {
group: this.group,
names: {
kind: this.kind,
plural: this.#options.names.plural,
singular: this.#options.names.singular,
},
scope: 'Namespaced',
versions: [
{
name: this.version,
served: true,
storage: true,
schema: {
openAPIV3Schema: {
type: 'object',
properties: {
spec: this.spec,
status: customResourceStatusSchema as ExpectedAny,
},
},
},
subresources: {
status: {},
},
},
],
},
};
};
}
const createCustomResource = <TSpec extends TSchema>(
options: CustomResourceConstructor<TSpec> & {
update?: (options: CustomResourceHandlerOptions<TSpec>) => Promise<void>;
create?: (options: CustomResourceHandlerOptions<TSpec>) => Promise<void>;
delete?: (options: CustomResourceHandlerOptions<TSpec>) => Promise<void>;
},
) => {
return class extends CustomResource<TSpec> {
constructor() {
super(options);
}
public update = options.update ?? noopAsync;
public create = options.create;
public delete = options.delete;
};
};
export {
CustomResource,
type CustomResourceConstructor,
type CustomResourceHandlerOptions,
type EnsureSecretOptions,
createCustomResource,
};