diff --git a/src/index.ts b/src/index.ts index 29241b8..bf408ba 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import { Services } from './utils/service.ts'; import { CustomResourceService } from './services/custom-resources/custom-resources.ts'; import { WatcherService } from './services/watchers/watchers.ts'; import { customResources } from './custom-resouces/custom-resources.ts'; +import { StorageProvider } from './storage-provider/storage-provider.ts'; process.on('uncaughtException', (error) => { console.log('UNCAUGHT EXCEPTION'); @@ -29,6 +30,8 @@ process.on('unhandledRejection', (error) => { const services = new Services(); const watcherService = services.get(WatcherService); +const storageProvider = services.get(StorageProvider); +await storageProvider.start(); await watcherService .create({ path: '/apis/apiextensions.k8s.io/v1/customresourcedefinitions', diff --git a/src/storage-provider/storage-provider.ts b/src/storage-provider/storage-provider.ts new file mode 100644 index 0000000..726041c --- /dev/null +++ b/src/storage-provider/storage-provider.ts @@ -0,0 +1,73 @@ +import { mkdir } from 'fs/promises'; + +import { V1PersistentVolume, type V1PersistentVolumeClaim } from '@kubernetes/client-node'; + +import { Watcher, WatcherService } from '../services/watchers/watchers.ts'; +import type { Services } from '../utils/service.ts'; +import { ResourceService, type Resource } from '../services/resources/resources.ts'; + +const PROVISIONER = 'reuse-local-path-provisioner'; +const LABEL_SELECTOR = `provisioner=${PROVISIONER}`; + +class StorageProvider { + #watcher: Watcher; + #services: Services; + + constructor(services: Services) { + this.#services = services; + const watchService = this.#services.get(WatcherService); + this.#watcher = watchService.create({ + path: '/api/v1/persistantvolumeclaims', + list: (k8s) => + k8s.api.listPersistentVolumeClaimForAllNamespaces({ + labelSelector: LABEL_SELECTOR, + }), + verbs: ['add', 'update', 'delete'], + selector: LABEL_SELECTOR, + }); + this.#watcher.on('changed', this.#handleChange); + } + + #handleChange = async (pvc: Resource) => { + const target = `/data/volumes/${pvc.namespace}/${pvc.name}`; + await mkdir(target, { recursive: true }); + const resourceService = this.#services.get(ResourceService); + const pv = resourceService.get({ + apiVersion: 'v1', + kind: 'PersistantVolume', + name: pvc.name, + namespace: pvc.namespace, + }); + await pv.load(); + await pv.patch({ + metadata: { + labels: { + provisioner: PROVISIONER, + }, + }, + spec: { + hostPath: { + path: target, + }, + capacity: { + storage: pvc.spec?.resources?.requests?.storage ?? '1GB', + }, + persistentVolumeReclaimPolicy: 'Retain', + accessModes: pvc.spec?.accessModes, + claimRef: { + uid: pvc.metadata?.uid, + resourceVersion: pvc.metadata?.resourceVersion, + apiVersion: pvc.apiVersion, + name: pvc.name, + namespace: pvc.namespace, + }, + }, + }); + }; + + public start = async () => { + await this.#watcher.start(); + }; +} + +export { StorageProvider };