From cd63d0fb681ccdee9bc7d137ba08c2ac9036d934 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Sat, 27 Sep 2025 01:22:50 +0530 Subject: [PATCH 01/55] K8s agent as addon --- api/v1alpha1/addon_types.go | 21 ++ api/v1alpha1/constants.go | 2 + ...ren.nutanix.com_nutanixclusterconfigs.yaml | 29 ++ api/v1alpha1/zz_generated.deepcopy.go | 41 +++ api/variables/aggregate_types.go | 6 + .../README.md | 2 + .../values-template.yaml | 31 ++ .../templates/deployment.yaml | 1 + .../templates/helm-config.yaml | 4 + .../helm-addon-installation.yaml | 12 + .../values.schema.json | 21 ++ .../values.yaml | 5 + docs/content/addons/k8s-registration-agent.md | 30 ++ .../nutanix-cluster-calico-crs.yaml | 1 + .../nutanix-cluster-calico-helm-addon.yaml | 1 + .../nutanix-cluster-cilium-crs.yaml | 1 + .../nutanix-cluster-cilium-helm-addon.yaml | 1 + ...luster-with-failuredomains-cilium-crs.yaml | 1 + ...with-failuredomains-cilium-helm-addon.yaml | 1 + hack/addons/helm-chart-bundler/repos.yaml | 5 + .../kustomization.yaml.tmpl | 18 + .../nutanix/cluster/kustomization.yaml.tmpl | 3 + .../nutanix/k8s-registration-agent.yaml | 6 + hack/tools/fetch-images/main.go | 2 + make/addons.mk | 2 + .../lifecycle/k8sregistrationagent/doc.go | 8 + .../lifecycle/k8sregistrationagent/handler.go | 328 ++++++++++++++++++ .../k8sregistrationagent/variables_test.go | 57 +++ pkg/handlers/lifecycle/config/cm.go | 1 + pkg/handlers/lifecycle/handlers.go | 95 ++--- 30 files changed, 691 insertions(+), 45 deletions(-) create mode 100644 charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml create mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/k8s-registration-agent/helm-addon-installation.yaml create mode 100644 docs/content/addons/k8s-registration-agent.md create mode 100644 hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl create mode 100644 hack/examples/patches/nutanix/k8s-registration-agent.yaml create mode 100644 pkg/handlers/generic/lifecycle/k8sregistrationagent/doc.go create mode 100644 pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go create mode 100644 pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 1d32e8905..6fdfddde6 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -85,6 +85,9 @@ type NutanixAddons struct { // +kubebuilder:validation:Optional COSI *NutanixCOSI `json:"cosi,omitempty"` + + // +kubebuilder:validation:Optional + K8sRegistrationAgent *NutanixK8sRegistrationAgent `json:"k8sRegistrationAgent,omitempty"` } type GenericAddons struct { @@ -359,3 +362,21 @@ type RegistryAddon struct { // +kubebuilder:validation:Enum="CNCF Distribution" Provider string `json:"provider"` } + +type NutanixK8sRegistrationAgent struct { + // A reference to the Secret for credential information for the target Prism Central instance + // +kubebuilder:validation:Optional + Credentials *NutanixK8sAgentCredentials `json:"credentials,omitempty"` + + // Addon strategy used to deploy the Nutanix k8s-registration-agent to the k8s cluster. + // +kubebuilder:default=HelmAddon + // +kubebuilder:validation:Optional + // +kubebuilder:validation:Enum=ClusterResourceSet;HelmAddon + Strategy AddonStrategy `json:"strategy,omitzero"` +} + +type NutanixK8sAgentCredentials struct { + // A reference to the Secret containing the credentials used by the CCM provider. + // +kubebuilder:validation:Required + SecretRef LocalObjectReference `json:"secretRef"` +} diff --git a/api/v1alpha1/constants.go b/api/v1alpha1/constants.go index 1093bd273..c4ce187f0 100644 --- a/api/v1alpha1/constants.go +++ b/api/v1alpha1/constants.go @@ -32,6 +32,8 @@ const ( ServiceLoadBalancerVariableName = "serviceLoadBalancer" // RegistryAddonVariableName is the OCI registry config patch variable name. RegistryAddonVariableName = "registry" + // K8sRegistrationAgentVariableName is the Nutanix k8s-registration-agent addon config patch variable name. + K8sRegistrationAgentVariableName = "k8sRegistrationAgent" // GlobalMirrorVariableName is the global image registry mirror patch variable name. GlobalMirrorVariableName = "globalImageRegistryMirror" diff --git a/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml b/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml index b9979c1c4..ccba81174 100644 --- a/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml +++ b/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml @@ -235,6 +235,35 @@ spec: - defaultStorage - providers type: object + k8sRegistrationAgent: + properties: + credentials: + description: A reference to the Secret for credential information for the target Prism Central instance + properties: + secretRef: + description: A reference to the Secret containing the credentials used by the CCM provider. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + maxLength: 253 + minLength: 1 + type: string + required: + - name + type: object + required: + - secretRef + type: object + strategy: + default: HelmAddon + description: Addon strategy used to deploy the Nutanix k8s-registration-agent to the k8s cluster. + enum: + - ClusterResourceSet + - HelmAddon + type: string + type: object nfd: description: NFD tells us to enable or disable the node feature discovery addon. properties: diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 134fcf24f..76d12db5a 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1702,6 +1702,11 @@ func (in *NutanixAddons) DeepCopyInto(out *NutanixAddons) { *out = new(NutanixCOSI) **out = **in } + if in.K8sRegistrationAgent != nil { + in, out := &in.K8sRegistrationAgent, &out.K8sRegistrationAgent + *out = new(NutanixK8sRegistrationAgent) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixAddons. @@ -1879,6 +1884,42 @@ func (in *NutanixControlPlaneSpec) DeepCopy() *NutanixControlPlaneSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NutanixK8sAgentCredentials) DeepCopyInto(out *NutanixK8sAgentCredentials) { + *out = *in + out.SecretRef = in.SecretRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixK8sAgentCredentials. +func (in *NutanixK8sAgentCredentials) DeepCopy() *NutanixK8sAgentCredentials { + if in == nil { + return nil + } + out := new(NutanixK8sAgentCredentials) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NutanixK8sRegistrationAgent) DeepCopyInto(out *NutanixK8sRegistrationAgent) { + *out = *in + if in.Credentials != nil { + in, out := &in.Credentials, &out.Credentials + *out = new(NutanixK8sAgentCredentials) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixK8sRegistrationAgent. +func (in *NutanixK8sRegistrationAgent) DeepCopy() *NutanixK8sRegistrationAgent { + if in == nil { + return nil + } + out := new(NutanixK8sRegistrationAgent) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NutanixMachineDetails) DeepCopyInto(out *NutanixMachineDetails) { *out = *in diff --git a/api/variables/aggregate_types.go b/api/variables/aggregate_types.go index 267fde218..a0e25c6e6 100644 --- a/api/variables/aggregate_types.go +++ b/api/variables/aggregate_types.go @@ -66,6 +66,12 @@ type Addons struct { CSI *CSI `json:"csi,omitempty"` COSI *COSI `json:"cosi,omitempty"` + + NutanixK8sRegistrationAgent *NutanixK8sRegistrationAgent `json:"k8sRegistrationAgent,omitempty"` +} + +type NutanixK8sRegistrationAgent struct { + carenv1.NutanixK8sRegistrationAgent `json:",inline"` } type CSI struct { diff --git a/charts/cluster-api-runtime-extensions-nutanix/README.md b/charts/cluster-api-runtime-extensions-nutanix/README.md index 94ddf736c..ea9d7c903 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/README.md +++ b/charts/cluster-api-runtime-extensions-nutanix/README.md @@ -96,6 +96,8 @@ A Helm chart for cluster-api-runtime-extensions-nutanix | hooks.registrySyncer.defaultValueTemplateConfigMap.name | string | `"default-registry-syncer-helm-values-template"` | | | hooks.serviceLoadBalancer.metalLB.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.serviceLoadBalancer.metalLB.defaultValueTemplateConfigMap.name | string | `"default-metallb-helm-values-template"` | | +| hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | +| hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-k8s-registrationagent-helm-values-template"` | | | image.pullPolicy | string | `"IfNotPresent"` | | | image.repository | string | `"ghcr.io/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix"` | | | image.tag | string | `""` | | diff --git a/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml b/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml new file mode 100644 index 000000000..edc180e3d --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml @@ -0,0 +1,31 @@ +agent: + namespaceOverride: ntnx-system + name: nutanix-agent + port: 8080 + image: + repository: docker.io/nutanix + name: nke-k8s-agent + pullPolicy: IfNotPresent + tag: "688" + privateRegistry: true + imageCredentials: + dockerconfig: replace_base64_encoded_creds + updateConfigInMin: 10 + updateMetricsInMin: 360 + config: + registration: + delete: + force: false + kubeconfig: + delete: + force: false + +pc: + port: {{ .PrismCentralPort }} + insecure: {{ .PrismCentralInsecure }} #set this to true if PC does not have https enabled + endpoint: {{ .PrismCentralHost }} # eg: ip or fqdn + username: "DCFSPpwNEOuG" # eg: admin or any other user with Kubernetes Infrastructure provision role + password: "gHVU2vO64xwIt3Lz09aSQ85p1su7mKDr" +k8sClusterName: {{ .ClusterName }} +k8sDistribution: "CAPX" # eg: CAPX or NKE or OCP or EKSA or NKP +categoryMappings: "" # "one or more comma separated key=value" eg: "key1=value1" or "key1=value1\,key2=value2" diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml index 22672cb3e..cb1b26397 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml @@ -45,6 +45,7 @@ spec: - --csi.snapshot-controller.helm-addon.default-values-template-configmap-name={{ (index .Values.hooks.csi "snapshot-controller").helmAddonStrategy.defaultValueTemplateConfigMap.name }} - --ccm.aws.helm-addon.default-values-template-configmap-name={{ .Values.hooks.ccm.aws.helmAddonStrategy.defaultValueTemplateConfigMap.name }} - --cosi.controller.helm-addon.default-values-template-configmap-name={{ .Values.hooks.cosi.controller.helmAddonStrategy.defaultValueTemplateConfigMap.name }} + - --k8s-registration-agent.helm-addon.default-values-template-configmap-name={{ .Values.hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name }} {{- range $k, $v := .Values.hooks.ccm.aws.k8sMinorVersionToCCMVersion }} - --ccm.aws.aws-ccm-versions={{ $k }}={{ $v }} {{- end }} diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index 9d668b380..6d8eed0b6 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -31,6 +31,10 @@ data: ChartName: cosi ChartVersion: 0.0.1-alpha.5 RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://mesosphere.github.io/charts/stable/{{ end }}' + k8s-registration-agent: | + ChartName: nutanix-k8s-agent + ChartVersion: 0.0.1-alpha.1 + RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.3:8080{{ end }}' local-path-provisioner-csi: | ChartName: local-path-provisioner ChartVersion: 0.0.31 diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/k8s-registration-agent/helm-addon-installation.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/k8s-registration-agent/helm-addon-installation.yaml new file mode 100644 index 000000000..f32c4bd6b --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/k8s-registration-agent/helm-addon-installation.yaml @@ -0,0 +1,12 @@ +# Copyright 2025 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +{{- if .Values.hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: '{{ .Values.hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name }}' +data: + values.yaml: |- + {{- .Files.Get "addons/k8s-registration-agent/values-template.yaml" | nindent 4 }} +{{- end -}} diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.schema.json b/charts/cluster-api-runtime-extensions-nutanix/values.schema.json index c59eeba83..98e86b52b 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.schema.json +++ b/charts/cluster-api-runtime-extensions-nutanix/values.schema.json @@ -407,6 +407,27 @@ } } }, + "k8sRegistrationAgent": { + "properties": { + "helmAddonStrategy": { + "properties": { + "defaultValueTemplateConfigMap": { + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, "csi": { "type": "object", "properties": { diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.yaml b/charts/cluster-api-runtime-extensions-nutanix/values.yaml index d08e0eca6..519b0d142 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/values.yaml @@ -101,6 +101,11 @@ hooks: defaultValueTemplateConfigMap: create: true name: default-metallb-helm-values-template + k8sRegistrationAgent: + helmAddonStrategy: + defaultValueTemplateConfigMap: + create: true + name: default-k8s-registrationagent-helm-values-template cosi: controller: helmAddonStrategy: diff --git a/docs/content/addons/k8s-registration-agent.md b/docs/content/addons/k8s-registration-agent.md new file mode 100644 index 000000000..5b2756dd0 --- /dev/null +++ b/docs/content/addons/k8s-registration-agent.md @@ -0,0 +1,30 @@ ++++ +title = " Kubernets cluster registration addon" +icon = "fa-solid fa-object-group" ++++ + +By leveraging CAPI cluster lifecycle hooks, this handler deploys [Kubernetes cluster registration agent] +on the new cluster at the `AfterControlPlaneInitialized` phase. + +The hook uses the [Cluster API Add-on Provider for Helm] to deploy the k8s-registration resources. + +## Example + +To enable deployment of kubernets registration agent on a cluster, specify the following values: + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: +spec: + topology: + variables: + - name: clusterConfig + value: + addons: + k8sRegistrationAgent: {} +``` + +[Container Object Storage Interface]: https://github.com/nutanix-core/k8s-agent +[Cluster API Add-on Provider for Helm]: https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 2212645ed..82cbf4b36 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -74,6 +74,7 @@ spec: provider: Calico strategy: ClusterResourceSet cosi: {} + k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index 482dd0a1a..1f44691a6 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -72,6 +72,7 @@ spec: cni: provider: Calico cosi: {} + k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index 9ee987eec..df340959e 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -74,6 +74,7 @@ spec: provider: Cilium strategy: ClusterResourceSet cosi: {} + k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 094f84c1b..9a2220d83 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -72,6 +72,7 @@ spec: cni: provider: Cilium cosi: {} + k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index 7e9152a2d..40e90b1f0 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -110,6 +110,7 @@ spec: provider: Cilium strategy: ClusterResourceSet cosi: {} + k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index 0ba4c8594..689b4c71f 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -108,6 +108,7 @@ spec: cni: provider: Cilium cosi: {} + k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix diff --git a/hack/addons/helm-chart-bundler/repos.yaml b/hack/addons/helm-chart-bundler/repos.yaml index 159824de0..cfcb62d74 100644 --- a/hack/addons/helm-chart-bundler/repos.yaml +++ b/hack/addons/helm-chart-bundler/repos.yaml @@ -61,6 +61,11 @@ repositories: charts: nutanix-csi-storage: - 3.3.4 + nutanix-k8s-agent: + repoURL: http://192.168.1.3:8080 + charts: + nutanix-k8s-agent: + - 0.0.1-alpha.1 registry-syncer: repoURL: https://mesosphere.github.io/charts/staging/ charts: diff --git a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl new file mode 100644 index 000000000..1826f679a --- /dev/null +++ b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl @@ -0,0 +1,18 @@ +# Copyright 2025 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +metadata: + name: k8s-registration-agent-kustomize + +helmCharts: +- name: nutanix-k8s-agent + namespace: kube-system + #repo: https://mesosphere.github.io/charts/stable + repo: http://192.168.1.3:8080 + releaseName: k8s-registration-agent + version: ${K8S_REGISTRATION_AGENT_VERSION} + includeCRDs: true + skipTests: true diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index 207dc1d1d..399f1f2d2 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -33,6 +33,9 @@ patches: - target: kind: Cluster path: ../../../patches/nutanix/cosi.yaml +- target: + kind: Cluster + path: ../../../patches/nutanix/k8s-registration-agent.yaml - target: kind: Cluster path: ../../../patches/nutanix/ccm.yaml diff --git a/hack/examples/patches/nutanix/k8s-registration-agent.yaml b/hack/examples/patches/nutanix/k8s-registration-agent.yaml new file mode 100644 index 000000000..679c4a04c --- /dev/null +++ b/hack/examples/patches/nutanix/k8s-registration-agent.yaml @@ -0,0 +1,6 @@ +# Copyright 2025 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +- op: "add" + path: "/spec/topology/variables/0/value/addons/k8sRegistrationAgent" + value: {} diff --git a/hack/tools/fetch-images/main.go b/hack/tools/fetch-images/main.go index dcc84584a..52ded24e1 100644 --- a/hack/tools/fetch-images/main.go +++ b/hack/tools/fetch-images/main.go @@ -351,6 +351,8 @@ func getValuesFileForChartIfNeeded(chartName, carenChartDirectory string) (strin return tempFile.Name(), nil case "cosi-controller": return filepath.Join(carenChartDirectory, "addons", "cosi", "controller", defaultHelmAddonFilename), nil + case "k8s-registration-agent": + return filepath.Join(carenChartDirectory, "addons", "k8s-registration-agent", defaultHelmAddonFilename), nil case "metallb": return filepath.Join( carenChartDirectory, diff --git a/make/addons.mk b/make/addons.mk index 4bc086fac..3394f4c16 100644 --- a/make/addons.mk +++ b/make/addons.mk @@ -26,6 +26,8 @@ export METALLB_CHART_VERSION := 0.15.2 export COSI_CONTROLLER_VERSION := 0.0.1-alpha.5 +export K8S_REGISTRATION_AGENT_VERSION := 0.0.1-alpha.1 + .PHONY: addons.sync addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler snapshot-controller local-path-provisioner-csi aws-ebs-csi kube-vip) addons.sync: $(addprefix update-addon.aws-ccm.,130 131 132 133) diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/doc.go b/pkg/handlers/generic/lifecycle/k8sregistrationagent/doc.go new file mode 100644 index 000000000..419f9f4fe --- /dev/null +++ b/pkg/handlers/generic/lifecycle/k8sregistrationagent/doc.go @@ -0,0 +1,8 @@ +// Copyright 2023 Nutanix. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Package k8s-registration-agent provides a handler for managing k8s agent deployments on clusters +// +// +kubebuilder:rbac:groups=addons.cluster.x-k8s.io,resources=clusterresourcesets,verbs=watch;list;get;create;patch;update;delete +// +kubebuilder:rbac:groups="",resources=configmaps,verbs=watch;list;get;create;patch;update;delete +package k8sregistrationagent diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go new file mode 100644 index 000000000..e65c50cc8 --- /dev/null +++ b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go @@ -0,0 +1,328 @@ +// Copyright 2023 Nutanix. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package k8sregistrationagent + +import ( + "bytes" + "context" + "fmt" + "strings" + "text/template" + + "github.com/spf13/pflag" + corev1 "k8s.io/api/core/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + apivariables "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/variables" + commonhandlers "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/addons" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" + handlersutils "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/utils" +) + +const ( + defaultHelmReleaseName = "k8s-registration-agent" + defaultHelmReleaseNamespace = "ntnx-system" + defaultCredentialsSecretName = "nutanix-k8s-agent-credentials" +) + +type ControllerConfig struct { + *options.GlobalOptions + + helmAddonConfig *addons.HelmAddonConfig +} + +func NewControllerConfig(globalOptions *options.GlobalOptions) *ControllerConfig { + return &ControllerConfig{ + GlobalOptions: globalOptions, + helmAddonConfig: addons.NewHelmAddonConfig( + "default-k8sRegistrationAgent--helm-values-template", + defaultHelmReleaseNamespace, + defaultHelmReleaseName, + ), + } +} + +func (c *ControllerConfig) AddFlags(prefix string, flags *pflag.FlagSet) { + c.helmAddonConfig.AddFlags(prefix+".helm-addon", flags) +} + +type DefaultK8sRegistrtionAgent struct { + client ctrlclient.Client + config *ControllerConfig + helmChartInfoGetter *config.HelmChartGetter + + variableName string // points to the global config variable + variablePath []string // path of this variable on the global config variable +} + +var ( + _ commonhandlers.Named = &DefaultK8sRegistrtionAgent{} + _ lifecycle.AfterControlPlaneInitialized = &DefaultK8sRegistrtionAgent{} + _ lifecycle.BeforeClusterUpgrade = &DefaultK8sRegistrtionAgent{} +) + +func New( + c ctrlclient.Client, + cfg *ControllerConfig, + helmChartInfoGetter *config.HelmChartGetter, +) *DefaultK8sRegistrtionAgent { + return &DefaultK8sRegistrtionAgent{ + client: c, + config: cfg, + helmChartInfoGetter: helmChartInfoGetter, + variableName: v1alpha1.ClusterConfigVariableName, + variablePath: []string{"addons", v1alpha1.K8sRegistrationAgentVariableName}, + } +} + +func (n *DefaultK8sRegistrtionAgent) Name() string { + return "K8sRegistrationAgentHandler" +} + +func (n *DefaultK8sRegistrtionAgent) AfterControlPlaneInitialized( + ctx context.Context, + req *runtimehooksv1.AfterControlPlaneInitializedRequest, + resp *runtimehooksv1.AfterControlPlaneInitializedResponse, +) { + commonResponse := &runtimehooksv1.CommonResponse{} + n.apply(ctx, &req.Cluster, commonResponse) + resp.Status = commonResponse.GetStatus() + resp.Message = commonResponse.GetMessage() +} + +func (n *DefaultK8sRegistrtionAgent) BeforeClusterUpgrade( + ctx context.Context, + req *runtimehooksv1.BeforeClusterUpgradeRequest, + resp *runtimehooksv1.BeforeClusterUpgradeResponse, +) { + commonResponse := &runtimehooksv1.CommonResponse{} + n.apply(ctx, &req.Cluster, commonResponse) + resp.Status = commonResponse.GetStatus() + resp.Message = commonResponse.GetMessage() +} + +func (n *DefaultK8sRegistrtionAgent) apply( + ctx context.Context, + cluster *clusterv1.Cluster, + resp *runtimehooksv1.CommonResponse, +) { + clusterKey := ctrlclient.ObjectKeyFromObject(cluster) + + log := ctrl.LoggerFrom(ctx).WithValues( + "cluster", + clusterKey, + ) + + varMap := variables.ClusterVariablesToVariablesMap(cluster.Spec.Topology.Variables) + // log.Info("debug 1: %v", varMap) + k8sAgentVar, err := variables.Get[apivariables.NutanixK8sRegistrationAgent]( + varMap, + n.variableName, + n.variablePath...) + if err != nil { + if variables.IsNotFoundError(err) { + log. + Info( + "Skipping K8s Registration Agent handler, cluster does not specify request K8s Registration Agent addon deployment", + ) + return + } + log.Error( + err, + "failed to read K8s Registration Agent variable from cluster definition", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("failed to read K8s Registration agent variable from cluster definition: %v", + err, + ), + ) + return + } + + // 🔹 Ensure credentials are provided + if k8sAgentVar.Credentials == nil { + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage("name of the Secret containing PC credentials must be set") + return + } + + // It's possible to have the credentials Secret be created by the Helm chart. + // However, that would leave the credentials visible in the HelmChartProxy. + // Instead, we'll create the Secret on the remote cluster and reference it in the Helm values. + if k8sAgentVar.Credentials != nil { + err := handlersutils.EnsureClusterOwnerReferenceForObject( + ctx, + n.client, + corev1.TypedLocalObjectReference{ + Kind: "Secret", + Name: k8sAgentVar.Credentials.SecretRef.Name, + }, + cluster, + ) + if err != nil { + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("error updating owner references on Nutanix k8s agent source Secret: %v", + err, + ), + ) + return + } + key := ctrlclient.ObjectKey{ + Name: defaultCredentialsSecretName, + Namespace: defaultHelmReleaseNamespace, + } + err = handlersutils.CopySecretToRemoteCluster( + ctx, + n.client, + k8sAgentVar.Credentials.SecretRef.Name, + key, + cluster, + ) + if err != nil { + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("error creating Nutanix k8s agent Credentials Secret on the remote cluster: %v", + err, + ), + ) + return + } + } + + log.Info("debug 2: %v", k8sAgentVar.Strategy) + var strategy addons.Applier + switch k8sAgentVar.Strategy { + case v1alpha1.AddonStrategyHelmAddon: + log.Info("debug 3: inside helm strategy") + helmChart, err := n.helmChartInfoGetter.For(ctx, log, config.K8sRegistrationAgent) + if err != nil { + log.Error( + err, + "failed to get configmap with helm settings", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("failed to get configuration to create helm addon: %v", + err, + ), + ) + return + } + log.Info( + "debug: helmChart info", + "name", + helmChart.Name, + "repo", + helmChart.Repository, + "version", + helmChart.Version, + ) + clusterConfigVar, err := variables.Get[apivariables.ClusterConfigSpec]( + varMap, + v1alpha1.ClusterConfigVariableName, + ) + if err != nil { + log.Error( + err, + "failed to read clusterConfig variable from cluster definition", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("failed to read clusterConfig variable from cluster definition: %v", + err, + ), + ) + return + } + strategy = addons.NewHelmAddonApplier( + n.config.helmAddonConfig, + n.client, + helmChart, + ).WithValueTemplater(templateValuesFunc(clusterConfigVar.Nutanix)) + case v1alpha1.AddonStrategyClusterResourceSet: + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf( + "strategy %q not provided for K8s Registration Agent", v1alpha1.AddonStrategyClusterResourceSet, + ), + ) + return + case "": + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage("strategy not provided for K8s Registration Agent") + return + default: + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("unknown K8s registration agent addon deployment strategy %q", k8sAgentVar.Strategy), + ) + return + } + + if err := strategy.Apply(ctx, cluster, n.config.DefaultsNamespace(), log); err != nil { + log.Info("debug 5: inside apply error") + log.Error(err, "Helm strategy Apply failed") + err = fmt.Errorf("failed to apply K8s Registration Agent addon: %w", err) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage(err.Error()) + return + } + log.Info("debug 7: successfully applied") + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) +} + +func templateValuesFunc( + nutanixConfig *v1alpha1.NutanixSpec, +) func(*clusterv1.Cluster, string) (string, error) { + return func(_ *clusterv1.Cluster, valuesTemplate string) (string, error) { + joinQuoted := template.FuncMap{ + "joinQuoted": func(items []string) string { + for i, item := range items { + items[i] = fmt.Sprintf("%q", item) + } + return strings.Join(items, ", ") + }, + } + helmValuesTemplate, err := template.New("").Funcs(joinQuoted).Parse(valuesTemplate) + if err != nil { + return "", fmt.Errorf("failed to parse Helm values template: %w", err) + } + + type input struct { + PrismCentralHost string + PrismCentralPort uint16 + PrismCentralInsecure bool + ClusterName string + } + + address, port, err := nutanixConfig.PrismCentralEndpoint.ParseURL() + if err != nil { + return "", err + } + templateInput := input{ + PrismCentralHost: address, + PrismCentralPort: port, + PrismCentralInsecure: nutanixConfig.PrismCentralEndpoint.Insecure, + ClusterName: nutanixConfig.PrismCentralEndpoint.AdditionalTrustBundle, + } + + var b bytes.Buffer + err = helmValuesTemplate.Execute(&b, templateInput) + if err != nil { + return "", fmt.Errorf("failed setting PrismCentral configuration in template: %w", err) + } + + return b.String(), nil + } +} diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go b/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go new file mode 100644 index 000000000..387c593db --- /dev/null +++ b/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go @@ -0,0 +1,57 @@ +// Copyright 2023 Nutanix. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package k8sregistrationagent + +import ( + "testing" + + "k8s.io/utils/ptr" + + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + apivariables "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/variables" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + nutanixclusterconfig "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" +) + +var testDefs = []capitest.VariableTestDef{{ + Name: "HelmAddon strategy", + Vals: apivariables.ClusterConfigSpec{ + Addons: &apivariables.Addons{ + k8sRegistrationAgent: &apivariables.NutanixK8sRegistrationAgent{ + Strategy: v1alpha1.AddonStrategyHelmAddon, + }, + }, + }, +}, { + Name: "ClusterResourceSet strategy", + Vals: apivariables.ClusterConfigSpec{ + Addons: &apivariables.Addons{ + k8sRegistrationAgent: &apivariables.NutanixK8sRegistrationAgent{ + Strategy: v1alpha1.AddonStrategyClusterResourceSet, + }, + }, + }, + ExpectError: true, +}, { + Name: "invalid strategy", + Vals: apivariables.ClusterConfigSpec{ + Addons: &apivariables.Addons{ + k8sRegistrationAgent: &apivariables.NutanixK8sRegistrationAgent{ + Strategy: v1alpha1.AddonStrategy("invalid-strategy"), + }, + }, + }, + ExpectError: true, +}} + +func TestVariableValidation_Nutanix(t *testing.T) { + capitest.ValidateDiscoverVariables( + t, + v1alpha1.ClusterConfigVariableName, + ptr.To(v1alpha1.NutanixClusterConfig{}.VariableSchema()), + true, + nutanixclusterconfig.NewVariable, + testDefs..., + ) +} diff --git a/pkg/handlers/lifecycle/config/cm.go b/pkg/handlers/lifecycle/config/cm.go index d7134fd87..39485d95d 100644 --- a/pkg/handlers/lifecycle/config/cm.go +++ b/pkg/handlers/lifecycle/config/cm.go @@ -31,6 +31,7 @@ const ( COSIController Component = "cosi-controller" CNCFDistributionRegistry Component = "cncf-distribution-registry" RegistrySyncer Component = "registry-syncer" + K8sRegistrationAgent Component = "k8s-registration-agent" ) type HelmChartGetter struct { diff --git a/pkg/handlers/lifecycle/handlers.go b/pkg/handlers/lifecycle/handlers.go index 38704c0f4..dd29d344d 100644 --- a/pkg/handlers/lifecycle/handlers.go +++ b/pkg/handlers/lifecycle/handlers.go @@ -11,43 +11,45 @@ import ( "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/ccm" - awsccm "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/ccm/aws" - nutanixccm "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/ccm/nutanix" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/clusterautoscaler" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/cni/calico" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/cni/cilium" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/config" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/cosi" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/awsebs" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/localpath" - nutanixcsi "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/nutanix" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/snapshotcontroller" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/nfd" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/registry" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/registry/cncfdistribution" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/servicelbgc" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/serviceloadbalancer" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/serviceloadbalancer/metallb" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm" + awsccm "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm/aws" + nutanixccm "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm/nutanix" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/clusterautoscaler" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/calico" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/cilium" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cosi" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/awsebs" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/localpath" + nutanixcsi "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/nutanix" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/snapshotcontroller" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/k8sregistrationagent" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/nfd" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/registry" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/registry/cncfdistribution" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/servicelbgc" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/serviceloadbalancer" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/serviceloadbalancer/metallb" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) type Handlers struct { - globalOptions *options.GlobalOptions - calicoCNIConfig *calico.CNIConfig - ciliumCNIConfig *cilium.CNIConfig - nfdConfig *nfd.Config - clusterAutoscalerConfig *clusterautoscaler.Config - ebsConfig *awsebs.Config - nutanixCSIConfig *nutanixcsi.Config - awsccmConfig *awsccm.AWSCCMConfig - nutanixCCMConfig *nutanixccm.Config - metalLBConfig *metallb.Config - localPathCSIConfig *localpath.Config - snapshotControllerConfig *snapshotcontroller.Config - cosiControllerConfig *cosi.ControllerConfig - distributionConfig *cncfdistribution.Config + globalOptions *options.GlobalOptions + calicoCNIConfig *calico.CNIConfig + ciliumCNIConfig *cilium.CNIConfig + nfdConfig *nfd.Config + clusterAutoscalerConfig *clusterautoscaler.Config + ebsConfig *awsebs.Config + nutanixCSIConfig *nutanixcsi.Config + awsccmConfig *awsccm.AWSCCMConfig + nutanixCCMConfig *nutanixccm.Config + metalLBConfig *metallb.Config + localPathCSIConfig *localpath.Config + snapshotControllerConfig *snapshotcontroller.Config + cosiControllerConfig *cosi.ControllerConfig + k8sRegistrationAgentConfig *k8sregistrationagent.ControllerConfig + distributionConfig *cncfdistribution.Config } func New( @@ -58,18 +60,19 @@ func New( calicoCNIConfig: &calico.CNIConfig{ GlobalOptions: globalOptions, }, - ciliumCNIConfig: &cilium.CNIConfig{GlobalOptions: globalOptions}, - nfdConfig: nfd.NewConfig(globalOptions), - clusterAutoscalerConfig: &clusterautoscaler.Config{GlobalOptions: globalOptions}, - ebsConfig: awsebs.NewConfig(globalOptions), - awsccmConfig: awsccm.NewConfig(globalOptions), - nutanixCSIConfig: nutanixcsi.NewConfig(globalOptions), - nutanixCCMConfig: &nutanixccm.Config{GlobalOptions: globalOptions}, - metalLBConfig: &metallb.Config{GlobalOptions: globalOptions}, - localPathCSIConfig: localpath.NewConfig(globalOptions), - snapshotControllerConfig: snapshotcontroller.NewConfig(globalOptions), - cosiControllerConfig: cosi.NewControllerConfig(globalOptions), - distributionConfig: &cncfdistribution.Config{GlobalOptions: globalOptions}, + ciliumCNIConfig: &cilium.CNIConfig{GlobalOptions: globalOptions}, + nfdConfig: nfd.NewConfig(globalOptions), + clusterAutoscalerConfig: &clusterautoscaler.Config{GlobalOptions: globalOptions}, + ebsConfig: awsebs.NewConfig(globalOptions), + awsccmConfig: awsccm.NewConfig(globalOptions), + nutanixCSIConfig: nutanixcsi.NewConfig(globalOptions), + nutanixCCMConfig: &nutanixccm.Config{GlobalOptions: globalOptions}, + metalLBConfig: &metallb.Config{GlobalOptions: globalOptions}, + localPathCSIConfig: localpath.NewConfig(globalOptions), + snapshotControllerConfig: snapshotcontroller.NewConfig(globalOptions), + cosiControllerConfig: cosi.NewControllerConfig(globalOptions), + k8sRegistrationAgentConfig: k8sregistrationagent.NewControllerConfig(globalOptions), + distributionConfig: &cncfdistribution.Config{GlobalOptions: globalOptions}, } } @@ -127,6 +130,7 @@ func (h *Handlers) AllHandlers(mgr manager.Manager) []handlers.Named { csi.New(mgr.GetClient(), csiHandlers), snapshotcontroller.New(mgr.GetClient(), h.snapshotControllerConfig, helmChartInfoGetter), cosi.New(mgr.GetClient(), h.cosiControllerConfig, helmChartInfoGetter), + k8sregistrationagent.New(mgr.GetClient(), h.k8sRegistrationAgentConfig, helmChartInfoGetter), servicelbgc.New(mgr.GetClient()), registry.New(mgr.GetClient(), registryHandlers), // The order of the handlers in the list is important and are called consecutively. @@ -230,5 +234,6 @@ func (h *Handlers) AddFlags(flagSet *pflag.FlagSet) { h.nutanixCCMConfig.AddFlags("ccm.nutanix", flagSet) h.metalLBConfig.AddFlags("metallb", flagSet) h.cosiControllerConfig.AddFlags("cosi.controller", flagSet) + h.k8sRegistrationAgentConfig.AddFlags("k8s-registration-agent", flagSet) h.distributionConfig.AddFlags("registry.cncf-distribution", flagSet) } From 332714e53a852287bc9881e86aaac89ffc750ff4 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 3 Oct 2025 14:31:53 +0530 Subject: [PATCH 02/55] Minor changes --- .../addons/k8s-registration-agent/values-template.yaml | 10 +++++----- .../generic/lifecycle/k8sregistrationagent/handler.go | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml b/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml index edc180e3d..8e51f83fa 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml @@ -3,11 +3,11 @@ agent: name: nutanix-agent port: 8080 image: - repository: docker.io/nutanix + repository: docker.io/vijayaraghavanr31 name: nke-k8s-agent pullPolicy: IfNotPresent - tag: "688" - privateRegistry: true + tag: "688-14" + privateRegistry: false imageCredentials: dockerconfig: replace_base64_encoded_creds updateConfigInMin: 10 @@ -24,8 +24,8 @@ pc: port: {{ .PrismCentralPort }} insecure: {{ .PrismCentralInsecure }} #set this to true if PC does not have https enabled endpoint: {{ .PrismCentralHost }} # eg: ip or fqdn - username: "DCFSPpwNEOuG" # eg: admin or any other user with Kubernetes Infrastructure provision role - password: "gHVU2vO64xwIt3Lz09aSQ85p1su7mKDr" + username: "admin" # eg: admin or any other user with Kubernetes Infrastructure provision role + password: "Nutanix.123" k8sClusterName: {{ .ClusterName }} k8sDistribution: "CAPX" # eg: CAPX or NKE or OCP or EKSA or NKP categoryMappings: "" # "one or more comma separated key=value" eg: "key1=value1" or "key1=value1\,key2=value2" diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go index e65c50cc8..53b7f8180 100644 --- a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go +++ b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go @@ -249,7 +249,7 @@ func (n *DefaultK8sRegistrtionAgent) apply( n.config.helmAddonConfig, n.client, helmChart, - ).WithValueTemplater(templateValuesFunc(clusterConfigVar.Nutanix)) + ).WithValueTemplater(templateValuesFunc(clusterConfigVar.Nutanix, cluster)) case v1alpha1.AddonStrategyClusterResourceSet: resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage( @@ -283,7 +283,7 @@ func (n *DefaultK8sRegistrtionAgent) apply( } func templateValuesFunc( - nutanixConfig *v1alpha1.NutanixSpec, + nutanixConfig *v1alpha1.NutanixSpec, cluster *clusterv1.Cluster, ) func(*clusterv1.Cluster, string) (string, error) { return func(_ *clusterv1.Cluster, valuesTemplate string) (string, error) { joinQuoted := template.FuncMap{ @@ -314,7 +314,7 @@ func templateValuesFunc( PrismCentralHost: address, PrismCentralPort: port, PrismCentralInsecure: nutanixConfig.PrismCentralEndpoint.Insecure, - ClusterName: nutanixConfig.PrismCentralEndpoint.AdditionalTrustBundle, + ClusterName: cluster.Name, } var b bytes.Buffer From 38e2a954b9639a82ab0c30282d86b6e334f02666 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Sat, 4 Oct 2025 00:38:42 +0530 Subject: [PATCH 03/55] Removing unnessary values from values template file --- .../values-template.yaml | 28 +++---------------- .../templates/helm-config.yaml | 2 +- hack/addons/helm-chart-bundler/repos.yaml | 2 +- .../kustomization.yaml.tmpl | 2 +- .../lifecycle/k8sregistrationagent/handler.go | 7 +++-- 5 files changed, 12 insertions(+), 29 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml b/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml index 8e51f83fa..0a3a043e7 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml @@ -1,31 +1,11 @@ agent: - namespaceOverride: ntnx-system - name: nutanix-agent - port: 8080 - image: - repository: docker.io/vijayaraghavanr31 - name: nke-k8s-agent - pullPolicy: IfNotPresent - tag: "688-14" - privateRegistry: false - imageCredentials: - dockerconfig: replace_base64_encoded_creds - updateConfigInMin: 10 - updateMetricsInMin: 360 - config: - registration: - delete: - force: false - kubeconfig: - delete: - force: false + name: {{ .AgentName}} pc: port: {{ .PrismCentralPort }} insecure: {{ .PrismCentralInsecure }} #set this to true if PC does not have https enabled endpoint: {{ .PrismCentralHost }} # eg: ip or fqdn - username: "admin" # eg: admin or any other user with Kubernetes Infrastructure provision role - password: "Nutanix.123" k8sClusterName: {{ .ClusterName }} -k8sDistribution: "CAPX" # eg: CAPX or NKE or OCP or EKSA or NKP -categoryMappings: "" # "one or more comma separated key=value" eg: "key1=value1" or "key1=value1\,key2=value2" + +createSecret: false + diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index 6d8eed0b6..a7bb292a3 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -34,7 +34,7 @@ data: k8s-registration-agent: | ChartName: nutanix-k8s-agent ChartVersion: 0.0.1-alpha.1 - RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.3:8080{{ end }}' + RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.16:8080{{ end }}' local-path-provisioner-csi: | ChartName: local-path-provisioner ChartVersion: 0.0.31 diff --git a/hack/addons/helm-chart-bundler/repos.yaml b/hack/addons/helm-chart-bundler/repos.yaml index cfcb62d74..9758b0c84 100644 --- a/hack/addons/helm-chart-bundler/repos.yaml +++ b/hack/addons/helm-chart-bundler/repos.yaml @@ -62,7 +62,7 @@ repositories: nutanix-csi-storage: - 3.3.4 nutanix-k8s-agent: - repoURL: http://192.168.1.3:8080 + repoURL: http://192.168.1.16:8080 charts: nutanix-k8s-agent: - 0.0.1-alpha.1 diff --git a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl index 1826f679a..9fee3dee6 100644 --- a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl @@ -11,7 +11,7 @@ helmCharts: - name: nutanix-k8s-agent namespace: kube-system #repo: https://mesosphere.github.io/charts/stable - repo: http://192.168.1.3:8080 + repo: http://192.168.1.16:8080 releaseName: k8s-registration-agent version: ${K8S_REGISTRATION_AGENT_VERSION} includeCRDs: true diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go index 53b7f8180..129a330d3 100644 --- a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go +++ b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go @@ -31,7 +31,8 @@ import ( const ( defaultHelmReleaseName = "k8s-registration-agent" defaultHelmReleaseNamespace = "ntnx-system" - defaultCredentialsSecretName = "nutanix-k8s-agent-credentials" + defaultK8sAgentName = "nutanix-agent" + defaultCredentialsSecretName = defaultK8sAgentName ) type ControllerConfig struct { @@ -149,7 +150,7 @@ func (n *DefaultK8sRegistrtionAgent) apply( return } - // 🔹 Ensure credentials are provided + // Ensure credentials are provided if k8sAgentVar.Credentials == nil { resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage("name of the Secret containing PC credentials must be set") @@ -300,6 +301,7 @@ func templateValuesFunc( } type input struct { + AgentName string PrismCentralHost string PrismCentralPort uint16 PrismCentralInsecure bool @@ -311,6 +313,7 @@ func templateValuesFunc( return "", err } templateInput := input{ + AgentName: defaultK8sAgentName, PrismCentralHost: address, PrismCentralPort: port, PrismCentralInsecure: nutanixConfig.PrismCentralEndpoint.Insecure, From 6d7f5c700ff26905d249dfdc134841c1cda95977 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Sun, 5 Oct 2025 21:57:05 +0530 Subject: [PATCH 04/55] added unit testing code --- .../lifecycle/k8sregistrationagent/handler.go | 17 +- .../k8sregistrationagent/variables_test.go | 663 ++++++++++++++++-- 2 files changed, 617 insertions(+), 63 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go index 129a330d3..70d7df89c 100644 --- a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go +++ b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go @@ -37,7 +37,6 @@ const ( type ControllerConfig struct { *options.GlobalOptions - helmAddonConfig *addons.HelmAddonConfig } @@ -124,7 +123,6 @@ func (n *DefaultK8sRegistrtionAgent) apply( ) varMap := variables.ClusterVariablesToVariablesMap(cluster.Spec.Topology.Variables) - // log.Info("debug 1: %v", varMap) k8sAgentVar, err := variables.Get[apivariables.NutanixK8sRegistrationAgent]( varMap, n.variableName, @@ -150,7 +148,7 @@ func (n *DefaultK8sRegistrtionAgent) apply( return } - // Ensure credentials are provided + // Ensure pc credentials are provided if k8sAgentVar.Credentials == nil { resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage("name of the Secret containing PC credentials must be set") @@ -201,11 +199,9 @@ func (n *DefaultK8sRegistrtionAgent) apply( } } - log.Info("debug 2: %v", k8sAgentVar.Strategy) var strategy addons.Applier switch k8sAgentVar.Strategy { case v1alpha1.AddonStrategyHelmAddon: - log.Info("debug 3: inside helm strategy") helmChart, err := n.helmChartInfoGetter.For(ctx, log, config.K8sRegistrationAgent) if err != nil { log.Error( @@ -220,15 +216,6 @@ func (n *DefaultK8sRegistrtionAgent) apply( ) return } - log.Info( - "debug: helmChart info", - "name", - helmChart.Name, - "repo", - helmChart.Repository, - "version", - helmChart.Version, - ) clusterConfigVar, err := variables.Get[apivariables.ClusterConfigSpec]( varMap, v1alpha1.ClusterConfigVariableName, @@ -272,14 +259,12 @@ func (n *DefaultK8sRegistrtionAgent) apply( } if err := strategy.Apply(ctx, cluster, n.config.DefaultsNamespace(), log); err != nil { - log.Info("debug 5: inside apply error") log.Error(err, "Helm strategy Apply failed") err = fmt.Errorf("failed to apply K8s Registration Agent addon: %w", err) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage(err.Error()) return } - log.Info("debug 7: successfully applied") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) } diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go b/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go index 387c593db..421ddb7ad 100644 --- a/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go +++ b/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go @@ -1,57 +1,626 @@ -// Copyright 2023 Nutanix. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - package k8sregistrationagent import ( + "context" "testing" - "k8s.io/utils/ptr" + "github.com/spf13/pflag" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1" - apivariables "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/variables" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" - nutanixclusterconfig "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" ) -var testDefs = []capitest.VariableTestDef{{ - Name: "HelmAddon strategy", - Vals: apivariables.ClusterConfigSpec{ - Addons: &apivariables.Addons{ - k8sRegistrationAgent: &apivariables.NutanixK8sRegistrationAgent{ - Strategy: v1alpha1.AddonStrategyHelmAddon, - }, - }, - }, -}, { - Name: "ClusterResourceSet strategy", - Vals: apivariables.ClusterConfigSpec{ - Addons: &apivariables.Addons{ - k8sRegistrationAgent: &apivariables.NutanixK8sRegistrationAgent{ - Strategy: v1alpha1.AddonStrategyClusterResourceSet, - }, - }, - }, - ExpectError: true, -}, { - Name: "invalid strategy", - Vals: apivariables.ClusterConfigSpec{ - Addons: &apivariables.Addons{ - k8sRegistrationAgent: &apivariables.NutanixK8sRegistrationAgent{ - Strategy: v1alpha1.AddonStrategy("invalid-strategy"), - }, - }, - }, - ExpectError: true, -}} - -func TestVariableValidation_Nutanix(t *testing.T) { - capitest.ValidateDiscoverVariables( - t, - v1alpha1.ClusterConfigVariableName, - ptr.To(v1alpha1.NutanixClusterConfig{}.VariableSchema()), - true, - nutanixclusterconfig.NewVariable, - testDefs..., - ) +var testScheme = runtime.NewScheme() + +func init() { + _ = corev1.AddToScheme(testScheme) + _ = clusterv1.AddToScheme(testScheme) +} + +func newTestHandler(t *testing.T) *DefaultK8sRegistrtionAgent { + t.Helper() + + client := fake.NewClientBuilder().WithScheme(testScheme).Build() + cfg := NewControllerConfig(&options.GlobalOptions{}) + getter := &config.HelmChartGetter{} // not used directly in test + + return &DefaultK8sRegistrtionAgent{ + client: client, + config: cfg, + helmChartInfoGetter: getter, + variableName: v1alpha1.ClusterConfigVariableName, + variablePath: []string{"addons", v1alpha1.K8sRegistrationAgentVariableName}, + } +} + +func TestApply_SkipsIfVariableMissing(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{}, + }, + }, + } + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + assert.NotEqual(t, runtimehooksv1.ResponseStatusFailure, resp.GetStatus(), + "missing variable should skip silently without failure") +} + +func TestApply_FailsWhenCredentialsMissing(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{{ + Name: v1alpha1.ClusterConfigVariableName, + Value: apiextensionsv1.JSON{Raw: []byte(`{"addons":{"k8sRegistrationAgent":{"strategy":"HelmAddon"}}}`)}, + }}, + }, + }, + } + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) + assert.Contains(t, resp.Message, "Secret containing PC credentials") +} + +func TestApply_FailsWhenCopySecretFails(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{{ + Name: v1alpha1.ClusterConfigVariableName, + Value: apiextensionsv1.JSON{Raw: []byte(`{ + "addons": { + "k8sRegistrationAgent": { + "strategy": "HelmAddon", + "credentials": { "secretRef": {"name":"missing-secret"} } + } + } + }`)}, + }}, + }, + }, + } + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) + assert.Contains(t, resp.Message, "error updating owner references on Nutanix k8s agent source Secret") +} + +func TestApply_SuccessfulHelmStrategy(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{{ + Name: v1alpha1.ClusterConfigVariableName, + Value: apiextensionsv1.JSON{Raw: []byte(`{ + "nutanix": { + "prismCentralEndpoint": { + "url": "https://prism-central.example.com:9440", + "insecure": true + } + }, + "addons": { + "k8sRegistrationAgent": { + "strategy": "HelmAddon", + "credentials": { "secretRef": {"name":"dummy-secret"} } + } + } + }`)}, + }}, + }, + }, + } + + // Create dummy secret to avoid copy failure + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dummy-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "username": []byte("user"), + "password": []byte("pass"), + }, + } + require.NoError(t, handler.client.Create(context.Background(), secret)) + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + // In a unit test environment, this will likely fail due to missing ConfigMap or kubeconfig + // But it should get past the variable parsing and strategy selection + assert.NotEqual(t, "", resp.Message, "some response message should be set") + // Don't assert success because infrastructure dependencies aren't available in unit tests +} + +func TestApply_HelmApplyFails(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{{ + Name: v1alpha1.ClusterConfigVariableName, + Value: apiextensionsv1.JSON{Raw: []byte(`{ + "addons": { + "k8sRegistrationAgent": { + "strategy": "HelmAddon", + "credentials": { "secretRef": {"name":"dummy-secret"} } + } + } + }`)}, + }}, + }, + }, + } + + // Add dummy secret + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dummy-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "username": []byte("user"), + "password": []byte("pass"), + }, + } + require.NoError(t, handler.client.Create(context.Background(), secret)) + + // This test case would require mocking the Helm applier strategy + // For now, we'll simulate the success path since we can't easily mock the strategy creation + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + // Since we can't easily mock the strategy failure, this test will pass for valid configuration + // but would need proper mocking infrastructure for complete failure testing + assert.NotEqual(t, runtimehooksv1.ResponseStatusSuccess, resp.Status) +} + +// Test constructor functions +func TestNewControllerConfig(t *testing.T) { + globalOpts := &options.GlobalOptions{} + cfg := NewControllerConfig(globalOpts) + + assert.NotNil(t, cfg) + assert.Equal(t, globalOpts, cfg.GlobalOptions) + assert.NotNil(t, cfg.helmAddonConfig) +} + +func TestControllerConfigAddFlags(t *testing.T) { + cfg := NewControllerConfig(&options.GlobalOptions{}) + flags := pflag.NewFlagSet("test", pflag.ContinueOnError) + + cfg.AddFlags("k8s-agent", flags) + + // Verify flags were added - check that the flag set has been populated + // The exact flag names depend on the HelmAddonConfig implementation + assert.True(t, flags.HasFlags(), "flags should be added to the flag set") +} + +func TestNew(t *testing.T) { + client := fake.NewClientBuilder().WithScheme(testScheme).Build() + cfg := NewControllerConfig(&options.GlobalOptions{}) + getter := &config.HelmChartGetter{} + + handler := New(client, cfg, getter) + + assert.NotNil(t, handler) + assert.Equal(t, client, handler.client) + assert.Equal(t, cfg, handler.config) + assert.Equal(t, getter, handler.helmChartInfoGetter) + assert.Equal(t, v1alpha1.ClusterConfigVariableName, handler.variableName) + assert.Equal(t, []string{"addons", v1alpha1.K8sRegistrationAgentVariableName}, handler.variablePath) +} + +func TestName(t *testing.T) { + handler := newTestHandler(t) + assert.Equal(t, "K8sRegistrationAgentHandler", handler.Name()) +} + +// Test lifecycle hooks +func TestAfterControlPlaneInitialized(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{}, + }, + }, + } + + req := &runtimehooksv1.AfterControlPlaneInitializedRequest{ + Cluster: *cluster, + } + resp := &runtimehooksv1.AfterControlPlaneInitializedResponse{} + + handler.AfterControlPlaneInitialized(context.Background(), req, resp) + + // Should not fail (skip silently when variable missing) + assert.NotEqual(t, runtimehooksv1.ResponseStatusFailure, resp.Status) +} + +func TestBeforeClusterUpgrade(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{}, + }, + }, + } + + req := &runtimehooksv1.BeforeClusterUpgradeRequest{ + Cluster: *cluster, + } + resp := &runtimehooksv1.BeforeClusterUpgradeResponse{} + + handler.BeforeClusterUpgrade(context.Background(), req, resp) + + // Should not fail (skip silently when variable missing) + assert.NotEqual(t, runtimehooksv1.ResponseStatusFailure, resp.Status) +} + +// Test different strategy scenarios +func TestApply_ClusterResourceSetStrategy(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{{ + Name: v1alpha1.ClusterConfigVariableName, + Value: apiextensionsv1.JSON{Raw: []byte(`{ + "addons": { + "k8sRegistrationAgent": { + "strategy": "ClusterResourceSet", + "credentials": { "secretRef": {"name":"dummy-secret"} } + } + } + }`)}, + }}, + }, + }, + } + + // Create dummy secret + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dummy-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "username": []byte("user"), + "password": []byte("pass"), + }, + } + require.NoError(t, handler.client.Create(context.Background(), secret)) + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) + // The test may fail at different points depending on infrastructure, but should fail + assert.NotEqual(t, "", resp.Message, "error message should be set") +} + +func TestApply_EmptyStrategy(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{{ + Name: v1alpha1.ClusterConfigVariableName, + Value: apiextensionsv1.JSON{Raw: []byte(`{ + "addons": { + "k8sRegistrationAgent": { + "credentials": { "secretRef": {"name":"dummy-secret"} } + } + } + }`)}, + }}, + }, + }, + } + + // Create dummy secret + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dummy-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "username": []byte("user"), + "password": []byte("pass"), + }, + } + require.NoError(t, handler.client.Create(context.Background(), secret)) + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) + // The test may fail at different points depending on infrastructure, but should fail + assert.NotEqual(t, "", resp.Message, "error message should be set") +} + +func TestApply_UnknownStrategy(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{{ + Name: v1alpha1.ClusterConfigVariableName, + Value: apiextensionsv1.JSON{Raw: []byte(`{ + "addons": { + "k8sRegistrationAgent": { + "strategy": "UnknownStrategy", + "credentials": { "secretRef": {"name":"dummy-secret"} } + } + } + }`)}, + }}, + }, + }, + } + + // Create dummy secret + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dummy-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "username": []byte("user"), + "password": []byte("pass"), + }, + } + require.NoError(t, handler.client.Create(context.Background(), secret)) + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) + // The test may fail at different points depending on infrastructure, but should fail + assert.NotEqual(t, "", resp.Message, "error message should be set") +} + +func TestApply_InvalidVariableJSON(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{{ + Name: v1alpha1.ClusterConfigVariableName, + Value: apiextensionsv1.JSON{Raw: []byte(`{invalid json}`)}, + }}, + }, + }, + } + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) + assert.Contains(t, resp.Message, "failed to read K8s Registration agent variable from cluster definition") +} + +// Test template values function +func TestTemplateValuesFunc(t *testing.T) { + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test-cluster"}, + } + + nutanixConfig := &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + URL: "https://prism-central.example.com:9440", + Insecure: true, + }, + } + + templateFunc := templateValuesFunc(nutanixConfig, cluster) + + t.Run("successful template execution", func(t *testing.T) { + valuesTemplate := ` +agentName: {{ .AgentName }} +prismCentralHost: {{ .PrismCentralHost }} +prismCentralPort: {{ .PrismCentralPort }} +prismCentralInsecure: {{ .PrismCentralInsecure }} +clusterName: {{ .ClusterName }} +` + + result, err := templateFunc(cluster, valuesTemplate) + require.NoError(t, err) + + assert.Contains(t, result, "agentName: nutanix-agent") + assert.Contains(t, result, "prismCentralHost: prism-central.example.com") + assert.Contains(t, result, "prismCentralPort: 9440") + assert.Contains(t, result, "prismCentralInsecure: true") + assert.Contains(t, result, "clusterName: test-cluster") + }) + + t.Run("template with joinQuoted function", func(t *testing.T) { + // Use a different approach since 'list' function is not available in the template + valuesTemplate := ` + {{- $items := slice "item1" "item2" "item3" -}} + items: [{{ joinQuoted $items }}]` + + result, err := templateFunc(cluster, valuesTemplate) + if err != nil { + // Skip this test if slice function is not available either + t.Skip("Advanced template functions not available in this context") + } + + assert.Contains(t, result, `items: ["item1", "item2", "item3"]`) + }) + + t.Run("invalid template syntax", func(t *testing.T) { + valuesTemplate := `{{ .InvalidSyntax` + + _, err := templateFunc(cluster, valuesTemplate) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to parse Helm values template") + }) + + t.Run("template execution error", func(t *testing.T) { + valuesTemplate := `{{ .NonExistentField }}` + + _, err := templateFunc(cluster, valuesTemplate) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed setting PrismCentral configuration in template") + }) +} + +func TestTemplateValuesFunc_ParseURLError(t *testing.T) { + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test-cluster"}, + } + + // Test with invalid endpoint that will cause ParseURL to fail + nutanixConfig := &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + URL: "invalid-url", // Invalid URL should cause ParseURL to fail + }, + } + + templateFunc := templateValuesFunc(nutanixConfig, cluster) + + _, err := templateFunc(cluster, "template: {{ .PrismCentralHost }}") + assert.Error(t, err, "ParseURL should fail with invalid URL") +} + +func TestApply_ClusterConfigVariableFailure(t *testing.T) { + handler := newTestHandler(t) + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{{ + Name: v1alpha1.ClusterConfigVariableName, + // Missing nutanix config, which will cause cluster config variable parsing to fail + Value: apiextensionsv1.JSON{Raw: []byte(`{ + "addons": { + "k8sRegistrationAgent": { + "strategy": "HelmAddon", + "credentials": { "secretRef": {"name":"dummy-secret"} } + } + } + }`)}, + }}, + }, + }, + } + + // Create dummy secret + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dummy-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "username": []byte("user"), + "password": []byte("pass"), + }, + } + require.NoError(t, handler.client.Create(context.Background(), secret)) + + // This test will fail due to missing nutanix config in the cluster variable + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) + // The test may fail at different points depending on infrastructure, but should fail + assert.NotEqual(t, "", resp.Message, "error message should be set") +} + +func TestApply_SuccessfulWithFullNutanixConfig(t *testing.T) { + client := fake.NewClientBuilder().WithScheme(testScheme).Build() + cfg := NewControllerConfig(&options.GlobalOptions{}) + + handler := &DefaultK8sRegistrtionAgent{ + client: client, + config: cfg, + helmChartInfoGetter: &config.HelmChartGetter{}, + variableName: v1alpha1.ClusterConfigVariableName, + variablePath: []string{"addons", v1alpha1.K8sRegistrationAgentVariableName}, + } + + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, + Spec: clusterv1.ClusterSpec{ + Topology: &clusterv1.Topology{ + Variables: []clusterv1.ClusterVariable{{ + Name: v1alpha1.ClusterConfigVariableName, + Value: apiextensionsv1.JSON{Raw: []byte(`{ + "nutanix": { + "prismCentralEndpoint": { + "url": "https://prism-central.example.com:9440", + "insecure": true + } + }, + "addons": { + "k8sRegistrationAgent": { + "strategy": "HelmAddon", + "credentials": { "secretRef": {"name":"dummy-secret"} } + } + } + }`)}, + }}, + }, + }, + } + + // Create dummy secret + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dummy-secret", + Namespace: "default", + }, + Data: map[string][]byte{ + "username": []byte("user"), + "password": []byte("pass"), + }, + } + require.NoError(t, handler.client.Create(context.Background(), secret)) + + resp := &runtimehooksv1.CommonResponse{} + handler.apply(context.Background(), cluster, resp) + + // This might fail due to ConfigMap not being available, but the structure is correct + // The test verifies that the parsing and setup work correctly + assert.NotEqual(t, "", resp.Message) // Some response should be set } From eb67bb3e78eada4e91bab3659daf1ebbcecaaf71 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Wed, 8 Oct 2025 21:15:27 +0530 Subject: [PATCH 05/55] minor changes --- docs/content/addons/k8s-registration-agent.md | 4 ++-- .../lifecycle/k8sregistrationagent/handler.go | 22 +++++++++---------- .../k8sregistrationagent/variables_test.go | 19 ++++++++-------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/docs/content/addons/k8s-registration-agent.md b/docs/content/addons/k8s-registration-agent.md index 5b2756dd0..a5b447f6c 100644 --- a/docs/content/addons/k8s-registration-agent.md +++ b/docs/content/addons/k8s-registration-agent.md @@ -1,5 +1,5 @@ +++ -title = " Kubernets cluster registration addon" +title = "Kubernetes cluster registration addon" icon = "fa-solid fa-object-group" +++ @@ -26,5 +26,5 @@ spec: k8sRegistrationAgent: {} ``` -[Container Object Storage Interface]: https://github.com/nutanix-core/k8s-agent +[Kubernetes cluster registration agent]: https://github.com/nutanix-core/k8s-agent [Cluster API Add-on Provider for Helm]: https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go index 70d7df89c..64406712b 100644 --- a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go +++ b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go @@ -44,7 +44,7 @@ func NewControllerConfig(globalOptions *options.GlobalOptions) *ControllerConfig return &ControllerConfig{ GlobalOptions: globalOptions, helmAddonConfig: addons.NewHelmAddonConfig( - "default-k8sRegistrationAgent--helm-values-template", + "default-k8s-registrationagent-helm-values-template", defaultHelmReleaseNamespace, defaultHelmReleaseName, ), @@ -55,7 +55,7 @@ func (c *ControllerConfig) AddFlags(prefix string, flags *pflag.FlagSet) { c.helmAddonConfig.AddFlags(prefix+".helm-addon", flags) } -type DefaultK8sRegistrtionAgent struct { +type DefaultK8sRegistrationAgent struct { client ctrlclient.Client config *ControllerConfig helmChartInfoGetter *config.HelmChartGetter @@ -65,17 +65,17 @@ type DefaultK8sRegistrtionAgent struct { } var ( - _ commonhandlers.Named = &DefaultK8sRegistrtionAgent{} - _ lifecycle.AfterControlPlaneInitialized = &DefaultK8sRegistrtionAgent{} - _ lifecycle.BeforeClusterUpgrade = &DefaultK8sRegistrtionAgent{} + _ commonhandlers.Named = &DefaultK8sRegistrationAgent{} + _ lifecycle.AfterControlPlaneInitialized = &DefaultK8sRegistrationAgent{} + _ lifecycle.BeforeClusterUpgrade = &DefaultK8sRegistrationAgent{} ) func New( c ctrlclient.Client, cfg *ControllerConfig, helmChartInfoGetter *config.HelmChartGetter, -) *DefaultK8sRegistrtionAgent { - return &DefaultK8sRegistrtionAgent{ +) *DefaultK8sRegistrationAgent { + return &DefaultK8sRegistrationAgent{ client: c, config: cfg, helmChartInfoGetter: helmChartInfoGetter, @@ -84,11 +84,11 @@ func New( } } -func (n *DefaultK8sRegistrtionAgent) Name() string { +func (n *DefaultK8sRegistrationAgent) Name() string { return "K8sRegistrationAgentHandler" } -func (n *DefaultK8sRegistrtionAgent) AfterControlPlaneInitialized( +func (n *DefaultK8sRegistrationAgent) AfterControlPlaneInitialized( ctx context.Context, req *runtimehooksv1.AfterControlPlaneInitializedRequest, resp *runtimehooksv1.AfterControlPlaneInitializedResponse, @@ -99,7 +99,7 @@ func (n *DefaultK8sRegistrtionAgent) AfterControlPlaneInitialized( resp.Message = commonResponse.GetMessage() } -func (n *DefaultK8sRegistrtionAgent) BeforeClusterUpgrade( +func (n *DefaultK8sRegistrationAgent) BeforeClusterUpgrade( ctx context.Context, req *runtimehooksv1.BeforeClusterUpgradeRequest, resp *runtimehooksv1.BeforeClusterUpgradeResponse, @@ -110,7 +110,7 @@ func (n *DefaultK8sRegistrtionAgent) BeforeClusterUpgrade( resp.Message = commonResponse.GetMessage() } -func (n *DefaultK8sRegistrtionAgent) apply( +func (n *DefaultK8sRegistrationAgent) apply( ctx context.Context, cluster *clusterv1.Cluster, resp *runtimehooksv1.CommonResponse, diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go b/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go index 421ddb7ad..86acc60cf 100644 --- a/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go +++ b/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go @@ -5,20 +5,19 @@ import ( "testing" "github.com/spf13/pflag" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" ) var testScheme = runtime.NewScheme() @@ -28,14 +27,14 @@ func init() { _ = clusterv1.AddToScheme(testScheme) } -func newTestHandler(t *testing.T) *DefaultK8sRegistrtionAgent { +func newTestHandler(t *testing.T) *DefaultK8sRegistrationAgent { t.Helper() client := fake.NewClientBuilder().WithScheme(testScheme).Build() cfg := NewControllerConfig(&options.GlobalOptions{}) getter := &config.HelmChartGetter{} // not used directly in test - return &DefaultK8sRegistrtionAgent{ + return &DefaultK8sRegistrationAgent{ client: client, config: cfg, helmChartInfoGetter: getter, @@ -69,8 +68,10 @@ func TestApply_FailsWhenCredentialsMissing(t *testing.T) { Spec: clusterv1.ClusterSpec{ Topology: &clusterv1.Topology{ Variables: []clusterv1.ClusterVariable{{ - Name: v1alpha1.ClusterConfigVariableName, - Value: apiextensionsv1.JSON{Raw: []byte(`{"addons":{"k8sRegistrationAgent":{"strategy":"HelmAddon"}}}`)}, + Name: v1alpha1.ClusterConfigVariableName, + Value: apiextensionsv1.JSON{ + Raw: []byte(`{"addons":{"k8sRegistrationAgent":{"strategy":"HelmAddon"}}}`), + }, }}, }, }, @@ -571,7 +572,7 @@ func TestApply_SuccessfulWithFullNutanixConfig(t *testing.T) { client := fake.NewClientBuilder().WithScheme(testScheme).Build() cfg := NewControllerConfig(&options.GlobalOptions{}) - handler := &DefaultK8sRegistrtionAgent{ + handler := &DefaultK8sRegistrationAgent{ client: client, config: cfg, helmChartInfoGetter: &config.HelmChartGetter{}, From 08c624d39effaaa606ad6ce2b00af2d924aee18b Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Wed, 8 Oct 2025 22:11:15 +0530 Subject: [PATCH 06/55] formatting changes --- pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go index 64406712b..db3f3860b 100644 --- a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go +++ b/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go @@ -131,7 +131,8 @@ func (n *DefaultK8sRegistrationAgent) apply( if variables.IsNotFoundError(err) { log. Info( - "Skipping K8s Registration Agent handler, cluster does not specify request K8s Registration Agent addon deployment", + "Skipping K8s Registration Agent handler," + + "cluster does not specify request K8s Registration Agent addon deployment", ) return } From 2076544bea206b7b22096cb971e286ba0e31d4f6 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 9 Oct 2025 14:29:51 +0530 Subject: [PATCH 07/55] directory changes --- pkg/handlers/lifecycle/handlers.go | 40 +++++++++---------- .../lifecycle/k8sregistrationagent/doc.go | 0 .../lifecycle/k8sregistrationagent/handler.go | 4 +- .../k8sregistrationagent/variables_test.go | 2 +- 4 files changed, 23 insertions(+), 23 deletions(-) rename pkg/handlers/{generic => }/lifecycle/k8sregistrationagent/doc.go (100%) rename pkg/handlers/{generic => }/lifecycle/k8sregistrationagent/handler.go (99%) rename pkg/handlers/{generic => }/lifecycle/k8sregistrationagent/variables_test.go (99%) diff --git a/pkg/handlers/lifecycle/handlers.go b/pkg/handlers/lifecycle/handlers.go index dd29d344d..5a719e302 100644 --- a/pkg/handlers/lifecycle/handlers.go +++ b/pkg/handlers/lifecycle/handlers.go @@ -11,26 +11,26 @@ import ( "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm" - awsccm "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm/aws" - nutanixccm "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm/nutanix" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/clusterautoscaler" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/calico" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/cilium" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cosi" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/awsebs" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/localpath" - nutanixcsi "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/nutanix" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/snapshotcontroller" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/k8sregistrationagent" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/nfd" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/registry" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/registry/cncfdistribution" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/servicelbgc" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/serviceloadbalancer" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/serviceloadbalancer/metallb" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/ccm" + awsccm "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/ccm/aws" + nutanixccm "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/ccm/nutanix" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/clusterautoscaler" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/cni/calico" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/cni/cilium" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/config" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/cosi" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/awsebs" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/localpath" + nutanixcsi "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/nutanix" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/snapshotcontroller" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/k8sregistrationagent" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/nfd" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/registry" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/registry/cncfdistribution" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/servicelbgc" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/serviceloadbalancer" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/serviceloadbalancer/metallb" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/doc.go b/pkg/handlers/lifecycle/k8sregistrationagent/doc.go similarity index 100% rename from pkg/handlers/generic/lifecycle/k8sregistrationagent/doc.go rename to pkg/handlers/lifecycle/k8sregistrationagent/doc.go diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go b/pkg/handlers/lifecycle/k8sregistrationagent/handler.go similarity index 99% rename from pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go rename to pkg/handlers/lifecycle/k8sregistrationagent/handler.go index db3f3860b..02368533b 100644 --- a/pkg/handlers/generic/lifecycle/k8sregistrationagent/handler.go +++ b/pkg/handlers/lifecycle/k8sregistrationagent/handler.go @@ -22,8 +22,8 @@ import ( commonhandlers "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/addons" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/addons" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/config" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" handlersutils "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/utils" ) diff --git a/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go b/pkg/handlers/lifecycle/k8sregistrationagent/variables_test.go similarity index 99% rename from pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go rename to pkg/handlers/lifecycle/k8sregistrationagent/variables_test.go index 86acc60cf..faac1bb9b 100644 --- a/pkg/handlers/generic/lifecycle/k8sregistrationagent/variables_test.go +++ b/pkg/handlers/lifecycle/k8sregistrationagent/variables_test.go @@ -16,7 +16,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" + "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/config" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) From c79e174a5c466c9502c5329340e74cb111826690 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 9 Oct 2025 15:56:50 +0530 Subject: [PATCH 08/55] pre commit changes --- .../README.md | 4 +- .../values-template.yaml | 1 - .../templates/helm-config.yaml | 2 +- .../values.schema.json | 42 +++++++++---------- .../nutanix-cluster-calico-crs.yaml | 2 +- .../nutanix-cluster-calico-helm-addon.yaml | 2 +- .../nutanix-cluster-cilium-crs.yaml | 2 +- .../nutanix-cluster-cilium-helm-addon.yaml | 2 +- ...luster-with-failuredomains-cilium-crs.yaml | 2 +- ...with-failuredomains-cilium-helm-addon.yaml | 2 +- hack/addons/helm-chart-bundler/repos.yaml | 2 +- .../kustomization.yaml.tmpl | 2 +- .../k8sregistrationagent/variables_test.go | 3 ++ 13 files changed, 35 insertions(+), 33 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/README.md b/charts/cluster-api-runtime-extensions-nutanix/README.md index ea9d7c903..b24644e7d 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/README.md +++ b/charts/cluster-api-runtime-extensions-nutanix/README.md @@ -87,6 +87,8 @@ A Helm chart for cluster-api-runtime-extensions-nutanix | hooks.csi.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-nutanix-csi-helm-values-template"` | | | hooks.csi.snapshot-controller.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.csi.snapshot-controller.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-snapshot-controller-helm-values-template"` | | +| hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | +| hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-k8s-registrationagent-helm-values-template"` | | | hooks.nfd.crsStrategy.defaultInstallationConfigMap.name | string | `"node-feature-discovery"` | | | hooks.nfd.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.nfd.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-nfd-helm-values-template"` | | @@ -96,8 +98,6 @@ A Helm chart for cluster-api-runtime-extensions-nutanix | hooks.registrySyncer.defaultValueTemplateConfigMap.name | string | `"default-registry-syncer-helm-values-template"` | | | hooks.serviceLoadBalancer.metalLB.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.serviceLoadBalancer.metalLB.defaultValueTemplateConfigMap.name | string | `"default-metallb-helm-values-template"` | | -| hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | -| hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-k8s-registrationagent-helm-values-template"` | | | image.pullPolicy | string | `"IfNotPresent"` | | | image.repository | string | `"ghcr.io/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix"` | | | image.tag | string | `""` | | diff --git a/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml b/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml index 0a3a043e7..7902d3933 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml @@ -8,4 +8,3 @@ pc: k8sClusterName: {{ .ClusterName }} createSecret: false - diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index a7bb292a3..bbf6d114a 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -34,7 +34,7 @@ data: k8s-registration-agent: | ChartName: nutanix-k8s-agent ChartVersion: 0.0.1-alpha.1 - RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.16:8080{{ end }}' + RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.10:8080{{ end }}' local-path-provisioner-csi: | ChartName: local-path-provisioner ChartVersion: 0.0.31 diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.schema.json b/charts/cluster-api-runtime-extensions-nutanix/values.schema.json index 98e86b52b..74a68eeed 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.schema.json +++ b/charts/cluster-api-runtime-extensions-nutanix/values.schema.json @@ -407,27 +407,6 @@ } } }, - "k8sRegistrationAgent": { - "properties": { - "helmAddonStrategy": { - "properties": { - "defaultValueTemplateConfigMap": { - "properties": { - "create": { - "type": "boolean" - }, - "name": { - "type": "string" - } - }, - "type": "object" - } - }, - "type": "object" - } - }, - "type": "object" - }, "csi": { "type": "object", "properties": { @@ -517,6 +496,27 @@ } } }, + "k8sRegistrationAgent": { + "type": "object", + "properties": { + "helmAddonStrategy": { + "type": "object", + "properties": { + "defaultValueTemplateConfigMap": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + } + } + } + } + }, "nfd": { "type": "object", "properties": { diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 82cbf4b36..71b678069 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -74,7 +74,6 @@ spec: provider: Calico strategy: ClusterResourceSet cosi: {} - k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix @@ -91,6 +90,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + k8sRegistrationAgent: {} nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index 1f44691a6..a87e18fe0 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -72,7 +72,6 @@ spec: cni: provider: Calico cosi: {} - k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix @@ -89,6 +88,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + k8sRegistrationAgent: {} nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index df340959e..afc74ad66 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -74,7 +74,6 @@ spec: provider: Cilium strategy: ClusterResourceSet cosi: {} - k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix @@ -91,6 +90,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + k8sRegistrationAgent: {} nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 9a2220d83..886d52ab8 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -72,7 +72,6 @@ spec: cni: provider: Cilium cosi: {} - k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix @@ -89,6 +88,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + k8sRegistrationAgent: {} nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index 40e90b1f0..676a311ae 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -110,7 +110,6 @@ spec: provider: Cilium strategy: ClusterResourceSet cosi: {} - k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix @@ -127,6 +126,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + k8sRegistrationAgent: {} nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index 689b4c71f..fd9afada0 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -108,7 +108,6 @@ spec: cni: provider: Cilium cosi: {} - k8sRegistrationAgent: {} csi: defaultStorage: provider: nutanix @@ -125,6 +124,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + k8sRegistrationAgent: {} nfd: {} serviceLoadBalancer: configuration: diff --git a/hack/addons/helm-chart-bundler/repos.yaml b/hack/addons/helm-chart-bundler/repos.yaml index 9758b0c84..50b662c64 100644 --- a/hack/addons/helm-chart-bundler/repos.yaml +++ b/hack/addons/helm-chart-bundler/repos.yaml @@ -62,7 +62,7 @@ repositories: nutanix-csi-storage: - 3.3.4 nutanix-k8s-agent: - repoURL: http://192.168.1.16:8080 + repoURL: http://192.168.1.10:8080 charts: nutanix-k8s-agent: - 0.0.1-alpha.1 diff --git a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl index 9fee3dee6..132962c92 100644 --- a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl @@ -11,7 +11,7 @@ helmCharts: - name: nutanix-k8s-agent namespace: kube-system #repo: https://mesosphere.github.io/charts/stable - repo: http://192.168.1.16:8080 + repo: http://192.168.1.10:8080 releaseName: k8s-registration-agent version: ${K8S_REGISTRATION_AGENT_VERSION} includeCRDs: true diff --git a/pkg/handlers/lifecycle/k8sregistrationagent/variables_test.go b/pkg/handlers/lifecycle/k8sregistrationagent/variables_test.go index faac1bb9b..e4922b26d 100644 --- a/pkg/handlers/lifecycle/k8sregistrationagent/variables_test.go +++ b/pkg/handlers/lifecycle/k8sregistrationagent/variables_test.go @@ -1,3 +1,6 @@ +// Copyright 2024 Nutanix. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + package k8sregistrationagent import ( From d8f05313fa5c6a6da5a0ef27e80c407a7dd02faf Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Mon, 13 Oct 2025 13:19:49 +0530 Subject: [PATCH 09/55] feat: updating k8s registration agent chat versions --- .../templates/helm-config.yaml | 4 ++-- hack/addons/helm-chart-bundler/repos.yaml | 4 ++-- .../kustomize/k8s-registration-agent/kustomization.yaml.tmpl | 2 +- make/addons.mk | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index bbf6d114a..78b4256df 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -33,8 +33,8 @@ data: RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://mesosphere.github.io/charts/stable/{{ end }}' k8s-registration-agent: | ChartName: nutanix-k8s-agent - ChartVersion: 0.0.1-alpha.1 - RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.10:8080{{ end }}' + ChartVersion: 1.3.0-rc.0 + RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.21:8080{{ end }}' local-path-provisioner-csi: | ChartName: local-path-provisioner ChartVersion: 0.0.31 diff --git a/hack/addons/helm-chart-bundler/repos.yaml b/hack/addons/helm-chart-bundler/repos.yaml index 50b662c64..97b1607e0 100644 --- a/hack/addons/helm-chart-bundler/repos.yaml +++ b/hack/addons/helm-chart-bundler/repos.yaml @@ -62,10 +62,10 @@ repositories: nutanix-csi-storage: - 3.3.4 nutanix-k8s-agent: - repoURL: http://192.168.1.10:8080 + repoURL: http://192.168.1.21:8080 charts: nutanix-k8s-agent: - - 0.0.1-alpha.1 + - 1.3.0-rc.0 registry-syncer: repoURL: https://mesosphere.github.io/charts/staging/ charts: diff --git a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl index 132962c92..4ed4032ef 100644 --- a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl @@ -11,7 +11,7 @@ helmCharts: - name: nutanix-k8s-agent namespace: kube-system #repo: https://mesosphere.github.io/charts/stable - repo: http://192.168.1.10:8080 + repo: http://192.168.1.21:8080 releaseName: k8s-registration-agent version: ${K8S_REGISTRATION_AGENT_VERSION} includeCRDs: true diff --git a/make/addons.mk b/make/addons.mk index 3394f4c16..fccae4183 100644 --- a/make/addons.mk +++ b/make/addons.mk @@ -26,7 +26,7 @@ export METALLB_CHART_VERSION := 0.15.2 export COSI_CONTROLLER_VERSION := 0.0.1-alpha.5 -export K8S_REGISTRATION_AGENT_VERSION := 0.0.1-alpha.1 +export K8S_REGISTRATION_AGENT_VERSION := 1.3.0-rc.0 .PHONY: addons.sync addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler snapshot-controller local-path-provisioner-csi aws-ebs-csi kube-vip) From e3a3c1616060ed7c1d89301f13f3f7a719cec78e Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Tue, 14 Oct 2025 21:36:16 +0530 Subject: [PATCH 10/55] feat:Adding before cluster delete hook --- .../lifecycle/k8sregistrationagent/handler.go | 289 ++++++++++++++++++ 1 file changed, 289 insertions(+) diff --git a/pkg/handlers/lifecycle/k8sregistrationagent/handler.go b/pkg/handlers/lifecycle/k8sregistrationagent/handler.go index 02368533b..007ec6d1c 100644 --- a/pkg/handlers/lifecycle/k8sregistrationagent/handler.go +++ b/pkg/handlers/lifecycle/k8sregistrationagent/handler.go @@ -9,14 +9,20 @@ import ( "fmt" "strings" "text/template" + "time" + "github.com/go-logr/logr" "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" ctrl "sigs.k8s.io/controller-runtime" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + caaphv1 "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1" apivariables "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/variables" commonhandlers "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" @@ -68,6 +74,7 @@ var ( _ commonhandlers.Named = &DefaultK8sRegistrationAgent{} _ lifecycle.AfterControlPlaneInitialized = &DefaultK8sRegistrationAgent{} _ lifecycle.BeforeClusterUpgrade = &DefaultK8sRegistrationAgent{} + _ lifecycle.BeforeClusterDelete = &DefaultK8sRegistrationAgent{} ) func New( @@ -315,3 +322,285 @@ func templateValuesFunc( return b.String(), nil } } + +func (n *DefaultK8sRegistrationAgent) BeforeClusterDelete( + ctx context.Context, + req *runtimehooksv1.BeforeClusterDeleteRequest, + resp *runtimehooksv1.BeforeClusterDeleteResponse, +) { + cluster := &req.Cluster + clusterKey := ctrlclient.ObjectKeyFromObject(cluster) + + log := ctrl.LoggerFrom(ctx).WithValues( + "cluster", + clusterKey, + ) + + varMap := variables.ClusterVariablesToVariablesMap(cluster.Spec.Topology.Variables) + k8sAgentVar, err := variables.Get[apivariables.NutanixK8sRegistrationAgent]( + varMap, + n.variableName, + n.variablePath...) + if err != nil { + if variables.IsNotFoundError(err) { + log.Info( + "Skipping K8s Registration Agent cleanup, addon not specified in cluster definition", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + return + } + log.Error( + err, + "failed to read K8s Registration Agent variable from cluster definition", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("failed to read K8s Registration Agent variable from cluster definition: %v", + err, + ), + ) + return + } + + // Only handle HelmAddon strategy for cleanup + switch k8sAgentVar.Strategy { + case v1alpha1.AddonStrategyHelmAddon: + // Check if cleanup is already in progress or completed + cleanupStatus, err := n.checkCleanupStatus(ctx, cluster, log) + if err != nil { + log.Error(err, "Failed to check cleanup status") + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage(err.Error()) + return + } + + switch cleanupStatus { + case "completed": + log.Info("K8s Registration Agent cleanup already completed") + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + return + case "in-progress": + log.Info("K8s Registration Agent cleanup in progress, requesting retry") + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + resp.SetRetryAfterSeconds(10) // Retry after 10 seconds + return + case "not-started": + log.Info("Starting K8s Registration Agent cleanup") + // Proceed with cleanup below + } + + err = n.deleteHelmChart(ctx, cluster, log) + if err != nil { + log.Error(err, "Failed to delete helm chart") + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage(err.Error()) + return + } + + // After initiating cleanup, request a retry to monitor completion + log.Info("K8s Registration Agent cleanup initiated, will monitor progress") + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + resp.SetRetryAfterSeconds(5) // Quick retry to start monitoring + + case v1alpha1.AddonStrategyClusterResourceSet: + log.Info("ClusterResourceSet strategy does not require cleanup") + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + case "": + log.Info("No strategy specified, skipping cleanup") + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + default: + log.Info( + "Unknown K8s Registration Agent strategy, skipping cleanup", + "strategy", k8sAgentVar.Strategy, + ) + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + } +} + +func (n *DefaultK8sRegistrationAgent) deleteHelmChart( + ctx context.Context, + cluster *clusterv1.Cluster, + log logr.Logger, +) error { + clusterUUID, ok := cluster.Annotations[v1alpha1.ClusterUUIDAnnotationKey] + if !ok { + return fmt.Errorf( + "cluster UUID not found in cluster annotations - missing key %s", + v1alpha1.ClusterUUIDAnnotationKey, + ) + } + + // Create HelmChartProxy with the same naming pattern used during creation + hcp := &caaphv1.HelmChartProxy{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", defaultHelmReleaseName, clusterUUID), + Namespace: cluster.Namespace, + }, + } + + // First, try to gracefully trigger helm uninstall while cluster is still accessible + log.Info("Initiating graceful deletion of K8s Registration Agent", "name", hcp.Name, "namespace", hcp.Namespace) + + // Get the current HCP to check if it exists and get its current state + currentHCP := &caaphv1.HelmChartProxy{} + err := n.client.Get(ctx, ctrlclient.ObjectKeyFromObject(hcp), currentHCP) + if err != nil { + if ctrlclient.IgnoreNotFound(err) == nil { + log.Info("K8s Registration Agent HelmChartProxy already deleted", "name", hcp.Name) + return nil + } + return fmt.Errorf("failed to get HelmChartProxy %q: %w", ctrlclient.ObjectKeyFromObject(hcp), err) + } + + // Add a deletion timestamp annotation to help CAAPH prioritize this deletion + // and set a shorter timeout to fail fast if cluster becomes unreachable + if currentHCP.Annotations == nil { + currentHCP.Annotations = make(map[string]string) + } + currentHCP.Annotations["cluster.x-k8s.io/delete-priority"] = "high" + currentHCP.Annotations["cluster.x-k8s.io/delete-timeout"] = "60s" + + // Update the HCP with priority annotations before deletion + if err := n.client.Update(ctx, currentHCP); err != nil { + log.Info("Failed to update HCP annotations, proceeding with deletion", "error", err) + } + + // Now delete the HelmChartProxy - CAAPH will handle the helm uninstall + log.Info("Deleting K8s Registration Agent HelmChartProxy", "name", hcp.Name, "namespace", hcp.Namespace) + if err := n.client.Delete(ctx, currentHCP); err != nil { + if ctrlclient.IgnoreNotFound(err) == nil { + log.Info("K8s Registration Agent HelmChartProxy already deleted", "name", hcp.Name) + return nil + } + return fmt.Errorf( + "failed to delete K8s Registration Agent HelmChartProxy %q: %w", + ctrlclient.ObjectKeyFromObject(hcp), + err, + ) + } + + // Wait for CAAPH to complete the helm uninstall before allowing cluster deletion to proceed + // This ensures graceful deletion order - helm uninstall completes before infrastructure teardown + log.Info("Waiting for helm uninstall to complete before proceeding with cluster deletion", "name", hcp.Name) + + if err := n.waitForHelmUninstallCompletion(ctx, hcp, log); err != nil { + log.Error(err, "Helm uninstall did not complete gracefully, proceeding with cluster deletion", "name", hcp.Name) + // Don't return error here - we want cluster deletion to proceed even if helm uninstall times out + // The important thing is we gave it a reasonable chance to complete + } else { + log.Info("Helm uninstall completed successfully", "name", hcp.Name) + } + + return nil +} + +// checkCleanupStatus checks the current status of K8s Registration Agent cleanup +// Returns: "completed", "in-progress", or "not-started" +func (n *DefaultK8sRegistrationAgent) checkCleanupStatus( + ctx context.Context, + cluster *clusterv1.Cluster, + log logr.Logger, +) (string, error) { + clusterUUID, ok := cluster.Annotations[v1alpha1.ClusterUUIDAnnotationKey] + if !ok { + return "completed", nil // If no UUID, assume no agent was installed + } + + // Check if HelmChartProxy exists + hcp := &caaphv1.HelmChartProxy{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-%s", defaultHelmReleaseName, clusterUUID), + Namespace: cluster.Namespace, + }, + } + + err := n.client.Get(ctx, ctrlclient.ObjectKeyFromObject(hcp), hcp) + if err != nil { + if apierrors.IsNotFound(err) { + log.Info("HelmChartProxy not found, cleanup completed", "name", hcp.Name) + return "completed", nil + } + return "", fmt.Errorf("failed to get HelmChartProxy %q: %w", ctrlclient.ObjectKeyFromObject(hcp), err) + } + + // HCP exists - check if it's being deleted + if hcp.DeletionTimestamp != nil { + log.Info("HelmChartProxy is being deleted, cleanup in progress", "name", hcp.Name) + return "in-progress", nil + } + + // HCP exists and is not being deleted + log.Info("HelmChartProxy exists, cleanup not started", "name", hcp.Name) + return "not-started", nil +} + +// waitForHelmUninstallCompletion waits for CAAPH to complete the helm uninstall process +// before allowing cluster deletion to proceed. This ensures graceful deletion order. +func (n *DefaultK8sRegistrationAgent) waitForHelmUninstallCompletion( + ctx context.Context, + hcp *caaphv1.HelmChartProxy, + log logr.Logger, +) error { + // Create a context with timeout to avoid blocking cluster deletion indefinitely + // 90 seconds should be enough for most helm uninstalls while still being reasonable + waitCtx, cancel := context.WithTimeout(ctx, 90*time.Second) + defer cancel() + + log.Info("Monitoring HelmChartProxy deletion progress", "name", hcp.Name) + + // First wait for the HelmChartProxy to be fully processed for deletion + // This indicates CAAPH has acknowledged the deletion request + err := wait.PollUntilContextTimeout( + waitCtx, + 2*time.Second, + 30*time.Second, + true, + func(pollCtx context.Context) (bool, error) { + currentHCP := &caaphv1.HelmChartProxy{} + err := n.client.Get(pollCtx, ctrlclient.ObjectKeyFromObject(hcp), currentHCP) + if err != nil { + if apierrors.IsNotFound(err) { + log.Info("HelmChartProxy has been deleted", "name", hcp.Name) + return true, nil + } + // If we can't reach the API server, the cluster might be shutting down + // In this case, we should not block cluster deletion + log.Info("Error checking HelmChartProxy status, cluster may be shutting down", "error", err) + return true, nil + } + + // Check if the HCP is in deletion phase + if currentHCP.DeletionTimestamp != nil { + log.Info("HelmChartProxy is being deleted, waiting for completion", "name", hcp.Name) + return false, nil + } + + // If HCP still exists without deletion timestamp, something might be wrong + log.Info("HelmChartProxy still exists, waiting for deletion to start", "name", hcp.Name) + return false, nil + }, + ) + if err != nil { + if wait.Interrupted(err) { + return fmt.Errorf("timeout waiting for HelmChartProxy deletion to complete") + } + return fmt.Errorf("error waiting for HelmChartProxy deletion: %w", err) + } + + // Additional wait to give CAAPH more time to complete the helm uninstall + // even after the HCP is deleted. This accounts for any cleanup operations. + log.Info("HelmChartProxy deleted, allowing additional time for helm uninstall completion") + + // Use a shorter additional wait to not delay cluster deletion too much + additionalWaitCtx, additionalCancel := context.WithTimeout(ctx, 30*time.Second) + defer additionalCancel() + + select { + case <-additionalWaitCtx.Done(): + log.Info("Additional wait period completed, proceeding with cluster deletion") + case <-time.After(10 * time.Second): + log.Info("Reasonable wait time elapsed, proceeding with cluster deletion") + } + + return nil +} From 91375c1f7a175d190b1652b9c57c30e41d601186 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Tue, 14 Oct 2025 21:59:11 +0530 Subject: [PATCH 11/55] Apply suggestions from code review Co-authored-by: Manoj Surudwad --- api/v1alpha1/addon_types.go | 6 +++--- .../k8s-registration-agent/values-template.yaml | 2 +- pkg/handlers/lifecycle/handlers.go | 4 ++-- .../lifecycle/k8sregistrationagent/handler.go | 12 ++---------- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 6fdfddde6..b3fd98f80 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -87,7 +87,7 @@ type NutanixAddons struct { COSI *NutanixCOSI `json:"cosi,omitempty"` // +kubebuilder:validation:Optional - K8sRegistrationAgent *NutanixK8sRegistrationAgent `json:"k8sRegistrationAgent,omitempty"` + KonnectorAgent *NutanixKonnectorAgent`json:"konnectorAgent,omitempty"` } type GenericAddons struct { @@ -363,7 +363,7 @@ type RegistryAddon struct { Provider string `json:"provider"` } -type NutanixK8sRegistrationAgent struct { +type NutanixKonnectorAgent struct { // A reference to the Secret for credential information for the target Prism Central instance // +kubebuilder:validation:Optional Credentials *NutanixK8sAgentCredentials `json:"credentials,omitempty"` @@ -376,7 +376,7 @@ type NutanixK8sRegistrationAgent struct { } type NutanixK8sAgentCredentials struct { - // A reference to the Secret containing the credentials used by the CCM provider. + // A reference to the Secret containing the credentials used by the Konnector agent. // +kubebuilder:validation:Required SecretRef LocalObjectReference `json:"secretRef"` } diff --git a/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml b/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml index 7902d3933..99889d734 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml @@ -6,5 +6,5 @@ pc: insecure: {{ .PrismCentralInsecure }} #set this to true if PC does not have https enabled endpoint: {{ .PrismCentralHost }} # eg: ip or fqdn k8sClusterName: {{ .ClusterName }} - +k8sDistribution: NKP createSecret: false diff --git a/pkg/handlers/lifecycle/handlers.go b/pkg/handlers/lifecycle/handlers.go index 5a719e302..929fc0957 100644 --- a/pkg/handlers/lifecycle/handlers.go +++ b/pkg/handlers/lifecycle/handlers.go @@ -48,7 +48,7 @@ type Handlers struct { localPathCSIConfig *localpath.Config snapshotControllerConfig *snapshotcontroller.Config cosiControllerConfig *cosi.ControllerConfig - k8sRegistrationAgentConfig *k8sregistrationagent.ControllerConfig + k8sRegistrationAgentConfig *k8sregistrationagent.Config distributionConfig *cncfdistribution.Config } @@ -71,7 +71,7 @@ func New( localPathCSIConfig: localpath.NewConfig(globalOptions), snapshotControllerConfig: snapshotcontroller.NewConfig(globalOptions), cosiControllerConfig: cosi.NewControllerConfig(globalOptions), - k8sRegistrationAgentConfig: k8sregistrationagent.NewControllerConfig(globalOptions), + k8sRegistrationAgentConfig: k8sregistrationagent.NewConfig(globalOptions), distributionConfig: &cncfdistribution.Config{GlobalOptions: globalOptions}, } } diff --git a/pkg/handlers/lifecycle/k8sregistrationagent/handler.go b/pkg/handlers/lifecycle/k8sregistrationagent/handler.go index 007ec6d1c..b572e5641 100644 --- a/pkg/handlers/lifecycle/k8sregistrationagent/handler.go +++ b/pkg/handlers/lifecycle/k8sregistrationagent/handler.go @@ -37,7 +37,7 @@ import ( const ( defaultHelmReleaseName = "k8s-registration-agent" defaultHelmReleaseNamespace = "ntnx-system" - defaultK8sAgentName = "nutanix-agent" + defaultK8sAgentName = "konnector-agent" defaultCredentialsSecretName = defaultK8sAgentName ) @@ -63,7 +63,7 @@ func (c *ControllerConfig) AddFlags(prefix string, flags *pflag.FlagSet) { type DefaultK8sRegistrationAgent struct { client ctrlclient.Client - config *ControllerConfig + config *Config helmChartInfoGetter *config.HelmChartGetter variableName string // points to the global config variable @@ -246,14 +246,6 @@ func (n *DefaultK8sRegistrationAgent) apply( n.client, helmChart, ).WithValueTemplater(templateValuesFunc(clusterConfigVar.Nutanix, cluster)) - case v1alpha1.AddonStrategyClusterResourceSet: - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage( - fmt.Sprintf( - "strategy %q not provided for K8s Registration Agent", v1alpha1.AddonStrategyClusterResourceSet, - ), - ) - return case "": resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage("strategy not provided for K8s Registration Agent") From f0829976be9d32349356eab97ed7939490124f2b Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Tue, 14 Oct 2025 22:57:38 +0530 Subject: [PATCH 12/55] renaming k8s registration agent to konnector agent --- api/v1alpha1/addon_types.go | 8 +-- api/v1alpha1/constants.go | 4 +- ...ren.nutanix.com_nutanixclusterconfigs.yaml | 6 +- api/v1alpha1/zz_generated.deepcopy.go | 34 +++++----- api/variables/aggregate_types.go | 6 +- .../README.md | 4 +- .../values-template.yaml | 0 .../templates/deployment.yaml | 2 +- .../templates/helm-config.yaml | 2 +- .../helm-addon-installation.yaml | 12 ---- .../helm-addon-installation.yaml | 12 ++++ .../values.schema.json | 2 +- .../values.yaml | 4 +- docs/content/addons/k8s-registration-agent.md | 2 +- .../nutanix-cluster-calico-crs.yaml | 2 +- .../nutanix-cluster-calico-helm-addon.yaml | 2 +- .../nutanix-cluster-cilium-crs.yaml | 2 +- .../nutanix-cluster-cilium-helm-addon.yaml | 2 +- ...luster-with-failuredomains-cilium-crs.yaml | 2 +- ...with-failuredomains-cilium-helm-addon.yaml | 2 +- .../kustomization.yaml.tmpl | 4 +- .../nutanix/cluster/kustomization.yaml.tmpl | 2 +- ...ration-agent.yaml => konnector-agent.yaml} | 2 +- hack/tools/fetch-images/main.go | 4 +- pkg/handlers/lifecycle/config/cm.go | 2 +- pkg/handlers/lifecycle/handlers.go | 62 ++++++++--------- .../doc.go | 4 +- .../handler.go | 66 ++++++++++--------- .../variables_test.go | 48 +++++++------- 29 files changed, 153 insertions(+), 151 deletions(-) rename charts/cluster-api-runtime-extensions-nutanix/addons/{k8s-registration-agent => konnector-agent}/values-template.yaml (100%) delete mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/k8s-registration-agent/helm-addon-installation.yaml create mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/konnector-agent/helm-addon-installation.yaml rename hack/examples/patches/nutanix/{k8s-registration-agent.yaml => konnector-agent.yaml} (60%) rename pkg/handlers/lifecycle/{k8sregistrationagent => konnectoragent}/doc.go (71%) rename pkg/handlers/lifecycle/{k8sregistrationagent => konnectoragent}/handler.go (91%) rename pkg/handlers/lifecycle/{k8sregistrationagent => konnectoragent}/variables_test.go (93%) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index b3fd98f80..6b30c2157 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -87,7 +87,7 @@ type NutanixAddons struct { COSI *NutanixCOSI `json:"cosi,omitempty"` // +kubebuilder:validation:Optional - KonnectorAgent *NutanixKonnectorAgent`json:"konnectorAgent,omitempty"` + KonnectorAgent *NutanixKonnectorAgent `json:"konnectorAgent,omitempty"` } type GenericAddons struct { @@ -366,16 +366,16 @@ type RegistryAddon struct { type NutanixKonnectorAgent struct { // A reference to the Secret for credential information for the target Prism Central instance // +kubebuilder:validation:Optional - Credentials *NutanixK8sAgentCredentials `json:"credentials,omitempty"` + Credentials *NutanixKonnectorAgentCredentials `json:"credentials,omitempty"` - // Addon strategy used to deploy the Nutanix k8s-registration-agent to the k8s cluster. + // Addon strategy used to deploy the Nutanix konnector-agent to the k8s cluster. // +kubebuilder:default=HelmAddon // +kubebuilder:validation:Optional // +kubebuilder:validation:Enum=ClusterResourceSet;HelmAddon Strategy AddonStrategy `json:"strategy,omitzero"` } -type NutanixK8sAgentCredentials struct { +type NutanixKonnectorAgentCredentials struct { // A reference to the Secret containing the credentials used by the Konnector agent. // +kubebuilder:validation:Required SecretRef LocalObjectReference `json:"secretRef"` diff --git a/api/v1alpha1/constants.go b/api/v1alpha1/constants.go index c4ce187f0..5b59822d7 100644 --- a/api/v1alpha1/constants.go +++ b/api/v1alpha1/constants.go @@ -32,8 +32,8 @@ const ( ServiceLoadBalancerVariableName = "serviceLoadBalancer" // RegistryAddonVariableName is the OCI registry config patch variable name. RegistryAddonVariableName = "registry" - // K8sRegistrationAgentVariableName is the Nutanix k8s-registration-agent addon config patch variable name. - K8sRegistrationAgentVariableName = "k8sRegistrationAgent" + // KonnectorAgentVariableName is the Nutanix konnector-agent addon config patch variable name. + KonnectorAgentVariableName = "konnectorAgent" // GlobalMirrorVariableName is the global image registry mirror patch variable name. GlobalMirrorVariableName = "globalImageRegistryMirror" diff --git a/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml b/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml index ccba81174..9d0ff6248 100644 --- a/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml +++ b/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml @@ -235,13 +235,13 @@ spec: - defaultStorage - providers type: object - k8sRegistrationAgent: + konnectorAgent: properties: credentials: description: A reference to the Secret for credential information for the target Prism Central instance properties: secretRef: - description: A reference to the Secret containing the credentials used by the CCM provider. + description: A reference to the Secret containing the credentials used by the Konnector agent. properties: name: description: |- @@ -258,7 +258,7 @@ spec: type: object strategy: default: HelmAddon - description: Addon strategy used to deploy the Nutanix k8s-registration-agent to the k8s cluster. + description: Addon strategy used to deploy the Nutanix konnector-agent to the k8s cluster. enum: - ClusterResourceSet - HelmAddon diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 76d12db5a..a0ceae8fe 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1702,9 +1702,9 @@ func (in *NutanixAddons) DeepCopyInto(out *NutanixAddons) { *out = new(NutanixCOSI) **out = **in } - if in.K8sRegistrationAgent != nil { - in, out := &in.K8sRegistrationAgent, &out.K8sRegistrationAgent - *out = new(NutanixK8sRegistrationAgent) + if in.KonnectorAgent != nil { + in, out := &in.KonnectorAgent, &out.KonnectorAgent + *out = new(NutanixKonnectorAgent) (*in).DeepCopyInto(*out) } } @@ -1885,37 +1885,37 @@ func (in *NutanixControlPlaneSpec) DeepCopy() *NutanixControlPlaneSpec { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NutanixK8sAgentCredentials) DeepCopyInto(out *NutanixK8sAgentCredentials) { +func (in *NutanixKonnectorAgent) DeepCopyInto(out *NutanixKonnectorAgent) { *out = *in - out.SecretRef = in.SecretRef + if in.Credentials != nil { + in, out := &in.Credentials, &out.Credentials + *out = new(NutanixKonnectorAgentCredentials) + **out = **in + } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixK8sAgentCredentials. -func (in *NutanixK8sAgentCredentials) DeepCopy() *NutanixK8sAgentCredentials { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixKonnectorAgent. +func (in *NutanixKonnectorAgent) DeepCopy() *NutanixKonnectorAgent { if in == nil { return nil } - out := new(NutanixK8sAgentCredentials) + out := new(NutanixKonnectorAgent) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NutanixK8sRegistrationAgent) DeepCopyInto(out *NutanixK8sRegistrationAgent) { +func (in *NutanixKonnectorAgentCredentials) DeepCopyInto(out *NutanixKonnectorAgentCredentials) { *out = *in - if in.Credentials != nil { - in, out := &in.Credentials, &out.Credentials - *out = new(NutanixK8sAgentCredentials) - **out = **in - } + out.SecretRef = in.SecretRef } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixK8sRegistrationAgent. -func (in *NutanixK8sRegistrationAgent) DeepCopy() *NutanixK8sRegistrationAgent { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixKonnectorAgentCredentials. +func (in *NutanixKonnectorAgentCredentials) DeepCopy() *NutanixKonnectorAgentCredentials { if in == nil { return nil } - out := new(NutanixK8sRegistrationAgent) + out := new(NutanixKonnectorAgentCredentials) in.DeepCopyInto(out) return out } diff --git a/api/variables/aggregate_types.go b/api/variables/aggregate_types.go index a0e25c6e6..2e2a033c5 100644 --- a/api/variables/aggregate_types.go +++ b/api/variables/aggregate_types.go @@ -67,11 +67,11 @@ type Addons struct { COSI *COSI `json:"cosi,omitempty"` - NutanixK8sRegistrationAgent *NutanixK8sRegistrationAgent `json:"k8sRegistrationAgent,omitempty"` + NutanixKonnectorAgent *NutanixKonnectorAgent `json:"konnectorAgent,omitempty"` } -type NutanixK8sRegistrationAgent struct { - carenv1.NutanixK8sRegistrationAgent `json:",inline"` +type NutanixKonnectorAgent struct { + carenv1.NutanixKonnectorAgent `json:",inline"` } type CSI struct { diff --git a/charts/cluster-api-runtime-extensions-nutanix/README.md b/charts/cluster-api-runtime-extensions-nutanix/README.md index b24644e7d..0d2529907 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/README.md +++ b/charts/cluster-api-runtime-extensions-nutanix/README.md @@ -87,8 +87,8 @@ A Helm chart for cluster-api-runtime-extensions-nutanix | hooks.csi.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-nutanix-csi-helm-values-template"` | | | hooks.csi.snapshot-controller.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.csi.snapshot-controller.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-snapshot-controller-helm-values-template"` | | -| hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | -| hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-k8s-registrationagent-helm-values-template"` | | +| hooks.konnectorAgent.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | +| hooks.konnectorAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-konnector-agent-helm-values-template"` | | | hooks.nfd.crsStrategy.defaultInstallationConfigMap.name | string | `"node-feature-discovery"` | | | hooks.nfd.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.nfd.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-nfd-helm-values-template"` | | diff --git a/charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml b/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml similarity index 100% rename from charts/cluster-api-runtime-extensions-nutanix/addons/k8s-registration-agent/values-template.yaml rename to charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml index cb1b26397..647519413 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml @@ -45,7 +45,7 @@ spec: - --csi.snapshot-controller.helm-addon.default-values-template-configmap-name={{ (index .Values.hooks.csi "snapshot-controller").helmAddonStrategy.defaultValueTemplateConfigMap.name }} - --ccm.aws.helm-addon.default-values-template-configmap-name={{ .Values.hooks.ccm.aws.helmAddonStrategy.defaultValueTemplateConfigMap.name }} - --cosi.controller.helm-addon.default-values-template-configmap-name={{ .Values.hooks.cosi.controller.helmAddonStrategy.defaultValueTemplateConfigMap.name }} - - --k8s-registration-agent.helm-addon.default-values-template-configmap-name={{ .Values.hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name }} + - --konnector-agent.helm-addon.default-values-template-configmap-name={{ .Values.hooks.konnectorAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name }} {{- range $k, $v := .Values.hooks.ccm.aws.k8sMinorVersionToCCMVersion }} - --ccm.aws.aws-ccm-versions={{ $k }}={{ $v }} {{- end }} diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index 78b4256df..84fb306f5 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -31,7 +31,7 @@ data: ChartName: cosi ChartVersion: 0.0.1-alpha.5 RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://mesosphere.github.io/charts/stable/{{ end }}' - k8s-registration-agent: | + konnector-agent: | ChartName: nutanix-k8s-agent ChartVersion: 1.3.0-rc.0 RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.21:8080{{ end }}' diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/k8s-registration-agent/helm-addon-installation.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/k8s-registration-agent/helm-addon-installation.yaml deleted file mode 100644 index f32c4bd6b..000000000 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/k8s-registration-agent/helm-addon-installation.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright 2025 Nutanix. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -{{- if .Values.hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: '{{ .Values.hooks.k8sRegistrationAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name }}' -data: - values.yaml: |- - {{- .Files.Get "addons/k8s-registration-agent/values-template.yaml" | nindent 4 }} -{{- end -}} diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/konnector-agent/helm-addon-installation.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/konnector-agent/helm-addon-installation.yaml new file mode 100644 index 000000000..690319c75 --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/konnector-agent/helm-addon-installation.yaml @@ -0,0 +1,12 @@ +# Copyright 2025 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +{{- if .Values.hooks.konnectorAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: '{{ .Values.hooks.konnectorAgent.helmAddonStrategy.defaultValueTemplateConfigMap.name }}' +data: + values.yaml: |- + {{- .Files.Get "addons/konnector-agent/values-template.yaml" | nindent 4 }} +{{- end -}} diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.schema.json b/charts/cluster-api-runtime-extensions-nutanix/values.schema.json index 74a68eeed..b1e6e5f13 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.schema.json +++ b/charts/cluster-api-runtime-extensions-nutanix/values.schema.json @@ -496,7 +496,7 @@ } } }, - "k8sRegistrationAgent": { + "konnectorAgent": { "type": "object", "properties": { "helmAddonStrategy": { diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.yaml b/charts/cluster-api-runtime-extensions-nutanix/values.yaml index 519b0d142..2d0e80efd 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/values.yaml @@ -101,11 +101,11 @@ hooks: defaultValueTemplateConfigMap: create: true name: default-metallb-helm-values-template - k8sRegistrationAgent: + konnectorAgent: helmAddonStrategy: defaultValueTemplateConfigMap: create: true - name: default-k8s-registrationagent-helm-values-template + name: default-konnector-agent-helm-values-template cosi: controller: helmAddonStrategy: diff --git a/docs/content/addons/k8s-registration-agent.md b/docs/content/addons/k8s-registration-agent.md index a5b447f6c..2b729b7da 100644 --- a/docs/content/addons/k8s-registration-agent.md +++ b/docs/content/addons/k8s-registration-agent.md @@ -23,7 +23,7 @@ spec: - name: clusterConfig value: addons: - k8sRegistrationAgent: {} + konnectorAgent: {} ``` [Kubernetes cluster registration agent]: https://github.com/nutanix-core/k8s-agent diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 71b678069..2dbe0cb50 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -90,7 +90,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - k8sRegistrationAgent: {} + konnectorAgent: {} nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index a87e18fe0..f89e47547 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -88,7 +88,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - k8sRegistrationAgent: {} + konnectorAgent: {} nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index afc74ad66..6385e8eb0 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -90,7 +90,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - k8sRegistrationAgent: {} + konnectorAgent: {} nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 886d52ab8..f0707c9e4 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -88,7 +88,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - k8sRegistrationAgent: {} + konnectorAgent: {} nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index 676a311ae..d0157f5eb 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -126,7 +126,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - k8sRegistrationAgent: {} + konnectorAgent: {} nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index fd9afada0..f5044c87b 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -124,7 +124,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - k8sRegistrationAgent: {} + konnectorAgent: {} nfd: {} serviceLoadBalancer: configuration: diff --git a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl index 4ed4032ef..69d50d188 100644 --- a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl @@ -5,14 +5,14 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization metadata: - name: k8s-registration-agent-kustomize + name: konnector-agent-kustomize helmCharts: - name: nutanix-k8s-agent namespace: kube-system #repo: https://mesosphere.github.io/charts/stable repo: http://192.168.1.21:8080 - releaseName: k8s-registration-agent + releaseName: konnector-agent version: ${K8S_REGISTRATION_AGENT_VERSION} includeCRDs: true skipTests: true diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index 399f1f2d2..20ec2c37c 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -35,7 +35,7 @@ patches: path: ../../../patches/nutanix/cosi.yaml - target: kind: Cluster - path: ../../../patches/nutanix/k8s-registration-agent.yaml + path: ../../../patches/nutanix/konnector-agent.yaml - target: kind: Cluster path: ../../../patches/nutanix/ccm.yaml diff --git a/hack/examples/patches/nutanix/k8s-registration-agent.yaml b/hack/examples/patches/nutanix/konnector-agent.yaml similarity index 60% rename from hack/examples/patches/nutanix/k8s-registration-agent.yaml rename to hack/examples/patches/nutanix/konnector-agent.yaml index 679c4a04c..c85413205 100644 --- a/hack/examples/patches/nutanix/k8s-registration-agent.yaml +++ b/hack/examples/patches/nutanix/konnector-agent.yaml @@ -2,5 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 - op: "add" - path: "/spec/topology/variables/0/value/addons/k8sRegistrationAgent" + path: "/spec/topology/variables/0/value/addons/konnectorAgent" value: {} diff --git a/hack/tools/fetch-images/main.go b/hack/tools/fetch-images/main.go index 52ded24e1..20bdc239b 100644 --- a/hack/tools/fetch-images/main.go +++ b/hack/tools/fetch-images/main.go @@ -351,8 +351,8 @@ func getValuesFileForChartIfNeeded(chartName, carenChartDirectory string) (strin return tempFile.Name(), nil case "cosi-controller": return filepath.Join(carenChartDirectory, "addons", "cosi", "controller", defaultHelmAddonFilename), nil - case "k8s-registration-agent": - return filepath.Join(carenChartDirectory, "addons", "k8s-registration-agent", defaultHelmAddonFilename), nil + case "konnector-agent": + return filepath.Join(carenChartDirectory, "addons", "konnector-agent", defaultHelmAddonFilename), nil case "metallb": return filepath.Join( carenChartDirectory, diff --git a/pkg/handlers/lifecycle/config/cm.go b/pkg/handlers/lifecycle/config/cm.go index 39485d95d..a5b9b4ee5 100644 --- a/pkg/handlers/lifecycle/config/cm.go +++ b/pkg/handlers/lifecycle/config/cm.go @@ -31,7 +31,7 @@ const ( COSIController Component = "cosi-controller" CNCFDistributionRegistry Component = "cncf-distribution-registry" RegistrySyncer Component = "registry-syncer" - K8sRegistrationAgent Component = "k8s-registration-agent" + KonnectorAgent Component = "konnector-agent" ) type HelmChartGetter struct { diff --git a/pkg/handlers/lifecycle/handlers.go b/pkg/handlers/lifecycle/handlers.go index 929fc0957..28aab7c35 100644 --- a/pkg/handlers/lifecycle/handlers.go +++ b/pkg/handlers/lifecycle/handlers.go @@ -24,7 +24,7 @@ import ( "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/localpath" nutanixcsi "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/nutanix" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/snapshotcontroller" - "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/k8sregistrationagent" + konnectoragent "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/konnectoragent" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/nfd" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/registry" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/registry/cncfdistribution" @@ -35,21 +35,21 @@ import ( ) type Handlers struct { - globalOptions *options.GlobalOptions - calicoCNIConfig *calico.CNIConfig - ciliumCNIConfig *cilium.CNIConfig - nfdConfig *nfd.Config - clusterAutoscalerConfig *clusterautoscaler.Config - ebsConfig *awsebs.Config - nutanixCSIConfig *nutanixcsi.Config - awsccmConfig *awsccm.AWSCCMConfig - nutanixCCMConfig *nutanixccm.Config - metalLBConfig *metallb.Config - localPathCSIConfig *localpath.Config - snapshotControllerConfig *snapshotcontroller.Config - cosiControllerConfig *cosi.ControllerConfig - k8sRegistrationAgentConfig *k8sregistrationagent.Config - distributionConfig *cncfdistribution.Config + globalOptions *options.GlobalOptions + calicoCNIConfig *calico.CNIConfig + ciliumCNIConfig *cilium.CNIConfig + nfdConfig *nfd.Config + clusterAutoscalerConfig *clusterautoscaler.Config + ebsConfig *awsebs.Config + nutanixCSIConfig *nutanixcsi.Config + awsccmConfig *awsccm.AWSCCMConfig + nutanixCCMConfig *nutanixccm.Config + metalLBConfig *metallb.Config + localPathCSIConfig *localpath.Config + snapshotControllerConfig *snapshotcontroller.Config + cosiControllerConfig *cosi.ControllerConfig + konnectorAgentConfig *konnectoragent.Config + distributionConfig *cncfdistribution.Config } func New( @@ -60,19 +60,19 @@ func New( calicoCNIConfig: &calico.CNIConfig{ GlobalOptions: globalOptions, }, - ciliumCNIConfig: &cilium.CNIConfig{GlobalOptions: globalOptions}, - nfdConfig: nfd.NewConfig(globalOptions), - clusterAutoscalerConfig: &clusterautoscaler.Config{GlobalOptions: globalOptions}, - ebsConfig: awsebs.NewConfig(globalOptions), - awsccmConfig: awsccm.NewConfig(globalOptions), - nutanixCSIConfig: nutanixcsi.NewConfig(globalOptions), - nutanixCCMConfig: &nutanixccm.Config{GlobalOptions: globalOptions}, - metalLBConfig: &metallb.Config{GlobalOptions: globalOptions}, - localPathCSIConfig: localpath.NewConfig(globalOptions), - snapshotControllerConfig: snapshotcontroller.NewConfig(globalOptions), - cosiControllerConfig: cosi.NewControllerConfig(globalOptions), - k8sRegistrationAgentConfig: k8sregistrationagent.NewConfig(globalOptions), - distributionConfig: &cncfdistribution.Config{GlobalOptions: globalOptions}, + ciliumCNIConfig: &cilium.CNIConfig{GlobalOptions: globalOptions}, + nfdConfig: nfd.NewConfig(globalOptions), + clusterAutoscalerConfig: &clusterautoscaler.Config{GlobalOptions: globalOptions}, + ebsConfig: awsebs.NewConfig(globalOptions), + awsccmConfig: awsccm.NewConfig(globalOptions), + nutanixCSIConfig: nutanixcsi.NewConfig(globalOptions), + nutanixCCMConfig: &nutanixccm.Config{GlobalOptions: globalOptions}, + metalLBConfig: &metallb.Config{GlobalOptions: globalOptions}, + localPathCSIConfig: localpath.NewConfig(globalOptions), + snapshotControllerConfig: snapshotcontroller.NewConfig(globalOptions), + cosiControllerConfig: cosi.NewControllerConfig(globalOptions), + konnectorAgentConfig: konnectoragent.NewConfig(globalOptions), + distributionConfig: &cncfdistribution.Config{GlobalOptions: globalOptions}, } } @@ -130,7 +130,7 @@ func (h *Handlers) AllHandlers(mgr manager.Manager) []handlers.Named { csi.New(mgr.GetClient(), csiHandlers), snapshotcontroller.New(mgr.GetClient(), h.snapshotControllerConfig, helmChartInfoGetter), cosi.New(mgr.GetClient(), h.cosiControllerConfig, helmChartInfoGetter), - k8sregistrationagent.New(mgr.GetClient(), h.k8sRegistrationAgentConfig, helmChartInfoGetter), + konnectoragent.New(mgr.GetClient(), h.konnectorAgentConfig, helmChartInfoGetter), servicelbgc.New(mgr.GetClient()), registry.New(mgr.GetClient(), registryHandlers), // The order of the handlers in the list is important and are called consecutively. @@ -234,6 +234,6 @@ func (h *Handlers) AddFlags(flagSet *pflag.FlagSet) { h.nutanixCCMConfig.AddFlags("ccm.nutanix", flagSet) h.metalLBConfig.AddFlags("metallb", flagSet) h.cosiControllerConfig.AddFlags("cosi.controller", flagSet) - h.k8sRegistrationAgentConfig.AddFlags("k8s-registration-agent", flagSet) + h.konnectorAgentConfig.AddFlags("konnector-agent", flagSet) h.distributionConfig.AddFlags("registry.cncf-distribution", flagSet) } diff --git a/pkg/handlers/lifecycle/k8sregistrationagent/doc.go b/pkg/handlers/lifecycle/konnectoragent/doc.go similarity index 71% rename from pkg/handlers/lifecycle/k8sregistrationagent/doc.go rename to pkg/handlers/lifecycle/konnectoragent/doc.go index 419f9f4fe..05c8b4d3c 100644 --- a/pkg/handlers/lifecycle/k8sregistrationagent/doc.go +++ b/pkg/handlers/lifecycle/konnectoragent/doc.go @@ -1,8 +1,8 @@ // Copyright 2023 Nutanix. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// Package k8s-registration-agent provides a handler for managing k8s agent deployments on clusters +// Package konnector-agent provides a handler for managing k8s agent deployments on clusters // // +kubebuilder:rbac:groups=addons.cluster.x-k8s.io,resources=clusterresourcesets,verbs=watch;list;get;create;patch;update;delete // +kubebuilder:rbac:groups="",resources=configmaps,verbs=watch;list;get;create;patch;update;delete -package k8sregistrationagent +package konnectoragent diff --git a/pkg/handlers/lifecycle/k8sregistrationagent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go similarity index 91% rename from pkg/handlers/lifecycle/k8sregistrationagent/handler.go rename to pkg/handlers/lifecycle/konnectoragent/handler.go index b572e5641..7887d72ec 100644 --- a/pkg/handlers/lifecycle/k8sregistrationagent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -1,7 +1,7 @@ // Copyright 2023 Nutanix. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package k8sregistrationagent +package konnectoragent import ( "bytes" @@ -35,33 +35,33 @@ import ( ) const ( - defaultHelmReleaseName = "k8s-registration-agent" + defaultHelmReleaseName = "konnector-agent" defaultHelmReleaseNamespace = "ntnx-system" defaultK8sAgentName = "konnector-agent" defaultCredentialsSecretName = defaultK8sAgentName ) -type ControllerConfig struct { +type Config struct { *options.GlobalOptions helmAddonConfig *addons.HelmAddonConfig } -func NewControllerConfig(globalOptions *options.GlobalOptions) *ControllerConfig { - return &ControllerConfig{ +func NewConfig(globalOptions *options.GlobalOptions) *Config { + return &Config{ GlobalOptions: globalOptions, helmAddonConfig: addons.NewHelmAddonConfig( - "default-k8s-registrationagent-helm-values-template", + "default-konnector-agent-helm-values-template", defaultHelmReleaseNamespace, defaultHelmReleaseName, ), } } -func (c *ControllerConfig) AddFlags(prefix string, flags *pflag.FlagSet) { +func (c *Config) AddFlags(prefix string, flags *pflag.FlagSet) { c.helmAddonConfig.AddFlags(prefix+".helm-addon", flags) } -type DefaultK8sRegistrationAgent struct { +type DefaultKonnectorAgent struct { client ctrlclient.Client config *Config helmChartInfoGetter *config.HelmChartGetter @@ -71,31 +71,31 @@ type DefaultK8sRegistrationAgent struct { } var ( - _ commonhandlers.Named = &DefaultK8sRegistrationAgent{} - _ lifecycle.AfterControlPlaneInitialized = &DefaultK8sRegistrationAgent{} - _ lifecycle.BeforeClusterUpgrade = &DefaultK8sRegistrationAgent{} - _ lifecycle.BeforeClusterDelete = &DefaultK8sRegistrationAgent{} + _ commonhandlers.Named = &DefaultKonnectorAgent{} + _ lifecycle.AfterControlPlaneInitialized = &DefaultKonnectorAgent{} + _ lifecycle.BeforeClusterUpgrade = &DefaultKonnectorAgent{} + _ lifecycle.BeforeClusterDelete = &DefaultKonnectorAgent{} ) func New( c ctrlclient.Client, - cfg *ControllerConfig, + cfg *Config, helmChartInfoGetter *config.HelmChartGetter, -) *DefaultK8sRegistrationAgent { - return &DefaultK8sRegistrationAgent{ +) *DefaultKonnectorAgent { + return &DefaultKonnectorAgent{ client: c, config: cfg, helmChartInfoGetter: helmChartInfoGetter, variableName: v1alpha1.ClusterConfigVariableName, - variablePath: []string{"addons", v1alpha1.K8sRegistrationAgentVariableName}, + variablePath: []string{"addons", v1alpha1.KonnectorAgentVariableName}, } } -func (n *DefaultK8sRegistrationAgent) Name() string { - return "K8sRegistrationAgentHandler" +func (n *DefaultKonnectorAgent) Name() string { + return "KonnectorAgentHandler" } -func (n *DefaultK8sRegistrationAgent) AfterControlPlaneInitialized( +func (n *DefaultKonnectorAgent) AfterControlPlaneInitialized( ctx context.Context, req *runtimehooksv1.AfterControlPlaneInitializedRequest, resp *runtimehooksv1.AfterControlPlaneInitializedResponse, @@ -106,7 +106,7 @@ func (n *DefaultK8sRegistrationAgent) AfterControlPlaneInitialized( resp.Message = commonResponse.GetMessage() } -func (n *DefaultK8sRegistrationAgent) BeforeClusterUpgrade( +func (n *DefaultKonnectorAgent) BeforeClusterUpgrade( ctx context.Context, req *runtimehooksv1.BeforeClusterUpgradeRequest, resp *runtimehooksv1.BeforeClusterUpgradeResponse, @@ -117,7 +117,7 @@ func (n *DefaultK8sRegistrationAgent) BeforeClusterUpgrade( resp.Message = commonResponse.GetMessage() } -func (n *DefaultK8sRegistrationAgent) apply( +func (n *DefaultKonnectorAgent) apply( ctx context.Context, cluster *clusterv1.Cluster, resp *runtimehooksv1.CommonResponse, @@ -130,7 +130,7 @@ func (n *DefaultK8sRegistrationAgent) apply( ) varMap := variables.ClusterVariablesToVariablesMap(cluster.Spec.Topology.Variables) - k8sAgentVar, err := variables.Get[apivariables.NutanixK8sRegistrationAgent]( + k8sAgentVar, err := variables.Get[apivariables.NutanixKonnectorAgent]( varMap, n.variableName, n.variablePath...) @@ -210,7 +210,7 @@ func (n *DefaultK8sRegistrationAgent) apply( var strategy addons.Applier switch k8sAgentVar.Strategy { case v1alpha1.AddonStrategyHelmAddon: - helmChart, err := n.helmChartInfoGetter.For(ctx, log, config.K8sRegistrationAgent) + helmChart, err := n.helmChartInfoGetter.For(ctx, log, config.KonnectorAgent) if err != nil { log.Error( err, @@ -298,10 +298,12 @@ func templateValuesFunc( return "", err } templateInput := input{ - AgentName: defaultK8sAgentName, - PrismCentralHost: address, - PrismCentralPort: port, - PrismCentralInsecure: nutanixConfig.PrismCentralEndpoint.Insecure, + AgentName: defaultK8sAgentName, + PrismCentralHost: address, + PrismCentralPort: port, + // TODO: remove this once we have a way to set this. + // need to add support to accept PC's trust bundle in agent(it's not implemented currently) + PrismCentralInsecure: true, ClusterName: cluster.Name, } @@ -315,7 +317,7 @@ func templateValuesFunc( } } -func (n *DefaultK8sRegistrationAgent) BeforeClusterDelete( +func (n *DefaultKonnectorAgent) BeforeClusterDelete( ctx context.Context, req *runtimehooksv1.BeforeClusterDeleteRequest, resp *runtimehooksv1.BeforeClusterDeleteResponse, @@ -329,7 +331,7 @@ func (n *DefaultK8sRegistrationAgent) BeforeClusterDelete( ) varMap := variables.ClusterVariablesToVariablesMap(cluster.Spec.Topology.Variables) - k8sAgentVar, err := variables.Get[apivariables.NutanixK8sRegistrationAgent]( + k8sAgentVar, err := variables.Get[apivariables.NutanixKonnectorAgent]( varMap, n.variableName, n.variablePath...) @@ -409,7 +411,7 @@ func (n *DefaultK8sRegistrationAgent) BeforeClusterDelete( } } -func (n *DefaultK8sRegistrationAgent) deleteHelmChart( +func (n *DefaultKonnectorAgent) deleteHelmChart( ctx context.Context, cluster *clusterv1.Cluster, log logr.Logger, @@ -488,7 +490,7 @@ func (n *DefaultK8sRegistrationAgent) deleteHelmChart( // checkCleanupStatus checks the current status of K8s Registration Agent cleanup // Returns: "completed", "in-progress", or "not-started" -func (n *DefaultK8sRegistrationAgent) checkCleanupStatus( +func (n *DefaultKonnectorAgent) checkCleanupStatus( ctx context.Context, cluster *clusterv1.Cluster, log logr.Logger, @@ -528,7 +530,7 @@ func (n *DefaultK8sRegistrationAgent) checkCleanupStatus( // waitForHelmUninstallCompletion waits for CAAPH to complete the helm uninstall process // before allowing cluster deletion to proceed. This ensures graceful deletion order. -func (n *DefaultK8sRegistrationAgent) waitForHelmUninstallCompletion( +func (n *DefaultKonnectorAgent) waitForHelmUninstallCompletion( ctx context.Context, hcp *caaphv1.HelmChartProxy, log logr.Logger, diff --git a/pkg/handlers/lifecycle/k8sregistrationagent/variables_test.go b/pkg/handlers/lifecycle/konnectoragent/variables_test.go similarity index 93% rename from pkg/handlers/lifecycle/k8sregistrationagent/variables_test.go rename to pkg/handlers/lifecycle/konnectoragent/variables_test.go index e4922b26d..32b044753 100644 --- a/pkg/handlers/lifecycle/k8sregistrationagent/variables_test.go +++ b/pkg/handlers/lifecycle/konnectoragent/variables_test.go @@ -1,7 +1,7 @@ // Copyright 2024 Nutanix. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package k8sregistrationagent +package konnectoragent import ( "context" @@ -30,19 +30,19 @@ func init() { _ = clusterv1.AddToScheme(testScheme) } -func newTestHandler(t *testing.T) *DefaultK8sRegistrationAgent { +func newTestHandler(t *testing.T) *DefaultKonnectorAgent { t.Helper() client := fake.NewClientBuilder().WithScheme(testScheme).Build() - cfg := NewControllerConfig(&options.GlobalOptions{}) + cfg := NewConfig(&options.GlobalOptions{}) getter := &config.HelmChartGetter{} // not used directly in test - return &DefaultK8sRegistrationAgent{ + return &DefaultKonnectorAgent{ client: client, config: cfg, helmChartInfoGetter: getter, variableName: v1alpha1.ClusterConfigVariableName, - variablePath: []string{"addons", v1alpha1.K8sRegistrationAgentVariableName}, + variablePath: []string{"addons", v1alpha1.KonnectorAgentVariableName}, } } @@ -73,7 +73,7 @@ func TestApply_FailsWhenCredentialsMissing(t *testing.T) { Variables: []clusterv1.ClusterVariable{{ Name: v1alpha1.ClusterConfigVariableName, Value: apiextensionsv1.JSON{ - Raw: []byte(`{"addons":{"k8sRegistrationAgent":{"strategy":"HelmAddon"}}}`), + Raw: []byte(`{"addons":{"konnectorAgent":{"strategy":"HelmAddon"}}}`), }, }}, }, @@ -97,7 +97,7 @@ func TestApply_FailsWhenCopySecretFails(t *testing.T) { Name: v1alpha1.ClusterConfigVariableName, Value: apiextensionsv1.JSON{Raw: []byte(`{ "addons": { - "k8sRegistrationAgent": { + "konnectorAgent": { "strategy": "HelmAddon", "credentials": { "secretRef": {"name":"missing-secret"} } } @@ -131,7 +131,7 @@ func TestApply_SuccessfulHelmStrategy(t *testing.T) { } }, "addons": { - "k8sRegistrationAgent": { + "konnectorAgent": { "strategy": "HelmAddon", "credentials": { "secretRef": {"name":"dummy-secret"} } } @@ -174,7 +174,7 @@ func TestApply_HelmApplyFails(t *testing.T) { Name: v1alpha1.ClusterConfigVariableName, Value: apiextensionsv1.JSON{Raw: []byte(`{ "addons": { - "k8sRegistrationAgent": { + "konnectorAgent": { "strategy": "HelmAddon", "credentials": { "secretRef": {"name":"dummy-secret"} } } @@ -210,17 +210,17 @@ func TestApply_HelmApplyFails(t *testing.T) { } // Test constructor functions -func TestNewControllerConfig(t *testing.T) { +func TestNewConfig(t *testing.T) { globalOpts := &options.GlobalOptions{} - cfg := NewControllerConfig(globalOpts) + cfg := NewConfig(globalOpts) assert.NotNil(t, cfg) assert.Equal(t, globalOpts, cfg.GlobalOptions) assert.NotNil(t, cfg.helmAddonConfig) } -func TestControllerConfigAddFlags(t *testing.T) { - cfg := NewControllerConfig(&options.GlobalOptions{}) +func TestConfigAddFlags(t *testing.T) { + cfg := NewConfig(&options.GlobalOptions{}) flags := pflag.NewFlagSet("test", pflag.ContinueOnError) cfg.AddFlags("k8s-agent", flags) @@ -232,7 +232,7 @@ func TestControllerConfigAddFlags(t *testing.T) { func TestNew(t *testing.T) { client := fake.NewClientBuilder().WithScheme(testScheme).Build() - cfg := NewControllerConfig(&options.GlobalOptions{}) + cfg := NewConfig(&options.GlobalOptions{}) getter := &config.HelmChartGetter{} handler := New(client, cfg, getter) @@ -242,12 +242,12 @@ func TestNew(t *testing.T) { assert.Equal(t, cfg, handler.config) assert.Equal(t, getter, handler.helmChartInfoGetter) assert.Equal(t, v1alpha1.ClusterConfigVariableName, handler.variableName) - assert.Equal(t, []string{"addons", v1alpha1.K8sRegistrationAgentVariableName}, handler.variablePath) + assert.Equal(t, []string{"addons", v1alpha1.KonnectorAgentVariableName}, handler.variablePath) } func TestName(t *testing.T) { handler := newTestHandler(t) - assert.Equal(t, "K8sRegistrationAgentHandler", handler.Name()) + assert.Equal(t, "KonnectorAgentHandler", handler.Name()) } // Test lifecycle hooks @@ -306,7 +306,7 @@ func TestApply_ClusterResourceSetStrategy(t *testing.T) { Name: v1alpha1.ClusterConfigVariableName, Value: apiextensionsv1.JSON{Raw: []byte(`{ "addons": { - "k8sRegistrationAgent": { + "konnectorAgent": { "strategy": "ClusterResourceSet", "credentials": { "secretRef": {"name":"dummy-secret"} } } @@ -348,7 +348,7 @@ func TestApply_EmptyStrategy(t *testing.T) { Name: v1alpha1.ClusterConfigVariableName, Value: apiextensionsv1.JSON{Raw: []byte(`{ "addons": { - "k8sRegistrationAgent": { + "konnectorAgent": { "credentials": { "secretRef": {"name":"dummy-secret"} } } } @@ -389,7 +389,7 @@ func TestApply_UnknownStrategy(t *testing.T) { Name: v1alpha1.ClusterConfigVariableName, Value: apiextensionsv1.JSON{Raw: []byte(`{ "addons": { - "k8sRegistrationAgent": { + "konnectorAgent": { "strategy": "UnknownStrategy", "credentials": { "secretRef": {"name":"dummy-secret"} } } @@ -537,7 +537,7 @@ func TestApply_ClusterConfigVariableFailure(t *testing.T) { // Missing nutanix config, which will cause cluster config variable parsing to fail Value: apiextensionsv1.JSON{Raw: []byte(`{ "addons": { - "k8sRegistrationAgent": { + "konnectorAgent": { "strategy": "HelmAddon", "credentials": { "secretRef": {"name":"dummy-secret"} } } @@ -573,14 +573,14 @@ func TestApply_ClusterConfigVariableFailure(t *testing.T) { func TestApply_SuccessfulWithFullNutanixConfig(t *testing.T) { client := fake.NewClientBuilder().WithScheme(testScheme).Build() - cfg := NewControllerConfig(&options.GlobalOptions{}) + cfg := NewConfig(&options.GlobalOptions{}) - handler := &DefaultK8sRegistrationAgent{ + handler := &DefaultKonnectorAgent{ client: client, config: cfg, helmChartInfoGetter: &config.HelmChartGetter{}, variableName: v1alpha1.ClusterConfigVariableName, - variablePath: []string{"addons", v1alpha1.K8sRegistrationAgentVariableName}, + variablePath: []string{"addons", v1alpha1.KonnectorAgentVariableName}, } cluster := &clusterv1.Cluster{ @@ -597,7 +597,7 @@ func TestApply_SuccessfulWithFullNutanixConfig(t *testing.T) { } }, "addons": { - "k8sRegistrationAgent": { + "konnectorAgent": { "strategy": "HelmAddon", "credentials": { "secretRef": {"name":"dummy-secret"} } } From fb4018c456ad78f0b7477d3f03117672c47b9f32 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Tue, 14 Oct 2025 23:06:16 +0530 Subject: [PATCH 13/55] feat: variable name updates --- .../kustomize/k8s-registration-agent/kustomization.yaml.tmpl | 2 +- make/addons.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl index 69d50d188..d43c98834 100644 --- a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl @@ -13,6 +13,6 @@ helmCharts: #repo: https://mesosphere.github.io/charts/stable repo: http://192.168.1.21:8080 releaseName: konnector-agent - version: ${K8S_REGISTRATION_AGENT_VERSION} + version: ${KONNECTOR_AGENT_VERSION} includeCRDs: true skipTests: true diff --git a/make/addons.mk b/make/addons.mk index fccae4183..1ac18925f 100644 --- a/make/addons.mk +++ b/make/addons.mk @@ -26,7 +26,7 @@ export METALLB_CHART_VERSION := 0.15.2 export COSI_CONTROLLER_VERSION := 0.0.1-alpha.5 -export K8S_REGISTRATION_AGENT_VERSION := 1.3.0-rc.0 +export KONNECTOR_AGENT_VERSION := 1.3.0-rc.0 .PHONY: addons.sync addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler snapshot-controller local-path-provisioner-csi aws-ebs-csi kube-vip) From 07e6c4d312349a429216efab1abd0b607d8a211b Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Tue, 14 Oct 2025 23:21:38 +0530 Subject: [PATCH 14/55] feat: changin chart name --- hack/addons/helm-chart-bundler/repos.yaml | 4 ++-- .../kustomize/k8s-registration-agent/kustomization.yaml.tmpl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hack/addons/helm-chart-bundler/repos.yaml b/hack/addons/helm-chart-bundler/repos.yaml index 97b1607e0..1e68fa1eb 100644 --- a/hack/addons/helm-chart-bundler/repos.yaml +++ b/hack/addons/helm-chart-bundler/repos.yaml @@ -61,10 +61,10 @@ repositories: charts: nutanix-csi-storage: - 3.3.4 - nutanix-k8s-agent: + konnector-agent: repoURL: http://192.168.1.21:8080 charts: - nutanix-k8s-agent: + konnector-agent: - 1.3.0-rc.0 registry-syncer: repoURL: https://mesosphere.github.io/charts/staging/ diff --git a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl index d43c98834..28fa52f7b 100644 --- a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl @@ -8,7 +8,7 @@ metadata: name: konnector-agent-kustomize helmCharts: -- name: nutanix-k8s-agent +- name: konnector-agent namespace: kube-system #repo: https://mesosphere.github.io/charts/stable repo: http://192.168.1.21:8080 From 073f35010ff74f768a0a692a91a1b843282489ef Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Wed, 15 Oct 2025 11:00:29 +0530 Subject: [PATCH 15/55] feat: konnector agent name change --- .../templates/helm-config.yaml | 4 ++-- hack/addons/helm-chart-bundler/repos.yaml | 10 +++++----- .../kustomization.yaml.tmpl | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) rename hack/addons/kustomize/{k8s-registration-agent => konnector-agent}/kustomization.yaml.tmpl (92%) diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index 84fb306f5..74ea10087 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -32,9 +32,9 @@ data: ChartVersion: 0.0.1-alpha.5 RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://mesosphere.github.io/charts/stable/{{ end }}' konnector-agent: | - ChartName: nutanix-k8s-agent + ChartName: konnector-agent ChartVersion: 1.3.0-rc.0 - RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.21:8080{{ end }}' + RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://10.138.100.18:8080{{ end }}' local-path-provisioner-csi: | ChartName: local-path-provisioner ChartVersion: 0.0.31 diff --git a/hack/addons/helm-chart-bundler/repos.yaml b/hack/addons/helm-chart-bundler/repos.yaml index 1e68fa1eb..af5d34365 100644 --- a/hack/addons/helm-chart-bundler/repos.yaml +++ b/hack/addons/helm-chart-bundler/repos.yaml @@ -36,6 +36,11 @@ repositories: charts: docker-registry: - 2.3.5 + konnector-agent: + repoURL: http://10.138.100.18:8080 + charts: + konnector-agent: + - 1.3.0-rc.0 local-path-provisioner: repoURL: https://charts.containeroo.ch charts: @@ -61,11 +66,6 @@ repositories: charts: nutanix-csi-storage: - 3.3.4 - konnector-agent: - repoURL: http://192.168.1.21:8080 - charts: - konnector-agent: - - 1.3.0-rc.0 registry-syncer: repoURL: https://mesosphere.github.io/charts/staging/ charts: diff --git a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl similarity index 92% rename from hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl rename to hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl index 28fa52f7b..452a10599 100644 --- a/hack/addons/kustomize/k8s-registration-agent/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl @@ -11,7 +11,7 @@ helmCharts: - name: konnector-agent namespace: kube-system #repo: https://mesosphere.github.io/charts/stable - repo: http://192.168.1.21:8080 + repo: http://10.138.100.18:8080 releaseName: konnector-agent version: ${KONNECTOR_AGENT_VERSION} includeCRDs: true From 1147c4a7f2686ce8b9572ddd49578b2f00752247 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Wed, 15 Oct 2025 11:45:47 +0530 Subject: [PATCH 16/55] feat: updating konnector agent doc --- docs/content/addons/k8s-registration-agent.md | 30 --- docs/content/addons/konnector-agent.md | 194 ++++++++++++++++++ .../nutanix-cluster-calico-crs.yaml | 6 +- .../nutanix-cluster-calico-helm-addon.yaml | 6 +- .../nutanix-cluster-cilium-crs.yaml | 6 +- .../nutanix-cluster-cilium-helm-addon.yaml | 6 +- ...luster-with-failuredomains-cilium-crs.yaml | 6 +- ...with-failuredomains-cilium-helm-addon.yaml | 6 +- .../lifecycle/konnectoragent/handler.go | 94 ++++----- 9 files changed, 272 insertions(+), 82 deletions(-) delete mode 100644 docs/content/addons/k8s-registration-agent.md create mode 100644 docs/content/addons/konnector-agent.md diff --git a/docs/content/addons/k8s-registration-agent.md b/docs/content/addons/k8s-registration-agent.md deleted file mode 100644 index 2b729b7da..000000000 --- a/docs/content/addons/k8s-registration-agent.md +++ /dev/null @@ -1,30 +0,0 @@ -+++ -title = "Kubernetes cluster registration addon" -icon = "fa-solid fa-object-group" -+++ - -By leveraging CAPI cluster lifecycle hooks, this handler deploys [Kubernetes cluster registration agent] -on the new cluster at the `AfterControlPlaneInitialized` phase. - -The hook uses the [Cluster API Add-on Provider for Helm] to deploy the k8s-registration resources. - -## Example - -To enable deployment of kubernets registration agent on a cluster, specify the following values: - -```yaml -apiVersion: cluster.x-k8s.io/v1beta1 -kind: Cluster -metadata: - name: -spec: - topology: - variables: - - name: clusterConfig - value: - addons: - konnectorAgent: {} -``` - -[Kubernetes cluster registration agent]: https://github.com/nutanix-core/k8s-agent -[Cluster API Add-on Provider for Helm]: https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm diff --git a/docs/content/addons/konnector-agent.md b/docs/content/addons/konnector-agent.md new file mode 100644 index 000000000..7d1448c28 --- /dev/null +++ b/docs/content/addons/konnector-agent.md @@ -0,0 +1,194 @@ ++++ +title = "Konnector Agent Addon" +icon = "fa-solid fa-plug" ++++ + +The Konnector Agent addon enables automatic registration of Kubernetes clusters with Nutanix Prism Central. This addon leverages Cluster API lifecycle hooks to deploy the [Konnector Agent](https://github.com/nutanix-core/k8s-agent) on the new clusters. + +## Overview + +The Konnector Agent addon provides: +- **Automatic cluster registration** with Nutanix Prism Central +- **Lifecycle management** through Cluster API hooks +- **Credential management** for secure Prism Central connectivity + +## Lifecycle Hooks + +The addon implements the following Cluster API lifecycle hooks: + +### AfterControlPlaneInitialized +- **Purpose**: Deploys the Konnector Agent after the control plane is ready +- **Timing**: Executes when the cluster control plane is fully initialized +- **Actions**: + - Creates credentials secret on the target cluster + - Deploys the Konnector Agent using the specified strategy + - Configures Prism Central connectivity + +### BeforeClusterUpgrade +- **Purpose**: Ensures the agent is properly configured before cluster upgrades +- **Timing**: Executes before cluster upgrade operations +- **Actions**: Re-applies the agent configuration if needed + +### BeforeClusterDelete +- **Purpose**: Gracefully removes the Konnector Agent before cluster deletion +- **Timing**: Executes before cluster deletion begins +- **Actions**: + - Initiates graceful helm uninstall + - Waits for cleanup completion + - Ensures proper cleanup order + +## Configuration + +### Basic Configuration + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: my-cluster +spec: + topology: + variables: + - name: clusterConfig + value: + addons: + konnectorAgent: {} +``` + +### Advanced Configuration + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: my-cluster +spec: + topology: + variables: + - name: clusterConfig + value: + addons: + konnectorAgent: + strategy: HelmAddon + credentials: + secretRef: + name: prism-central-credentials-for-konnector-agent +``` + +## Configuration Reference + +### NutanixKonnectorAgent + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `strategy` | string | No | `HelmAddon` | Deployment strategy (`HelmAddon`) | +| `credentials` | object | No | - | Prism Central credentials configuration | + +### NutanixKonnectorAgentCredentials + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `secretRef.name` | string | Yes | Name of the Secret containing Prism Central credentials | + +## Prerequisites + +### 1. Prism Central Credentials Secret + +Create a secret containing Prism Central credentials: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: prism-central-credentials-for-konnector-agent + namespace: default +type: Opaque +stringData: + username: admin + password: password +``` + +## Examples + +### Minimal Configuration + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: minimal-cluster +spec: + topology: + variables: + - name: clusterConfig + value: + addons: + konnectorAgent: {} +``` + +### With Custom Credentials + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: custom-credentials-cluster +spec: + topology: + variables: + - name: clusterConfig + value: + addons: + konnectorAgent: + strategy: HelmAddon + credentials: + secretRef: + name: prism-central-credentials-for-konnector-agent +``` + +## Default Values + +The addon uses the following default values: + +- **Helm Release Name**: `konnector-agent` +- **Namespace**: `ntnx-system` +- **Agent Name**: `konnector-agent` +- **Strategy**: `HelmAddon` +- **Chart**: `konnector-agent` +- **Version**: `1.3.0-rc.0` + +## Troubleshooting + +### Common Issues + +1. **Missing Credentials Secret** + - Ensure the secret exists in the management cluster + - Verify the secret name matches the configuration + +2. **Prism Central Connectivity** + - Check network connectivity between the cluster and Prism Central + - Verify the Prism Central endpoint is correct + - Ensure credentials are valid + +3. **Helm Chart Issues** + - Check the Helm repository is accessible + - Verify the chart version exists + - Review HelmChartProxy status + +### Monitoring + +Monitor the Konnector Agent deployment: + +```bash +# Check HelmChartProxy status +kubectl get helmchartproxy -A + +# Check agent logs +kubectl logs hook-preinstall -n ntnx-system +``` + +## References + +- [Konnector Agent Repository](https://github.com/nutanix-core/k8s-agent) +- [Cluster API Add-on Provider for Helm](https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm) +- [Cluster API Runtime Hooks](https://cluster-api.sigs.k8s.io/tasks/experimental-features/runtime-sdk/hooks.html) diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 2dbe0cb50..768f1cd27 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -90,7 +90,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + strategy: HelmAddon + credentials: + secretRef: + name: prism-central-credentials-for-konnector-agent nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index f89e47547..37b48dada 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -88,7 +88,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + strategy: HelmAddon + credentials: + secretRef: + name: prism-central-credentials-for-konnector-agent nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index 6385e8eb0..f64375fa9 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -90,7 +90,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + strategy: HelmAddon + credentials: + secretRef: + name: prism-central-credentials-for-konnector-agent nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index f0707c9e4..071db5aee 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -88,7 +88,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + strategy: HelmAddon + credentials: + secretRef: + name: prism-central-credentials-for-konnector-agent nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index d0157f5eb..eb077f1f4 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -126,7 +126,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + strategy: HelmAddon + credentials: + secretRef: + name: prism-central-credentials-for-konnector-agent nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index f5044c87b..9cfacf7b1 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -124,7 +124,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + strategy: HelmAddon + credentials: + secretRef: + name: prism-central-credentials-for-konnector-agent nfd: {} serviceLoadBalancer: configuration: diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index 7887d72ec..69226e965 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -39,6 +39,10 @@ const ( defaultHelmReleaseNamespace = "ntnx-system" defaultK8sAgentName = "konnector-agent" defaultCredentialsSecretName = defaultK8sAgentName + + cleanupStatusCompleted = "completed" + cleanupStatusInProgress = "in-progress" + cleanupStatusNotStarted = "not-started" ) type Config struct { @@ -166,45 +170,43 @@ func (n *DefaultKonnectorAgent) apply( // It's possible to have the credentials Secret be created by the Helm chart. // However, that would leave the credentials visible in the HelmChartProxy. // Instead, we'll create the Secret on the remote cluster and reference it in the Helm values. - if k8sAgentVar.Credentials != nil { - err := handlersutils.EnsureClusterOwnerReferenceForObject( - ctx, - n.client, - corev1.TypedLocalObjectReference{ - Kind: "Secret", - Name: k8sAgentVar.Credentials.SecretRef.Name, - }, - cluster, + err = handlersutils.EnsureClusterOwnerReferenceForObject( + ctx, + n.client, + corev1.TypedLocalObjectReference{ + Kind: "Secret", + Name: k8sAgentVar.Credentials.SecretRef.Name, + }, + cluster, + ) + if err != nil { + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("error updating owner references on Nutanix k8s agent source Secret: %v", + err, + ), ) - if err != nil { - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage( - fmt.Sprintf("error updating owner references on Nutanix k8s agent source Secret: %v", - err, - ), - ) - return - } - key := ctrlclient.ObjectKey{ - Name: defaultCredentialsSecretName, - Namespace: defaultHelmReleaseNamespace, - } - err = handlersutils.CopySecretToRemoteCluster( - ctx, - n.client, - k8sAgentVar.Credentials.SecretRef.Name, - key, - cluster, + return + } + key := ctrlclient.ObjectKey{ + Name: defaultCredentialsSecretName, + Namespace: defaultHelmReleaseNamespace, + } + err = handlersutils.CopySecretToRemoteCluster( + ctx, + n.client, + k8sAgentVar.Credentials.SecretRef.Name, + key, + cluster, + ) + if err != nil { + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("error creating Nutanix k8s agent Credentials Secret on the remote cluster: %v", + err, + ), ) - if err != nil { - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage( - fmt.Sprintf("error creating Nutanix k8s agent Credentials Secret on the remote cluster: %v", - err, - ), - ) - return - } + return } var strategy addons.Applier @@ -369,16 +371,16 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( } switch cleanupStatus { - case "completed": + case cleanupStatusCompleted: log.Info("K8s Registration Agent cleanup already completed") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) return - case "in-progress": + case cleanupStatusInProgress: log.Info("K8s Registration Agent cleanup in progress, requesting retry") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) resp.SetRetryAfterSeconds(10) // Retry after 10 seconds return - case "not-started": + case cleanupStatusNotStarted: log.Info("Starting K8s Registration Agent cleanup") // Proceed with cleanup below } @@ -488,8 +490,8 @@ func (n *DefaultKonnectorAgent) deleteHelmChart( return nil } -// checkCleanupStatus checks the current status of K8s Registration Agent cleanup -// Returns: "completed", "in-progress", or "not-started" +// checkCleanupStatus checks the current status of K8s Registration Agent cleanup. +// Returns: "completed", "in-progress", or "not-started". func (n *DefaultKonnectorAgent) checkCleanupStatus( ctx context.Context, cluster *clusterv1.Cluster, @@ -497,7 +499,7 @@ func (n *DefaultKonnectorAgent) checkCleanupStatus( ) (string, error) { clusterUUID, ok := cluster.Annotations[v1alpha1.ClusterUUIDAnnotationKey] if !ok { - return "completed", nil // If no UUID, assume no agent was installed + return cleanupStatusCompleted, nil // If no UUID, assume no agent was installed } // Check if HelmChartProxy exists @@ -512,7 +514,7 @@ func (n *DefaultKonnectorAgent) checkCleanupStatus( if err != nil { if apierrors.IsNotFound(err) { log.Info("HelmChartProxy not found, cleanup completed", "name", hcp.Name) - return "completed", nil + return cleanupStatusCompleted, nil } return "", fmt.Errorf("failed to get HelmChartProxy %q: %w", ctrlclient.ObjectKeyFromObject(hcp), err) } @@ -520,12 +522,12 @@ func (n *DefaultKonnectorAgent) checkCleanupStatus( // HCP exists - check if it's being deleted if hcp.DeletionTimestamp != nil { log.Info("HelmChartProxy is being deleted, cleanup in progress", "name", hcp.Name) - return "in-progress", nil + return cleanupStatusInProgress, nil } // HCP exists and is not being deleted log.Info("HelmChartProxy exists, cleanup not started", "name", hcp.Name) - return "not-started", nil + return cleanupStatusNotStarted, nil } // waitForHelmUninstallCompletion waits for CAAPH to complete the helm uninstall process From 3724a821f061d2c491e80d8a5a9d5f02f05f0cf0 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Wed, 15 Oct 2025 17:16:47 +0530 Subject: [PATCH 17/55] feat: updating values template --- .../addons/konnector-agent/values-template.yaml | 4 +++- .../templates/helm-config.yaml | 2 +- hack/addons/helm-chart-bundler/repos.yaml | 2 +- hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml b/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml index 99889d734..59cc44417 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml @@ -1,6 +1,8 @@ agent: name: {{ .AgentName}} - + image: + repository: quay.io/karbon + name: k8s-agent pc: port: {{ .PrismCentralPort }} insecure: {{ .PrismCentralInsecure }} #set this to true if PC does not have https enabled diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index 74ea10087..e0d37bcfa 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -34,7 +34,7 @@ data: konnector-agent: | ChartName: konnector-agent ChartVersion: 1.3.0-rc.0 - RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://10.138.100.18:8080{{ end }}' + RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.7:8080{{ end }}' local-path-provisioner-csi: | ChartName: local-path-provisioner ChartVersion: 0.0.31 diff --git a/hack/addons/helm-chart-bundler/repos.yaml b/hack/addons/helm-chart-bundler/repos.yaml index af5d34365..3d0480ca3 100644 --- a/hack/addons/helm-chart-bundler/repos.yaml +++ b/hack/addons/helm-chart-bundler/repos.yaml @@ -37,7 +37,7 @@ repositories: docker-registry: - 2.3.5 konnector-agent: - repoURL: http://10.138.100.18:8080 + repoURL: http://192.168.1.7:8080 charts: konnector-agent: - 1.3.0-rc.0 diff --git a/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl index 452a10599..38aea2be4 100644 --- a/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl @@ -11,7 +11,7 @@ helmCharts: - name: konnector-agent namespace: kube-system #repo: https://mesosphere.github.io/charts/stable - repo: http://10.138.100.18:8080 + repo: http://192.168.1.7:8080 releaseName: konnector-agent version: ${KONNECTOR_AGENT_VERSION} includeCRDs: true From 812b844c3132a967659b2111d79a90c62584c5c4 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 16 Oct 2025 13:58:41 +0530 Subject: [PATCH 18/55] feat: precommit fix --- docs/content/addons/konnector-agent.md | 8 ++++++-- examples/capi-quick-start/nutanix-cluster-calico-crs.yaml | 6 +----- .../nutanix-cluster-calico-helm-addon.yaml | 6 +----- examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml | 6 +----- .../nutanix-cluster-cilium-helm-addon.yaml | 6 +----- .../nutanix-cluster-with-failuredomains-cilium-crs.yaml | 6 +----- ...nix-cluster-with-failuredomains-cilium-helm-addon.yaml | 6 +----- pkg/handlers/lifecycle/konnectoragent/variables_test.go | 2 +- 8 files changed, 13 insertions(+), 33 deletions(-) diff --git a/docs/content/addons/konnector-agent.md b/docs/content/addons/konnector-agent.md index 7d1448c28..eb5ede64b 100644 --- a/docs/content/addons/konnector-agent.md +++ b/docs/content/addons/konnector-agent.md @@ -8,6 +8,7 @@ The Konnector Agent addon enables automatic registration of Kubernetes clusters ## Overview The Konnector Agent addon provides: + - **Automatic cluster registration** with Nutanix Prism Central - **Lifecycle management** through Cluster API hooks - **Credential management** for secure Prism Central connectivity @@ -17,19 +18,22 @@ The Konnector Agent addon provides: The addon implements the following Cluster API lifecycle hooks: ### AfterControlPlaneInitialized + - **Purpose**: Deploys the Konnector Agent after the control plane is ready - **Timing**: Executes when the cluster control plane is fully initialized -- **Actions**: +- **Actions**: - Creates credentials secret on the target cluster - Deploys the Konnector Agent using the specified strategy - Configures Prism Central connectivity ### BeforeClusterUpgrade + - **Purpose**: Ensures the agent is properly configured before cluster upgrades - **Timing**: Executes before cluster upgrade operations - **Actions**: Re-applies the agent configuration if needed ### BeforeClusterDelete + - **Purpose**: Gracefully removes the Konnector Agent before cluster deletion - **Timing**: Executes before cluster deletion begins - **Actions**: @@ -184,7 +188,7 @@ Monitor the Konnector Agent deployment: kubectl get helmchartproxy -A # Check agent logs -kubectl logs hook-preinstall -n ntnx-system +kubectl logs hook-preinstall -n ntnx-system ``` ## References diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 768f1cd27..2dbe0cb50 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -90,11 +90,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - strategy: HelmAddon - credentials: - secretRef: - name: prism-central-credentials-for-konnector-agent + konnectorAgent: {} nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index 37b48dada..f89e47547 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -88,11 +88,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - strategy: HelmAddon - credentials: - secretRef: - name: prism-central-credentials-for-konnector-agent + konnectorAgent: {} nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index f64375fa9..6385e8eb0 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -90,11 +90,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - strategy: HelmAddon - credentials: - secretRef: - name: prism-central-credentials-for-konnector-agent + konnectorAgent: {} nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 071db5aee..f0707c9e4 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -88,11 +88,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - strategy: HelmAddon - credentials: - secretRef: - name: prism-central-credentials-for-konnector-agent + konnectorAgent: {} nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index eb077f1f4..d0157f5eb 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -126,11 +126,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - strategy: HelmAddon - credentials: - secretRef: - name: prism-central-credentials-for-konnector-agent + konnectorAgent: {} nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index 9cfacf7b1..f5044c87b 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -124,11 +124,7 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - strategy: HelmAddon - credentials: - secretRef: - name: prism-central-credentials-for-konnector-agent + konnectorAgent: {} nfd: {} serviceLoadBalancer: configuration: diff --git a/pkg/handlers/lifecycle/konnectoragent/variables_test.go b/pkg/handlers/lifecycle/konnectoragent/variables_test.go index 32b044753..2be462d97 100644 --- a/pkg/handlers/lifecycle/konnectoragent/variables_test.go +++ b/pkg/handlers/lifecycle/konnectoragent/variables_test.go @@ -469,7 +469,7 @@ clusterName: {{ .ClusterName }} result, err := templateFunc(cluster, valuesTemplate) require.NoError(t, err) - assert.Contains(t, result, "agentName: nutanix-agent") + assert.Contains(t, result, "agentName: konnector-agent") assert.Contains(t, result, "prismCentralHost: prism-central.example.com") assert.Contains(t, result, "prismCentralPort: 9440") assert.Contains(t, result, "prismCentralInsecure: true") From 0a9d85d2919e91ae0217a8e7fe560f301474b21d Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 16 Oct 2025 14:08:00 +0530 Subject: [PATCH 19/55] feat: Apply suggestions from code review Co-authored-by: Manoj Surudwad --- api/v1alpha1/addon_types.go | 2 +- docs/content/addons/konnector-agent.md | 4 ++-- .../kustomize/konnector-agent/kustomization.yaml.tmpl | 2 +- pkg/handlers/lifecycle/konnectoragent/doc.go | 2 +- pkg/handlers/lifecycle/konnectoragent/handler.go | 7 ++----- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 6b30c2157..5846e1703 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -371,7 +371,7 @@ type NutanixKonnectorAgent struct { // Addon strategy used to deploy the Nutanix konnector-agent to the k8s cluster. // +kubebuilder:default=HelmAddon // +kubebuilder:validation:Optional - // +kubebuilder:validation:Enum=ClusterResourceSet;HelmAddon + // +kubebuilder:validation:Enum=HelmAddon Strategy AddonStrategy `json:"strategy,omitzero"` } diff --git a/docs/content/addons/konnector-agent.md b/docs/content/addons/konnector-agent.md index eb5ede64b..37d9f23c0 100644 --- a/docs/content/addons/konnector-agent.md +++ b/docs/content/addons/konnector-agent.md @@ -7,7 +7,7 @@ The Konnector Agent addon enables automatic registration of Kubernetes clusters ## Overview -The Konnector Agent addon provides: +Konnector Agent's addon management via CAREN(Cluster API Runtime Extensions - Nutanix) provides: - **Automatic cluster registration** with Nutanix Prism Central - **Lifecycle management** through Cluster API hooks @@ -193,6 +193,6 @@ kubectl logs hook-preinstall -n ntnx-system ## References -- [Konnector Agent Repository](https://github.com/nutanix-core/k8s-agent) +- [Konnector Agent ](https://portal.nutanix.com/page/documents/details?targetId=Prism-Central-Guide-vpc_7_3:mul-cluster-kubernetes-clusters-manage-pc-c.html) - [Cluster API Add-on Provider for Helm](https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm) - [Cluster API Runtime Hooks](https://cluster-api.sigs.k8s.io/tasks/experimental-features/runtime-sdk/hooks.html) diff --git a/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl index 38aea2be4..b1ded64a5 100644 --- a/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl @@ -9,7 +9,7 @@ metadata: helmCharts: - name: konnector-agent - namespace: kube-system + namespace: ntnx-system #repo: https://mesosphere.github.io/charts/stable repo: http://192.168.1.7:8080 releaseName: konnector-agent diff --git a/pkg/handlers/lifecycle/konnectoragent/doc.go b/pkg/handlers/lifecycle/konnectoragent/doc.go index 05c8b4d3c..7de3fe15a 100644 --- a/pkg/handlers/lifecycle/konnectoragent/doc.go +++ b/pkg/handlers/lifecycle/konnectoragent/doc.go @@ -3,6 +3,6 @@ // Package konnector-agent provides a handler for managing k8s agent deployments on clusters // -// +kubebuilder:rbac:groups=addons.cluster.x-k8s.io,resources=clusterresourcesets,verbs=watch;list;get;create;patch;update;delete +// +kubebuilder:rbac:groups=addons.cluster.x-k8s.io,resources=helmchartproxies,verbs=watch;list;get;create;patch;update;delete // +kubebuilder:rbac:groups="",resources=configmaps,verbs=watch;list;get;create;patch;update;delete package konnectoragent diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index 69226e965..0b287f07a 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -398,9 +398,6 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) resp.SetRetryAfterSeconds(5) // Quick retry to start monitoring - case v1alpha1.AddonStrategyClusterResourceSet: - log.Info("ClusterResourceSet strategy does not require cleanup") - resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) case "": log.Info("No strategy specified, skipping cleanup") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) @@ -413,7 +410,7 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( } } -func (n *DefaultKonnectorAgent) deleteHelmChart( +func (n *DefaultKonnectorAgent) deleteHelmChartProxy( ctx context.Context, cluster *clusterv1.Cluster, log logr.Logger, @@ -442,7 +439,7 @@ func (n *DefaultKonnectorAgent) deleteHelmChart( err := n.client.Get(ctx, ctrlclient.ObjectKeyFromObject(hcp), currentHCP) if err != nil { if ctrlclient.IgnoreNotFound(err) == nil { - log.Info("K8s Registration Agent HelmChartProxy already deleted", "name", hcp.Name) + log.Info("Konnector Agent HelmChartProxy is not present on cluster", "name", hcp.Name) return nil } return fmt.Errorf("failed to get HelmChartProxy %q: %w", ctrlclient.ObjectKeyFromObject(hcp), err) From ef92b3e24a9a6ff5eca3e668d41cf40b63a4e909 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 16 Oct 2025 18:19:21 +0530 Subject: [PATCH 20/55] feat: pre commit fixes --- ...ren.nutanix.com_nutanixclusterconfigs.yaml | 1 - .../nutanix-cluster-calico-crs.yaml | 6 ++- .../nutanix-cluster-calico-helm-addon.yaml | 6 ++- .../nutanix-cluster-cilium-crs.yaml | 6 ++- .../nutanix-cluster-cilium-helm-addon.yaml | 6 ++- ...luster-with-failuredomains-cilium-crs.yaml | 6 ++- ...with-failuredomains-cilium-helm-addon.yaml | 6 ++- .../patches/nutanix/konnector-agent.yaml | 6 ++- .../lifecycle/konnectoragent/handler.go | 42 +++++++++---------- 9 files changed, 56 insertions(+), 29 deletions(-) diff --git a/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml b/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml index 9d0ff6248..2b163b90c 100644 --- a/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml +++ b/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml @@ -260,7 +260,6 @@ spec: default: HelmAddon description: Addon strategy used to deploy the Nutanix konnector-agent to the k8s cluster. enum: - - ClusterResourceSet - HelmAddon type: string type: object diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 2dbe0cb50..2becc6e62 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -90,7 +90,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent + strategy: HelmAddon nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index f89e47547..1fdcf9df7 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -88,7 +88,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent + strategy: HelmAddon nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index 6385e8eb0..0572a10a4 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -90,7 +90,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent + strategy: HelmAddon nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index f0707c9e4..a9055e47f 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -88,7 +88,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent + strategy: HelmAddon nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index d0157f5eb..2f08baba8 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -126,7 +126,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent + strategy: HelmAddon nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index f5044c87b..72aae164f 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -124,7 +124,11 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: {} + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent + strategy: HelmAddon nfd: {} serviceLoadBalancer: configuration: diff --git a/hack/examples/patches/nutanix/konnector-agent.yaml b/hack/examples/patches/nutanix/konnector-agent.yaml index c85413205..eb7fddb09 100644 --- a/hack/examples/patches/nutanix/konnector-agent.yaml +++ b/hack/examples/patches/nutanix/konnector-agent.yaml @@ -3,4 +3,8 @@ - op: "add" path: "/spec/topology/variables/0/value/addons/konnectorAgent" - value: {} + value: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent + strategy: HelmAddon diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index 0b287f07a..769806dd2 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -142,18 +142,18 @@ func (n *DefaultKonnectorAgent) apply( if variables.IsNotFoundError(err) { log. Info( - "Skipping K8s Registration Agent handler," + - "cluster does not specify request K8s Registration Agent addon deployment", + "Skipping Konnector Agent handler," + + "cluster does not specify request Konnector Agent addon deployment", ) return } log.Error( err, - "failed to read K8s Registration Agent variable from cluster definition", + "failed to read Konnector Agent variable from cluster definition", ) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage( - fmt.Sprintf("failed to read K8s Registration agent variable from cluster definition: %v", + fmt.Sprintf("failed to read Konnector Agent variable from cluster definition: %v", err, ), ) @@ -250,19 +250,19 @@ func (n *DefaultKonnectorAgent) apply( ).WithValueTemplater(templateValuesFunc(clusterConfigVar.Nutanix, cluster)) case "": resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage("strategy not provided for K8s Registration Agent") + resp.SetMessage("strategy not provided for Konnector Agent") return default: resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage( - fmt.Sprintf("unknown K8s registration agent addon deployment strategy %q", k8sAgentVar.Strategy), + fmt.Sprintf("unknown Konnector Agent addon deployment strategy %q", k8sAgentVar.Strategy), ) return } if err := strategy.Apply(ctx, cluster, n.config.DefaultsNamespace(), log); err != nil { log.Error(err, "Helm strategy Apply failed") - err = fmt.Errorf("failed to apply K8s Registration Agent addon: %w", err) + err = fmt.Errorf("failed to apply Konnector Agent addon: %w", err) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage(err.Error()) return @@ -340,18 +340,18 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( if err != nil { if variables.IsNotFoundError(err) { log.Info( - "Skipping K8s Registration Agent cleanup, addon not specified in cluster definition", + "Skipping Konnector Agent cleanup, addon not specified in cluster definition", ) resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) return } log.Error( err, - "failed to read K8s Registration Agent variable from cluster definition", + "failed to read Konnector Agent variable from cluster definition", ) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage( - fmt.Sprintf("failed to read K8s Registration Agent variable from cluster definition: %v", + fmt.Sprintf("failed to read Konnector Agent variable from cluster definition: %v", err, ), ) @@ -372,20 +372,20 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( switch cleanupStatus { case cleanupStatusCompleted: - log.Info("K8s Registration Agent cleanup already completed") + log.Info("Konnector Agent cleanup already completed") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) return case cleanupStatusInProgress: - log.Info("K8s Registration Agent cleanup in progress, requesting retry") + log.Info("Konnector Agent cleanup in progress, requesting retry") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) resp.SetRetryAfterSeconds(10) // Retry after 10 seconds return case cleanupStatusNotStarted: - log.Info("Starting K8s Registration Agent cleanup") + log.Info("Starting Konnector Agent cleanup") // Proceed with cleanup below } - err = n.deleteHelmChart(ctx, cluster, log) + err = n.deleteHelmChartProxy(ctx, cluster, log) if err != nil { log.Error(err, "Failed to delete helm chart") resp.SetStatus(runtimehooksv1.ResponseStatusFailure) @@ -394,7 +394,7 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( } // After initiating cleanup, request a retry to monitor completion - log.Info("K8s Registration Agent cleanup initiated, will monitor progress") + log.Info("Konnector Agent cleanup initiated, will monitor progress") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) resp.SetRetryAfterSeconds(5) // Quick retry to start monitoring @@ -403,7 +403,7 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) default: log.Info( - "Unknown K8s Registration Agent strategy, skipping cleanup", + "Unknown Konnector Agent strategy, skipping cleanup", "strategy", k8sAgentVar.Strategy, ) resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) @@ -432,7 +432,7 @@ func (n *DefaultKonnectorAgent) deleteHelmChartProxy( } // First, try to gracefully trigger helm uninstall while cluster is still accessible - log.Info("Initiating graceful deletion of K8s Registration Agent", "name", hcp.Name, "namespace", hcp.Namespace) + log.Info("Initiating graceful deletion of Konnector Agent", "name", hcp.Name, "namespace", hcp.Namespace) // Get the current HCP to check if it exists and get its current state currentHCP := &caaphv1.HelmChartProxy{} @@ -459,14 +459,14 @@ func (n *DefaultKonnectorAgent) deleteHelmChartProxy( } // Now delete the HelmChartProxy - CAAPH will handle the helm uninstall - log.Info("Deleting K8s Registration Agent HelmChartProxy", "name", hcp.Name, "namespace", hcp.Namespace) + log.Info("Deleting Konnector Agent HelmChartProxy", "name", hcp.Name, "namespace", hcp.Namespace) if err := n.client.Delete(ctx, currentHCP); err != nil { if ctrlclient.IgnoreNotFound(err) == nil { - log.Info("K8s Registration Agent HelmChartProxy already deleted", "name", hcp.Name) + log.Info("Konnector Agent HelmChartProxy already deleted", "name", hcp.Name) return nil } return fmt.Errorf( - "failed to delete K8s Registration Agent HelmChartProxy %q: %w", + "failed to delete Konnector Agent HelmChartProxy %q: %w", ctrlclient.ObjectKeyFromObject(hcp), err, ) @@ -487,7 +487,7 @@ func (n *DefaultKonnectorAgent) deleteHelmChartProxy( return nil } -// checkCleanupStatus checks the current status of K8s Registration Agent cleanup. +// checkCleanupStatus checks the current status of Konnector Agent cleanup. // Returns: "completed", "in-progress", or "not-started". func (n *DefaultKonnectorAgent) checkCleanupStatus( ctx context.Context, From 4ba15945ac0cd2f402972f26050cf5eab3d2d5b4 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 16 Oct 2025 18:54:46 +0530 Subject: [PATCH 21/55] feat: Unit test fixes --- docs/content/addons/konnector-agent.md | 48 +++---------------- .../konnectoragent/variables_test.go | 2 +- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/docs/content/addons/konnector-agent.md b/docs/content/addons/konnector-agent.md index 37d9f23c0..3e68de7e0 100644 --- a/docs/content/addons/konnector-agent.md +++ b/docs/content/addons/konnector-agent.md @@ -3,7 +3,7 @@ title = "Konnector Agent Addon" icon = "fa-solid fa-plug" +++ -The Konnector Agent addon enables automatic registration of Kubernetes clusters with Nutanix Prism Central. This addon leverages Cluster API lifecycle hooks to deploy the [Konnector Agent](https://github.com/nutanix-core/k8s-agent) on the new clusters. +The Konnector Agent addon enables automatic registration of Kubernetes clusters with Nutanix Prism Central. This addon leverages Cluster API lifecycle hooks to deploy the [Konnector Agent](https://portal.nutanix.com/page/documents/details?targetId=Prism-Central-Guide-vpc_7_3:mul-cluster-kubernetes-clusters-manage-pc-c.html) on the new clusters. ## Overview @@ -43,24 +43,6 @@ The addon implements the following Cluster API lifecycle hooks: ## Configuration -### Basic Configuration - -```yaml -apiVersion: cluster.x-k8s.io/v1beta1 -kind: Cluster -metadata: - name: my-cluster -spec: - topology: - variables: - - name: clusterConfig - value: - addons: - konnectorAgent: {} -``` - -### Advanced Configuration - ```yaml apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster @@ -76,7 +58,7 @@ spec: strategy: HelmAddon credentials: secretRef: - name: prism-central-credentials-for-konnector-agent + name: cluster-name-pc-credentials-for-konnector-agent ``` ## Configuration Reference @@ -104,7 +86,7 @@ Create a secret containing Prism Central credentials: apiVersion: v1 kind: Secret metadata: - name: prism-central-credentials-for-konnector-agent + name: cluster-name-pc-credentials-for-konnector-agent namespace: default type: Opaque stringData: @@ -114,23 +96,7 @@ stringData: ## Examples -### Minimal Configuration - -```yaml -apiVersion: cluster.x-k8s.io/v1beta1 -kind: Cluster -metadata: - name: minimal-cluster -spec: - topology: - variables: - - name: clusterConfig - value: - addons: - konnectorAgent: {} -``` - -### With Custom Credentials +### Configuration ```yaml apiVersion: cluster.x-k8s.io/v1beta1 @@ -147,7 +113,7 @@ spec: strategy: HelmAddon credentials: secretRef: - name: prism-central-credentials-for-konnector-agent + name: cluster-name-pc-credentials-for-konnector-agent ``` ## Default Values @@ -185,7 +151,7 @@ Monitor the Konnector Agent deployment: ```bash # Check HelmChartProxy status -kubectl get helmchartproxy -A +kubectl get hcp -A # Check agent logs kubectl logs hook-preinstall -n ntnx-system @@ -193,6 +159,6 @@ kubectl logs hook-preinstall -n ntnx-system ## References -- [Konnector Agent ](https://portal.nutanix.com/page/documents/details?targetId=Prism-Central-Guide-vpc_7_3:mul-cluster-kubernetes-clusters-manage-pc-c.html) +- [Konnector Agent](https://portal.nutanix.com/page/documents/details?targetId=Prism-Central-Guide-vpc_7_3:mul-cluster-kubernetes-clusters-manage-pc-c.html) - [Cluster API Add-on Provider for Helm](https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm) - [Cluster API Runtime Hooks](https://cluster-api.sigs.k8s.io/tasks/experimental-features/runtime-sdk/hooks.html) diff --git a/pkg/handlers/lifecycle/konnectoragent/variables_test.go b/pkg/handlers/lifecycle/konnectoragent/variables_test.go index 2be462d97..86838b105 100644 --- a/pkg/handlers/lifecycle/konnectoragent/variables_test.go +++ b/pkg/handlers/lifecycle/konnectoragent/variables_test.go @@ -439,7 +439,7 @@ func TestApply_InvalidVariableJSON(t *testing.T) { handler.apply(context.Background(), cluster, resp) assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) - assert.Contains(t, resp.Message, "failed to read K8s Registration agent variable from cluster definition") + assert.Contains(t, resp.Message, "failed to read Konnector Agent variable from cluster definition") } // Test template values function From 48747d21b6fb0184e3ebe6a13bb7334c5ad16a06 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 16 Oct 2025 22:55:57 +0530 Subject: [PATCH 22/55] feat: updating konnector doc format --- docs/content/addons/konnector-agent.md | 4 +--- pkg/handlers/lifecycle/konnectoragent/handler.go | 15 +-------------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/docs/content/addons/konnector-agent.md b/docs/content/addons/konnector-agent.md index 3e68de7e0..949554b3b 100644 --- a/docs/content/addons/konnector-agent.md +++ b/docs/content/addons/konnector-agent.md @@ -94,9 +94,7 @@ stringData: password: password ``` -## Examples - -### Configuration +### Example Configuration ```yaml apiVersion: cluster.x-k8s.io/v1beta1 diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index 769806dd2..dea417ffa 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -378,7 +378,7 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( case cleanupStatusInProgress: log.Info("Konnector Agent cleanup in progress, requesting retry") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) - resp.SetRetryAfterSeconds(10) // Retry after 10 seconds + resp.SetRetryAfterSeconds(5) // Retry after 5 seconds return case cleanupStatusNotStarted: log.Info("Starting Konnector Agent cleanup") @@ -445,19 +445,6 @@ func (n *DefaultKonnectorAgent) deleteHelmChartProxy( return fmt.Errorf("failed to get HelmChartProxy %q: %w", ctrlclient.ObjectKeyFromObject(hcp), err) } - // Add a deletion timestamp annotation to help CAAPH prioritize this deletion - // and set a shorter timeout to fail fast if cluster becomes unreachable - if currentHCP.Annotations == nil { - currentHCP.Annotations = make(map[string]string) - } - currentHCP.Annotations["cluster.x-k8s.io/delete-priority"] = "high" - currentHCP.Annotations["cluster.x-k8s.io/delete-timeout"] = "60s" - - // Update the HCP with priority annotations before deletion - if err := n.client.Update(ctx, currentHCP); err != nil { - log.Info("Failed to update HCP annotations, proceeding with deletion", "error", err) - } - // Now delete the HelmChartProxy - CAAPH will handle the helm uninstall log.Info("Deleting Konnector Agent HelmChartProxy", "name", hcp.Name, "namespace", hcp.Namespace) if err := n.client.Delete(ctx, currentHCP); err != nil { From 715952baa8882998bf1911b128b61782c46f519c Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 17 Oct 2025 12:05:22 +0530 Subject: [PATCH 23/55] feat: updating chart repo url --- .../templates/helm-config.yaml | 2 +- common/pkg/server/server.go | 13 ++++++++++--- hack/addons/helm-chart-bundler/repos.yaml | 2 +- .../konnector-agent/kustomization.yaml.tmpl | 3 +-- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index e0d37bcfa..992789a74 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -34,7 +34,7 @@ data: konnector-agent: | ChartName: konnector-agent ChartVersion: 1.3.0-rc.0 - RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}http://192.168.1.7:8080{{ end }}' + RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://mesosphere.github.io/charts/stable/{{ end }}' local-path-provisioner-csi: | ChartName: local-path-provisioner ChartVersion: 0.0.31 diff --git a/common/pkg/server/server.go b/common/pkg/server/server.go index db2b551a7..bef7ca34d 100644 --- a/common/pkg/server/server.go +++ b/common/pkg/server/server.go @@ -126,9 +126,10 @@ func (s *Server) Start(ctx context.Context) error { if t, ok := h.(lifecycle.BeforeClusterDelete); ok { if err := webhookServer.AddExtensionHandler(runtimeserver.ExtensionHandler{ - Hook: runtimehooksv1.BeforeClusterDelete, - Name: strings.ToLower(h.Name()) + "-bcd", - HandlerFunc: t.BeforeClusterDelete, + Hook: runtimehooksv1.BeforeClusterDelete, + Name: strings.ToLower(h.Name()) + "-bcd", + HandlerFunc: t.BeforeClusterDelete, + TimeoutSeconds: intToInt32Ptr(30), // 30 seconds timeout }); err != nil { setupLog.Error(err, "error adding handler") return err @@ -178,3 +179,9 @@ func (s *Server) Start(ctx context.Context) error { return nil } + +// intToInt32Ptr converts an int to *int32 for use with TimeoutSeconds +func intToInt32Ptr(value int) *int32 { + t := int32(value) + return &t +} diff --git a/hack/addons/helm-chart-bundler/repos.yaml b/hack/addons/helm-chart-bundler/repos.yaml index 3d0480ca3..d47f657da 100644 --- a/hack/addons/helm-chart-bundler/repos.yaml +++ b/hack/addons/helm-chart-bundler/repos.yaml @@ -37,7 +37,7 @@ repositories: docker-registry: - 2.3.5 konnector-agent: - repoURL: http://192.168.1.7:8080 + repoURL: https://mesosphere.github.io/charts/stable/ charts: konnector-agent: - 1.3.0-rc.0 diff --git a/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl b/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl index b1ded64a5..4d08e85a1 100644 --- a/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/konnector-agent/kustomization.yaml.tmpl @@ -10,8 +10,7 @@ metadata: helmCharts: - name: konnector-agent namespace: ntnx-system - #repo: https://mesosphere.github.io/charts/stable - repo: http://192.168.1.7:8080 + repo: https://mesosphere.github.io/charts/stable releaseName: konnector-agent version: ${KONNECTOR_AGENT_VERSION} includeCRDs: true From dfe85ae8494940d9f9f5d5f60d61d1271ca9fc9a Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 17 Oct 2025 13:47:58 +0530 Subject: [PATCH 24/55] feat: precommit fixes --- .../templates/helm-config.yaml | 2 +- common/pkg/server/server.go | 2 +- hack/addons/helm-chart-bundler/repos.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index 992789a74..9b9853e3f 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -34,7 +34,7 @@ data: konnector-agent: | ChartName: konnector-agent ChartVersion: 1.3.0-rc.0 - RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://mesosphere.github.io/charts/stable/{{ end }}' + RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://mesosphere.github.io/charts/stable{{ end }}' local-path-provisioner-csi: | ChartName: local-path-provisioner ChartVersion: 0.0.31 diff --git a/common/pkg/server/server.go b/common/pkg/server/server.go index bef7ca34d..eb52fe082 100644 --- a/common/pkg/server/server.go +++ b/common/pkg/server/server.go @@ -180,7 +180,7 @@ func (s *Server) Start(ctx context.Context) error { return nil } -// intToInt32Ptr converts an int to *int32 for use with TimeoutSeconds +// intToInt32Ptr converts an int to *int32 for use with TimeoutSeconds. func intToInt32Ptr(value int) *int32 { t := int32(value) return &t diff --git a/hack/addons/helm-chart-bundler/repos.yaml b/hack/addons/helm-chart-bundler/repos.yaml index d47f657da..ef2dd7e98 100644 --- a/hack/addons/helm-chart-bundler/repos.yaml +++ b/hack/addons/helm-chart-bundler/repos.yaml @@ -37,7 +37,7 @@ repositories: docker-registry: - 2.3.5 konnector-agent: - repoURL: https://mesosphere.github.io/charts/stable/ + repoURL: https://mesosphere.github.io/charts/stable charts: konnector-agent: - 1.3.0-rc.0 From 0458c64bb6292c05296fa26567346727f5e4c61c Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 17 Oct 2025 14:25:58 +0530 Subject: [PATCH 25/55] feat: precommit fix --- common/pkg/server/server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/common/pkg/server/server.go b/common/pkg/server/server.go index eb52fe082..ae7e7e552 100644 --- a/common/pkg/server/server.go +++ b/common/pkg/server/server.go @@ -181,6 +181,7 @@ func (s *Server) Start(ctx context.Context) error { } // intToInt32Ptr converts an int to *int32 for use with TimeoutSeconds. +// #nosec G115 -- TimeoutSeconds is always within int32 safe range. func intToInt32Ptr(value int) *int32 { t := int32(value) return &t From f175449536d111c9ddf1a5014855177004b8d4cc Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Sat, 18 Oct 2025 00:13:35 +0530 Subject: [PATCH 26/55] feat: updating wait logic --- .../konnector-agent/values-template.yaml | 1 + .../lifecycle/konnectoragent/handler.go | 21 +++---------------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml b/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml index 59cc44417..ba3dbbebd 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml @@ -3,6 +3,7 @@ agent: image: repository: quay.io/karbon name: k8s-agent + tag: "1.3.0-rc.1" pc: port: {{ .PrismCentralPort }} insecure: {{ .PrismCentralInsecure }} #set this to true if PC does not have https enabled diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index dea417ffa..5bb85f837 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -522,8 +522,8 @@ func (n *DefaultKonnectorAgent) waitForHelmUninstallCompletion( log logr.Logger, ) error { // Create a context with timeout to avoid blocking cluster deletion indefinitely - // 90 seconds should be enough for most helm uninstalls while still being reasonable - waitCtx, cancel := context.WithTimeout(ctx, 90*time.Second) + // 30 seconds should be enough for most helm uninstalls while still being reasonable + waitCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() log.Info("Monitoring HelmChartProxy deletion progress", "name", hcp.Name) @@ -532,7 +532,7 @@ func (n *DefaultKonnectorAgent) waitForHelmUninstallCompletion( // This indicates CAAPH has acknowledged the deletion request err := wait.PollUntilContextTimeout( waitCtx, - 2*time.Second, + 3*time.Second, 30*time.Second, true, func(pollCtx context.Context) (bool, error) { @@ -567,20 +567,5 @@ func (n *DefaultKonnectorAgent) waitForHelmUninstallCompletion( return fmt.Errorf("error waiting for HelmChartProxy deletion: %w", err) } - // Additional wait to give CAAPH more time to complete the helm uninstall - // even after the HCP is deleted. This accounts for any cleanup operations. - log.Info("HelmChartProxy deleted, allowing additional time for helm uninstall completion") - - // Use a shorter additional wait to not delay cluster deletion too much - additionalWaitCtx, additionalCancel := context.WithTimeout(ctx, 30*time.Second) - defer additionalCancel() - - select { - case <-additionalWaitCtx.Done(): - log.Info("Additional wait period completed, proceeding with cluster deletion") - case <-time.After(10 * time.Second): - log.Info("Reasonable wait time elapsed, proceeding with cluster deletion") - } - return nil } From f79c5a0bfcec3e2bac2b00064765e484eb85d799 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 23 Oct 2025 19:06:10 +0530 Subject: [PATCH 27/55] feat: upgrading konnector agent version --- .../addons/konnector-agent/values-template.yaml | 1 - .../templates/helm-config.yaml | 2 +- docs/content/addons/konnector-agent.md | 2 +- hack/addons/helm-chart-bundler/repos.yaml | 2 +- make/addons.mk | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml b/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml index ba3dbbebd..59cc44417 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml @@ -3,7 +3,6 @@ agent: image: repository: quay.io/karbon name: k8s-agent - tag: "1.3.0-rc.1" pc: port: {{ .PrismCentralPort }} insecure: {{ .PrismCentralInsecure }} #set this to true if PC does not have https enabled diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index 9b9853e3f..b895522be 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -33,7 +33,7 @@ data: RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://mesosphere.github.io/charts/stable/{{ end }}' konnector-agent: | ChartName: konnector-agent - ChartVersion: 1.3.0-rc.0 + ChartVersion: 1.3.0-rc.1 RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://mesosphere.github.io/charts/stable{{ end }}' local-path-provisioner-csi: | ChartName: local-path-provisioner diff --git a/docs/content/addons/konnector-agent.md b/docs/content/addons/konnector-agent.md index 949554b3b..c657c3a41 100644 --- a/docs/content/addons/konnector-agent.md +++ b/docs/content/addons/konnector-agent.md @@ -123,7 +123,7 @@ The addon uses the following default values: - **Agent Name**: `konnector-agent` - **Strategy**: `HelmAddon` - **Chart**: `konnector-agent` -- **Version**: `1.3.0-rc.0` +- **Version**: `1.3.0-rc.1` ## Troubleshooting diff --git a/hack/addons/helm-chart-bundler/repos.yaml b/hack/addons/helm-chart-bundler/repos.yaml index ef2dd7e98..a54c7335f 100644 --- a/hack/addons/helm-chart-bundler/repos.yaml +++ b/hack/addons/helm-chart-bundler/repos.yaml @@ -40,7 +40,7 @@ repositories: repoURL: https://mesosphere.github.io/charts/stable charts: konnector-agent: - - 1.3.0-rc.0 + - 1.3.0-rc.1 local-path-provisioner: repoURL: https://charts.containeroo.ch charts: diff --git a/make/addons.mk b/make/addons.mk index 1ac18925f..995d2e09c 100644 --- a/make/addons.mk +++ b/make/addons.mk @@ -26,7 +26,7 @@ export METALLB_CHART_VERSION := 0.15.2 export COSI_CONTROLLER_VERSION := 0.0.1-alpha.5 -export KONNECTOR_AGENT_VERSION := 1.3.0-rc.0 +export KONNECTOR_AGENT_VERSION := 1.3.0-rc.1 .PHONY: addons.sync addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler snapshot-controller local-path-provisioner-csi aws-ebs-csi kube-vip) From cac45702f31cf465cd3f6b16fa775dbcb98c907f Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 23 Oct 2025 22:53:55 +0530 Subject: [PATCH 28/55] feat: formatting --- api/v1alpha1/addon_types.go | 2 +- api/variables/aggregate_types.go | 4 ++-- pkg/handlers/lifecycle/config/cm.go | 2 +- pkg/handlers/lifecycle/handlers.go | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index ac3f4ce36..3c1746810 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -390,5 +390,5 @@ type NutanixKonnectorAgent struct { type NutanixKonnectorAgentCredentials struct { // A reference to the Secret containing the credentials used by the Konnector agent. // +kubebuilder:validation:Required - SecretRef LocalObjectReference `json:"secretRef" + SecretRef LocalObjectReference `json:"secretRef"` } diff --git a/api/variables/aggregate_types.go b/api/variables/aggregate_types.go index 97996fb44..a08621e4f 100644 --- a/api/variables/aggregate_types.go +++ b/api/variables/aggregate_types.go @@ -66,8 +66,8 @@ type Addons struct { CSI *CSI `json:"csi,omitempty"` COSI *COSI `json:"cosi,omitempty"` - - Ingress *Ingress `json:"ingress,omitempty"` + + Ingress *Ingress `json:"ingress,omitempty"` NutanixKonnectorAgent *NutanixKonnectorAgent `json:"konnectorAgent,omitempty"` } diff --git a/pkg/handlers/lifecycle/config/cm.go b/pkg/handlers/lifecycle/config/cm.go index 6572b1bdf..67dcbd4f9 100644 --- a/pkg/handlers/lifecycle/config/cm.go +++ b/pkg/handlers/lifecycle/config/cm.go @@ -32,7 +32,7 @@ const ( COSIController Component = "cosi-controller" CNCFDistributionRegistry Component = "cncf-distribution-registry" RegistrySyncer Component = "registry-syncer" - KonnectorAgent Component = "konnector-agent" + KonnectorAgent Component = "konnector-agent" ) type HelmChartGetter struct { diff --git a/pkg/handlers/lifecycle/handlers.go b/pkg/handlers/lifecycle/handlers.go index 42d0bf3cf..947fae63c 100644 --- a/pkg/handlers/lifecycle/handlers.go +++ b/pkg/handlers/lifecycle/handlers.go @@ -24,8 +24,8 @@ import ( "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/localpath" nutanixcsi "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/nutanix" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/csi/snapshotcontroller" - konnectoragent "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/konnectoragent" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/ingress/awsloadbalancercontroller" + konnectoragent "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/konnectoragent" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/nfd" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/registry" "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/registry/cncfdistribution" @@ -50,7 +50,7 @@ type Handlers struct { snapshotControllerConfig *snapshotcontroller.Config cosiControllerConfig *cosi.ControllerConfig awsLoadBalancerControllerConfig *awsloadbalancercontroller.ControllerConfig - konnectorAgentConfig *konnectoragent.Config + konnectorAgentConfig *konnectoragent.Config distributionConfig *cncfdistribution.Config } @@ -74,7 +74,7 @@ func New( localPathCSIConfig: localpath.NewConfig(globalOptions), snapshotControllerConfig: snapshotcontroller.NewConfig(globalOptions), cosiControllerConfig: cosi.NewControllerConfig(globalOptions), - konnectorAgentConfig: konnectoragent.NewConfig(globalOptions), + konnectorAgentConfig: konnectoragent.NewConfig(globalOptions), distributionConfig: &cncfdistribution.Config{GlobalOptions: globalOptions}, } } From 2291df3c0583c5353194a3a00e52ca1ed0c055f4 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 23 Oct 2025 23:41:48 +0530 Subject: [PATCH 29/55] feat: pre-commit fix --- .../cluster-api-runtime-extensions-nutanix/values.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.schema.json b/charts/cluster-api-runtime-extensions-nutanix/values.schema.json index ed9f2fea9..3c517b6fb 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.schema.json +++ b/charts/cluster-api-runtime-extensions-nutanix/values.schema.json @@ -540,7 +540,7 @@ } } } - }, + }, "nfd": { "type": "object", "properties": { From 486228ae7ca06599471b94609c8f36cd15b5883c Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 23 Oct 2025 23:53:29 +0530 Subject: [PATCH 30/55] feat: pre-commit --- .../addons/konnector-agent/values-template.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml b/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml index 59cc44417..259eee7de 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/addons/konnector-agent/values-template.yaml @@ -1,5 +1,5 @@ agent: - name: {{ .AgentName}} + name: {{ .AgentName }} image: repository: quay.io/karbon name: k8s-agent From f13740b4bf77a9bb8aa76821633c6792bf8578f0 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 24 Oct 2025 11:28:47 +0530 Subject: [PATCH 31/55] feat: Update api/v1alpha1/addon_types.go Co-authored-by: Dimitri Koshkin --- api/v1alpha1/addon_types.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 3c1746810..950997ad0 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -380,11 +380,6 @@ type NutanixKonnectorAgent struct { // +kubebuilder:validation:Optional Credentials *NutanixKonnectorAgentCredentials `json:"credentials,omitempty"` - // Addon strategy used to deploy the Nutanix konnector-agent to the k8s cluster. - // +kubebuilder:default=HelmAddon - // +kubebuilder:validation:Optional - // +kubebuilder:validation:Enum=HelmAddon - Strategy AddonStrategy `json:"strategy,omitzero"` } type NutanixKonnectorAgentCredentials struct { From fc1e937636f657aa5ee244540784b7072c906098 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 24 Oct 2025 12:38:09 +0530 Subject: [PATCH 32/55] feat: removing addon strategy --- api/v1alpha1/addon_types.go | 1 - ...ren.nutanix.com_nutanixclusterconfigs.yaml | 6 - .../nutanix-cluster-calico-crs.yaml | 1 - .../nutanix-cluster-calico-helm-addon.yaml | 1 - .../nutanix-cluster-cilium-crs.yaml | 1 - .../nutanix-cluster-cilium-helm-addon.yaml | 1 - ...luster-with-failuredomains-cilium-crs.yaml | 1 - ...with-failuredomains-cilium-helm-addon.yaml | 1 - .../patches/nutanix/konnector-agent.yaml | 1 - .../lifecycle/konnectoragent/handler.go | 149 +++++++----------- .../konnectoragent/variables_test.go | 133 +--------------- 11 files changed, 62 insertions(+), 234 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 950997ad0..afbd8bdf2 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -379,7 +379,6 @@ type NutanixKonnectorAgent struct { // A reference to the Secret for credential information for the target Prism Central instance // +kubebuilder:validation:Optional Credentials *NutanixKonnectorAgentCredentials `json:"credentials,omitempty"` - } type NutanixKonnectorAgentCredentials struct { diff --git a/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml b/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml index 2b163b90c..560b56e93 100644 --- a/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml +++ b/api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml @@ -256,12 +256,6 @@ spec: required: - secretRef type: object - strategy: - default: HelmAddon - description: Addon strategy used to deploy the Nutanix konnector-agent to the k8s cluster. - enum: - - HelmAddon - type: string type: object nfd: description: NFD tells us to enable or disable the node feature discovery addon. diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 2becc6e62..3fb92c30f 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -94,7 +94,6 @@ spec: credentials: secretRef: name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent - strategy: HelmAddon nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index 1fdcf9df7..84f70a8ac 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -92,7 +92,6 @@ spec: credentials: secretRef: name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent - strategy: HelmAddon nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index 0572a10a4..e7c6775ed 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -94,7 +94,6 @@ spec: credentials: secretRef: name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent - strategy: HelmAddon nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index a9055e47f..05744f8db 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -92,7 +92,6 @@ spec: credentials: secretRef: name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent - strategy: HelmAddon nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index 2f08baba8..a31c041b0 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -130,7 +130,6 @@ spec: credentials: secretRef: name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent - strategy: HelmAddon nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index 72aae164f..e1ed82ae0 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -128,7 +128,6 @@ spec: credentials: secretRef: name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent - strategy: HelmAddon nfd: {} serviceLoadBalancer: configuration: diff --git a/hack/examples/patches/nutanix/konnector-agent.yaml b/hack/examples/patches/nutanix/konnector-agent.yaml index eb7fddb09..35db223dc 100644 --- a/hack/examples/patches/nutanix/konnector-agent.yaml +++ b/hack/examples/patches/nutanix/konnector-agent.yaml @@ -7,4 +7,3 @@ credentials: secretRef: name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent - strategy: HelmAddon diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index 5bb85f837..8332cfcc3 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -210,55 +210,42 @@ func (n *DefaultKonnectorAgent) apply( } var strategy addons.Applier - switch k8sAgentVar.Strategy { - case v1alpha1.AddonStrategyHelmAddon: - helmChart, err := n.helmChartInfoGetter.For(ctx, log, config.KonnectorAgent) - if err != nil { - log.Error( - err, - "failed to get configmap with helm settings", - ) - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage( - fmt.Sprintf("failed to get configuration to create helm addon: %v", - err, - ), - ) - return - } - clusterConfigVar, err := variables.Get[apivariables.ClusterConfigSpec]( - varMap, - v1alpha1.ClusterConfigVariableName, + helmChart, err := n.helmChartInfoGetter.For(ctx, log, config.KonnectorAgent) + if err != nil { + log.Error( + err, + "failed to get configmap with helm settings", ) - if err != nil { - log.Error( - err, - "failed to read clusterConfig variable from cluster definition", - ) - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage( - fmt.Sprintf("failed to read clusterConfig variable from cluster definition: %v", - err, - ), - ) - return - } - strategy = addons.NewHelmAddonApplier( - n.config.helmAddonConfig, - n.client, - helmChart, - ).WithValueTemplater(templateValuesFunc(clusterConfigVar.Nutanix, cluster)) - case "": resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage("strategy not provided for Konnector Agent") + resp.SetMessage( + fmt.Sprintf("failed to get configuration to create helm addon: %v", + err, + ), + ) return - default: + } + clusterConfigVar, err := variables.Get[apivariables.ClusterConfigSpec]( + varMap, + v1alpha1.ClusterConfigVariableName, + ) + if err != nil { + log.Error( + err, + "failed to read clusterConfig variable from cluster definition", + ) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage( - fmt.Sprintf("unknown Konnector Agent addon deployment strategy %q", k8sAgentVar.Strategy), + fmt.Sprintf("failed to read clusterConfig variable from cluster definition: %v", + err, + ), ) return } + strategy = addons.NewHelmAddonApplier( + n.config.helmAddonConfig, + n.client, + helmChart, + ).WithValueTemplater(templateValuesFunc(clusterConfigVar.Nutanix, cluster)) if err := strategy.Apply(ctx, cluster, n.config.DefaultsNamespace(), log); err != nil { log.Error(err, "Helm strategy Apply failed") @@ -333,7 +320,7 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( ) varMap := variables.ClusterVariablesToVariablesMap(cluster.Spec.Topology.Variables) - k8sAgentVar, err := variables.Get[apivariables.NutanixKonnectorAgent]( + _, err := variables.Get[apivariables.NutanixKonnectorAgent]( varMap, n.variableName, n.variablePath...) @@ -358,56 +345,42 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( return } - // Only handle HelmAddon strategy for cleanup - switch k8sAgentVar.Strategy { - case v1alpha1.AddonStrategyHelmAddon: - // Check if cleanup is already in progress or completed - cleanupStatus, err := n.checkCleanupStatus(ctx, cluster, log) - if err != nil { - log.Error(err, "Failed to check cleanup status") - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage(err.Error()) - return - } - - switch cleanupStatus { - case cleanupStatusCompleted: - log.Info("Konnector Agent cleanup already completed") - resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) - return - case cleanupStatusInProgress: - log.Info("Konnector Agent cleanup in progress, requesting retry") - resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) - resp.SetRetryAfterSeconds(5) // Retry after 5 seconds - return - case cleanupStatusNotStarted: - log.Info("Starting Konnector Agent cleanup") - // Proceed with cleanup below - } - - err = n.deleteHelmChartProxy(ctx, cluster, log) - if err != nil { - log.Error(err, "Failed to delete helm chart") - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage(err.Error()) - return - } - - // After initiating cleanup, request a retry to monitor completion - log.Info("Konnector Agent cleanup initiated, will monitor progress") - resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) - resp.SetRetryAfterSeconds(5) // Quick retry to start monitoring + // Check if cleanup is already in progress or completed + cleanupStatus, err := n.checkCleanupStatus(ctx, cluster, log) + if err != nil { + log.Error(err, "Failed to check cleanup status") + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage(err.Error()) + return + } - case "": - log.Info("No strategy specified, skipping cleanup") + switch cleanupStatus { + case cleanupStatusCompleted: + log.Info("Konnector Agent cleanup already completed") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) - default: - log.Info( - "Unknown Konnector Agent strategy, skipping cleanup", - "strategy", k8sAgentVar.Strategy, - ) + return + case cleanupStatusInProgress: + log.Info("Konnector Agent cleanup in progress, requesting retry") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + resp.SetRetryAfterSeconds(5) // Retry after 5 seconds + return + case cleanupStatusNotStarted: + log.Info("Starting Konnector Agent cleanup") + // Proceed with cleanup below } + + err = n.deleteHelmChartProxy(ctx, cluster, log) + if err != nil { + log.Error(err, "Failed to delete helm chart") + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage(err.Error()) + return + } + + // After initiating cleanup, request a retry to monitor completion + log.Info("Konnector Agent cleanup initiated, will monitor progress") + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + resp.SetRetryAfterSeconds(5) // Quick retry to start monitoring } func (n *DefaultKonnectorAgent) deleteHelmChartProxy( diff --git a/pkg/handlers/lifecycle/konnectoragent/variables_test.go b/pkg/handlers/lifecycle/konnectoragent/variables_test.go index 86838b105..f51bff7cb 100644 --- a/pkg/handlers/lifecycle/konnectoragent/variables_test.go +++ b/pkg/handlers/lifecycle/konnectoragent/variables_test.go @@ -73,7 +73,7 @@ func TestApply_FailsWhenCredentialsMissing(t *testing.T) { Variables: []clusterv1.ClusterVariable{{ Name: v1alpha1.ClusterConfigVariableName, Value: apiextensionsv1.JSON{ - Raw: []byte(`{"addons":{"konnectorAgent":{"strategy":"HelmAddon"}}}`), + Raw: []byte(`{"addons":{"konnectorAgent":{}}}`), }, }}, }, @@ -98,7 +98,6 @@ func TestApply_FailsWhenCopySecretFails(t *testing.T) { Value: apiextensionsv1.JSON{Raw: []byte(`{ "addons": { "konnectorAgent": { - "strategy": "HelmAddon", "credentials": { "secretRef": {"name":"missing-secret"} } } } @@ -132,7 +131,6 @@ func TestApply_SuccessfulHelmStrategy(t *testing.T) { }, "addons": { "konnectorAgent": { - "strategy": "HelmAddon", "credentials": { "secretRef": {"name":"dummy-secret"} } } } @@ -175,7 +173,6 @@ func TestApply_HelmApplyFails(t *testing.T) { Value: apiextensionsv1.JSON{Raw: []byte(`{ "addons": { "konnectorAgent": { - "strategy": "HelmAddon", "credentials": { "secretRef": {"name":"dummy-secret"} } } } @@ -295,132 +292,6 @@ func TestBeforeClusterUpgrade(t *testing.T) { assert.NotEqual(t, runtimehooksv1.ResponseStatusFailure, resp.Status) } -// Test different strategy scenarios -func TestApply_ClusterResourceSetStrategy(t *testing.T) { - handler := newTestHandler(t) - cluster := &clusterv1.Cluster{ - ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, - Spec: clusterv1.ClusterSpec{ - Topology: &clusterv1.Topology{ - Variables: []clusterv1.ClusterVariable{{ - Name: v1alpha1.ClusterConfigVariableName, - Value: apiextensionsv1.JSON{Raw: []byte(`{ - "addons": { - "konnectorAgent": { - "strategy": "ClusterResourceSet", - "credentials": { "secretRef": {"name":"dummy-secret"} } - } - } - }`)}, - }}, - }, - }, - } - - // Create dummy secret - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dummy-secret", - Namespace: "default", - }, - Data: map[string][]byte{ - "username": []byte("user"), - "password": []byte("pass"), - }, - } - require.NoError(t, handler.client.Create(context.Background(), secret)) - - resp := &runtimehooksv1.CommonResponse{} - handler.apply(context.Background(), cluster, resp) - - assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) - // The test may fail at different points depending on infrastructure, but should fail - assert.NotEqual(t, "", resp.Message, "error message should be set") -} - -func TestApply_EmptyStrategy(t *testing.T) { - handler := newTestHandler(t) - cluster := &clusterv1.Cluster{ - ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, - Spec: clusterv1.ClusterSpec{ - Topology: &clusterv1.Topology{ - Variables: []clusterv1.ClusterVariable{{ - Name: v1alpha1.ClusterConfigVariableName, - Value: apiextensionsv1.JSON{Raw: []byte(`{ - "addons": { - "konnectorAgent": { - "credentials": { "secretRef": {"name":"dummy-secret"} } - } - } - }`)}, - }}, - }, - }, - } - - // Create dummy secret - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dummy-secret", - Namespace: "default", - }, - Data: map[string][]byte{ - "username": []byte("user"), - "password": []byte("pass"), - }, - } - require.NoError(t, handler.client.Create(context.Background(), secret)) - - resp := &runtimehooksv1.CommonResponse{} - handler.apply(context.Background(), cluster, resp) - - assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) - // The test may fail at different points depending on infrastructure, but should fail - assert.NotEqual(t, "", resp.Message, "error message should be set") -} - -func TestApply_UnknownStrategy(t *testing.T) { - handler := newTestHandler(t) - cluster := &clusterv1.Cluster{ - ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "default"}, - Spec: clusterv1.ClusterSpec{ - Topology: &clusterv1.Topology{ - Variables: []clusterv1.ClusterVariable{{ - Name: v1alpha1.ClusterConfigVariableName, - Value: apiextensionsv1.JSON{Raw: []byte(`{ - "addons": { - "konnectorAgent": { - "strategy": "UnknownStrategy", - "credentials": { "secretRef": {"name":"dummy-secret"} } - } - } - }`)}, - }}, - }, - }, - } - - // Create dummy secret - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dummy-secret", - Namespace: "default", - }, - Data: map[string][]byte{ - "username": []byte("user"), - "password": []byte("pass"), - }, - } - require.NoError(t, handler.client.Create(context.Background(), secret)) - - resp := &runtimehooksv1.CommonResponse{} - handler.apply(context.Background(), cluster, resp) - - assert.Equal(t, runtimehooksv1.ResponseStatusFailure, resp.Status) - // The test may fail at different points depending on infrastructure, but should fail - assert.NotEqual(t, "", resp.Message, "error message should be set") -} - func TestApply_InvalidVariableJSON(t *testing.T) { handler := newTestHandler(t) cluster := &clusterv1.Cluster{ @@ -538,7 +409,6 @@ func TestApply_ClusterConfigVariableFailure(t *testing.T) { Value: apiextensionsv1.JSON{Raw: []byte(`{ "addons": { "konnectorAgent": { - "strategy": "HelmAddon", "credentials": { "secretRef": {"name":"dummy-secret"} } } } @@ -598,7 +468,6 @@ func TestApply_SuccessfulWithFullNutanixConfig(t *testing.T) { }, "addons": { "konnectorAgent": { - "strategy": "HelmAddon", "credentials": { "secretRef": {"name":"dummy-secret"} } } } From cdb678b38fc6e25a322f109d51e890bba9ffdc84 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 24 Oct 2025 14:32:08 +0530 Subject: [PATCH 33/55] feat: updating fetch imges file for konnector agent --- hack/tools/fetch-images/main.go | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/hack/tools/fetch-images/main.go b/hack/tools/fetch-images/main.go index b4c87ff9f..c55cbf55d 100644 --- a/hack/tools/fetch-images/main.go +++ b/hack/tools/fetch-images/main.go @@ -370,7 +370,32 @@ prismEndPoint: endpoint case "cosi-controller": return filepath.Join(carenChartDirectory, "addons", "cosi", "controller", defaultHelmAddonFilename), nil case "konnector-agent": - return filepath.Join(carenChartDirectory, "addons", "konnector-agent", defaultHelmAddonFilename), nil + f := filepath.Join(carenChartDirectory, "addons", "konnector-agent", defaultHelmAddonFilename) + tempFile, err := os.CreateTemp("", "") + if err != nil { + return "", fmt.Errorf("failed to create temp file: %w", err) + } + + templateInput := struct { + AgentName string + PrismCentralHost string + PrismCentralPort uint16 + PrismCentralInsecure bool + ClusterName string + }{ + AgentName: "konnector-agent", + PrismCentralHost: "prism-central.example.com", + PrismCentralPort: 9440, + PrismCentralInsecure: true, + ClusterName: "test-cluster", + } + + err = template.Must(template.New(defaultHelmAddonFilename).ParseFiles(f)).Execute(tempFile, &templateInput) + if err != nil { + return "", fmt.Errorf("failed to execute helm values template %w", err) + } + + return tempFile.Name(), nil case "metallb": return filepath.Join( carenChartDirectory, From f80421b1ae5e2ee8ddf3c31f2df2111756b97056 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Mon, 27 Oct 2025 21:00:10 +0530 Subject: [PATCH 34/55] feat: updating helm uninstallation timeouts --- pkg/handlers/lifecycle/konnectoragent/handler.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index 8332cfcc3..ee1fc4c1d 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -496,7 +496,7 @@ func (n *DefaultKonnectorAgent) waitForHelmUninstallCompletion( ) error { // Create a context with timeout to avoid blocking cluster deletion indefinitely // 30 seconds should be enough for most helm uninstalls while still being reasonable - waitCtx, cancel := context.WithTimeout(ctx, 30*time.Second) + waitCtx, cancel := context.WithTimeout(ctx, 25*time.Second) defer cancel() log.Info("Monitoring HelmChartProxy deletion progress", "name", hcp.Name) @@ -506,7 +506,7 @@ func (n *DefaultKonnectorAgent) waitForHelmUninstallCompletion( err := wait.PollUntilContextTimeout( waitCtx, 3*time.Second, - 30*time.Second, + 22*time.Second, true, func(pollCtx context.Context) (bool, error) { currentHCP := &caaphv1.HelmChartProxy{} From 44af7d9b19bd47da8d776cd9844f7b91a2005419 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Wed, 29 Oct 2025 12:06:47 +0530 Subject: [PATCH 35/55] feat: updating timout configs --- common/pkg/server/server.go | 7 +- .../lifecycle/konnectoragent/handler.go | 74 +------------------ 2 files changed, 5 insertions(+), 76 deletions(-) diff --git a/common/pkg/server/server.go b/common/pkg/server/server.go index ae7e7e552..a54efc0a7 100644 --- a/common/pkg/server/server.go +++ b/common/pkg/server/server.go @@ -126,10 +126,9 @@ func (s *Server) Start(ctx context.Context) error { if t, ok := h.(lifecycle.BeforeClusterDelete); ok { if err := webhookServer.AddExtensionHandler(runtimeserver.ExtensionHandler{ - Hook: runtimehooksv1.BeforeClusterDelete, - Name: strings.ToLower(h.Name()) + "-bcd", - HandlerFunc: t.BeforeClusterDelete, - TimeoutSeconds: intToInt32Ptr(30), // 30 seconds timeout + Hook: runtimehooksv1.BeforeClusterDelete, + Name: strings.ToLower(h.Name()) + "-bcd", + HandlerFunc: t.BeforeClusterDelete, }); err != nil { setupLog.Error(err, "error adding handler") return err diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index ee1fc4c1d..f41fa59f9 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -9,14 +9,12 @@ import ( "fmt" "strings" "text/template" - "time" "github.com/go-logr/logr" "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" ctrl "sigs.k8s.io/controller-runtime" @@ -361,7 +359,7 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( return case cleanupStatusInProgress: log.Info("Konnector Agent cleanup in progress, requesting retry") - resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetRetryAfterSeconds(5) // Retry after 5 seconds return case cleanupStatusNotStarted: @@ -379,7 +377,7 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( // After initiating cleanup, request a retry to monitor completion log.Info("Konnector Agent cleanup initiated, will monitor progress") - resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetRetryAfterSeconds(5) // Quick retry to start monitoring } @@ -432,18 +430,6 @@ func (n *DefaultKonnectorAgent) deleteHelmChartProxy( ) } - // Wait for CAAPH to complete the helm uninstall before allowing cluster deletion to proceed - // This ensures graceful deletion order - helm uninstall completes before infrastructure teardown - log.Info("Waiting for helm uninstall to complete before proceeding with cluster deletion", "name", hcp.Name) - - if err := n.waitForHelmUninstallCompletion(ctx, hcp, log); err != nil { - log.Error(err, "Helm uninstall did not complete gracefully, proceeding with cluster deletion", "name", hcp.Name) - // Don't return error here - we want cluster deletion to proceed even if helm uninstall times out - // The important thing is we gave it a reasonable chance to complete - } else { - log.Info("Helm uninstall completed successfully", "name", hcp.Name) - } - return nil } @@ -486,59 +472,3 @@ func (n *DefaultKonnectorAgent) checkCleanupStatus( log.Info("HelmChartProxy exists, cleanup not started", "name", hcp.Name) return cleanupStatusNotStarted, nil } - -// waitForHelmUninstallCompletion waits for CAAPH to complete the helm uninstall process -// before allowing cluster deletion to proceed. This ensures graceful deletion order. -func (n *DefaultKonnectorAgent) waitForHelmUninstallCompletion( - ctx context.Context, - hcp *caaphv1.HelmChartProxy, - log logr.Logger, -) error { - // Create a context with timeout to avoid blocking cluster deletion indefinitely - // 30 seconds should be enough for most helm uninstalls while still being reasonable - waitCtx, cancel := context.WithTimeout(ctx, 25*time.Second) - defer cancel() - - log.Info("Monitoring HelmChartProxy deletion progress", "name", hcp.Name) - - // First wait for the HelmChartProxy to be fully processed for deletion - // This indicates CAAPH has acknowledged the deletion request - err := wait.PollUntilContextTimeout( - waitCtx, - 3*time.Second, - 22*time.Second, - true, - func(pollCtx context.Context) (bool, error) { - currentHCP := &caaphv1.HelmChartProxy{} - err := n.client.Get(pollCtx, ctrlclient.ObjectKeyFromObject(hcp), currentHCP) - if err != nil { - if apierrors.IsNotFound(err) { - log.Info("HelmChartProxy has been deleted", "name", hcp.Name) - return true, nil - } - // If we can't reach the API server, the cluster might be shutting down - // In this case, we should not block cluster deletion - log.Info("Error checking HelmChartProxy status, cluster may be shutting down", "error", err) - return true, nil - } - - // Check if the HCP is in deletion phase - if currentHCP.DeletionTimestamp != nil { - log.Info("HelmChartProxy is being deleted, waiting for completion", "name", hcp.Name) - return false, nil - } - - // If HCP still exists without deletion timestamp, something might be wrong - log.Info("HelmChartProxy still exists, waiting for deletion to start", "name", hcp.Name) - return false, nil - }, - ) - if err != nil { - if wait.Interrupted(err) { - return fmt.Errorf("timeout waiting for HelmChartProxy deletion to complete") - } - return fmt.Errorf("error waiting for HelmChartProxy deletion: %w", err) - } - - return nil -} From 44dcc33dcf4790f01e2cfbfe2bd4e69c1a06d9b6 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Wed, 29 Oct 2025 12:46:54 +0530 Subject: [PATCH 36/55] feat: removing intToInt32Ptr from server.go --- common/pkg/server/server.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/common/pkg/server/server.go b/common/pkg/server/server.go index a54efc0a7..db2b551a7 100644 --- a/common/pkg/server/server.go +++ b/common/pkg/server/server.go @@ -178,10 +178,3 @@ func (s *Server) Start(ctx context.Context) error { return nil } - -// intToInt32Ptr converts an int to *int32 for use with TimeoutSeconds. -// #nosec G115 -- TimeoutSeconds is always within int32 safe range. -func intToInt32Ptr(value int) *int32 { - t := int32(value) - return &t -} From cd590c69847c1c1d5e9b194a2b1f6a7ba8b21a74 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Wed, 29 Oct 2025 19:03:28 +0530 Subject: [PATCH 37/55] feat: fixing timeout issues during helm uninstallation --- .../lifecycle/konnectoragent/handler.go | 87 ++++++++++++++++--- 1 file changed, 75 insertions(+), 12 deletions(-) diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index f41fa59f9..6bb4230ba 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -9,6 +9,7 @@ import ( "fmt" "strings" "text/template" + "time" "github.com/go-logr/logr" "github.com/spf13/pflag" @@ -41,6 +42,11 @@ const ( cleanupStatusCompleted = "completed" cleanupStatusInProgress = "in-progress" cleanupStatusNotStarted = "not-started" + cleanupStatusTimedOut = "timed-out" + + // helmUninstallTimeout is the maximum time to wait for HelmChartProxy deletion + // before giving up and allowing cluster deletion to proceed + helmUninstallTimeout = 5 * time.Minute ) type Config struct { @@ -344,7 +350,7 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( } // Check if cleanup is already in progress or completed - cleanupStatus, err := n.checkCleanupStatus(ctx, cluster, log) + cleanupStatus, statusMsg, err := n.checkCleanupStatus(ctx, cluster, log) if err != nil { log.Error(err, "Failed to check cleanup status") resp.SetStatus(runtimehooksv1.ResponseStatusFailure) @@ -357,10 +363,32 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( log.Info("Konnector Agent cleanup already completed") resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) return + case cleanupStatusTimedOut: + // Log the error prominently and block cluster deletion + log.Error( + fmt.Errorf("konnector Agent helm uninstallation timed out"), + "ERROR: Konnector Agent cleanup timed out - blocking cluster deletion", + "details", statusMsg, + "action", "Manual intervention required - check HelmChartProxy status and remove finalizers if needed", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage(fmt.Sprintf( + "Konnector Agent helm uninstallation timed out after %v. "+ + "The HelmChartProxy is stuck in deletion state. "+ + "Manual intervention required: Check HelmChartProxy status and remove finalizers if needed. "+ + "Details: %s", + helmUninstallTimeout, + statusMsg, + )) + return case cleanupStatusInProgress: - log.Info("Konnector Agent cleanup in progress, requesting retry") + log.Info("Konnector Agent cleanup in progress, requesting retry", "details", statusMsg) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetRetryAfterSeconds(5) // Retry after 5 seconds + resp.SetMessage(fmt.Sprintf( + "Konnector Agent cleanup in progress. Waiting for HelmChartProxy deletion to complete. %s", + statusMsg, + )) return case cleanupStatusNotStarted: log.Info("Starting Konnector Agent cleanup") @@ -369,9 +397,9 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( err = n.deleteHelmChartProxy(ctx, cluster, log) if err != nil { - log.Error(err, "Failed to delete helm chart") + log.Error(err, "Failed to delete HelmChartProxy") resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage(err.Error()) + resp.SetMessage(fmt.Sprintf("Failed to delete Konnector Agent HelmChartProxy: %v", err)) return } @@ -379,6 +407,7 @@ func (n *DefaultKonnectorAgent) BeforeClusterDelete( log.Info("Konnector Agent cleanup initiated, will monitor progress") resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetRetryAfterSeconds(5) // Quick retry to start monitoring + resp.SetMessage("Konnector Agent cleanup initiated. Waiting for HelmChartProxy deletion to start.") } func (n *DefaultKonnectorAgent) deleteHelmChartProxy( @@ -434,15 +463,15 @@ func (n *DefaultKonnectorAgent) deleteHelmChartProxy( } // checkCleanupStatus checks the current status of Konnector Agent cleanup. -// Returns: "completed", "in-progress", or "not-started". +// Returns: status ("completed", "in-progress", "not-started", or "timed-out"), status message, and error. func (n *DefaultKonnectorAgent) checkCleanupStatus( ctx context.Context, cluster *clusterv1.Cluster, log logr.Logger, -) (string, error) { +) (string, string, error) { clusterUUID, ok := cluster.Annotations[v1alpha1.ClusterUUIDAnnotationKey] if !ok { - return cleanupStatusCompleted, nil // If no UUID, assume no agent was installed + return cleanupStatusCompleted, "No cluster UUID found, assuming no agent installed", nil } // Check if HelmChartProxy exists @@ -457,18 +486,52 @@ func (n *DefaultKonnectorAgent) checkCleanupStatus( if err != nil { if apierrors.IsNotFound(err) { log.Info("HelmChartProxy not found, cleanup completed", "name", hcp.Name) - return cleanupStatusCompleted, nil + return cleanupStatusCompleted, "HelmChartProxy successfully deleted", nil } - return "", fmt.Errorf("failed to get HelmChartProxy %q: %w", ctrlclient.ObjectKeyFromObject(hcp), err) + return "", "", fmt.Errorf("failed to get HelmChartProxy %q: %w", ctrlclient.ObjectKeyFromObject(hcp), err) } // HCP exists - check if it's being deleted if hcp.DeletionTimestamp != nil { - log.Info("HelmChartProxy is being deleted, cleanup in progress", "name", hcp.Name) - return cleanupStatusInProgress, nil + // Check if deletion has timed out + deletionDuration := time.Since(hcp.DeletionTimestamp.Time) + if deletionDuration > helmUninstallTimeout { + statusMsg := fmt.Sprintf( + "HelmChartProxy %q has been in deletion state for %v (timeout: %v). "+ + "Possible causes: stuck finalizers, helm uninstall failure, or workload cluster unreachable. "+ + "HelmChartProxy status: %+v", + ctrlclient.ObjectKeyFromObject(hcp), + deletionDuration, + helmUninstallTimeout, + hcp.Status, + ) + log.Error( + fmt.Errorf("helm uninstall timeout exceeded"), + "HelmChartProxy deletion timed out", + "name", hcp.Name, + "deletionTimestamp", hcp.DeletionTimestamp.Time, + "duration", deletionDuration, + "timeout", helmUninstallTimeout, + "finalizers", hcp.Finalizers, + "status", hcp.Status, + ) + return cleanupStatusTimedOut, statusMsg, nil + } + + statusMsg := fmt.Sprintf( + "HelmChartProxy is being deleted (in progress for %v, timeout in %v)", + deletionDuration, + helmUninstallTimeout-deletionDuration, + ) + log.Info("HelmChartProxy is being deleted, cleanup in progress", + "name", hcp.Name, + "deletionDuration", deletionDuration, + "remainingTime", helmUninstallTimeout-deletionDuration, + ) + return cleanupStatusInProgress, statusMsg, nil } // HCP exists and is not being deleted log.Info("HelmChartProxy exists, cleanup not started", "name", hcp.Name) - return cleanupStatusNotStarted, nil + return cleanupStatusNotStarted, "HelmChartProxy exists and needs to be deleted", nil } From 841e67bd729d455e088088a593f61f2bca93a119 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Wed, 29 Oct 2025 20:42:06 +0530 Subject: [PATCH 38/55] feat: pre-commit changes --- pkg/handlers/lifecycle/konnectoragent/handler.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index 6bb4230ba..69ccd657a 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -45,7 +45,7 @@ const ( cleanupStatusTimedOut = "timed-out" // helmUninstallTimeout is the maximum time to wait for HelmChartProxy deletion - // before giving up and allowing cluster deletion to proceed + // before giving up and allowing cluster deletion to proceed. helmUninstallTimeout = 5 * time.Minute ) @@ -468,7 +468,7 @@ func (n *DefaultKonnectorAgent) checkCleanupStatus( ctx context.Context, cluster *clusterv1.Cluster, log logr.Logger, -) (string, string, error) { +) (status, statusMsg string, err error) { clusterUUID, ok := cluster.Annotations[v1alpha1.ClusterUUIDAnnotationKey] if !ok { return cleanupStatusCompleted, "No cluster UUID found, assuming no agent installed", nil @@ -482,7 +482,7 @@ func (n *DefaultKonnectorAgent) checkCleanupStatus( }, } - err := n.client.Get(ctx, ctrlclient.ObjectKeyFromObject(hcp), hcp) + err = n.client.Get(ctx, ctrlclient.ObjectKeyFromObject(hcp), hcp) if err != nil { if apierrors.IsNotFound(err) { log.Info("HelmChartProxy not found, cleanup completed", "name", hcp.Name) From c0feb1c35a5db552ebfa1eb33266e04baa6a4691 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 30 Oct 2025 11:25:39 +0530 Subject: [PATCH 39/55] feat: adding e2e testcases --- .../nutanix-cluster-calico-crs.yaml | 20 ++++++ .../nutanix-cluster-calico-helm-addon.yaml | 20 ++++++ .../nutanix-cluster-cilium-crs.yaml | 20 ++++++ .../nutanix-cluster-cilium-helm-addon.yaml | 20 ++++++ ...luster-with-failuredomains-cilium-crs.yaml | 20 ++++++ ...with-failuredomains-cilium-helm-addon.yaml | 20 ++++++ .../nutanix/konnector-agent-secret.yaml | 21 +++++++ .../nutanix/cluster/kustomization.yaml.tmpl | 1 + test/e2e/addon_helpers.go | 11 ++++ test/e2e/konnectoragent_helpers.go | 61 +++++++++++++++++++ 10 files changed, 214 insertions(+) create mode 100644 hack/examples/additional-resources/nutanix/konnector-agent-secret.yaml create mode 100644 test/e2e/konnectoragent_helpers.go diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 3fb92c30f..76ee61296 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -20,6 +20,26 @@ stringData: --- apiVersion: v1 kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] +--- +apiVersion: v1 +kind: Secret metadata: labels: cluster.x-k8s.io/provider: nutanix diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index 84f70a8ac..e6404f4e1 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -20,6 +20,26 @@ stringData: --- apiVersion: v1 kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] +--- +apiVersion: v1 +kind: Secret metadata: labels: cluster.x-k8s.io/provider: nutanix diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index e7c6775ed..782068bd9 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -20,6 +20,26 @@ stringData: --- apiVersion: v1 kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] +--- +apiVersion: v1 +kind: Secret metadata: labels: cluster.x-k8s.io/provider: nutanix diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 05744f8db..34d0aded7 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -20,6 +20,26 @@ stringData: --- apiVersion: v1 kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] +--- +apiVersion: v1 +kind: Secret metadata: labels: cluster.x-k8s.io/provider: nutanix diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index a31c041b0..3c569a044 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -56,6 +56,26 @@ stringData: --- apiVersion: v1 kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] +--- +apiVersion: v1 +kind: Secret metadata: labels: cluster.x-k8s.io/provider: nutanix diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index e1ed82ae0..e6a0bbe68 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -56,6 +56,26 @@ stringData: --- apiVersion: v1 kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] +--- +apiVersion: v1 +kind: Secret metadata: labels: cluster.x-k8s.io/provider: nutanix diff --git a/hack/examples/additional-resources/nutanix/konnector-agent-secret.yaml b/hack/examples/additional-resources/nutanix/konnector-agent-secret.yaml new file mode 100644 index 000000000..993f35783 --- /dev/null +++ b/hack/examples/additional-resources/nutanix/konnector-agent-secret.yaml @@ -0,0 +1,21 @@ +# Copyright 2025 Nutanix. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +--- +apiVersion: v1 +kind: Secret +metadata: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index 20ec2c37c..41ca178a7 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -7,6 +7,7 @@ kind: Kustomization resources: - ../../../additional-resources/dockerhub-secret.yaml - ../../../additional-resources/nutanix/csi-secret.yaml +- ../../../additional-resources/nutanix/konnector-agent-secret.yaml - https://github.com/nutanix-cloud-native/cluster-api-provider-nutanix/releases/download/${CAPX_VERSION}/cluster-template-topology.yaml sortOptions: diff --git a/test/e2e/addon_helpers.go b/test/e2e/addon_helpers.go index 1871f4144..9fb90b07c 100644 --- a/test/e2e/addon_helpers.go +++ b/test/e2e/addon_helpers.go @@ -141,4 +141,15 @@ func WaitForAddonsToBeReadyInWorkloadCluster( HelmReleaseIntervals: input.HelmReleaseIntervals, }, ) + + WaitForKonnectorAgentToBeReadyInWorkloadCluster( + ctx, + WaitForKonnectorAgentToBeReadyInWorkloadClusterInput{ + KonnectorAgent: input.AddonsConfig.NutanixKonnectorAgent, + WorkloadCluster: input.WorkloadCluster, + ClusterProxy: input.ClusterProxy, + DeploymentIntervals: input.DeploymentIntervals, + HelmReleaseIntervals: input.HelmReleaseIntervals, + }, + ) } diff --git a/test/e2e/konnectoragent_helpers.go b/test/e2e/konnectoragent_helpers.go new file mode 100644 index 000000000..d438a6166 --- /dev/null +++ b/test/e2e/konnectoragent_helpers.go @@ -0,0 +1,61 @@ +//go:build e2e + +// Copyright 2024 Nutanix. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package e2e + +import ( + "context" + + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + "sigs.k8s.io/cluster-api/test/framework" + + apivariables "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/variables" +) + +type WaitForKonnectorAgentToBeReadyInWorkloadClusterInput struct { + KonnectorAgent *apivariables.NutanixKonnectorAgent + WorkloadCluster *clusterv1.Cluster + ClusterProxy framework.ClusterProxy + DeploymentIntervals []interface{} + HelmReleaseIntervals []interface{} +} + +func WaitForKonnectorAgentToBeReadyInWorkloadCluster( + ctx context.Context, + input WaitForKonnectorAgentToBeReadyInWorkloadClusterInput, //nolint:gocritic // This hugeParam is OK in tests. +) { + if input.KonnectorAgent == nil { + return + } + + // Wait for HelmReleaseProxy to be ready + WaitForHelmReleaseProxyReadyForCluster( + ctx, + WaitForHelmReleaseProxyReadyForClusterInput{ + GetLister: input.ClusterProxy.GetClient(), + Cluster: input.WorkloadCluster, + HelmReleaseName: "konnector-agent", + }, + input.HelmReleaseIntervals..., + ) + + // Get workload cluster client to check resources in the workload cluster + workloadClusterClient := input.ClusterProxy.GetWorkloadCluster( + ctx, input.WorkloadCluster.Namespace, input.WorkloadCluster.Name, + ).GetClient() + + // Wait for konnector-agent deployment to be available + WaitForDeploymentsAvailable(ctx, framework.WaitForDeploymentsAvailableInput{ + Getter: workloadClusterClient, + Deployment: &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: "konnector-agent", + Namespace: "ntnx-system", + }, + }, + }, input.DeploymentIntervals...) +} From 25e243083f37ddb8859bd6e19242f33db9c62a24 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 30 Oct 2025 16:05:23 +0530 Subject: [PATCH 40/55] feat: updating konnector secret --- .../nutanix-cluster-calico-crs.yaml | 14 ++------------ .../nutanix-cluster-calico-helm-addon.yaml | 14 ++------------ .../nutanix-cluster-cilium-crs.yaml | 14 ++------------ .../nutanix-cluster-cilium-helm-addon.yaml | 14 ++------------ ...nix-cluster-with-failuredomains-cilium-crs.yaml | 14 ++------------ ...ster-with-failuredomains-cilium-helm-addon.yaml | 14 ++------------ .../nutanix/konnector-agent-secret.yaml | 14 ++------------ 7 files changed, 14 insertions(+), 84 deletions(-) diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 76ee61296..be59a091c 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -25,18 +25,8 @@ metadata: cluster.x-k8s.io/provider: nutanix name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - } - } - } - ] + password: ${NUTANIX_PASSWORD} + username: ${NUTANIX_USER} --- apiVersion: v1 kind: Secret diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index e6404f4e1..b422e6705 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -25,18 +25,8 @@ metadata: cluster.x-k8s.io/provider: nutanix name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - } - } - } - ] + password: ${NUTANIX_PASSWORD} + username: ${NUTANIX_USER} --- apiVersion: v1 kind: Secret diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index 782068bd9..67219a427 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -25,18 +25,8 @@ metadata: cluster.x-k8s.io/provider: nutanix name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - } - } - } - ] + password: ${NUTANIX_PASSWORD} + username: ${NUTANIX_USER} --- apiVersion: v1 kind: Secret diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 34d0aded7..91667248d 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -25,18 +25,8 @@ metadata: cluster.x-k8s.io/provider: nutanix name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - } - } - } - ] + password: ${NUTANIX_PASSWORD} + username: ${NUTANIX_USER} --- apiVersion: v1 kind: Secret diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index 3c569a044..31d2e0310 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -61,18 +61,8 @@ metadata: cluster.x-k8s.io/provider: nutanix name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - } - } - } - ] + password: ${NUTANIX_PASSWORD} + username: ${NUTANIX_USER} --- apiVersion: v1 kind: Secret diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index e6a0bbe68..a6cdb9888 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -61,18 +61,8 @@ metadata: cluster.x-k8s.io/provider: nutanix name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - } - } - } - ] + password: ${NUTANIX_PASSWORD} + username: ${NUTANIX_USER} --- apiVersion: v1 kind: Secret diff --git a/hack/examples/additional-resources/nutanix/konnector-agent-secret.yaml b/hack/examples/additional-resources/nutanix/konnector-agent-secret.yaml index 993f35783..1be94755c 100644 --- a/hack/examples/additional-resources/nutanix/konnector-agent-secret.yaml +++ b/hack/examples/additional-resources/nutanix/konnector-agent-secret.yaml @@ -7,15 +7,5 @@ kind: Secret metadata: name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - } - } - } - ] + username: "${NUTANIX_USER}" + password: "${NUTANIX_PASSWORD}" From 5af33490f08ef590cc913e88d9271f35e5d91bc4 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 30 Oct 2025 17:18:48 +0530 Subject: [PATCH 41/55] feat: fixing clustername length --- .../lifecycle/konnectoragent/handler.go | 13 ++++++++- .../konnectoragent/variables_test.go | 28 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/pkg/handlers/lifecycle/konnectoragent/handler.go b/pkg/handlers/lifecycle/konnectoragent/handler.go index 69ccd657a..c4b51cb8f 100644 --- a/pkg/handlers/lifecycle/konnectoragent/handler.go +++ b/pkg/handlers/lifecycle/konnectoragent/handler.go @@ -47,6 +47,9 @@ const ( // helmUninstallTimeout is the maximum time to wait for HelmChartProxy deletion // before giving up and allowing cluster deletion to proceed. helmUninstallTimeout = 5 * time.Minute + + // maxClusterNameLength is the maximum cluster name length supported by Prism Central. + maxClusterNameLength = 40 ) type Config struct { @@ -290,6 +293,14 @@ func templateValuesFunc( if err != nil { return "", err } + + // Prism Central has a limit on cluster name length + // Truncate the cluster name if it exceeds this limit + clusterName := cluster.Name + if len(clusterName) > maxClusterNameLength { + clusterName = clusterName[:maxClusterNameLength] + } + templateInput := input{ AgentName: defaultK8sAgentName, PrismCentralHost: address, @@ -297,7 +308,7 @@ func templateValuesFunc( // TODO: remove this once we have a way to set this. // need to add support to accept PC's trust bundle in agent(it's not implemented currently) PrismCentralInsecure: true, - ClusterName: cluster.Name, + ClusterName: clusterName, } var b bytes.Buffer diff --git a/pkg/handlers/lifecycle/konnectoragent/variables_test.go b/pkg/handlers/lifecycle/konnectoragent/variables_test.go index f51bff7cb..58c5c39d5 100644 --- a/pkg/handlers/lifecycle/konnectoragent/variables_test.go +++ b/pkg/handlers/lifecycle/konnectoragent/variables_test.go @@ -397,6 +397,34 @@ func TestTemplateValuesFunc_ParseURLError(t *testing.T) { assert.Error(t, err, "ParseURL should fail with invalid URL") } +func TestTemplateValuesFunc_TruncatesLongClusterName(t *testing.T) { + // Create a cluster name longer than 40 characters (Prism Central's limit) + longClusterName := "quick-start-mgz51rkcx7ul1m6h1lbsb824zdf7kyfj62rvhhii044bmdksil5" + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: longClusterName, + }, + } + + nutanixConfig := &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + URL: "https://prism-central.example.com:9440", + }, + } + + templateFunc := templateValuesFunc(nutanixConfig, cluster) + + valuesTemplate := `clusterName: {{ .ClusterName }}` + result, err := templateFunc(cluster, valuesTemplate) + + assert.NoError(t, err) + // Verify the cluster name is truncated to 40 characters + expectedTruncated := longClusterName[:maxClusterNameLength] + assert.Contains(t, result, "clusterName: "+expectedTruncated) + assert.NotContains(t, result, longClusterName) + assert.Equal(t, maxClusterNameLength, len(expectedTruncated), "Truncated name should be exactly 40 characters") +} + func TestApply_ClusterConfigVariableFailure(t *testing.T) { handler := newTestHandler(t) cluster := &clusterv1.Cluster{ From 558ae4dfad49e214ea4f3fc43346a016ca0eb030 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 30 Oct 2025 21:35:28 +0530 Subject: [PATCH 42/55] feat: adding log collection in workflow file --- .github/workflows/e2e.yml | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 0169e0477..6adaa8a04 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -91,6 +91,54 @@ jobs: KINDEST_IMAGE_TAG: ${{ inputs.kubernetes-version }} E2E_KUBERNETES_VERSION: ${{ inputs.kubernetes-version }} + - name: Collect bootstrap cluster pod logs on failure + if: failure() + run: | + echo "Collecting pod logs from bootstrap cluster..." + mkdir -p bootstrap-pod-logs + + # Get kubeconfig path for bootstrap cluster + BOOTSTRAP_KUBECONFIG=$(find _artifacts/clusters/bootstrap -name kubeconfig 2>/dev/null | head -n 1) + + if [[ -n "$BOOTSTRAP_KUBECONFIG" ]]; then + export KUBECONFIG="$BOOTSTRAP_KUBECONFIG" + + # Get all pods overview + kubectl get pods -A -o wide > bootstrap-pod-logs/all-pods.txt 2>&1 || echo "Failed to get pods" > bootstrap-pod-logs/all-pods.txt + + # Get CAREN controller logs (main focus) + echo "Collecting CAREN controller logs..." + kubectl logs -n caren-system -l app.kubernetes.io/name=cluster-api-runtime-extensions-nutanix --all-containers=true --tail=1000 > bootstrap-pod-logs/caren-controller.log 2>&1 || echo "Failed to get CAREN logs" > bootstrap-pod-logs/caren-controller.log + + # Get all CAPI provider logs + echo "Collecting CAPI provider logs..." + for ns in capi-system capi-kubeadm-bootstrap-system capi-kubeadm-control-plane-system capd-system capn-system capa-system caaph-system; do + if kubectl get namespace "$ns" >/dev/null 2>&1; then + mkdir -p "bootstrap-pod-logs/$ns" + kubectl get pods -n "$ns" -o wide > "bootstrap-pod-logs/$ns/pods.txt" 2>&1 || true + for pod in $(kubectl get pods -n "$ns" -o name 2>/dev/null); do + pod_name=$(basename "$pod") + kubectl logs -n "$ns" "$pod_name" --all-containers=true --tail=500 > "bootstrap-pod-logs/$ns/${pod_name}.log" 2>&1 || true + done + fi + done + + # Get HelmReleaseProxy and HelmChartProxy resources + echo "Collecting Helm addon resources..." + kubectl get helmreleaseproxies -A -o yaml > bootstrap-pod-logs/helmreleaseproxies.yaml 2>&1 || true + kubectl get helmchartproxies -A -o yaml > bootstrap-pod-logs/helmchartproxies.yaml 2>&1 || true + else + echo "Bootstrap kubeconfig not found" > bootstrap-pod-logs/error.txt + fi + + - name: Upload bootstrap pod logs + if: failure() + uses: actions/upload-artifact@v4 + with: + name: bootstrap-pod-logs-${{ inputs.provider }}-${{ inputs.kubernetes-version }} + path: bootstrap-pod-logs/ + if-no-files-found: warn + - if: success() || failure() # always run even if the previous step fails name: Publish e2e test report uses: mikepenz/action-junit-report@v5 From 8807e64b724a2e7e09827e90feb95bcef447c2e1 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 30 Oct 2025 21:51:33 +0530 Subject: [PATCH 43/55] feat: precommit fix --- .github/workflows/e2e.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 6adaa8a04..4586d8212 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -96,20 +96,20 @@ jobs: run: | echo "Collecting pod logs from bootstrap cluster..." mkdir -p bootstrap-pod-logs - + # Get kubeconfig path for bootstrap cluster BOOTSTRAP_KUBECONFIG=$(find _artifacts/clusters/bootstrap -name kubeconfig 2>/dev/null | head -n 1) - + if [[ -n "$BOOTSTRAP_KUBECONFIG" ]]; then export KUBECONFIG="$BOOTSTRAP_KUBECONFIG" - + # Get all pods overview kubectl get pods -A -o wide > bootstrap-pod-logs/all-pods.txt 2>&1 || echo "Failed to get pods" > bootstrap-pod-logs/all-pods.txt - + # Get CAREN controller logs (main focus) echo "Collecting CAREN controller logs..." kubectl logs -n caren-system -l app.kubernetes.io/name=cluster-api-runtime-extensions-nutanix --all-containers=true --tail=1000 > bootstrap-pod-logs/caren-controller.log 2>&1 || echo "Failed to get CAREN logs" > bootstrap-pod-logs/caren-controller.log - + # Get all CAPI provider logs echo "Collecting CAPI provider logs..." for ns in capi-system capi-kubeadm-bootstrap-system capi-kubeadm-control-plane-system capd-system capn-system capa-system caaph-system; do @@ -122,7 +122,7 @@ jobs: done fi done - + # Get HelmReleaseProxy and HelmChartProxy resources echo "Collecting Helm addon resources..." kubectl get helmreleaseproxies -A -o yaml > bootstrap-pod-logs/helmreleaseproxies.yaml 2>&1 || true From a18aadc03b0a3f96aefeee000ec52a56b9b43656 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Thu, 30 Oct 2025 23:34:07 +0530 Subject: [PATCH 44/55] feat: collect logs on failure --- .github/workflows/e2e.yml | 60 +++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 4586d8212..e1496adb1 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -94,26 +94,58 @@ jobs: - name: Collect bootstrap cluster pod logs on failure if: failure() run: | - echo "Collecting pod logs from bootstrap cluster..." + set -x # Enable debug mode to see all commands + echo "===== Starting log collection =====" mkdir -p bootstrap-pod-logs - # Get kubeconfig path for bootstrap cluster - BOOTSTRAP_KUBECONFIG=$(find _artifacts/clusters/bootstrap -name kubeconfig 2>/dev/null | head -n 1) + # Check if Kind cluster exists first + echo "Checking for Kind clusters..." + devbox run -- kind get clusters > bootstrap-pod-logs/kind-clusters.txt 2>&1 || true + cat bootstrap-pod-logs/kind-clusters.txt - if [[ -n "$BOOTSTRAP_KUBECONFIG" ]]; then - export KUBECONFIG="$BOOTSTRAP_KUBECONFIG" + # Get kubeconfig from Kind cluster (name: caren-e2e from test/e2e/config/caren.yaml) + echo "Getting kubeconfig from Kind cluster 'caren-e2e'..." + if devbox run -- kind get kubeconfig --name caren-e2e > bootstrap-pod-logs/kubeconfig.yaml 2>&1; then + echo "✓ Successfully retrieved kubeconfig from Kind cluster" + + # Use absolute path for KUBECONFIG + export KUBECONFIG="${PWD}/bootstrap-pod-logs/kubeconfig.yaml" + echo "✓ KUBECONFIG set to: $KUBECONFIG" + + # Verify kubectl works + echo "Verifying kubectl connectivity..." + if kubectl cluster-info &> bootstrap-pod-logs/cluster-info.txt; then + echo "✓ kubectl can connect to cluster" + cat bootstrap-pod-logs/cluster-info.txt + else + echo "✗ kubectl cannot connect to cluster" + cat bootstrap-pod-logs/cluster-info.txt + exit 0 # Exit gracefully, don't fail the workflow + fi # Get all pods overview + echo "Getting all pods..." kubectl get pods -A -o wide > bootstrap-pod-logs/all-pods.txt 2>&1 || echo "Failed to get pods" > bootstrap-pod-logs/all-pods.txt + echo "✓ Saved all-pods.txt" + + # Get all namespaces + kubectl get namespaces > bootstrap-pod-logs/namespaces.txt 2>&1 || true + echo "✓ Saved namespaces.txt" - # Get CAREN controller logs (main focus) + # Get CAREN controller logs (main focus - this is what you need for konnector-agent debugging) echo "Collecting CAREN controller logs..." kubectl logs -n caren-system -l app.kubernetes.io/name=cluster-api-runtime-extensions-nutanix --all-containers=true --tail=1000 > bootstrap-pod-logs/caren-controller.log 2>&1 || echo "Failed to get CAREN logs" > bootstrap-pod-logs/caren-controller.log + echo "✓ Saved caren-controller.log ($(wc -l < bootstrap-pod-logs/caren-controller.log) lines)" + + # Get CAREN controller pod descriptions + kubectl describe pods -n caren-system -l app.kubernetes.io/name=cluster-api-runtime-extensions-nutanix > bootstrap-pod-logs/caren-pods-describe.txt 2>&1 || true + echo "✓ Saved caren-pods-describe.txt" # Get all CAPI provider logs echo "Collecting CAPI provider logs..." for ns in capi-system capi-kubeadm-bootstrap-system capi-kubeadm-control-plane-system capd-system capn-system capa-system caaph-system; do if kubectl get namespace "$ns" >/dev/null 2>&1; then + echo " ✓ Collecting logs from namespace: $ns" mkdir -p "bootstrap-pod-logs/$ns" kubectl get pods -n "$ns" -o wide > "bootstrap-pod-logs/$ns/pods.txt" 2>&1 || true for pod in $(kubectl get pods -n "$ns" -o name 2>/dev/null); do @@ -123,12 +155,24 @@ jobs: fi done - # Get HelmReleaseProxy and HelmChartProxy resources + # Get HelmReleaseProxy and HelmChartProxy resources (critical for konnector-agent debugging) echo "Collecting Helm addon resources..." kubectl get helmreleaseproxies -A -o yaml > bootstrap-pod-logs/helmreleaseproxies.yaml 2>&1 || true kubectl get helmchartproxies -A -o yaml > bootstrap-pod-logs/helmchartproxies.yaml 2>&1 || true + echo "✓ Saved Helm resources" + + # Get all events (helpful for debugging) + echo "Collecting cluster events..." + kubectl get events -A --sort-by='.lastTimestamp' > bootstrap-pod-logs/events.txt 2>&1 || true + echo "✓ Saved events.txt" + + echo "===== ✓ Log collection completed successfully =====" + ls -lh bootstrap-pod-logs/ else - echo "Bootstrap kubeconfig not found" > bootstrap-pod-logs/error.txt + echo "===== ✗ Failed to get kubeconfig =====" + cat bootstrap-pod-logs/kubeconfig.yaml || echo "No kubeconfig file" + echo "Checking Docker containers..." + docker ps -a > bootstrap-pod-logs/docker-ps.txt 2>&1 || true fi - name: Upload bootstrap pod logs From 657404319fa81cf7c6a3f37defa7a44d2d12e9dd Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 31 Oct 2025 05:17:49 +0530 Subject: [PATCH 45/55] feat: log collection changes --- .github/workflows/e2e.yml | 10 +++++++++- test/e2e/config/caren.yaml | 26 +++++++++++++------------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index e1496adb1..273b60ee3 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -73,7 +73,7 @@ jobs: df -h - name: Run e2e tests - run: devbox run -- make e2e-test E2E_LABEL='provider:${{ inputs.provider }}' E2E_SKIP='${{ inputs.skip }}' E2E_FOCUS='${{ inputs.focus }}' E2E_VERBOSE=true + run: devbox run -- make e2e-test E2E_LABEL='provider:${{ inputs.provider }}' E2E_SKIP='${{ inputs.skip }}' E2E_FOCUS='${{ inputs.focus }}' E2E_VERBOSE=true E2E_SKIP_CLEANUP=true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} @@ -183,6 +183,14 @@ jobs: path: bootstrap-pod-logs/ if-no-files-found: warn + - name: Cleanup Kind cluster after log collection + if: always() + run: | + echo "Cleaning up Kind cluster..." + devbox run -- kind get clusters || true + devbox run -- kind delete cluster --name caren-e2e || true + echo "Cleanup completed" + - if: success() || failure() # always run even if the previous step fails name: Publish e2e test report uses: mikepenz/action-junit-report@v5 diff --git a/test/e2e/config/caren.yaml b/test/e2e/config/caren.yaml index 1827ceebc..e27ba8dac 100644 --- a/test/e2e/config/caren.yaml +++ b/test/e2e/config/caren.yaml @@ -217,16 +217,16 @@ variables: # DOCKER_HUB_PASSWORD: "" intervals: - default/wait-controllers: ["3m", "10s"] - default/wait-cluster: ["10m", "10s"] - default/wait-control-plane: ["10m", "10s"] - default/wait-worker-nodes: ["10m", "10s"] - default/wait-delete-cluster: ["30m", "10s"] - default/wait-nodes-ready: ["10m", "10s"] - default/wait-deployment: ["10m", "10s"] - default/wait-daemonset: [ "5m", "10s" ] - default/wait-statefulset: [ "10m", "10s" ] - default/wait-service: [ "10m", "10s" ] - default/wait-clusterresourceset: [ "5m", "10s" ] - default/wait-helmrelease: [ "5m", "10s" ] - default/wait-resource: [ "5m", "10s" ] + default/wait-controllers: ["15m", "10s"] + default/wait-cluster: ["15m", "10s"] + default/wait-control-plane: ["15m", "10s"] + default/wait-worker-nodes: ["15m", "10s"] + default/wait-delete-cluster: ["15m", "10s"] + default/wait-nodes-ready: ["15m", "10s"] + default/wait-deployment: ["15m", "10s"] + default/wait-daemonset: [ "10m", "10s" ] + default/wait-statefulset: [ "15m", "10s" ] + default/wait-service: [ "15m", "10s" ] + default/wait-clusterresourceset: [ "10m", "10s" ] + default/wait-helmrelease: [ "15m", "10s" ] + default/wait-resource: [ "10m", "10s" ] From 77f57773eb51a43b20321c1396c8551efafa0139 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 31 Oct 2025 06:49:12 +0530 Subject: [PATCH 46/55] feat: collecting workload cluster pod logs --- .github/workflows/e2e.yml | 83 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 273b60ee3..e9aef90a8 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -165,7 +165,88 @@ jobs: echo "Collecting cluster events..." kubectl get events -A --sort-by='.lastTimestamp' > bootstrap-pod-logs/events.txt 2>&1 || true echo "✓ Saved events.txt" - + + # Get all clusters + echo "Getting list of workload clusters..." + kubectl get clusters -A > bootstrap-pod-logs/clusters.txt 2>&1 || true + + # Collect logs from workload cluster (where konnector-agent actually runs) + echo "===== Collecting logs from WORKLOAD CLUSTER =====" + mkdir -p bootstrap-pod-logs/workload-cluster + + # Find the workload cluster name (starts with "quick-start") + WORKLOAD_CLUSTER=$(kubectl get clusters -A -o jsonpath='{.items[?(@.metadata.name contains "quick-start")].metadata.name}' 2>/dev/null | head -n 1) + WORKLOAD_NAMESPACE=$(kubectl get clusters -A -o jsonpath='{.items[?(@.metadata.name contains "quick-start")].metadata.namespace}' 2>/dev/null | head -n 1) + + if [[ -n "$WORKLOAD_CLUSTER" && -n "$WORKLOAD_NAMESPACE" ]]; then + echo "Found workload cluster: $WORKLOAD_CLUSTER in namespace $WORKLOAD_NAMESPACE" + + # Get workload cluster kubeconfig from secret + echo "Retrieving workload cluster kubeconfig..." + if kubectl get secret -n "$WORKLOAD_NAMESPACE" "${WORKLOAD_CLUSTER}-kubeconfig" -o jsonpath='{.data.value}' 2>/dev/null | base64 -d > bootstrap-pod-logs/workload-cluster/kubeconfig.yaml; then + export WORKLOAD_KUBECONFIG="${PWD}/bootstrap-pod-logs/workload-cluster/kubeconfig.yaml" + echo "✓ Retrieved workload cluster kubeconfig" + + # Test connectivity + if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" cluster-info &> bootstrap-pod-logs/workload-cluster/cluster-info.txt; then + echo "✓ Can connect to workload cluster" + + # Get all pods in ntnx-system namespace + echo "Getting pods in ntnx-system namespace..." + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pods -n ntnx-system -o wide > bootstrap-pod-logs/workload-cluster/ntnx-system-pods.txt 2>&1 || true + + # Get konnector-agent pod descriptions (THIS IS WHAT YOU WANT!) + echo "Getting konnector-agent pod descriptions..." + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" describe pods -n ntnx-system -l app.kubernetes.io/name=konnector-agent > bootstrap-pod-logs/workload-cluster/konnector-agent-describe.txt 2>&1 || true + + # Get konnector-agent pod logs + echo "Getting konnector-agent pod logs..." + for pod in $(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pods -n ntnx-system -l app.kubernetes.io/name=konnector-agent -o name 2>/dev/null); do + pod_name=$(basename "$pod") + echo " Getting logs for $pod_name..." + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" logs -n ntnx-system "$pod_name" --all-containers=true --tail=1000 > "bootstrap-pod-logs/workload-cluster/${pod_name}.log" 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" logs -n ntnx-system "$pod_name" --all-containers=true --previous --tail=500 > "bootstrap-pod-logs/workload-cluster/${pod_name}-previous.log" 2>&1 || true + done + + # Get hook pod descriptions and logs (hook-preinstall is what fails) + echo "Getting hook pod information..." + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pods -n ntnx-system | grep hook > bootstrap-pod-logs/workload-cluster/hook-pods.txt 2>&1 || true + + for hook_pod in hook-preinstall hook-postinstall; do + if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pod -n ntnx-system "$hook_pod" &>/dev/null; then + echo " Found $hook_pod, collecting info..." + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" describe pod -n ntnx-system "$hook_pod" > "bootstrap-pod-logs/workload-cluster/${hook_pod}-describe.txt" 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" logs -n ntnx-system "$hook_pod" --all-containers=true --tail=1000 > "bootstrap-pod-logs/workload-cluster/${hook_pod}.log" 2>&1 || true + fi + done + + # Get konnector-agent secret info (without credentials) + echo "Getting konnector-agent secret info..." + if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get secret -n ntnx-system konnector-agent &>/dev/null; then + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get secret -n ntnx-system konnector-agent -o yaml | grep -v "password\|credential" > bootstrap-pod-logs/workload-cluster/konnector-agent-secret.yaml 2>&1 || true + echo "Secret keys present:" > bootstrap-pod-logs/workload-cluster/konnector-agent-secret-keys.txt + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get secret -n ntnx-system konnector-agent -o jsonpath='{.data}' | grep -o '"[^"]*":' | tr -d '":' >> bootstrap-pod-logs/workload-cluster/konnector-agent-secret-keys.txt 2>&1 || true + fi + + # Get workload cluster events + echo "Getting workload cluster events..." + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get events -n ntnx-system --sort-by='.lastTimestamp' > bootstrap-pod-logs/workload-cluster/events.txt 2>&1 || true + + # Get all namespaces in workload cluster + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get namespaces > bootstrap-pod-logs/workload-cluster/namespaces.txt 2>&1 || true + + echo "✓ Workload cluster logs collected successfully" + else + echo "✗ Cannot connect to workload cluster" + cat bootstrap-pod-logs/workload-cluster/cluster-info.txt + fi + else + echo "✗ Failed to retrieve workload cluster kubeconfig" + fi + else + echo "No workload cluster found (this is normal if cluster creation failed early)" + fi + echo "===== ✓ Log collection completed successfully =====" ls -lh bootstrap-pod-logs/ else From ccb069096075a56a177d0d454a50d451f39d2f59 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 31 Oct 2025 06:51:33 +0530 Subject: [PATCH 47/55] feat: collecting logs --- .github/workflows/e2e.yml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index e9aef90a8..521f8a59f 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -165,40 +165,40 @@ jobs: echo "Collecting cluster events..." kubectl get events -A --sort-by='.lastTimestamp' > bootstrap-pod-logs/events.txt 2>&1 || true echo "✓ Saved events.txt" - + # Get all clusters echo "Getting list of workload clusters..." kubectl get clusters -A > bootstrap-pod-logs/clusters.txt 2>&1 || true - + # Collect logs from workload cluster (where konnector-agent actually runs) echo "===== Collecting logs from WORKLOAD CLUSTER =====" mkdir -p bootstrap-pod-logs/workload-cluster - + # Find the workload cluster name (starts with "quick-start") WORKLOAD_CLUSTER=$(kubectl get clusters -A -o jsonpath='{.items[?(@.metadata.name contains "quick-start")].metadata.name}' 2>/dev/null | head -n 1) WORKLOAD_NAMESPACE=$(kubectl get clusters -A -o jsonpath='{.items[?(@.metadata.name contains "quick-start")].metadata.namespace}' 2>/dev/null | head -n 1) - + if [[ -n "$WORKLOAD_CLUSTER" && -n "$WORKLOAD_NAMESPACE" ]]; then echo "Found workload cluster: $WORKLOAD_CLUSTER in namespace $WORKLOAD_NAMESPACE" - + # Get workload cluster kubeconfig from secret echo "Retrieving workload cluster kubeconfig..." if kubectl get secret -n "$WORKLOAD_NAMESPACE" "${WORKLOAD_CLUSTER}-kubeconfig" -o jsonpath='{.data.value}' 2>/dev/null | base64 -d > bootstrap-pod-logs/workload-cluster/kubeconfig.yaml; then export WORKLOAD_KUBECONFIG="${PWD}/bootstrap-pod-logs/workload-cluster/kubeconfig.yaml" echo "✓ Retrieved workload cluster kubeconfig" - + # Test connectivity if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" cluster-info &> bootstrap-pod-logs/workload-cluster/cluster-info.txt; then echo "✓ Can connect to workload cluster" - + # Get all pods in ntnx-system namespace echo "Getting pods in ntnx-system namespace..." kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pods -n ntnx-system -o wide > bootstrap-pod-logs/workload-cluster/ntnx-system-pods.txt 2>&1 || true - + # Get konnector-agent pod descriptions (THIS IS WHAT YOU WANT!) echo "Getting konnector-agent pod descriptions..." kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" describe pods -n ntnx-system -l app.kubernetes.io/name=konnector-agent > bootstrap-pod-logs/workload-cluster/konnector-agent-describe.txt 2>&1 || true - + # Get konnector-agent pod logs echo "Getting konnector-agent pod logs..." for pod in $(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pods -n ntnx-system -l app.kubernetes.io/name=konnector-agent -o name 2>/dev/null); do @@ -207,11 +207,11 @@ jobs: kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" logs -n ntnx-system "$pod_name" --all-containers=true --tail=1000 > "bootstrap-pod-logs/workload-cluster/${pod_name}.log" 2>&1 || true kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" logs -n ntnx-system "$pod_name" --all-containers=true --previous --tail=500 > "bootstrap-pod-logs/workload-cluster/${pod_name}-previous.log" 2>&1 || true done - + # Get hook pod descriptions and logs (hook-preinstall is what fails) echo "Getting hook pod information..." kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pods -n ntnx-system | grep hook > bootstrap-pod-logs/workload-cluster/hook-pods.txt 2>&1 || true - + for hook_pod in hook-preinstall hook-postinstall; do if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pod -n ntnx-system "$hook_pod" &>/dev/null; then echo " Found $hook_pod, collecting info..." @@ -219,7 +219,7 @@ jobs: kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" logs -n ntnx-system "$hook_pod" --all-containers=true --tail=1000 > "bootstrap-pod-logs/workload-cluster/${hook_pod}.log" 2>&1 || true fi done - + # Get konnector-agent secret info (without credentials) echo "Getting konnector-agent secret info..." if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get secret -n ntnx-system konnector-agent &>/dev/null; then @@ -227,14 +227,14 @@ jobs: echo "Secret keys present:" > bootstrap-pod-logs/workload-cluster/konnector-agent-secret-keys.txt kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get secret -n ntnx-system konnector-agent -o jsonpath='{.data}' | grep -o '"[^"]*":' | tr -d '":' >> bootstrap-pod-logs/workload-cluster/konnector-agent-secret-keys.txt 2>&1 || true fi - + # Get workload cluster events echo "Getting workload cluster events..." kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get events -n ntnx-system --sort-by='.lastTimestamp' > bootstrap-pod-logs/workload-cluster/events.txt 2>&1 || true - + # Get all namespaces in workload cluster kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get namespaces > bootstrap-pod-logs/workload-cluster/namespaces.txt 2>&1 || true - + echo "✓ Workload cluster logs collected successfully" else echo "✗ Cannot connect to workload cluster" @@ -246,7 +246,7 @@ jobs: else echo "No workload cluster found (this is normal if cluster creation failed early)" fi - + echo "===== ✓ Log collection completed successfully =====" ls -lh bootstrap-pod-logs/ else From b592db1390fc18589179a8ce44f2addd7e7c369a Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 31 Oct 2025 08:56:09 +0530 Subject: [PATCH 48/55] feat: collecting logs --- .github/workflows/e2e.yml | 124 ++++++++++++++++++++++++++++++-------- 1 file changed, 100 insertions(+), 24 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 521f8a59f..4b545bd40 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -135,7 +135,8 @@ jobs: # Get CAREN controller logs (main focus - this is what you need for konnector-agent debugging) echo "Collecting CAREN controller logs..." kubectl logs -n caren-system -l app.kubernetes.io/name=cluster-api-runtime-extensions-nutanix --all-containers=true --tail=1000 > bootstrap-pod-logs/caren-controller.log 2>&1 || echo "Failed to get CAREN logs" > bootstrap-pod-logs/caren-controller.log - echo "✓ Saved caren-controller.log ($(wc -l < bootstrap-pod-logs/caren-controller.log) lines)" + CAREN_LOG_LINES=$(wc -l < bootstrap-pod-logs/caren-controller.log) + echo "✓ Saved caren-controller.log (${CAREN_LOG_LINES} lines)" # Get CAREN controller pod descriptions kubectl describe pods -n caren-system -l app.kubernetes.io/name=cluster-api-runtime-extensions-nutanix > bootstrap-pod-logs/caren-pods-describe.txt 2>&1 || true @@ -161,6 +162,28 @@ jobs: kubectl get helmchartproxies -A -o yaml > bootstrap-pod-logs/helmchartproxies.yaml 2>&1 || true echo "✓ Saved Helm resources" + # Get Prism Central credentials info from bootstrap cluster + echo "Collecting Prism Central configuration..." + { + echo "=== Prism Central Configuration from Environment ===" + echo "NUTANIX_ENDPOINT: ${NUTANIX_ENDPOINT:-NOT_SET}" + echo "NUTANIX_PORT: ${NUTANIX_PORT:-NOT_SET}" + echo "NUTANIX_USER: ${NUTANIX_USER:-NOT_SET}" + echo "NUTANIX_PASSWORD: ${NUTANIX_PASSWORD:-NOT_SET}" + echo "" + echo "=== Checking for Nutanix credentials in bootstrap cluster ===" + + # Check for any nutanix-related secrets + kubectl get secrets -A | grep -i nutanix || echo "No nutanix secrets found" + echo "" + + # Get konnector-agent HelmReleaseProxy values (shows what's being passed) + echo "=== Konnector-Agent HelmReleaseProxy Values ===" + kubectl get helmreleaseproxies -A -l helmreleaseproxy.addons.cluster.x-k8s.io/helmchartproxy-name=~konnector-agent -o jsonpath='{.items[0].spec.values}' 2>/dev/null || echo "No HelmReleaseProxy found yet" + echo "" + } > bootstrap-pod-logs/prism-central-config.txt 2>&1 || true + echo "✓ Saved Prism Central config" + # Get all events (helpful for debugging) echo "Collecting cluster events..." kubectl get events -A --sort-by='.lastTimestamp' > bootstrap-pod-logs/events.txt 2>&1 || true @@ -187,58 +210,111 @@ jobs: export WORKLOAD_KUBECONFIG="${PWD}/bootstrap-pod-logs/workload-cluster/kubeconfig.yaml" echo "✓ Retrieved workload cluster kubeconfig" - # Test connectivity - if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" cluster-info &> bootstrap-pod-logs/workload-cluster/cluster-info.txt; then - echo "✓ Can connect to workload cluster" + # Verify kubeconfig has content + if [[ -s "$WORKLOAD_KUBECONFIG" ]]; then + WORKLOAD_KC_LINES=$(wc -l < "$WORKLOAD_KUBECONFIG") + echo "✓ Kubeconfig file has content (${WORKLOAD_KC_LINES} lines)" + + # Test connectivity (use --request-timeout to avoid hanging) + echo "Testing connectivity to workload cluster..." + if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=10s get nodes &> bootstrap-pod-logs/workload-cluster/cluster-info.txt; then + echo "✓ Can connect to workload cluster" + else + echo "⚠ Cannot connect to workload cluster yet, but will try collecting logs anyway" + cat bootstrap-pod-logs/workload-cluster/cluster-info.txt + fi - # Get all pods in ntnx-system namespace + # Get all pods in ntnx-system namespace (try with timeout) echo "Getting pods in ntnx-system namespace..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pods -n ntnx-system -o wide > bootstrap-pod-logs/workload-cluster/ntnx-system-pods.txt 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get pods -n ntnx-system -o wide > bootstrap-pod-logs/workload-cluster/ntnx-system-pods.txt 2>&1 || echo "Could not get pods (cluster may not be ready yet)" > bootstrap-pod-logs/workload-cluster/ntnx-system-pods.txt # Get konnector-agent pod descriptions (THIS IS WHAT YOU WANT!) echo "Getting konnector-agent pod descriptions..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" describe pods -n ntnx-system -l app.kubernetes.io/name=konnector-agent > bootstrap-pod-logs/workload-cluster/konnector-agent-describe.txt 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s describe pods -n ntnx-system -l app.kubernetes.io/name=konnector-agent > bootstrap-pod-logs/workload-cluster/konnector-agent-describe.txt 2>&1 || echo "Could not describe konnector-agent pods" > bootstrap-pod-logs/workload-cluster/konnector-agent-describe.txt # Get konnector-agent pod logs echo "Getting konnector-agent pod logs..." - for pod in $(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pods -n ntnx-system -l app.kubernetes.io/name=konnector-agent -o name 2>/dev/null); do + for pod in $(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get pods -n ntnx-system -l app.kubernetes.io/name=konnector-agent -o name 2>/dev/null); do pod_name=$(basename "$pod") echo " Getting logs for $pod_name..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" logs -n ntnx-system "$pod_name" --all-containers=true --tail=1000 > "bootstrap-pod-logs/workload-cluster/${pod_name}.log" 2>&1 || true - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" logs -n ntnx-system "$pod_name" --all-containers=true --previous --tail=500 > "bootstrap-pod-logs/workload-cluster/${pod_name}-previous.log" 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s logs -n ntnx-system "$pod_name" --all-containers=true --tail=1000 > "bootstrap-pod-logs/workload-cluster/${pod_name}.log" 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s logs -n ntnx-system "$pod_name" --all-containers=true --previous --tail=500 > "bootstrap-pod-logs/workload-cluster/${pod_name}-previous.log" 2>&1 || true done # Get hook pod descriptions and logs (hook-preinstall is what fails) echo "Getting hook pod information..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pods -n ntnx-system | grep hook > bootstrap-pod-logs/workload-cluster/hook-pods.txt 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get pods -n ntnx-system 2>/dev/null | grep hook > bootstrap-pod-logs/workload-cluster/hook-pods.txt 2>&1 || echo "No hook pods found or cluster not accessible" > bootstrap-pod-logs/workload-cluster/hook-pods.txt for hook_pod in hook-preinstall hook-postinstall; do - if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get pod -n ntnx-system "$hook_pod" &>/dev/null; then + echo " Checking for $hook_pod..." + if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get pod -n ntnx-system "$hook_pod" &>/dev/null; then echo " Found $hook_pod, collecting info..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" describe pod -n ntnx-system "$hook_pod" > "bootstrap-pod-logs/workload-cluster/${hook_pod}-describe.txt" 2>&1 || true - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" logs -n ntnx-system "$hook_pod" --all-containers=true --tail=1000 > "bootstrap-pod-logs/workload-cluster/${hook_pod}.log" 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s describe pod -n ntnx-system "$hook_pod" > "bootstrap-pod-logs/workload-cluster/${hook_pod}-describe.txt" 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s logs -n ntnx-system "$hook_pod" --all-containers=true --tail=1000 > "bootstrap-pod-logs/workload-cluster/${hook_pod}.log" 2>&1 || true + else + echo " $hook_pod not found or not accessible" fi done - # Get konnector-agent secret info (without credentials) + # Get konnector-agent secret info with credential details echo "Getting konnector-agent secret info..." - if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get secret -n ntnx-system konnector-agent &>/dev/null; then - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get secret -n ntnx-system konnector-agent -o yaml | grep -v "password\|credential" > bootstrap-pod-logs/workload-cluster/konnector-agent-secret.yaml 2>&1 || true - echo "Secret keys present:" > bootstrap-pod-logs/workload-cluster/konnector-agent-secret-keys.txt - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get secret -n ntnx-system konnector-agent -o jsonpath='{.data}' | grep -o '"[^"]*":' | tr -d '":' >> bootstrap-pod-logs/workload-cluster/konnector-agent-secret-keys.txt 2>&1 || true + if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent &>/dev/null; then + { + echo "=== Konnector-Agent Secret in Workload Cluster ===" + echo "" + echo "Secret keys present:" + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent -o jsonpath='{.data}' 2>/dev/null | grep -o '"[^"]*":' | tr -d '":' || echo "Could not get keys" + echo "" + echo "=== Secret Data (base64 decoded - FULL VALUES) ===" + + # Get username if it exists + USERNAME=$(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent -o jsonpath='{.data.username}' 2>/dev/null | base64 -d 2>/dev/null) + if [[ -n "$USERNAME" ]]; then + echo "username: $USERNAME" + else + echo "username: NOT_FOUND" + fi + + # Get password (FULL VALUE - NO MASKING) + PASSWORD=$(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent -o jsonpath='{.data.password}' 2>/dev/null | base64 -d 2>/dev/null) + if [[ -n "$PASSWORD" ]]; then + echo "password: $PASSWORD" + else + echo "password: NOT_FOUND" + fi + + # Check for old 'credentials' format (should NOT exist) + CREDENTIALS=$(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent -o jsonpath='{.data.credentials}' 2>/dev/null | base64 -d 2>/dev/null) + if [[ -n "$CREDENTIALS" ]]; then + echo "credentials: FOUND (OLD FORMAT - THIS IS THE PROBLEM!)" + echo "credentials value: $CREDENTIALS" + else + echo "credentials: NOT_FOUND (good - using new format)" + fi + + echo "" + echo "=== Full Secret YAML ===" + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent -o yaml || true + + } > bootstrap-pod-logs/workload-cluster/konnector-agent-secret-details.txt 2>&1 || true + else + echo "konnector-agent secret not found or not accessible" > bootstrap-pod-logs/workload-cluster/konnector-agent-secret-details.txt fi # Get workload cluster events echo "Getting workload cluster events..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get events -n ntnx-system --sort-by='.lastTimestamp' > bootstrap-pod-logs/workload-cluster/events.txt 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get events -n ntnx-system --sort-by='.lastTimestamp' > bootstrap-pod-logs/workload-cluster/events.txt 2>&1 || echo "Could not get events" > bootstrap-pod-logs/workload-cluster/events.txt # Get all namespaces in workload cluster - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" get namespaces > bootstrap-pod-logs/workload-cluster/namespaces.txt 2>&1 || true + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get namespaces > bootstrap-pod-logs/workload-cluster/namespaces.txt 2>&1 || echo "Could not get namespaces" > bootstrap-pod-logs/workload-cluster/namespaces.txt + + # Try to get nodes + echo "Getting workload cluster nodes..." + kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get nodes -o wide > bootstrap-pod-logs/workload-cluster/nodes.txt 2>&1 || echo "Could not get nodes" > bootstrap-pod-logs/workload-cluster/nodes.txt - echo "✓ Workload cluster logs collected successfully" + echo "✓ Workload cluster log collection attempted (check individual files for results)" else - echo "✗ Cannot connect to workload cluster" - cat bootstrap-pod-logs/workload-cluster/cluster-info.txt + echo "✗ Kubeconfig file is empty" fi else echo "✗ Failed to retrieve workload cluster kubeconfig" From 4b89c28fb494918a900795e0d087ca032f9416d8 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 31 Oct 2025 10:04:12 +0530 Subject: [PATCH 49/55] feat: Update caren.yaml for intervals --- test/e2e/config/caren.yaml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/e2e/config/caren.yaml b/test/e2e/config/caren.yaml index e27ba8dac..6a3924f51 100644 --- a/test/e2e/config/caren.yaml +++ b/test/e2e/config/caren.yaml @@ -140,8 +140,8 @@ providers: versions: # Upgrade e2e tests will use this as the "upgrade from" version. # This should reference the most recent successful release. - - name: "{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.34}" - value: "https://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/releases/download/{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.34}/runtime-extensions-components.yaml" + - name: "{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.35}" + value: "https://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/releases/download/{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.35}/runtime-extensions-components.yaml" type: "url" contract: v1beta1 files: @@ -151,7 +151,7 @@ providers: new: "--v=8" - old: --metrics-addr=127.0.0.1:8080 new: --metrics-addr=:8080 - - name: v0.36.99 # "vNext"; use manifests from local source files + - name: v0.37.99 # "vNext"; use manifests from local source files value: "file://../../../runtime-extensions-components.yaml" type: "url" contract: v1beta1 @@ -217,16 +217,16 @@ variables: # DOCKER_HUB_PASSWORD: "" intervals: - default/wait-controllers: ["15m", "10s"] - default/wait-cluster: ["15m", "10s"] - default/wait-control-plane: ["15m", "10s"] - default/wait-worker-nodes: ["15m", "10s"] - default/wait-delete-cluster: ["15m", "10s"] - default/wait-nodes-ready: ["15m", "10s"] - default/wait-deployment: ["15m", "10s"] - default/wait-daemonset: [ "10m", "10s" ] - default/wait-statefulset: [ "15m", "10s" ] - default/wait-service: [ "15m", "10s" ] - default/wait-clusterresourceset: [ "10m", "10s" ] - default/wait-helmrelease: [ "15m", "10s" ] - default/wait-resource: [ "10m", "10s" ] + default/wait-controllers: ["3m", "10s"] + default/wait-cluster: ["10m", "10s"] + default/wait-control-plane: ["10m", "10s"] + default/wait-worker-nodes: ["10m", "10s"] + default/wait-delete-cluster: ["30m", "10s"] + default/wait-nodes-ready: ["10m", "10s"] + default/wait-deployment: ["10m", "10s"] + default/wait-daemonset: [ "5m", "10s" ] + default/wait-statefulset: [ "10m", "10s" ] + default/wait-service: [ "10m", "10s" ] + default/wait-clusterresourceset: [ "5m", "10s" ] + default/wait-helmrelease: [ "5m", "10s" ] + default/wait-resource: [ "5m", "10s" ] From 22b09d12962255255fa4002cacb60f717d0f62c2 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 31 Oct 2025 13:36:28 +0530 Subject: [PATCH 50/55] feat: removing e2e test changes for konnector agent --- .github/workflows/e2e.yml | 259 +----------------- .../nutanix-cluster-calico-crs.yaml | 4 - .../nutanix-cluster-calico-helm-addon.yaml | 4 - .../nutanix-cluster-cilium-crs.yaml | 4 - .../nutanix-cluster-cilium-helm-addon.yaml | 4 - ...luster-with-failuredomains-cilium-crs.yaml | 4 - ...with-failuredomains-cilium-helm-addon.yaml | 4 - .../nutanix/cluster/kustomization.yaml.tmpl | 6 +- test/e2e/addon_helpers.go | 11 - test/e2e/config/caren.yaml | 6 +- 10 files changed, 7 insertions(+), 299 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 4b545bd40..0169e0477 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -73,7 +73,7 @@ jobs: df -h - name: Run e2e tests - run: devbox run -- make e2e-test E2E_LABEL='provider:${{ inputs.provider }}' E2E_SKIP='${{ inputs.skip }}' E2E_FOCUS='${{ inputs.focus }}' E2E_VERBOSE=true E2E_SKIP_CLEANUP=true + run: devbox run -- make e2e-test E2E_LABEL='provider:${{ inputs.provider }}' E2E_SKIP='${{ inputs.skip }}' E2E_FOCUS='${{ inputs.focus }}' E2E_VERBOSE=true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} @@ -91,263 +91,6 @@ jobs: KINDEST_IMAGE_TAG: ${{ inputs.kubernetes-version }} E2E_KUBERNETES_VERSION: ${{ inputs.kubernetes-version }} - - name: Collect bootstrap cluster pod logs on failure - if: failure() - run: | - set -x # Enable debug mode to see all commands - echo "===== Starting log collection =====" - mkdir -p bootstrap-pod-logs - - # Check if Kind cluster exists first - echo "Checking for Kind clusters..." - devbox run -- kind get clusters > bootstrap-pod-logs/kind-clusters.txt 2>&1 || true - cat bootstrap-pod-logs/kind-clusters.txt - - # Get kubeconfig from Kind cluster (name: caren-e2e from test/e2e/config/caren.yaml) - echo "Getting kubeconfig from Kind cluster 'caren-e2e'..." - if devbox run -- kind get kubeconfig --name caren-e2e > bootstrap-pod-logs/kubeconfig.yaml 2>&1; then - echo "✓ Successfully retrieved kubeconfig from Kind cluster" - - # Use absolute path for KUBECONFIG - export KUBECONFIG="${PWD}/bootstrap-pod-logs/kubeconfig.yaml" - echo "✓ KUBECONFIG set to: $KUBECONFIG" - - # Verify kubectl works - echo "Verifying kubectl connectivity..." - if kubectl cluster-info &> bootstrap-pod-logs/cluster-info.txt; then - echo "✓ kubectl can connect to cluster" - cat bootstrap-pod-logs/cluster-info.txt - else - echo "✗ kubectl cannot connect to cluster" - cat bootstrap-pod-logs/cluster-info.txt - exit 0 # Exit gracefully, don't fail the workflow - fi - - # Get all pods overview - echo "Getting all pods..." - kubectl get pods -A -o wide > bootstrap-pod-logs/all-pods.txt 2>&1 || echo "Failed to get pods" > bootstrap-pod-logs/all-pods.txt - echo "✓ Saved all-pods.txt" - - # Get all namespaces - kubectl get namespaces > bootstrap-pod-logs/namespaces.txt 2>&1 || true - echo "✓ Saved namespaces.txt" - - # Get CAREN controller logs (main focus - this is what you need for konnector-agent debugging) - echo "Collecting CAREN controller logs..." - kubectl logs -n caren-system -l app.kubernetes.io/name=cluster-api-runtime-extensions-nutanix --all-containers=true --tail=1000 > bootstrap-pod-logs/caren-controller.log 2>&1 || echo "Failed to get CAREN logs" > bootstrap-pod-logs/caren-controller.log - CAREN_LOG_LINES=$(wc -l < bootstrap-pod-logs/caren-controller.log) - echo "✓ Saved caren-controller.log (${CAREN_LOG_LINES} lines)" - - # Get CAREN controller pod descriptions - kubectl describe pods -n caren-system -l app.kubernetes.io/name=cluster-api-runtime-extensions-nutanix > bootstrap-pod-logs/caren-pods-describe.txt 2>&1 || true - echo "✓ Saved caren-pods-describe.txt" - - # Get all CAPI provider logs - echo "Collecting CAPI provider logs..." - for ns in capi-system capi-kubeadm-bootstrap-system capi-kubeadm-control-plane-system capd-system capn-system capa-system caaph-system; do - if kubectl get namespace "$ns" >/dev/null 2>&1; then - echo " ✓ Collecting logs from namespace: $ns" - mkdir -p "bootstrap-pod-logs/$ns" - kubectl get pods -n "$ns" -o wide > "bootstrap-pod-logs/$ns/pods.txt" 2>&1 || true - for pod in $(kubectl get pods -n "$ns" -o name 2>/dev/null); do - pod_name=$(basename "$pod") - kubectl logs -n "$ns" "$pod_name" --all-containers=true --tail=500 > "bootstrap-pod-logs/$ns/${pod_name}.log" 2>&1 || true - done - fi - done - - # Get HelmReleaseProxy and HelmChartProxy resources (critical for konnector-agent debugging) - echo "Collecting Helm addon resources..." - kubectl get helmreleaseproxies -A -o yaml > bootstrap-pod-logs/helmreleaseproxies.yaml 2>&1 || true - kubectl get helmchartproxies -A -o yaml > bootstrap-pod-logs/helmchartproxies.yaml 2>&1 || true - echo "✓ Saved Helm resources" - - # Get Prism Central credentials info from bootstrap cluster - echo "Collecting Prism Central configuration..." - { - echo "=== Prism Central Configuration from Environment ===" - echo "NUTANIX_ENDPOINT: ${NUTANIX_ENDPOINT:-NOT_SET}" - echo "NUTANIX_PORT: ${NUTANIX_PORT:-NOT_SET}" - echo "NUTANIX_USER: ${NUTANIX_USER:-NOT_SET}" - echo "NUTANIX_PASSWORD: ${NUTANIX_PASSWORD:-NOT_SET}" - echo "" - echo "=== Checking for Nutanix credentials in bootstrap cluster ===" - - # Check for any nutanix-related secrets - kubectl get secrets -A | grep -i nutanix || echo "No nutanix secrets found" - echo "" - - # Get konnector-agent HelmReleaseProxy values (shows what's being passed) - echo "=== Konnector-Agent HelmReleaseProxy Values ===" - kubectl get helmreleaseproxies -A -l helmreleaseproxy.addons.cluster.x-k8s.io/helmchartproxy-name=~konnector-agent -o jsonpath='{.items[0].spec.values}' 2>/dev/null || echo "No HelmReleaseProxy found yet" - echo "" - } > bootstrap-pod-logs/prism-central-config.txt 2>&1 || true - echo "✓ Saved Prism Central config" - - # Get all events (helpful for debugging) - echo "Collecting cluster events..." - kubectl get events -A --sort-by='.lastTimestamp' > bootstrap-pod-logs/events.txt 2>&1 || true - echo "✓ Saved events.txt" - - # Get all clusters - echo "Getting list of workload clusters..." - kubectl get clusters -A > bootstrap-pod-logs/clusters.txt 2>&1 || true - - # Collect logs from workload cluster (where konnector-agent actually runs) - echo "===== Collecting logs from WORKLOAD CLUSTER =====" - mkdir -p bootstrap-pod-logs/workload-cluster - - # Find the workload cluster name (starts with "quick-start") - WORKLOAD_CLUSTER=$(kubectl get clusters -A -o jsonpath='{.items[?(@.metadata.name contains "quick-start")].metadata.name}' 2>/dev/null | head -n 1) - WORKLOAD_NAMESPACE=$(kubectl get clusters -A -o jsonpath='{.items[?(@.metadata.name contains "quick-start")].metadata.namespace}' 2>/dev/null | head -n 1) - - if [[ -n "$WORKLOAD_CLUSTER" && -n "$WORKLOAD_NAMESPACE" ]]; then - echo "Found workload cluster: $WORKLOAD_CLUSTER in namespace $WORKLOAD_NAMESPACE" - - # Get workload cluster kubeconfig from secret - echo "Retrieving workload cluster kubeconfig..." - if kubectl get secret -n "$WORKLOAD_NAMESPACE" "${WORKLOAD_CLUSTER}-kubeconfig" -o jsonpath='{.data.value}' 2>/dev/null | base64 -d > bootstrap-pod-logs/workload-cluster/kubeconfig.yaml; then - export WORKLOAD_KUBECONFIG="${PWD}/bootstrap-pod-logs/workload-cluster/kubeconfig.yaml" - echo "✓ Retrieved workload cluster kubeconfig" - - # Verify kubeconfig has content - if [[ -s "$WORKLOAD_KUBECONFIG" ]]; then - WORKLOAD_KC_LINES=$(wc -l < "$WORKLOAD_KUBECONFIG") - echo "✓ Kubeconfig file has content (${WORKLOAD_KC_LINES} lines)" - - # Test connectivity (use --request-timeout to avoid hanging) - echo "Testing connectivity to workload cluster..." - if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=10s get nodes &> bootstrap-pod-logs/workload-cluster/cluster-info.txt; then - echo "✓ Can connect to workload cluster" - else - echo "⚠ Cannot connect to workload cluster yet, but will try collecting logs anyway" - cat bootstrap-pod-logs/workload-cluster/cluster-info.txt - fi - - # Get all pods in ntnx-system namespace (try with timeout) - echo "Getting pods in ntnx-system namespace..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get pods -n ntnx-system -o wide > bootstrap-pod-logs/workload-cluster/ntnx-system-pods.txt 2>&1 || echo "Could not get pods (cluster may not be ready yet)" > bootstrap-pod-logs/workload-cluster/ntnx-system-pods.txt - - # Get konnector-agent pod descriptions (THIS IS WHAT YOU WANT!) - echo "Getting konnector-agent pod descriptions..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s describe pods -n ntnx-system -l app.kubernetes.io/name=konnector-agent > bootstrap-pod-logs/workload-cluster/konnector-agent-describe.txt 2>&1 || echo "Could not describe konnector-agent pods" > bootstrap-pod-logs/workload-cluster/konnector-agent-describe.txt - - # Get konnector-agent pod logs - echo "Getting konnector-agent pod logs..." - for pod in $(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get pods -n ntnx-system -l app.kubernetes.io/name=konnector-agent -o name 2>/dev/null); do - pod_name=$(basename "$pod") - echo " Getting logs for $pod_name..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s logs -n ntnx-system "$pod_name" --all-containers=true --tail=1000 > "bootstrap-pod-logs/workload-cluster/${pod_name}.log" 2>&1 || true - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s logs -n ntnx-system "$pod_name" --all-containers=true --previous --tail=500 > "bootstrap-pod-logs/workload-cluster/${pod_name}-previous.log" 2>&1 || true - done - - # Get hook pod descriptions and logs (hook-preinstall is what fails) - echo "Getting hook pod information..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get pods -n ntnx-system 2>/dev/null | grep hook > bootstrap-pod-logs/workload-cluster/hook-pods.txt 2>&1 || echo "No hook pods found or cluster not accessible" > bootstrap-pod-logs/workload-cluster/hook-pods.txt - - for hook_pod in hook-preinstall hook-postinstall; do - echo " Checking for $hook_pod..." - if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get pod -n ntnx-system "$hook_pod" &>/dev/null; then - echo " Found $hook_pod, collecting info..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s describe pod -n ntnx-system "$hook_pod" > "bootstrap-pod-logs/workload-cluster/${hook_pod}-describe.txt" 2>&1 || true - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s logs -n ntnx-system "$hook_pod" --all-containers=true --tail=1000 > "bootstrap-pod-logs/workload-cluster/${hook_pod}.log" 2>&1 || true - else - echo " $hook_pod not found or not accessible" - fi - done - - # Get konnector-agent secret info with credential details - echo "Getting konnector-agent secret info..." - if kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent &>/dev/null; then - { - echo "=== Konnector-Agent Secret in Workload Cluster ===" - echo "" - echo "Secret keys present:" - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent -o jsonpath='{.data}' 2>/dev/null | grep -o '"[^"]*":' | tr -d '":' || echo "Could not get keys" - echo "" - echo "=== Secret Data (base64 decoded - FULL VALUES) ===" - - # Get username if it exists - USERNAME=$(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent -o jsonpath='{.data.username}' 2>/dev/null | base64 -d 2>/dev/null) - if [[ -n "$USERNAME" ]]; then - echo "username: $USERNAME" - else - echo "username: NOT_FOUND" - fi - - # Get password (FULL VALUE - NO MASKING) - PASSWORD=$(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent -o jsonpath='{.data.password}' 2>/dev/null | base64 -d 2>/dev/null) - if [[ -n "$PASSWORD" ]]; then - echo "password: $PASSWORD" - else - echo "password: NOT_FOUND" - fi - - # Check for old 'credentials' format (should NOT exist) - CREDENTIALS=$(kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent -o jsonpath='{.data.credentials}' 2>/dev/null | base64 -d 2>/dev/null) - if [[ -n "$CREDENTIALS" ]]; then - echo "credentials: FOUND (OLD FORMAT - THIS IS THE PROBLEM!)" - echo "credentials value: $CREDENTIALS" - else - echo "credentials: NOT_FOUND (good - using new format)" - fi - - echo "" - echo "=== Full Secret YAML ===" - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get secret -n ntnx-system konnector-agent -o yaml || true - - } > bootstrap-pod-logs/workload-cluster/konnector-agent-secret-details.txt 2>&1 || true - else - echo "konnector-agent secret not found or not accessible" > bootstrap-pod-logs/workload-cluster/konnector-agent-secret-details.txt - fi - - # Get workload cluster events - echo "Getting workload cluster events..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get events -n ntnx-system --sort-by='.lastTimestamp' > bootstrap-pod-logs/workload-cluster/events.txt 2>&1 || echo "Could not get events" > bootstrap-pod-logs/workload-cluster/events.txt - - # Get all namespaces in workload cluster - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get namespaces > bootstrap-pod-logs/workload-cluster/namespaces.txt 2>&1 || echo "Could not get namespaces" > bootstrap-pod-logs/workload-cluster/namespaces.txt - - # Try to get nodes - echo "Getting workload cluster nodes..." - kubectl --kubeconfig="$WORKLOAD_KUBECONFIG" --request-timeout=30s get nodes -o wide > bootstrap-pod-logs/workload-cluster/nodes.txt 2>&1 || echo "Could not get nodes" > bootstrap-pod-logs/workload-cluster/nodes.txt - - echo "✓ Workload cluster log collection attempted (check individual files for results)" - else - echo "✗ Kubeconfig file is empty" - fi - else - echo "✗ Failed to retrieve workload cluster kubeconfig" - fi - else - echo "No workload cluster found (this is normal if cluster creation failed early)" - fi - - echo "===== ✓ Log collection completed successfully =====" - ls -lh bootstrap-pod-logs/ - else - echo "===== ✗ Failed to get kubeconfig =====" - cat bootstrap-pod-logs/kubeconfig.yaml || echo "No kubeconfig file" - echo "Checking Docker containers..." - docker ps -a > bootstrap-pod-logs/docker-ps.txt 2>&1 || true - fi - - - name: Upload bootstrap pod logs - if: failure() - uses: actions/upload-artifact@v4 - with: - name: bootstrap-pod-logs-${{ inputs.provider }}-${{ inputs.kubernetes-version }} - path: bootstrap-pod-logs/ - if-no-files-found: warn - - - name: Cleanup Kind cluster after log collection - if: always() - run: | - echo "Cleaning up Kind cluster..." - devbox run -- kind get clusters || true - devbox run -- kind delete cluster --name caren-e2e || true - echo "Cleanup completed" - - if: success() || failure() # always run even if the previous step fails name: Publish e2e test report uses: mikepenz/action-junit-report@v5 diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index be59a091c..27d093f97 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -100,10 +100,6 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - credentials: - secretRef: - name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index b422e6705..7c173e29a 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -98,10 +98,6 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - credentials: - secretRef: - name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index 67219a427..36321f2e9 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -100,10 +100,6 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - credentials: - secretRef: - name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 91667248d..1ea9ee9a3 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -98,10 +98,6 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - credentials: - secretRef: - name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index 31d2e0310..feffe9a1a 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -136,10 +136,6 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - credentials: - secretRef: - name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index a6cdb9888..d77661102 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -134,10 +134,6 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon - konnectorAgent: - credentials: - secretRef: - name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: {} serviceLoadBalancer: configuration: diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index 41ca178a7..513656958 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -34,9 +34,9 @@ patches: - target: kind: Cluster path: ../../../patches/nutanix/cosi.yaml -- target: - kind: Cluster - path: ../../../patches/nutanix/konnector-agent.yaml +#- target: +# kind: Cluster +# path: ../../../patches/nutanix/konnector-agent.yaml - target: kind: Cluster path: ../../../patches/nutanix/ccm.yaml diff --git a/test/e2e/addon_helpers.go b/test/e2e/addon_helpers.go index 9fb90b07c..1871f4144 100644 --- a/test/e2e/addon_helpers.go +++ b/test/e2e/addon_helpers.go @@ -141,15 +141,4 @@ func WaitForAddonsToBeReadyInWorkloadCluster( HelmReleaseIntervals: input.HelmReleaseIntervals, }, ) - - WaitForKonnectorAgentToBeReadyInWorkloadCluster( - ctx, - WaitForKonnectorAgentToBeReadyInWorkloadClusterInput{ - KonnectorAgent: input.AddonsConfig.NutanixKonnectorAgent, - WorkloadCluster: input.WorkloadCluster, - ClusterProxy: input.ClusterProxy, - DeploymentIntervals: input.DeploymentIntervals, - HelmReleaseIntervals: input.HelmReleaseIntervals, - }, - ) } diff --git a/test/e2e/config/caren.yaml b/test/e2e/config/caren.yaml index 6a3924f51..1827ceebc 100644 --- a/test/e2e/config/caren.yaml +++ b/test/e2e/config/caren.yaml @@ -140,8 +140,8 @@ providers: versions: # Upgrade e2e tests will use this as the "upgrade from" version. # This should reference the most recent successful release. - - name: "{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.35}" - value: "https://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/releases/download/{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.35}/runtime-extensions-components.yaml" + - name: "{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.34}" + value: "https://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/releases/download/{go://github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix@v0.34}/runtime-extensions-components.yaml" type: "url" contract: v1beta1 files: @@ -151,7 +151,7 @@ providers: new: "--v=8" - old: --metrics-addr=127.0.0.1:8080 new: --metrics-addr=:8080 - - name: v0.37.99 # "vNext"; use manifests from local source files + - name: v0.36.99 # "vNext"; use manifests from local source files value: "file://../../../runtime-extensions-components.yaml" type: "url" contract: v1beta1 From 51f689301995695ccc9bdb0394b85872d8f080d7 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 31 Oct 2025 21:16:59 +0530 Subject: [PATCH 51/55] feat: increasing timeout interval --- test/e2e/config/caren.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/config/caren.yaml b/test/e2e/config/caren.yaml index 1827ceebc..d95698f7a 100644 --- a/test/e2e/config/caren.yaml +++ b/test/e2e/config/caren.yaml @@ -219,7 +219,7 @@ variables: intervals: default/wait-controllers: ["3m", "10s"] default/wait-cluster: ["10m", "10s"] - default/wait-control-plane: ["10m", "10s"] + default/wait-control-plane: ["20m", "10s"] default/wait-worker-nodes: ["10m", "10s"] default/wait-delete-cluster: ["30m", "10s"] default/wait-nodes-ready: ["10m", "10s"] From 2ec690c01246b62f2c9965534c4a46e8997496a5 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Fri, 31 Oct 2025 23:22:56 +0530 Subject: [PATCH 52/55] feat: Changing nutanix provider e2e as serial --- test/e2e/quick_start_test.go | 7 ++++--- test/e2e/self_hosted_test.go | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/test/e2e/quick_start_test.go b/test/e2e/quick_start_test.go index cd23a8f96..7cf785b2a 100644 --- a/test/e2e/quick_start_test.go +++ b/test/e2e/quick_start_test.go @@ -31,11 +31,12 @@ import ( var _ = Describe("Quick start", func() { for _, provider := range []string{"Docker", "AWS", "Nutanix"} { // Add any provider specific decorators here. - // Currently, only Docker requires Serial decorator to ensure the machine running the Docker e2e tests + // Docker and Nutanix require Serial decorator to ensure the machine running the e2e tests // doesn't have resources exhausted and lead to flaky tests. - // Other provider tests will run in parallel. + // This prevents parallel execution which can cause IP address pool exhaustion, + // VM capacity limits, and Prism Central API rate limiting. var providerSpecificDecorators []interface{} - if provider == "Docker" { + if provider == "Docker" || provider == "Nutanix" { providerSpecificDecorators = append(providerSpecificDecorators, Serial) } diff --git a/test/e2e/self_hosted_test.go b/test/e2e/self_hosted_test.go index d9b44772c..6cb9d4293 100644 --- a/test/e2e/self_hosted_test.go +++ b/test/e2e/self_hosted_test.go @@ -25,11 +25,12 @@ import ( var _ = Describe("Self-hosted", Serial, func() { for _, provider := range []string{"Docker", "Nutanix"} { // Add any provider specific decorators here. - // Currently, only Docker requires Serial decorator to ensure the machine running the Docker e2e tests + // Docker and Nutanix require Serial decorator to ensure the machine running the e2e tests // doesn't have resources exhausted and lead to flaky tests. - // Other provider tests will run in parallel. + // This prevents parallel execution which can cause IP address pool exhaustion, + // VM capacity limits, and Prism Central API rate limiting. var providerSpecificDecorators []interface{} - if provider == "Docker" { + if provider == "Docker" || provider == "Nutanix" { providerSpecificDecorators = append(providerSpecificDecorators, Serial) } Context(provider, Label("provider:"+provider), providerSpecificDecorators, func() { From e949fff35ad731c003eaa2480129ea6af7ccea77 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Sat, 1 Nov 2025 00:19:36 +0530 Subject: [PATCH 53/55] feat: Revert- Changing nutanix provider e2e as serial This reverts commit 2ec690c01246b62f2c9965534c4a46e8997496a5. --- test/e2e/quick_start_test.go | 7 +++---- test/e2e/self_hosted_test.go | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/test/e2e/quick_start_test.go b/test/e2e/quick_start_test.go index 7cf785b2a..cd23a8f96 100644 --- a/test/e2e/quick_start_test.go +++ b/test/e2e/quick_start_test.go @@ -31,12 +31,11 @@ import ( var _ = Describe("Quick start", func() { for _, provider := range []string{"Docker", "AWS", "Nutanix"} { // Add any provider specific decorators here. - // Docker and Nutanix require Serial decorator to ensure the machine running the e2e tests + // Currently, only Docker requires Serial decorator to ensure the machine running the Docker e2e tests // doesn't have resources exhausted and lead to flaky tests. - // This prevents parallel execution which can cause IP address pool exhaustion, - // VM capacity limits, and Prism Central API rate limiting. + // Other provider tests will run in parallel. var providerSpecificDecorators []interface{} - if provider == "Docker" || provider == "Nutanix" { + if provider == "Docker" { providerSpecificDecorators = append(providerSpecificDecorators, Serial) } diff --git a/test/e2e/self_hosted_test.go b/test/e2e/self_hosted_test.go index 6cb9d4293..d9b44772c 100644 --- a/test/e2e/self_hosted_test.go +++ b/test/e2e/self_hosted_test.go @@ -25,12 +25,11 @@ import ( var _ = Describe("Self-hosted", Serial, func() { for _, provider := range []string{"Docker", "Nutanix"} { // Add any provider specific decorators here. - // Docker and Nutanix require Serial decorator to ensure the machine running the e2e tests + // Currently, only Docker requires Serial decorator to ensure the machine running the Docker e2e tests // doesn't have resources exhausted and lead to flaky tests. - // This prevents parallel execution which can cause IP address pool exhaustion, - // VM capacity limits, and Prism Central API rate limiting. + // Other provider tests will run in parallel. var providerSpecificDecorators []interface{} - if provider == "Docker" || provider == "Nutanix" { + if provider == "Docker" { providerSpecificDecorators = append(providerSpecificDecorators, Serial) } Context(provider, Label("provider:"+provider), providerSpecificDecorators, func() { From c4b32a2c111b21a7a2fcbcb0c52d82a41aedbf25 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Sat, 1 Nov 2025 01:02:19 +0530 Subject: [PATCH 54/55] feat: reverting wait interval Co-authored-by: Dimitri Koshkin --- test/e2e/config/caren.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/config/caren.yaml b/test/e2e/config/caren.yaml index 4fc9d4d9b..6a3924f51 100644 --- a/test/e2e/config/caren.yaml +++ b/test/e2e/config/caren.yaml @@ -219,7 +219,7 @@ variables: intervals: default/wait-controllers: ["3m", "10s"] default/wait-cluster: ["10m", "10s"] - default/wait-control-plane: ["20m", "10s"] + default/wait-control-plane: ["10m", "10s"] default/wait-worker-nodes: ["10m", "10s"] default/wait-delete-cluster: ["30m", "10s"] default/wait-nodes-ready: ["10m", "10s"] From a7e9579c9ade44f136c8b2646d99f4f3d311bf40 Mon Sep 17 00:00:00 2001 From: vijayaraghavanr31 Date: Sat, 1 Nov 2025 01:10:09 +0530 Subject: [PATCH 55/55] feat: enabling e2e for konnector agent --- .../capi-quick-start/nutanix-cluster-calico-crs.yaml | 4 ++++ .../nutanix-cluster-calico-helm-addon.yaml | 4 ++++ .../capi-quick-start/nutanix-cluster-cilium-crs.yaml | 4 ++++ .../nutanix-cluster-cilium-helm-addon.yaml | 4 ++++ ...utanix-cluster-with-failuredomains-cilium-crs.yaml | 4 ++++ ...cluster-with-failuredomains-cilium-helm-addon.yaml | 4 ++++ .../bases/nutanix/cluster/kustomization.yaml.tmpl | 6 +++--- test/e2e/addon_helpers.go | 11 +++++++++++ 8 files changed, 38 insertions(+), 3 deletions(-) diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 27d093f97..be59a091c 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -100,6 +100,10 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index 7c173e29a..b422e6705 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -98,6 +98,10 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index 36321f2e9..67219a427 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -100,6 +100,10 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 1ea9ee9a3..91667248d 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -98,6 +98,10 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: {} serviceLoadBalancer: configuration: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml index feffe9a1a..31d2e0310 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-crs.yaml @@ -136,6 +136,10 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: strategy: ClusterResourceSet serviceLoadBalancer: diff --git a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml index d77661102..a6cdb9888 100644 --- a/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-with-failuredomains-cilium-helm-addon.yaml @@ -134,6 +134,10 @@ spec: strategy: HelmAddon snapshotController: strategy: HelmAddon + konnectorAgent: + credentials: + secretRef: + name: ${CLUSTER_NAME}-pc-creds-for-konnector-agent nfd: {} serviceLoadBalancer: configuration: diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index 513656958..41ca178a7 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -34,9 +34,9 @@ patches: - target: kind: Cluster path: ../../../patches/nutanix/cosi.yaml -#- target: -# kind: Cluster -# path: ../../../patches/nutanix/konnector-agent.yaml +- target: + kind: Cluster + path: ../../../patches/nutanix/konnector-agent.yaml - target: kind: Cluster path: ../../../patches/nutanix/ccm.yaml diff --git a/test/e2e/addon_helpers.go b/test/e2e/addon_helpers.go index 1871f4144..9fb90b07c 100644 --- a/test/e2e/addon_helpers.go +++ b/test/e2e/addon_helpers.go @@ -141,4 +141,15 @@ func WaitForAddonsToBeReadyInWorkloadCluster( HelmReleaseIntervals: input.HelmReleaseIntervals, }, ) + + WaitForKonnectorAgentToBeReadyInWorkloadCluster( + ctx, + WaitForKonnectorAgentToBeReadyInWorkloadClusterInput{ + KonnectorAgent: input.AddonsConfig.NutanixKonnectorAgent, + WorkloadCluster: input.WorkloadCluster, + ClusterProxy: input.ClusterProxy, + DeploymentIntervals: input.DeploymentIntervals, + HelmReleaseIntervals: input.HelmReleaseIntervals, + }, + ) }