diff --git a/charts/uik8sappscodecom-featureset-opscenter-observability-editor/templates/helm_toolkit_fluxcd_io_helm_release_prom_label_proxy.yaml b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/templates/helm_toolkit_fluxcd_io_helm_release_prom_label_proxy.yaml new file mode 100644 index 0000000000..9da062a198 --- /dev/null +++ b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/templates/helm_toolkit_fluxcd_io_helm_release_prom_label_proxy.yaml @@ -0,0 +1,5 @@ +{{- with .Values.resources }} +{{- with .helmToolkitFluxcdIoHelmRelease_prom_label_proxy }} +{{- . | toYaml }} +{{- end }} +{{- end }} diff --git a/charts/uik8sappscodecom-featureset-opscenter-observability-editor/templates/helm_toolkit_fluxcd_io_helm_release_tenant_operator.yaml b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/templates/helm_toolkit_fluxcd_io_helm_release_tenant_operator.yaml new file mode 100644 index 0000000000..6be434417d --- /dev/null +++ b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/templates/helm_toolkit_fluxcd_io_helm_release_tenant_operator.yaml @@ -0,0 +1,5 @@ +{{- with .Values.resources }} +{{- with .helmToolkitFluxcdIoHelmRelease_tenant_operator }} +{{- . | toYaml }} +{{- end }} +{{- end }} diff --git a/charts/uik8sappscodecom-featureset-opscenter-observability-editor/templates/helm_toolkit_fluxcd_io_helm_release_thanos_operator.yaml b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/templates/helm_toolkit_fluxcd_io_helm_release_thanos_operator.yaml new file mode 100644 index 0000000000..9e906b7d19 --- /dev/null +++ b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/templates/helm_toolkit_fluxcd_io_helm_release_thanos_operator.yaml @@ -0,0 +1,5 @@ +{{- with .Values.resources }} +{{- with .helmToolkitFluxcdIoHelmRelease_thanos_operator }} +{{- . | toYaml }} +{{- end }} +{{- end }} diff --git a/charts/uik8sappscodecom-featureset-opscenter-observability-editor/ui/create-ui.yaml b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/ui/create-ui.yaml index 2262c411b0..9aae7255fd 100644 --- a/charts/uik8sappscodecom-featureset-opscenter-observability-editor/ui/create-ui.yaml +++ b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/ui/create-ui.yaml @@ -1,25 +1,38 @@ step: -- elements: - - individualDisability: disableFeatures - init: - type: func - value: getEnabledFeatures - label: "" - loader: fetchFeatureSetOptions - schema: temp/properties/enabledFeatures - type: checkbox - watcher: - func: onEnabledFeaturesChange - paths: - - temp/properties/enabledFeatures - - customClass: mt-24 - label: 'Note: Enabling a feature auto enables any prerequisite features' - type: info - watcher: - func: checkIsResourceLoaded - paths: - - temp/properties/isResourceLoaded - id: opscenter-monitoring - loader: setReleaseNameAndNamespaceAndInitializeValues - type: single-step-form + - elements: + - individualDisability: disableFeatures + init: + type: func + value: getEnabledFeatures + label: '' + loader: fetchFeatureSetOptions + schema: temp/properties/enabledFeatures + type: checkbox + watcher: + func: onEnabledFeaturesChange + paths: + - temp/properties/enabledFeatures + - customClass: mt-24 + label: 'Note: Enabling a feature auto enables any prerequisite features' + type: info + watcher: + func: checkIsResourceLoaded + paths: + - temp/properties/isResourceLoaded + - type: select + if: + name: checkIsOtelStackEnabled + type: function + loader: fetchMonitoringClusterOptions + label: Select Monitoring Cluster + schema: temp/properties/monitoringClusterName + watcher: + func: onMonitoringClusterChange + paths: + - temp/properties/monitoringClusterName + validation: + type: required + id: opscenter-monitoring + loader: setReleaseNameAndNamespaceAndInitializeValues + type: single-step-form type: multi-step-form diff --git a/charts/uik8sappscodecom-featureset-opscenter-observability-editor/ui/functions.js b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/ui/functions.js index 52d045e26b..a82b69fb88 100644 --- a/charts/uik8sappscodecom-featureset-opscenter-observability-editor/ui/functions.js +++ b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/ui/functions.js @@ -8,6 +8,7 @@ export const useFunc = (model) => { setDiscriminatorValue('/enabledFeatures', []) setDiscriminatorValue('/isResourceLoaded', false) + const appsCodeOtelStack = 'appscode-otel-stack' let resources = {} // get specific feature details @@ -210,12 +211,57 @@ export const useFunc = (model) => { return resourceValuePath } - function onEnabledFeaturesChange() { + function deepMergeValues(existingValues, newValues) { + if (!newValues) return existingValues + if (!existingValues) return newValues + + const merged = { ...existingValues } + + Object.keys(newValues).forEach((key) => { + if ( + typeof newValues[key] === 'object' && + newValues[key] !== null && + !Array.isArray(newValues[key]) + ) { + merged[key] = deepMergeValues(existingValues[key], newValues[key]) + } else { + merged[key] = newValues[key] + } + }) + + return merged + } + + // fetch monitoring cluster configuration + async function fetchMonitoringClusterConfig(monitoringClusterName) { + if (!monitoringClusterName) { + return null + } + + const getRoute = storeGet('/route') + const spokeCluster = getRoute.params?.spoke + const owner = storeGet('/route/params/user') + const cluster = storeGet('/route/params/cluster') + let url = `/telemetry/${owner}/${monitoringClusterName}/values/appscode-otel-stack` + if (cluster) { + if (getRoute.fullPath.includes('/hubs/') && spokeCluster) { + url += `?targetClusterName=${encodeURIComponent(spokeCluster)}` + } else { + url += `?targetClusterName=${encodeURIComponent(cluster)}` + } + } + const { data } = await axios.get(url) + return data + } + + async function onEnabledFeaturesChange() { const enabledFeatures = getValue(discriminator, '/enabledFeatures') || [] + const monitoringClusterName = getValue(discriminator, '/monitoringClusterName') + let monitoringClusterConfig = getValue(discriminator, '/monitoringClusterConfig') const allFeatures = storeGet('/cluster/features/result') || [] - allFeatures.forEach((item) => { + for (const item of allFeatures) { const featureName = item?.metadata?.name || '' const resourceValuePath = getResourceValuePathFromFeature(item) @@ -233,6 +279,23 @@ export const useFunc = (model) => { if (isEnabled && !isManaged) { commit('wizard/model$delete', `/resources/${resourceValuePath}`) } else { + // Merge existing values with otelStack data only for appscode-otel-stack feature + const initialResourceValues = resources?.[resourceValuePath]?.spec?.values + let mergedResourceValues = initialResourceValues + + let finalSourceRef = sourceRef + if ( + featureName === appsCodeOtelStack && + monitoringClusterName && + monitoringClusterConfig + ) { + mergedResourceValues = deepMergeValues(initialResourceValues, monitoringClusterConfig) + finalSourceRef = { + ...sourceRef, + monitoringCluster: monitoringClusterName, + } + } + commit('wizard/model$update', { path: `/resources/${resourceValuePath}`, value: { @@ -247,10 +310,11 @@ export const useFunc = (model) => { }, spec: { ...resources?.[resourceValuePath]?.spec, + values: mergedResourceValues, chart: { spec: { chart, - sourceRef, + sourceRef: finalSourceRef, version, }, }, @@ -263,7 +327,7 @@ export const useFunc = (model) => { } else { commit('wizard/model$delete', `/resources/${resourceValuePath}`) } - }) + } } function returnFalse() { @@ -359,14 +423,61 @@ export const useFunc = (model) => { // this computed's main purpose is to watch isResourceLoaded flag // and fire the onEnabledFeatureChange function when it's true - function checkIsResourceLoaded() { + async function checkIsResourceLoaded() { // watchDependency('discriminator#/isResourceLoaded') const isResourceLoaded = getValue(discriminator, '/isResourceLoaded') if (isResourceLoaded) { - onEnabledFeaturesChange() + await onEnabledFeaturesChange() } } + //this function is used to check if AppsCode OpenTelemetry Stack is enabled + //it is the condition to show monitoring cluster dropdown + function checkIsOtelStackEnabled() { + // watchDependency('discriminator#/enabledFeatures') + const enabledFeatures = getValue(discriminator, '/enabledFeatures') || [] + if (enabledFeatures.includes(appsCodeOtelStack)) { + return true + } + return false + } + + //this function is used to fetch monitoring cluster options from dropdown + async function fetchMonitoringClusterOptions() { + const enabledFeatures = getValue(discriminator, '/enabledFeatures') || [] + if (!enabledFeatures.includes(appsCodeOtelStack)) { + return [] + } + + const getRoute = storeGet('/route') + const spokeCluster = getRoute.params?.spoke + const owner = storeGet('/route/params/user') + const cluster = storeGet('/route/params/cluster') + let url = `/telemetry/${owner}/monitoring-clusters` + if (cluster) { + if (getRoute.fullPath.includes('/hubs/') && spokeCluster) { + url += `?targetClusterName=${encodeURIComponent(spokeCluster)}` + } else { + url += `?targetClusterName=${encodeURIComponent(cluster)}` + } + } + const { data } = await axios.get(url) + + return data || [] + } + + async function onMonitoringClusterChange() { + const monitoringClusterName = getValue(discriminator, '/monitoringClusterName') + if (!monitoringClusterName) { + return + } + + const data = await fetchMonitoringClusterConfig(monitoringClusterName) + + setDiscriminatorValue('/monitoringClusterConfig', data) + await onEnabledFeaturesChange() + } + return { hideThisElement, checkIsResourceLoaded, @@ -380,5 +491,8 @@ export const useFunc = (model) => { returnFalse, setReleaseNameAndNamespaceAndInitializeValues, fetchFeatureSetOptions, + checkIsOtelStackEnabled, + fetchMonitoringClusterOptions, + onMonitoringClusterChange, } } diff --git a/charts/uik8sappscodecom-featureset-opscenter-observability-editor/values.yaml b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/values.yaml index cc64606e02..7f70491af7 100644 --- a/charts/uik8sappscodecom-featureset-opscenter-observability-editor/values.yaml +++ b/charts/uik8sappscodecom-featureset-opscenter-observability-editor/values.yaml @@ -195,6 +195,99 @@ resources: crds: CreateReplace remediation: retries: -1 + helmToolkitFluxcdIoHelmRelease_prom_label_proxy: # +doc-gen:break + apiVersion: helm.toolkit.fluxcd.io/v2 + kind: HelmRelease + metadata: + labels: + app.kubernetes.io/component: prom-label-proxy + name: prom-label-proxy + namespace: kubeops + spec: + chart: + spec: + chart: prom-label-proxy + sourceRef: + kind: HelmRepository + name: appscode-charts-oci + namespace: kubeops + version: v2025.4.30 + install: + crds: CreateReplace + createNamespace: true + remediation: + retries: -1 + interval: 5m + releaseName: prom-label-proxy + storageNamespace: monitoring + targetNamespace: monitoring + timeout: 30m + upgrade: + crds: CreateReplace + remediation: + retries: -1 + helmToolkitFluxcdIoHelmRelease_thanos_operator: # +doc-gen:break + apiVersion: helm.toolkit.fluxcd.io/v2 + kind: HelmRelease + metadata: + labels: + app.kubernetes.io/component: thanos-operator + name: thanos-operator + namespace: kubeops + spec: + chart: + spec: + chart: thanos-operator + sourceRef: + kind: HelmRepository + name: appscode-charts-oci + namespace: kubeops + version: v2025.4.30 + install: + crds: CreateReplace + createNamespace: true + remediation: + retries: -1 + interval: 5m + releaseName: thanos-operator + storageNamespace: monitoring + targetNamespace: monitoring + timeout: 30m + upgrade: + crds: CreateReplace + remediation: + retries: -1 + helmToolkitFluxcdIoHelmRelease_tenant_operator: # +doc-gen:break + apiVersion: helm.toolkit.fluxcd.io/v2 + kind: HelmRelease + metadata: + labels: + app.kubernetes.io/component: tenant-operator + name: tenant-operator + namespace: kubeops + spec: + chart: + spec: + chart: tenant-operator + sourceRef: + kind: HelmRepository + name: appscode-charts-oci + namespace: kubeops + version: v2025.4.30 + install: + crds: CreateReplace + createNamespace: true + remediation: + retries: -1 + interval: 5m + releaseName: tenant-operator + storageNamespace: monitoring + targetNamespace: monitoring + timeout: 30m + upgrade: + crds: CreateReplace + remediation: + retries: -1 helmToolkitFluxcdIoHelmRelease_kube_prometheus_stack: # +doc-gen:break apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease