9import { CustomObjectsApi } from '@kubernetes/client-node' 11export const k8sLonghornBackup = async ({bucket_name}: {bucket_name: string}) => { 14 const {endpoint, secretAccessKey, accessKeyId} = getS3Cfg({bucket_name}) 16 const backupTargetSecName = `longhorn-backuptarget-${bucket_name}` 17 const longhornUrl = `s3://${bucket_name}@dummyregion/` 23 namespace: 'longhorn-system', 24 name: backupTargetSecName, 26 AWS_ACCESS_KEY_ID: accessKeyId, 27 AWS_SECRET_ACCESS_KEY: secretAccessKey, 28 AWS_ENDPOINTS: endpoint, 32 apiVersion: 'longhorn.io/v1beta2', 36 namespace: 'longhorn-system', 39 backupTargetURL: longhornUrl, 40 credentialSecret: backupTargetSecName, 48type LonghornSetting = { 53const longhornSettingTmpl = ({name, value}: LonghornSetting) => ({ 54 apiVersion: 'longhorn.io/v1beta2', 58 namespace: 'longhorn-system', 63export const k8sLonghornSettings = async (settings: LonghornSetting[]) => { 68 resources: settings.map(longhornSettingTmpl), 72type VolumeReplicaSpec = { 74 desiredReplicaCnt: number 77export const k8sLonghornVolumeReconcile = async (specs: VolumeReplicaSpec[]) => { 80 const custObjApi = kubeConfig.makeApiClient(CustomObjectsApi) 82 for (const {pvcName, desiredReplicaCnt} of specs) { 84 resource: {apiVersion: 'v1', kind: 'PersistentVolumeClaim', metadata: {name: pvcName}}, 87 if (!pvc?.spec?.volumeName) { 88 betLog({pvcName, skipped: 'PVC not found or not bound'}) 92 const pvName = pvc.spec.volumeName 94 resource: {apiVersion: 'longhorn.io/v1beta2', kind: 'Volume', metadata: {name: pvName, namespace: 'longhorn-system'}}, 98 betLog({pvcName, skipped: 'no Longhorn volume'}) 102 const currentReplicas = lhVol.spec?.numberOfReplicas 103 const robustness = lhVol.status?.robustness 104 if (currentReplicas === desiredReplicaCnt && robustness === 'healthy') { 105 betLog({pvcName, pvName, replicas: currentReplicas, robustness, skipped: 'already correct'}) 109 if (robustness !== 'healthy' && currentReplicas <= desiredReplicaCnt) { 110 betLog({pvcName, pvName, replicas: currentReplicas, robustness, skipped: 'volume not healthy, not bumping replicas'}) 114 if (robustness !== 'healthy' && currentReplicas > desiredReplicaCnt) { 115 betLog({pvcName, pvName, replicas: `${currentReplicas} -> ${desiredReplicaCnt}`, robustness, action: 'self-heal down (sick + over-provisioned)'}) 116 await custObjApi.patchNamespacedCustomObject({ 117 group: 'longhorn.io', version: 'v1beta2', 118 namespace: 'longhorn-system', plural: 'volumes', name: pvName, 119 body: [{op: 'replace', path: '/spec/numberOfReplicas', value: desiredReplicaCnt}], 124 betLog({pvcName, pvName, replicas: `${currentReplicas} -> ${desiredReplicaCnt}`, robustness}) 125 await custObjApi.patchNamespacedCustomObject({ 126 group: 'longhorn.io', version: 'v1beta2', 127 namespace: 'longhorn-system', plural: 'volumes', name: pvName, 128 body: [{op: 'replace', path: '/spec/numberOfReplicas', value: desiredReplicaCnt}],