linting
This commit is contained in:
@@ -8,7 +8,6 @@ class K8sConfig {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.#config = new KubeConfig();
|
this.#config = new KubeConfig();
|
||||||
this.#config.loadFromDefault();
|
this.#config.loadFromDefault();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get kubeConfig() {
|
public get kubeConfig() {
|
||||||
@@ -17,7 +16,7 @@ class K8sConfig {
|
|||||||
|
|
||||||
public get objectsApi() {
|
public get objectsApi() {
|
||||||
if (!this.#objectsApi) {
|
if (!this.#objectsApi) {
|
||||||
this.#objectsApi = this.#config.makeApiClient(KubernetesObjectApi)
|
this.#objectsApi = this.#config.makeApiClient(KubernetesObjectApi);
|
||||||
}
|
}
|
||||||
return this.#objectsApi;
|
return this.#objectsApi;
|
||||||
}
|
}
|
||||||
@@ -31,7 +30,7 @@ class K8sConfig {
|
|||||||
|
|
||||||
public get extensionsApi() {
|
public get extensionsApi() {
|
||||||
if (!this.#extensionsApi) {
|
if (!this.#extensionsApi) {
|
||||||
this.#extensionsApi = this.#config.makeApiClient(ApiextensionsV1Api)
|
this.#extensionsApi = this.#config.makeApiClient(ApiextensionsV1Api);
|
||||||
}
|
}
|
||||||
return this.#extensionsApi;
|
return this.#extensionsApi;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import { z, type ZodType } from 'zod';
|
|||||||
import { PatchStrategy, setHeaderOptions, type KubernetesObject } from '@kubernetes/client-node';
|
import { PatchStrategy, setHeaderOptions, type KubernetesObject } from '@kubernetes/client-node';
|
||||||
import { CronJob, CronTime } from 'cron';
|
import { CronJob, CronTime } from 'cron';
|
||||||
import { CoalescingQueue } from '@morten-olsen/box-utils/coalescing-queue';
|
import { CoalescingQueue } from '@morten-olsen/box-utils/coalescing-queue';
|
||||||
import { FINALIZER } from '@morten-olsen/box-utils/consts';
|
// import { FINALIZER } from '@morten-olsen/box-utils/consts';
|
||||||
|
|
||||||
import { NotReadyError } from '../../errors/errors.js';
|
import { NotReadyError } from '../../errors/errors.js';
|
||||||
|
|
||||||
import { Resource, type ResourceOptions } from './resource.js';
|
|
||||||
import { K8sConfig } from '../../config/config.js';
|
import { K8sConfig } from '../../config/config.js';
|
||||||
import type { ResourceClass } from '../resources.service.js';
|
import type { ResourceClass } from '../resources.service.js';
|
||||||
|
|
||||||
|
import { Resource, type ResourceOptions } from './resource.js';
|
||||||
|
|
||||||
const customResourceStatusSchema = z.object({
|
const customResourceStatusSchema = z.object({
|
||||||
observedGeneration: z.number().optional(),
|
observedGeneration: z.number().optional(),
|
||||||
conditions: z
|
conditions: z
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ApiException, KubernetesObjectApi, PatchStrategy, type KubernetesObject } from '@kubernetes/client-node';
|
import { ApiException, PatchStrategy, type KubernetesObject } from '@kubernetes/client-node';
|
||||||
import deepEqual from 'deep-equal';
|
import deepEqual from 'deep-equal';
|
||||||
import type { Services } from '@morten-olsen/box-utils/services';
|
import type { Services } from '@morten-olsen/box-utils/services';
|
||||||
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ApiException, ApiextensionsV1Api, type KubernetesObject } from '@kubernetes/client-node';
|
import { ApiException, type KubernetesObject } from '@kubernetes/client-node';
|
||||||
import type { ZodType } from 'zod';
|
import type { ZodType } from 'zod';
|
||||||
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
import { EventEmitter } from '@morten-olsen/box-utils/event-emitter';
|
||||||
import type { Services } from '@morten-olsen/box-utils/services';
|
import type { Services } from '@morten-olsen/box-utils/services';
|
||||||
@@ -58,7 +58,7 @@ class ResourceService extends EventEmitter<ResourceServiceEvents> {
|
|||||||
resources: [],
|
resources: [],
|
||||||
});
|
});
|
||||||
if ('dependsOn' in resource && Array.isArray(resource.dependsOn)) {
|
if ('dependsOn' in resource && Array.isArray(resource.dependsOn)) {
|
||||||
await this.register(...resource.dependsOn as ResourceClass<ExplicitAny>[]);
|
await this.register(...(resource.dependsOn as ResourceClass<ExplicitAny>[]));
|
||||||
}
|
}
|
||||||
const watcherService = this.#services.get(WatcherService);
|
const watcherService = this.#services.get(WatcherService);
|
||||||
const watcher = watcherService.create({
|
const watcher = watcherService.create({
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class AuthentikServer extends CustomResource<typeof serverSpec> {
|
|||||||
);
|
);
|
||||||
throw new NotReadyError();
|
throw new NotReadyError();
|
||||||
}
|
}
|
||||||
const { secret } = this.#secret.value;
|
// const { secret } = this.#secret.value;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
import { CustomResource, NotReadyError, ResourceReference, Secret, type CustomResourceOptions } from "@morten-olsen/box-k8s";
|
import {
|
||||||
import { cloudflareAccountSchema } from "./account.schemas.js";
|
CustomResource,
|
||||||
import { API_VERSION } from "@morten-olsen/box-utils/consts";
|
NotReadyError,
|
||||||
|
ResourceReference,
|
||||||
|
Secret,
|
||||||
|
type CustomResourceOptions,
|
||||||
|
} from '@morten-olsen/box-k8s';
|
||||||
|
import { API_VERSION } from '@morten-olsen/box-utils/consts';
|
||||||
|
|
||||||
|
import { cloudflareAccountSchema } from './account.schemas.js';
|
||||||
|
|
||||||
class CloudflareAccountResource extends CustomResource<typeof cloudflareAccountSchema> {
|
class CloudflareAccountResource extends CustomResource<typeof cloudflareAccountSchema> {
|
||||||
public static readonly apiVersion = API_VERSION;
|
public static readonly apiVersion = API_VERSION;
|
||||||
public static readonly kind = "CloudflareAccount";
|
public static readonly kind = 'CloudflareAccount';
|
||||||
public static readonly spec = cloudflareAccountSchema;
|
public static readonly spec = cloudflareAccountSchema;
|
||||||
public static readonly scope = "Cluster";
|
public static readonly scope = 'Cluster';
|
||||||
public static readonly dependsOn = [Secret];
|
public static readonly dependsOn = [Secret];
|
||||||
|
|
||||||
#secret: ResourceReference<typeof Secret>;
|
#secret: ResourceReference<typeof Secret>;
|
||||||
@@ -30,19 +37,15 @@ class CloudflareAccountResource extends CustomResource<typeof cloudflareAccountS
|
|||||||
if (!spec) {
|
if (!spec) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return this.resources.get(
|
return this.resources.get(Secret, spec.token.secret, spec.token.namespace);
|
||||||
Secret,
|
};
|
||||||
spec.token.secret,
|
|
||||||
spec.token.namespace,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public reconcile = async () => {
|
public reconcile = async () => {
|
||||||
this.#secret.current = this.#getSecret();
|
this.#secret.current = this.#getSecret();
|
||||||
if (!this.token) {
|
if (!this.token) {
|
||||||
throw new NotReadyError('Token not found');
|
throw new NotReadyError('Token not found');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export { CloudflareAccountResource };
|
export { CloudflareAccountResource };
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import { CustomResource, NotReadyError } from '@morten-olsen/box-k8s';
|
import { CustomResource, NotReadyError } from '@morten-olsen/box-k8s';
|
||||||
|
import { API_VERSION } from '@morten-olsen/box-utils/consts';
|
||||||
|
|
||||||
import { CloudflareService } from '../../services/cloudflare/cloudflare.js';
|
import { CloudflareService } from '../../services/cloudflare/cloudflare.js';
|
||||||
|
// import { CloudflareAccountResource } from '../account/account.js';
|
||||||
|
|
||||||
import { cloudflareDnsRecordSchema } from './dns-record.schemas.js';
|
import { cloudflareDnsRecordSchema } from './dns-record.schemas.js';
|
||||||
import { API_VERSION } from '@morten-olsen/box-utils/consts';
|
|
||||||
import { CloudflareAccountResource } from '../account/account.js';
|
|
||||||
|
|
||||||
class CloudflareDnsRecordResource extends CustomResource<typeof cloudflareDnsRecordSchema> {
|
class CloudflareDnsRecordResource extends CustomResource<typeof cloudflareDnsRecordSchema> {
|
||||||
public static readonly apiVersion = API_VERSION;
|
public static readonly apiVersion = API_VERSION;
|
||||||
public static readonly kind = "CloudflareDnsRecord";
|
public static readonly kind = 'CloudflareDnsRecord';
|
||||||
public static readonly spec = cloudflareDnsRecordSchema;
|
public static readonly spec = cloudflareDnsRecordSchema;
|
||||||
public static readonly scope = "Namespaced";
|
public static readonly scope = 'Namespaced';
|
||||||
public static readonly dependsOn = [CloudflareAccountResource];
|
// public static readonly dependsOn = [CloudflareAccountResource];
|
||||||
|
|
||||||
public get dnsId() {
|
public get dnsId() {
|
||||||
return `homelab|${this.namespace}|${this.name}`
|
return `homelab|${this.namespace}|${this.name}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public reconcile = async () => {
|
public reconcile = async () => {
|
||||||
@@ -22,19 +22,18 @@ class CloudflareDnsRecordResource extends CustomResource<typeof cloudflareDnsRec
|
|||||||
throw new NotReadyError('Missing spec');
|
throw new NotReadyError('Missing spec');
|
||||||
}
|
}
|
||||||
const service = this.services.get(CloudflareService);
|
const service = this.services.get(CloudflareService);
|
||||||
const { getDnsRecord, ensrureDnsRecord } = service.getAccount(this.spec.account);
|
const { ensrureDnsRecord } = service.getAccount(this.spec.account);
|
||||||
await ensrureDnsRecord(this.dnsId, this.spec);
|
await ensrureDnsRecord(this.dnsId, this.spec);
|
||||||
};
|
};
|
||||||
|
|
||||||
public destroy = async () => {
|
public destroy = async () => {
|
||||||
|
|
||||||
if (!this.spec) {
|
if (!this.spec) {
|
||||||
throw new NotReadyError('Missing spec');
|
throw new NotReadyError('Missing spec');
|
||||||
}
|
}
|
||||||
const service = this.services.get(CloudflareService);
|
const service = this.services.get(CloudflareService);
|
||||||
const { removeDnsRecord } = service.getAccount(this.spec.account);
|
const { removeDnsRecord } = service.getAccount(this.spec.account);
|
||||||
await removeDnsRecord(this.dnsId, this.spec.domain);
|
await removeDnsRecord(this.dnsId, this.spec.domain);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export { CloudflareDnsRecordResource, cloudflareDnsRecordSchema };
|
export { CloudflareDnsRecordResource, cloudflareDnsRecordSchema };
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
import type { Services } from "@morten-olsen/box-utils/services";
|
import type { Services } from '@morten-olsen/box-utils/services';
|
||||||
import type { CloudflareAccountResource } from "../../resources/account/account.js"
|
|
||||||
import API from 'cloudflare';
|
import API from 'cloudflare';
|
||||||
import type { Zone } from "cloudflare/resources/zones/zones.mjs";
|
import type { Zone } from 'cloudflare/resources/zones/zones.mjs';
|
||||||
import type { z } from "@morten-olsen/box-k8s";
|
import type { z } from '@morten-olsen/box-k8s';
|
||||||
import type { cloudflareDnsRecordSchema } from "../../resources/dns-record/dns-record.schemas.js";
|
|
||||||
|
import type { CloudflareAccountResource } from '../../resources/account/account.js';
|
||||||
|
import type { cloudflareDnsRecordSchema } from '../../resources/dns-record/dns-record.schemas.js';
|
||||||
|
|
||||||
type CloudflareAccountOptions = {
|
type CloudflareAccountOptions = {
|
||||||
services: Services;
|
services: Services;
|
||||||
resource: CloudflareAccountResource;
|
resource: CloudflareAccountResource;
|
||||||
}
|
};
|
||||||
|
|
||||||
class CloudflareAccount {
|
class CloudflareAccount {
|
||||||
#options: CloudflareAccountOptions;
|
#options: CloudflareAccountOptions;
|
||||||
#api?: API;
|
#api?: API;
|
||||||
#zones: Map<string, Promise<Zone | undefined>>
|
#zones: Map<string, Promise<Zone | undefined>>;
|
||||||
|
|
||||||
constructor(options: CloudflareAccountOptions) {
|
constructor(options: CloudflareAccountOptions) {
|
||||||
this.#zones = new Map();
|
this.#zones = new Map();
|
||||||
@@ -31,7 +32,7 @@ class CloudflareAccount {
|
|||||||
if (!this.#api) {
|
if (!this.#api) {
|
||||||
this.#api = new API({
|
this.#api = new API({
|
||||||
apiToken: this.token,
|
apiToken: this.token,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
return this.#api;
|
return this.#api;
|
||||||
}
|
}
|
||||||
@@ -39,10 +40,10 @@ class CloudflareAccount {
|
|||||||
#getZone = async (name: string) => {
|
#getZone = async (name: string) => {
|
||||||
const zones = await this.api.zones.list({
|
const zones = await this.api.zones.list({
|
||||||
name,
|
name,
|
||||||
})
|
});
|
||||||
const [zone] = zones.result;
|
const [zone] = zones.result;
|
||||||
return zone;
|
return zone;
|
||||||
}
|
};
|
||||||
|
|
||||||
public getZone = async (name: string) => {
|
public getZone = async (name: string) => {
|
||||||
if (!this.#zones.has(name)) {
|
if (!this.#zones.has(name)) {
|
||||||
@@ -50,7 +51,7 @@ class CloudflareAccount {
|
|||||||
}
|
}
|
||||||
const current = this.#zones.get(name);
|
const current = this.#zones.get(name);
|
||||||
return await current;
|
return await current;
|
||||||
}
|
};
|
||||||
|
|
||||||
public getDnsRecord = async (id: string, domain: string) => {
|
public getDnsRecord = async (id: string, domain: string) => {
|
||||||
const zone = await this.getZone(domain);
|
const zone = await this.getZone(domain);
|
||||||
@@ -64,11 +65,11 @@ class CloudflareAccount {
|
|||||||
comment: {
|
comment: {
|
||||||
exact: id,
|
exact: id,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
const [dnsRecord] = dnsRecords.result;
|
const [dnsRecord] = dnsRecords.result;
|
||||||
|
|
||||||
return dnsRecord;
|
return dnsRecord;
|
||||||
}
|
};
|
||||||
|
|
||||||
public removeDnsRecord = async (id: string, domain: string) => {
|
public removeDnsRecord = async (id: string, domain: string) => {
|
||||||
const zone = await this.getZone(domain);
|
const zone = await this.getZone(domain);
|
||||||
@@ -83,7 +84,7 @@ class CloudflareAccount {
|
|||||||
await this.api.dns.records.delete(record.id, {
|
await this.api.dns.records.delete(record.id, {
|
||||||
zone_id: zone.id,
|
zone_id: zone.id,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
public ensrureDnsRecord = async (id: string, options: z.infer<typeof cloudflareDnsRecordSchema>) => {
|
public ensrureDnsRecord = async (id: string, options: z.infer<typeof cloudflareDnsRecordSchema>) => {
|
||||||
const { domain, subdomain, value, type, ttl = 1, proxy } = options;
|
const { domain, subdomain, value, type, ttl = 1, proxy } = options;
|
||||||
@@ -102,9 +103,8 @@ class CloudflareAccount {
|
|||||||
comment: id,
|
comment: id,
|
||||||
ttl,
|
ttl,
|
||||||
proxied: proxy,
|
proxied: proxy,
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
await this.api.dns.records.update(current.id, {
|
await this.api.dns.records.update(current.id, {
|
||||||
zone_id: zone.id,
|
zone_id: zone.id,
|
||||||
type,
|
type,
|
||||||
@@ -113,9 +113,9 @@ class CloudflareAccount {
|
|||||||
comment: id,
|
comment: id,
|
||||||
ttl,
|
ttl,
|
||||||
proxied: proxy,
|
proxied: proxy,
|
||||||
})
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export { CloudflareAccount };
|
export { CloudflareAccount };
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import type { Services } from "@morten-olsen/box-utils/services";
|
import type { Services } from '@morten-olsen/box-utils/services';
|
||||||
import { CloudflareAccount } from "./cloudflare.account.js";
|
import { ResourceService } from '@morten-olsen/box-k8s';
|
||||||
import { ResourceService } from "@morten-olsen/box-k8s";
|
|
||||||
import { CloudflareAccountResource } from "../../resources/account/account.js";
|
import { CloudflareAccountResource } from '../../resources/account/account.js';
|
||||||
|
|
||||||
|
import { CloudflareAccount } from './cloudflare.account.js';
|
||||||
|
|
||||||
class CloudflareService {
|
class CloudflareService {
|
||||||
#services: Services;
|
#services: Services;
|
||||||
@@ -16,17 +18,20 @@ class CloudflareService {
|
|||||||
if (!this.#instances.has(name)) {
|
if (!this.#instances.has(name)) {
|
||||||
const resourceService = this.#services.get(ResourceService);
|
const resourceService = this.#services.get(ResourceService);
|
||||||
const resource = resourceService.get(CloudflareAccountResource, name);
|
const resource = resourceService.get(CloudflareAccountResource, name);
|
||||||
this.#instances.set(name, new CloudflareAccount({
|
this.#instances.set(
|
||||||
|
name,
|
||||||
|
new CloudflareAccount({
|
||||||
resource,
|
resource,
|
||||||
services: this.#services,
|
services: this.#services,
|
||||||
}))
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const current = this.#instances.get(name);
|
const current = this.#instances.get(name);
|
||||||
if (!current) {
|
if (!current) {
|
||||||
throw new Error('Could not get cloudflare account');
|
throw new Error('Could not get cloudflare account');
|
||||||
}
|
}
|
||||||
return current;
|
return current;
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export { CloudflareService };
|
export { CloudflareService };
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
import { K8sOperator } from '@morten-olsen/box-k8s';
|
import { K8sOperator } from '@morten-olsen/box-k8s';
|
||||||
|
|
||||||
import { CloudflareAccountResource } from './resources/account/account.js';
|
import { CloudflareAccountResource } from './resources/account/account.js';
|
||||||
import { CloudflareDnsRecordResource } from './resources/dns-record/dns-record.js';
|
import { CloudflareDnsRecordResource } from './resources/dns-record/dns-record.js';
|
||||||
|
|
||||||
const operator = new K8sOperator();
|
const operator = new K8sOperator();
|
||||||
await operator.resources.install(
|
await operator.resources.install(CloudflareAccountResource, CloudflareDnsRecordResource);
|
||||||
CloudflareAccountResource,
|
await operator.resources.register(CloudflareAccountResource, CloudflareDnsRecordResource);
|
||||||
CloudflareDnsRecordResource,
|
|
||||||
)
|
|
||||||
await operator.resources.register(
|
|
||||||
CloudflareAccountResource,
|
|
||||||
CloudflareDnsRecordResource,
|
|
||||||
)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user