apiVersion: config.karmada.io/v1alpha1 kind: ResourceInterpreterCustomization metadata: name: declarative-configuration-helmrelease spec: target: apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease customizations: healthInterpretation: luaScript: > function InterpretHealth(observedObj) if observedObj.status ~= nil and observedObj.status.conditions ~= nil then for conditionIndex = 1, #observedObj.status.conditions do if observedObj.status.conditions[conditionIndex].type == 'Ready' and observedObj.status.conditions[conditionIndex].status == 'True' and observedObj.status.conditions[conditionIndex].reason == 'ReconciliationSucceeded' then return true end end end return false end statusAggregation: luaScript: > function AggregateStatus(desiredObj, statusItems) if desiredObj.status == nil then desiredObj.status = {} end if desiredObj.metadata.generation == nil then desiredObj.metadata.generation = 0 end if desiredObj.status.observedGeneration == nil then desiredObj.status.observedGeneration = 0 end -- Initialize status fields if status doest not exist -- If the Kustomization is not spread to any cluster, its status also should be aggregated if statusItems == nil then desiredObj.status.observedGeneration = desiredObj.metadata.generation desiredObj.status.lastAttemptedRevision = '' desiredObj.status.lastAppliedRevision = '' desiredObj.status.lastAttemptedValuesChecksum = '' desiredObj.status.helmChart = '' desiredObj.status.lastReleaseRevision = '' desiredObj.status.failures = 0 desiredObj.status.upgradeFailures = 0 desiredObj.status.installFailures = 0 desiredObj.status.conditions = {} return desiredObj end local conditions = {} local generation = desiredObj.metadata.generation local lastAttemptedRevision = desiredObj.status.lastAttemptedRevision local lastAppliedRevision = desiredObj.status.lastAppliedRevision local lastAttemptedValuesChecksum = desiredObj.status.lastAttemptedValuesChecksum local helmChart = desiredObj.status.helmChart local lastReleaseRevision = desiredObj.status.lastReleaseRevision local failures = desiredObj.status.failures local upgradeFailures = desiredObj.status.upgradeFailures local installFailures = desiredObj.status.installFailures -- Count all members that their status is updated to the latest generation local observedResourceTemplateGenerationCount = 0 local conditionsIndex = 1 for i = 1, #statusItems do if statusItems[i].status ~= nil and statusItems[i].status.lastAttemptedRevision ~= nil and statusItems[i].status.lastAttemptedRevision ~= '' then lastAttemptedRevision = statusItems[i].status.lastAttemptedRevision end if statusItems[i].status ~= nil and statusItems[i].status.lastAppliedRevision ~= nil and statusItems[i].status.lastAppliedRevision ~= '' then lastAppliedRevision = statusItems[i].status.lastAppliedRevision end if statusItems[i].status ~= nil and statusItems[i].status.lastAttemptedValuesChecksum ~= nil and statusItems[i].status.lastAttemptedValuesChecksum ~= '' then lastAttemptedValuesChecksum = statusItems[i].status.lastAttemptedValuesChecksum end if statusItems[i].status ~= nil and statusItems[i].status.helmChart ~= nil and statusItems[i].status.helmChart ~= '' then helmChart = statusItems[i].status.helmChart end if statusItems[i].status ~= nil and statusItems[i].status.lastReleaseRevision ~= nil then lastReleaseRevision = statusItems[i].status.lastReleaseRevision end if statusItems[i].status ~= nil and statusItems[i].status.failures ~= nil then if desiredObj.status.failures ~= nil then failures = failures + statusItems[i].status.failures end end if statusItems[i].status ~= nil and statusItems[i].status.upgradeFailures ~= nil then if desiredObj.status.upgradeFailures ~= nil then upgradeFailures = upgradeFailures + statusItems[i].status.upgradeFailures end end if statusItems[i].status ~= nil and statusItems[i].status.installFailures ~= nil then if desiredObj.status.installFailures ~= nil then installFailures = installFailures + statusItems[i].status.installFailures end end if statusItems[i].status ~= nil and statusItems[i].status.conditions ~= nil then for conditionIndex = 1, #statusItems[i].status.conditions do statusItems[i].status.conditions[conditionIndex].message = statusItems[i].clusterName..'='..statusItems[i].status.conditions[conditionIndex].message hasCondition = false for index = 1, #conditions do if conditions[index].type == statusItems[i].status.conditions[conditionIndex].type and conditions[index].status == statusItems[i].status.conditions[conditionIndex].status and conditions[index].reason == statusItems[i].status.conditions[conditionIndex].reason then conditions[index].message = conditions[index].message..', '..statusItems[i].status.conditions[conditionIndex].message hasCondition = true break end end if not hasCondition then conditions[conditionsIndex] = statusItems[i].status.conditions[conditionIndex] conditionsIndex = conditionsIndex + 1 end end end -- Check if the member's status is updated to the latest generation local resourceTemplateGeneration = 0 if statusItems[i].status ~= nil and statusItems[i].status.resourceTemplateGeneration ~= nil then resourceTemplateGeneration = statusItems[i].status.resourceTemplateGeneration end local memberGeneration = 0 if statusItems[i].status ~= nil and statusItems[i].status.generation ~= nil then memberGeneration = statusItems[i].status.generation end local memberObservedGeneration = 0 if statusItems[i].status ~= nil and statusItems[i].status.observedGeneration ~= nil then memberObservedGeneration = statusItems[i].status.observedGeneration end if resourceTemplateGeneration == generation and memberGeneration == memberObservedGeneration then observedResourceTemplateGenerationCount = observedResourceTemplateGenerationCount + 1 end end -- Update the observed generation based on the observedResourceTemplateGenerationCount if observedResourceTemplateGenerationCount == #statusItems then desiredObj.status.observedGeneration = generation else desiredObj.status.observedGeneration = observedGeneration end desiredObj.status.conditions = conditions desiredObj.status.lastAttemptedRevision = lastAttemptedRevision desiredObj.status.lastAppliedRevision = lastAppliedRevision desiredObj.status.lastAttemptedValuesChecksum = lastAttemptedValuesChecksum desiredObj.status.helmChart = helmChart desiredObj.status.lastReleaseRevision = lastReleaseRevision desiredObj.status.failures = failures desiredObj.status.upgradeFailures = upgradeFailures desiredObj.status.installFailures = installFailures return desiredObj end retention: luaScript: > function Retain(desiredObj, observedObj) if observedObj.spec.suspend ~= nil then desiredObj.spec.suspend = observedObj.spec.suspend end return desiredObj end statusReflection: luaScript: > function ReflectStatus (observedObj) local status = {} if observedObj == nil or observedObj.status == nil then return status end status.conditions = observedObj.status.conditions status.observedGeneration = observedObj.status.observedGeneration status.lastAttemptedRevision = observedObj.status.lastAttemptedRevision status.lastAppliedRevision = observedObj.status.lastAppliedRevision status.lastAttemptedValuesChecksum = observedObj.status.lastAttemptedValuesChecksum status.helmChart = observedObj.status.helmChart status.lastReleaseRevision = observedObj.status.lastReleaseRevision status.failures = observedObj.status.failures status.upgradeFailures = observedObj.status.upgradeFailures status.installFailures = observedObj.status.installFailures -- handle resource generation report if observedObj.metadata == nil then return status end status.generation = observedObj.metadata.generation if observedObj.metadata.annotations == nil then return status end local resourceTemplateGeneration = tonumber(observedObj.metadata.annotations["resourcetemplate.karmada.io/generation"]) if resourceTemplateGeneration ~= nil then status.resourceTemplateGeneration = resourceTemplateGeneration end return status end dependencyInterpretation: luaScript: > function GetDependencies(desiredObj) dependentSecrets = {} dependentSas = {} dependentCms = {} refs = {} local idx = 1 if desiredObj.spec.valuesFrom ~= nil then valuesFrom = desiredObj.spec.valuesFrom for valuesIndex = 1, #valuesFrom do if valuesFrom[valuesIndex].kind == 'Secret' then dependentSecrets[valuesFrom[valuesIndex].name] = true end if valuesFrom[valuesIndex].kind == 'ConfigMap' then dependentCms[valuesFrom[valuesIndex].name] = true end end end if desiredObj.spec.chart ~= nil and desiredObj.spec.chart.spec ~= nil and desiredObj.spec.chart.spec.verify ~= nil and desiredObj.spec.chart.spec.verify.secretRef ~= nil and desiredObj.spec.chart.spec.verify.secretRef.name ~= '' then dependentSecrets[desiredObj.spec.chart.spec.verify.secretRef.name] = true end if desiredObj.spec.kubeConfig ~= nil and desiredObj.spec.kubeConfig.secretRef ~= nil and desiredObj.spec.kubeConfig.secretRef.name ~= '' then dependentSecrets[desiredObj.spec.kubeConfig.secretRef.name] = true end if desiredObj.spec.serviceAccountName ~= nil and desiredObj.spec.serviceAccountName ~= '' then dependentSas[desiredObj.spec.serviceAccountName] = true end for key, value in pairs(dependentSecrets) do dependObj = {} dependObj.apiVersion = 'v1' dependObj.kind = 'Secret' dependObj.name = key dependObj.namespace = desiredObj.metadata.namespace refs[idx] = dependObj idx = idx + 1 end for key, value in pairs(dependentSas) do dependObj = {} dependObj.apiVersion = 'v1' dependObj.kind = 'ServiceAccount' dependObj.name = key dependObj.namespace = desiredObj.metadata.namespace refs[idx] = dependObj idx = idx + 1 end for key, value in pairs(dependentCms) do dependObj = {} dependObj.apiVersion = 'v1' dependObj.kind = 'ConfigMap' dependObj.name = key dependObj.namespace = desiredObj.metadata.namespace refs[idx] = dependObj idx = idx + 1 end return refs end