mirror of
https://github.com/morten-olsen/homelab-operator.git
synced 2026-02-08 01:36:28 +01:00
updates
This commit is contained in:
@@ -1,12 +1,10 @@
|
||||
import { mkdir } from 'fs/promises';
|
||||
|
||||
import { V1PersistentVolume, type V1PersistentVolumeClaim } from '@kubernetes/client-node';
|
||||
import { V1PersistentVolume, type V1PersistentVolumeClaim, CoreV1Event, V1StorageClass } 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 PROVISIONER = 'homelab-operator-local-path';
|
||||
|
||||
class StorageProvider {
|
||||
#watcher: Watcher<V1PersistentVolumeClaim>;
|
||||
@@ -32,46 +30,128 @@ class StorageProvider {
|
||||
}
|
||||
|
||||
#handleChange = async (pvc: Resource<V1PersistentVolumeClaim>) => {
|
||||
if (pvc.metadata?.annotations?.['volume.kubernetes.io/storage-provisioner'] !== PROVISIONER) {
|
||||
return;
|
||||
}
|
||||
const target = `/data/volumes/${pvc.namespace}/${pvc.name}`;
|
||||
try {
|
||||
await mkdir(target, { recursive: true });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
if (!pvc.exists || pvc.metadata?.deletionTimestamp) {
|
||||
return;
|
||||
}
|
||||
|
||||
const storageClassName = pvc.spec?.storageClassName;
|
||||
if (!storageClassName) {
|
||||
return;
|
||||
}
|
||||
const resourceService = this.#services.get(ResourceService);
|
||||
const storageClass = resourceService.get<V1StorageClass>({
|
||||
apiVersion: 'storage.k8s.io/v1',
|
||||
kind: 'StorageClass',
|
||||
name: storageClassName,
|
||||
});
|
||||
|
||||
if (!storageClass.exists || storageClass.manifest?.provisioner !== PROVISIONER) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pvc.status?.phase === 'Pending' && !pvc.spec?.volumeName) {
|
||||
await this.#provisionVolume(pvc, storageClass);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error handling PVC ${pvc.namespace}/${pvc.name}:`, error);
|
||||
await this.#createEvent(pvc, 'Warning', 'ProvisioningFailed', `Failed to provision volume: ${error}`);
|
||||
}
|
||||
const resourceService = this.#services.get(ResourceService);
|
||||
const pv = resourceService.get<V1PersistentVolume>({
|
||||
apiVersion: 'v1',
|
||||
kind: 'PersistentVolume',
|
||||
name: `${pvc.namespace}-${pvc.name}`,
|
||||
});
|
||||
await pv.load();
|
||||
await pv.patch({
|
||||
metadata: {
|
||||
labels: {
|
||||
provisioner: PROVISIONER,
|
||||
};
|
||||
|
||||
#provisionVolume = async (pvc: Resource<V1PersistentVolumeClaim>, storageClass: Resource<V1StorageClass>) => {
|
||||
const pvName = `pv-${pvc.namespace}-${pvc.name}`;
|
||||
const storageLocation = storageClass.manifest?.parameters?.storageLocation || '/data/volumes';
|
||||
const target = `${storageLocation}/${pvc.namespace}/${pvc.name}`;
|
||||
|
||||
try {
|
||||
const resourceService = this.#services.get(ResourceService);
|
||||
const pv = resourceService.get<V1PersistentVolume>({
|
||||
apiVersion: 'v1',
|
||||
kind: 'PersistentVolume',
|
||||
name: pvName,
|
||||
});
|
||||
|
||||
await pv.patch({
|
||||
metadata: {
|
||||
name: pvName,
|
||||
labels: {
|
||||
provisioner: PROVISIONER,
|
||||
'pvc-namespace': pvc.namespace || 'default',
|
||||
'pvc-name': pvc.name || 'unknown',
|
||||
},
|
||||
annotations: {
|
||||
'pv.kubernetes.io/provisioned-by': PROVISIONER,
|
||||
},
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
hostPath: {
|
||||
path: target,
|
||||
spec: {
|
||||
hostPath: {
|
||||
path: target,
|
||||
type: 'DirectoryOrCreate',
|
||||
},
|
||||
capacity: {
|
||||
storage: pvc.spec?.resources?.requests?.storage ?? '1Gi',
|
||||
},
|
||||
persistentVolumeReclaimPolicy: 'Retain',
|
||||
accessModes: pvc.spec?.accessModes ?? ['ReadWriteOnce'],
|
||||
storageClassName: pvc.spec?.storageClassName,
|
||||
claimRef: {
|
||||
uid: pvc.metadata?.uid,
|
||||
resourceVersion: pvc.metadata?.resourceVersion,
|
||||
apiVersion: pvc.apiVersion,
|
||||
kind: 'PersistentVolumeClaim',
|
||||
name: pvc.name,
|
||||
namespace: pvc.namespace,
|
||||
},
|
||||
},
|
||||
capacity: {
|
||||
storage: pvc.spec?.resources?.requests?.storage ?? '1Gi',
|
||||
},
|
||||
persistentVolumeReclaimPolicy: 'Retain',
|
||||
accessModes: pvc.spec?.accessModes,
|
||||
claimRef: {
|
||||
uid: pvc.metadata?.uid,
|
||||
resourceVersion: pvc.metadata?.resourceVersion,
|
||||
apiVersion: pvc.apiVersion,
|
||||
name: pvc.name,
|
||||
});
|
||||
|
||||
await this.#createEvent(pvc, 'Normal', 'Provisioning', `Successfully provisioned volume ${pvName}`);
|
||||
} catch (error) {
|
||||
console.error(`Failed to provision volume for PVC ${pvc.namespace}/${pvc.name}:`, error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
#createEvent = async (pvc: Resource<V1PersistentVolumeClaim>, type: string, reason: string, message: string) => {
|
||||
try {
|
||||
const resourceService = this.#services.get(ResourceService);
|
||||
const event = resourceService.get<CoreV1Event>({
|
||||
apiVersion: 'v1',
|
||||
kind: 'Event',
|
||||
name: `${pvc.name}-${Date.now()}`,
|
||||
namespace: pvc.namespace,
|
||||
});
|
||||
|
||||
if (!pvc.name || !pvc.namespace || !pvc.metadata?.uid) {
|
||||
console.error('Missing required PVC metadata for event creation');
|
||||
return;
|
||||
}
|
||||
|
||||
await event.patch({
|
||||
metadata: {
|
||||
namespace: pvc.namespace,
|
||||
},
|
||||
},
|
||||
});
|
||||
involvedObject: {
|
||||
apiVersion: pvc.apiVersion,
|
||||
kind: 'PersistentVolumeClaim',
|
||||
name: pvc.name,
|
||||
namespace: pvc.namespace,
|
||||
uid: pvc.metadata.uid,
|
||||
},
|
||||
type,
|
||||
reason,
|
||||
message,
|
||||
source: {
|
||||
component: PROVISIONER,
|
||||
},
|
||||
firstTimestamp: new Date(),
|
||||
lastTimestamp: new Date(),
|
||||
count: 1,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Failed to create event for PVC ${pvc.namespace}/${pvc.name}:`, error);
|
||||
}
|
||||
};
|
||||
|
||||
public start = async () => {
|
||||
@@ -79,4 +159,4 @@ class StorageProvider {
|
||||
};
|
||||
}
|
||||
|
||||
export { StorageProvider };
|
||||
export { StorageProvider, PROVISIONER };
|
||||
|
||||
Reference in New Issue
Block a user