├── docs ├── vscode-integration │ ├── settings.json │ ├── README.md │ └── tasks.json └── getting_started.md ├── pkg └── client │ ├── testdata │ ├── invalidTestConfigMissingCredentialRef.json │ ├── validTestConfig.json │ ├── validTestCredentials.json │ ├── validTestManagerCredentials.json │ ├── validTestCA.pem │ └── validTestManagerCA.pem │ ├── cache.go │ ├── cache_test.go │ └── status.go ├── config ├── prometheus │ ├── kustomization.yaml │ └── monitor.yaml ├── rbac │ ├── service_account.yaml │ ├── auth_proxy_client_clusterrole.yaml │ ├── role_binding.yaml │ ├── auth_proxy_role_binding.yaml │ ├── auth_proxy_service.yaml │ ├── leader_election_role_binding.yaml │ ├── auth_proxy_role.yaml │ ├── nutanixcluster_viewer_role.yaml │ ├── nutanixmachine_viewer_role.yaml │ ├── nutanixmachinetemplate_viewer_role.yaml │ ├── nutanixcluster_editor_role.yaml │ ├── nutanixmachine_editor_role.yaml │ ├── nutanixmachinetemplate_editor_role.yaml │ ├── leader_election_role.yaml │ ├── nutanixclustertemplate_viewer_role.yaml │ ├── nutanixclustertemplate_editor_role.yaml │ ├── kustomization.yaml │ └── role.yaml ├── manager │ ├── controller_manager_config.yaml │ └── kustomization.yaml ├── crd │ ├── patches │ │ ├── cainjection_in_nutanixclusters.yaml │ │ ├── cainjection_in_nutanixmachines.yaml │ │ ├── cainjection_in_nutanixclustertemplates.yaml │ │ ├── cainjection_in_nutanixmachinetemplates.yaml │ │ ├── webhook_in_nutanixclusters.yaml │ │ ├── webhook_in_nutanixmachines.yaml │ │ ├── webhook_in_nutanixclustertemplates.yaml │ │ └── webhook_in_nutanixmachinetemplates.yaml │ ├── kustomizeconfig.yaml │ └── kustomization.yaml └── default │ ├── manager_config_patch.yaml │ ├── manager_auth_proxy_patch.yaml │ └── kustomization.yaml ├── tools └── imagebuilder │ ├── terraform │ ├── outputs.tf │ ├── versions.tf │ ├── cloud-init.tpl │ ├── variables.tf │ └── scripts │ │ ├── build_os_image.sh │ │ └── install_prerequisites.sh │ ├── delete_image_build_vm.sh │ ├── create_image_build.sh │ └── README.md ├── templates ├── topology │ ├── ccm-patch.yaml │ ├── cm.yaml │ ├── kustomization.yaml │ ├── secret.yaml │ └── cluster-with-topology.yaml ├── base │ ├── cm.yaml │ ├── kustomization.yaml │ ├── secret.yaml │ ├── nutanix-cluster.yaml │ ├── cluster-without-topology.yaml │ ├── mhc.yaml │ ├── md.yaml │ ├── ccm-patch.yaml │ ├── kct.yaml │ └── nmt.yaml ├── csi │ ├── csi-patch.yaml │ ├── nutanix-csi.yaml │ ├── nutanix-csi-webhook.yaml │ ├── nutanix-csi-crs.yaml │ └── kustomization.yaml ├── csi3 │ ├── csi-patch.yaml │ ├── nutanix-csi.yaml │ ├── nutanix-csi-webhook.yaml │ ├── nutanix-csi-crs.yaml │ ├── kustomization.yaml │ └── nutanix-csi-secret.yaml ├── clusterclass │ ├── nct.yaml │ ├── kustomization.yaml │ ├── kct.yaml │ ├── nmt-cp.yaml │ └── nmt-md.yaml ├── ccm │ ├── kustomization.yaml │ ├── nutanix-ccm-crs.yaml │ └── nutanix-ccm-secret.yaml ├── failure-domains │ ├── kustomization.yaml │ ├── failure-domains-patch.yaml │ └── failure-domains.yaml ├── image-lookup │ ├── kustomization.yaml │ └── lookup-patch.yaml └── testdata │ ├── clusterctl-init.yaml │ ├── cluster-with-control-plane-endpoint.yaml │ ├── cluster-with-project-name.yaml │ ├── cluster-with-project-uuid.yaml │ ├── cluster-with-subnets.yaml │ ├── cluster-with-gpu.yaml │ ├── cluster-with-additional-categories.yaml │ └── cluster-with-failure-domain.yaml ├── test ├── e2e │ ├── data │ │ ├── infrastructure-nutanix │ │ │ ├── v1beta1 │ │ │ │ ├── base │ │ │ │ │ ├── cni-patch.yaml │ │ │ │ │ └── crs.yaml │ │ │ │ ├── cluster-template-clusterclass │ │ │ │ │ └── kustomization.yaml │ │ │ │ ├── no-kubeproxy │ │ │ │ │ ├── cluster-template-topology │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-csi │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-no-nmt │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-project │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-no-secret │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-upgrades │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-kcp-scale-in │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-failure-domains │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-kcp-remediation │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-md-remediation │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-clusterclass │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-no-nutanix-cluster │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── cluster-template-additional-categories │ │ │ │ │ │ └── kustomization.yaml │ │ │ │ │ ├── no-kubeproxy.yaml │ │ │ │ │ └── no-kubeproxy-clusterclass.yaml │ │ │ │ ├── cluster-template-no-nutanix-cluster │ │ │ │ │ ├── nc.yaml │ │ │ │ │ └── kustomization.yaml │ │ │ │ ├── cluster-template-additional-categories │ │ │ │ │ ├── kustomization.yaml │ │ │ │ │ └── nmt.yaml │ │ │ │ ├── cluster-template │ │ │ │ │ └── kustomization.yaml │ │ │ │ ├── cluster-template-topology │ │ │ │ │ └── kustomization.yaml │ │ │ │ ├── cluster-template-kcp-scale-in │ │ │ │ │ ├── kustomization.yaml │ │ │ │ │ └── cluster-with-kcp.yaml │ │ │ │ ├── cluster-template-md-remediation │ │ │ │ │ ├── md.yaml │ │ │ │ │ ├── mhc.yaml │ │ │ │ │ └── kustomization.yaml │ │ │ │ ├── cluster-template-csi │ │ │ │ │ ├── kustomization.yaml │ │ │ │ │ ├── kct.yaml │ │ │ │ │ └── kcp.yaml │ │ │ │ ├── cluster-template-csi3 │ │ │ │ │ ├── kustomization.yaml │ │ │ │ │ ├── kct.yaml │ │ │ │ │ └── kcp.yaml │ │ │ │ ├── cluster-template-project │ │ │ │ │ ├── nmt.yaml │ │ │ │ │ └── kustomization.yaml │ │ │ │ ├── cluster-template-image-lookup │ │ │ │ │ ├── kustomization.yaml │ │ │ │ │ └── lookup-patch.yaml │ │ │ │ ├── cluster-template-failure-domains │ │ │ │ │ ├── failure-domain-nmt.yaml │ │ │ │ │ ├── kustomization.yaml │ │ │ │ │ └── failure-domain-patch.yaml │ │ │ │ ├── cluster-template-failure-domains-migration │ │ │ │ │ ├── failure-domain-nmt.yaml │ │ │ │ │ ├── kustomization.yaml │ │ │ │ │ └── failure-domain-patch.yaml │ │ │ │ ├── cluster-template-kcp-remediation │ │ │ │ │ ├── mhc.yaml │ │ │ │ │ └── kustomization.yaml │ │ │ │ ├── cluster-template-no-nmt │ │ │ │ │ └── kustomization.yaml │ │ │ │ ├── cluster-template-no-secret │ │ │ │ │ └── kustomization.yaml │ │ │ │ └── cluster-template-upgrades │ │ │ │ │ ├── kustomization.yaml │ │ │ │ │ └── nmt.yaml │ │ │ └── v1.7.1 │ │ │ │ ├── base │ │ │ │ ├── cni-patch.yaml │ │ │ │ ├── crs.yaml │ │ │ │ └── controlplane-vip.yaml │ │ │ │ └── cluster-template │ │ │ │ └── kustomization.yaml │ │ ├── kubetest │ │ │ └── conformance.yaml │ │ └── shared │ │ │ └── metadata.yaml │ ├── README.md │ ├── k8s_conformance_test.go │ ├── md_rollout_test.go │ ├── mhc_remediations_test.go │ ├── log │ │ └── log.go │ ├── clusterctl_move_test.go │ ├── clusterclass_changes_test.go │ ├── capx_quick_start_test.go │ └── cluster_topology_k8s_configs.go └── helpers │ └── prism-go-client │ └── v3 │ └── client.go ├── OWNERS ├── testdata └── kubeconfig ├── .envrc ├── .github ├── codecov.yml ├── workflows │ ├── calico-conformance-periodic.yaml │ ├── cilium-conformance-periodic.yaml │ ├── flannel-conformance-periodic.yaml │ ├── cilium-without-kubeproxy-conformance-periodic.yaml │ ├── conventional-pr-title.yaml │ ├── trivy-scan.yaml │ ├── codeql-analysis.yml │ └── release.yaml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── release.yaml ├── dependabot.yml └── PULL_REQUEST_TEMPLATE.md ├── .yamllint ├── clusterctl.yaml.tmpl ├── tilt-provider.json ├── hack ├── boilerplate.go.txt └── flakes │ ├── flake.lock │ └── flake.nix ├── .golangci.yaml ├── api └── v1beta1 │ ├── doc.go │ ├── nutanixcluster_conversion.go │ ├── nutanixmachine_conversion.go │ ├── nutanixmachinetemplate_conversion.go │ ├── groupversion_info.go │ ├── suite_test.go │ ├── nutanixclustertemplate_types.go │ ├── nutanix_types_test.go │ └── nutanixmachinetemplate_types.go ├── devbox.json ├── hooks └── build-finalize.sh ├── package ├── docker │ └── Dockerfile └── certs │ └── digicertca.crt ├── scripts ├── csi_nutanix_update.sh ├── ccm_nutanix_update.sh ├── csi3_nutanix_update.sh └── gen-self-cert.sh ├── metadata.yaml ├── PROJECT ├── controllers ├── options.go └── suite_test.go ├── CONTRIBUTING.md ├── make ├── test-cluster-without-topology.mk └── test-cluster-with-topology.mk └── .gitignore /docs/vscode-integration/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "go.testEnvFile": "${workspaceFolder}/.vscode/test.env" 3 | } 4 | -------------------------------------------------------------------------------- /pkg/client/testdata/invalidTestConfigMissingCredentialRef.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "cluster-endpoint", 3 | "port": 9440 4 | } -------------------------------------------------------------------------------- /config/prometheus/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - monitor.yaml 3 | apiVersion: kustomize.config.k8s.io/v1beta1 4 | kind: Kustomization 5 | -------------------------------------------------------------------------------- /config/rbac/service_account.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | -------------------------------------------------------------------------------- /tools/imagebuilder/terraform/outputs.tf: -------------------------------------------------------------------------------- 1 | output "ip_address" { 2 | value = lookup(nutanix_virtual_machine.build_vm.nic_list.0.ip_endpoint_list[0], "ip") 3 | } 4 | -------------------------------------------------------------------------------- /templates/topology/ccm-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | ccm: "nutanix" 6 | name: "${CLUSTER_NAME}" 7 | -------------------------------------------------------------------------------- /tools/imagebuilder/terraform/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | nutanix = { 4 | source = "nutanix/nutanix" 5 | version = "1.4.1" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /templates/base/cm.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: ${CLUSTER_NAME}-pc-trusted-ca-bundle 6 | binaryData: 7 | ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} 8 | -------------------------------------------------------------------------------- /templates/csi/csi-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | csi: "nutanix" 6 | name: "${CLUSTER_NAME}" 7 | namespace: "${NAMESPACE}" 8 | -------------------------------------------------------------------------------- /templates/csi3/csi-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | csi: "nutanix" 6 | name: "${CLUSTER_NAME}" 7 | namespace: "${NAMESPACE}" 8 | -------------------------------------------------------------------------------- /templates/topology/cm.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: ${CLUSTER_NAME}-pc-trusted-ca-bundle 6 | binaryData: 7 | ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} 8 | -------------------------------------------------------------------------------- /pkg/client/testdata/validTestConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "cluster-endpoint", 3 | "port": 9440, 4 | "credentialRef": { 5 | "kind": "Secret", 6 | "name": "creds", 7 | "namespace": "test" 8 | } 9 | } -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/base/cni-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | cni: ${CLUSTER_NAME}-crs-cni 6 | name: "${CLUSTER_NAME}" 7 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | reviewers: 2 | - adiantum 3 | - deepakm-ntnx 4 | - thunderboltsid 5 | - tuxtof 6 | - yannickstruyf3 7 | approvers: 8 | - adiantum 9 | - deepakm-ntnx 10 | - thunderboltsid 11 | - tuxtof 12 | - yannickstruyf3 13 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-clusterclass/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/clusterclass/ 5 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-topology/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-topology/ 5 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-no-nutanix-cluster/nc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 2 | kind: NutanixCluster 3 | metadata: 4 | name: "${CLUSTER_NAME}" 5 | $patch: delete 6 | -------------------------------------------------------------------------------- /test/e2e/data/kubetest/conformance.yaml: -------------------------------------------------------------------------------- 1 | ginkgo.focus: \[Conformance\] 2 | ginkgo.skip: \[Serial\] 3 | disable-log-dump: true 4 | ginkgo.show-node-events: true 5 | ginkgo.flake-attempts: 3 6 | ginkgo.trace: true 7 | ginkgo.v: true 8 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_client_clusterrole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics-reader 5 | rules: 6 | - nonResourceURLs: 7 | - "/metrics" 8 | verbs: 9 | - get 10 | -------------------------------------------------------------------------------- /pkg/client/testdata/validTestCredentials.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "basic_auth", 4 | "data": { 5 | "prismCentral":{ 6 | "username": "user", 7 | "password": "password" 8 | } 9 | } 10 | } 11 | ] -------------------------------------------------------------------------------- /templates/clusterclass/nct.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 2 | kind: NutanixClusterTemplate 3 | metadata: 4 | name: nutanix-quick-start-nct 5 | spec: 6 | template: 7 | spec: 8 | failureDomains: [] 9 | -------------------------------------------------------------------------------- /templates/csi/nutanix-csi.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: nutanix-csi 6 | data: 7 | ns.yaml: |- 8 | apiVersion: v1 9 | kind: Namespace 10 | metadata: 11 | name: ntnx-system 12 | -------------------------------------------------------------------------------- /templates/csi3/nutanix-csi.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: nutanix-csi 6 | data: 7 | ns.yaml: |- 8 | apiVersion: v1 9 | kind: Namespace 10 | metadata: 11 | name: ntnx-system 12 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1.7.1/base/cni-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | cni: ${CLUSTER_NAME}-crs-cni 6 | name: "${CLUSTER_NAME}" 7 | namespace: "${NAMESPACE}" 8 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-additional-categories/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../cluster-template 5 | patches: 6 | - path: ./nmt.yaml 7 | -------------------------------------------------------------------------------- /pkg/client/testdata/validTestManagerCredentials.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "basic_auth", 4 | "data": { 5 | "prismCentral":{ 6 | "username": "admin", 7 | "password": "adminpassword" 8 | } 9 | } 10 | } 11 | ] -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /templates/clusterclass/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - ./nct.yaml 6 | - ./clusterclass.yaml 7 | - ./nmt-cp.yaml 8 | - ./nmt-md.yaml 9 | - ./kcpt.yaml 10 | - ./kct.yaml 11 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-csi/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-csi/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /templates/topology/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | resources: 5 | - ../ccm 6 | - ./cm.yaml 7 | - ./cluster-with-topology.yaml 8 | - ./secret.yaml 9 | 10 | patches: 11 | - path: ./ccm-patch.yaml 12 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-no-nmt/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-no-nmt/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-project/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-project/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /testdata/kubeconfig: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | clusters: 3 | - cluster: 4 | server: https://example.com:6443 5 | name: test 6 | contexts: 7 | - context: 8 | cluster: test 9 | name: test 10 | current-context: test 11 | kind: Config 12 | preferences: {} 13 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/base/ 5 | - ../base/crs.yaml 6 | patches: 7 | - path: ../base/cni-patch.yaml 8 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-no-secret/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-no-secret/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-upgrades/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-upgrades/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-kcp-scale-in/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-kcp-scale-in/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-failure-domains/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-failure-domains/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-kcp-remediation/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-kcp-remediation/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-md-remediation/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-md-remediation/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | # Automatically sets up your devbox environment whenever you cd into this 2 | # directory via our direnv integration: 3 | 4 | eval "$(devbox generate direnv --print-envrc)" 5 | 6 | # check out https://www.jetpack.io/devbox/docs/ide_configuration/direnv/ 7 | # for more details 8 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-topology/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/topology/ 5 | - ../base/crs.yaml 6 | patches: 7 | - path: ../base/cni-patch.yaml 8 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-clusterclass/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-clusterclass/ 5 | patches: 6 | - path: ../no-kubeproxy-clusterclass.yaml 7 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-no-nutanix-cluster/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-no-nutanix-cluster/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-kcp-scale-in/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../cluster-template-upgrades 5 | patches: 6 | - path: ../base/cni-patch.yaml 7 | - path: ./cluster-with-kcp.yaml 8 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/cluster-template-additional-categories/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../cluster-template-additional-categories/ 5 | patches: 6 | - path: ../no-kubeproxy.yaml 7 | -------------------------------------------------------------------------------- /templates/ccm/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | configMapGenerator: 5 | - behavior: merge 6 | files: 7 | - nutanix-ccm.yaml 8 | name: nutanix-ccm 9 | 10 | resources: 11 | - ./nutanix-ccm-crs.yaml 12 | - ./nutanix-ccm-secret.yaml 13 | -------------------------------------------------------------------------------- /templates/csi/nutanix-csi-webhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: csi-snapshot-validation-webhook-cert 6 | namespace: ntnx-system 7 | type: kubernetes.io/tls 8 | data: 9 | ca.crt: ${WEBHOOK_CA} 10 | tls.key: ${WEBHOOK_KEY} 11 | tls.crt: ${WEBHOOK_CERT} 12 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-md-remediation/md.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: MachineDeployment 3 | metadata: 4 | name: "${CLUSTER_NAME}-wmd" 5 | spec: 6 | template: 7 | metadata: 8 | labels: 9 | "e2e.remediation.label": "" 10 | -------------------------------------------------------------------------------- /templates/csi3/nutanix-csi-webhook.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: csi-snapshot-validation-webhook-cert 6 | namespace: ntnx-system 7 | type: kubernetes.io/tls 8 | data: 9 | ca.crt: ${WEBHOOK_CA} 10 | tls.key: ${WEBHOOK_KEY} 11 | tls.crt: ${WEBHOOK_CERT} 12 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-kcp-scale-in/cluster-with-kcp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 3 | kind: KubeadmControlPlane 4 | metadata: 5 | name: "${CLUSTER_NAME}-kcp" 6 | spec: 7 | rolloutStrategy: 8 | rollingUpdate: 9 | maxSurge: 0 10 | -------------------------------------------------------------------------------- /templates/csi/nutanix-csi-crs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: addons.cluster.x-k8s.io/v1beta1 2 | kind: ClusterResourceSet 3 | metadata: 4 | name: nutanix-csi-crs 5 | spec: 6 | clusterSelector: 7 | matchLabels: 8 | csi: nutanix 9 | resources: 10 | - kind: ConfigMap 11 | name: nutanix-csi 12 | strategy: ApplyOnce 13 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-csi/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/csi/ 5 | - ../base/crs.yaml 6 | patches: 7 | - path: ../base/cni-patch.yaml 8 | - path: ./kcp.yaml 9 | - path: ./kct.yaml 10 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-csi3/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/csi3/ 5 | - ../base/crs.yaml 6 | patches: 7 | - path: ../base/cni-patch.yaml 8 | - path: ./kcp.yaml 9 | - path: ./kct.yaml 10 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | require_ci_to_pass: true 3 | 4 | ignore: 5 | # ignore all generated controller-gen and conversion-gen code 6 | - "**/zz_generated.*.go" 7 | 8 | coverage: 9 | precision: 2 10 | round: down 11 | range: 75..100 12 | status: 13 | patch: 14 | default: 15 | target: 75% 16 | -------------------------------------------------------------------------------- /tools/imagebuilder/terraform/cloud-init.tpl: -------------------------------------------------------------------------------- 1 | #cloud-config 2 | 3 | # set the hostname 4 | fqdn: ${vmname} 5 | 6 | #cloud-config 7 | users: 8 | - name: ${username} 9 | sudo: ALL=(ALL) NOPASSWD:ALL 10 | shell: /bin/bash 11 | ssh-authorized-keys: 12 | - ${public_key} 13 | 14 | cloud_final_modules: 15 | - [ssh, always] -------------------------------------------------------------------------------- /config/manager/controller_manager_config.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: controller-runtime.sigs.k8s.io/v1alpha1 2 | kind: ControllerManagerConfig 3 | health: 4 | healthProbeBindAddress: :8081 5 | metrics: 6 | bindAddress: 127.0.0.1:8080 7 | webhook: 8 | port: 9443 9 | leaderElection: 10 | leaderElect: true 11 | resourceName: f265110d.cluster.x-k8s.io 12 | -------------------------------------------------------------------------------- /config/rbac/role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: manager-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: manager-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-project/nmt.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 3 | kind: NutanixMachineTemplate 4 | metadata: 5 | name: "${CLUSTER_NAME}-mt-0" 6 | spec: 7 | template: 8 | spec: 9 | project: 10 | type: name 11 | name: "${NUTANIX_PROJECT_NAME}" 12 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | extends: default 2 | 3 | rules: 4 | indentation: disable 5 | document-start: disable 6 | comments: disable 7 | line-length: disable 8 | 9 | ignore: | 10 | templates/csi/nutanix-csi-snapshot.yaml 11 | templates/csi/nutanix-csi-storage.yaml 12 | templates/csi3/nutanix-csi-snapshot.yaml 13 | templates/csi3/nutanix-csi-storage.yaml 14 | -------------------------------------------------------------------------------- /clusterctl.yaml.tmpl: -------------------------------------------------------------------------------- 1 | CLUSTERCTL_LOG_LEVEL: 10 2 | EXP_CLUSTER_RESOURCE_SET: "true" 3 | CLUSTER_TOPOLOGY: "true" 4 | 5 | providers: 6 | # add a custom provider 7 | - name: "nutanix" 8 | url: "file://${HOME}/.cluster-api/overrides/infrastructure-nutanix/${LOCAL_PROVIDER_VERSION}/infrastructure-components.yaml" 9 | type: "InfrastructureProvider" 10 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: proxy-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: proxy-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | control-plane: controller-manager 6 | name: controller-manager-metrics-service 7 | namespace: system 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | control-plane: controller-manager 15 | -------------------------------------------------------------------------------- /docs/getting_started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | The Cluster API Provider Nutanix Cloud Infrastructure (CAPX) documentation has been moved to [opendocs.nutanix.com](https://opendocs.nutanix.com/). Refer to [https://opendocs.nutanix.com/capx/latest/getting_started](https://opendocs.nutanix.com/capx/latest/getting_started/) for the latest version of the getting started guide. -------------------------------------------------------------------------------- /config/rbac/leader_election_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: RoleBinding 3 | metadata: 4 | name: leader-election-rolebinding 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: Role 8 | name: leader-election-role 9 | subjects: 10 | - kind: ServiceAccount 11 | name: controller-manager 12 | namespace: system 13 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_nutanixclusters.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 7 | name: nutanixclusters.infrastructure.cluster.x-k8s.io 8 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_nutanixmachines.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 7 | name: nutanixmachines.infrastructure.cluster.x-k8s.io 8 | -------------------------------------------------------------------------------- /config/rbac/auth_proxy_role.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: proxy-role 5 | rules: 6 | - apiGroups: 7 | - authentication.k8s.io 8 | resources: 9 | - tokenreviews 10 | verbs: 11 | - create 12 | - apiGroups: 13 | - authorization.k8s.io 14 | resources: 15 | - subjectaccessreviews 16 | verbs: 17 | - create 18 | -------------------------------------------------------------------------------- /templates/csi3/nutanix-csi-crs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: addons.cluster.x-k8s.io/v1beta1 2 | kind: ClusterResourceSet 3 | metadata: 4 | name: nutanix-csi-crs 5 | spec: 6 | clusterSelector: 7 | matchLabels: 8 | csi: nutanix 9 | resources: 10 | - kind: ConfigMap 11 | name: nutanix-csi 12 | - kind: Secret 13 | name: nutanix-csi-secret 14 | strategy: ApplyOnce 15 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1.7.1/cluster-template/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - https://github.com/nutanix-cloud-native/cluster-api-provider-nutanix/releases/download/v1.7.1/cluster-template.yaml 5 | - ../base/crs.yaml 6 | patches: 7 | - path: ../base/cni-patch.yaml 8 | - path: ../base/controlplane-vip.yaml 9 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_nutanixclustertemplates.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 7 | name: nutanixclustertemplates.infrastructure.cluster.x-k8s.io 8 | -------------------------------------------------------------------------------- /config/crd/patches/cainjection_in_nutanixmachinetemplates.yaml: -------------------------------------------------------------------------------- 1 | # The following patch adds a directive for certmanager to inject CA into the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | annotations: 6 | cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) 7 | name: nutanixmachinetemplates.infrastructure.cluster.x-k8s.io 8 | -------------------------------------------------------------------------------- /templates/base/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: ${NAMESPACE} 5 | 6 | 7 | resources: 8 | - ../ccm 9 | - ./cm.yaml 10 | - ./secret.yaml 11 | - ./nutanix-cluster.yaml 12 | - ./cluster-without-topology.yaml 13 | - ./kcp.yaml 14 | - ./kct.yaml 15 | - ./nmt.yaml 16 | - ./md.yaml 17 | - ./mhc.yaml 18 | patches: 19 | - path: ./ccm-patch.yaml 20 | -------------------------------------------------------------------------------- /templates/base/secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: "${CLUSTER_NAME}" 6 | stringData: 7 | credentials: | 8 | [ 9 | { 10 | "type": "basic_auth", 11 | "data": { 12 | "prismCentral":{ 13 | "username": "${NUTANIX_USER}", 14 | "password": "${NUTANIX_PASSWORD}" 15 | } 16 | } 17 | } 18 | ] 19 | -------------------------------------------------------------------------------- /templates/csi/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | configMapGenerator: 5 | - behavior: merge 6 | files: 7 | - nutanix-csi-storage.yaml 8 | - nutanix-csi-snapshot.yaml 9 | - nutanix-csi-webhook.yaml 10 | name: nutanix-csi 11 | 12 | resources: 13 | - ../base/ 14 | - nutanix-csi.yaml 15 | - nutanix-csi-crs.yaml 16 | 17 | patches: 18 | - path: csi-patch.yaml 19 | -------------------------------------------------------------------------------- /templates/topology/secret.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: "${CLUSTER_NAME}-pc-creds" 6 | stringData: 7 | credentials: | 8 | [ 9 | { 10 | "type": "basic_auth", 11 | "data": { 12 | "prismCentral":{ 13 | "username": "${NUTANIX_USER}", 14 | "password": "${NUTANIX_PASSWORD}" 15 | } 16 | } 17 | } 18 | ] 19 | -------------------------------------------------------------------------------- /.github/workflows/calico-conformance-periodic.yaml: -------------------------------------------------------------------------------- 1 | name: Periodic Conformance Test with Calico 2 | on: 3 | schedule: 4 | - cron: "0 6 * * *" # 6 AM 5 | jobs: 6 | e2e: 7 | uses: ./.github/workflows/e2e.yaml 8 | with: 9 | e2e-labels: "conformance || cluster-upgrade-conformance" 10 | make-target: "test-e2e-calico" 11 | secrets: inherit 12 | permissions: 13 | contents: read 14 | checks: write 15 | -------------------------------------------------------------------------------- /tilt-provider.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nutanix", 3 | "config": { 4 | "image": "ghcr.io/nutanix-cloud-native/cluster-api-provider-nutanix/controller", 5 | "live_reload_deps": [ 6 | "main.go", 7 | "go.mod", 8 | "go.sum", 9 | "api", 10 | "controllers", 11 | "pkg", 12 | "config" 13 | ], 14 | "label": "CAPX" 15 | } 16 | } -------------------------------------------------------------------------------- /.github/workflows/cilium-conformance-periodic.yaml: -------------------------------------------------------------------------------- 1 | name: Periodic Conformance Test with Cilium 2 | on: 3 | schedule: 4 | - cron: "0 0 * * *" # Midnight 5 | jobs: 6 | e2e: 7 | uses: ./.github/workflows/e2e.yaml 8 | with: 9 | e2e-labels: "conformance || cluster-upgrade-conformance" 10 | make-target: "test-e2e-cilium" 11 | secrets: inherit 12 | permissions: 13 | contents: read 14 | checks: write 15 | -------------------------------------------------------------------------------- /.github/workflows/flannel-conformance-periodic.yaml: -------------------------------------------------------------------------------- 1 | name: Periodic Conformance Test with Flannel 2 | on: 3 | schedule: 4 | - cron: "0 12 * * *" # Noon 5 | jobs: 6 | e2e: 7 | uses: ./.github/workflows/e2e.yaml 8 | with: 9 | e2e-labels: "conformance || cluster-upgrade-conformance" 10 | make-target: "test-e2e-flannel" 11 | secrets: inherit 12 | permissions: 13 | contents: read 14 | checks: write 15 | -------------------------------------------------------------------------------- /config/manager/kustomization.yaml: -------------------------------------------------------------------------------- 1 | resources: 2 | - manager.yaml 3 | 4 | generatorOptions: 5 | disableNameSuffixHash: true 6 | 7 | configMapGenerator: 8 | - files: 9 | - controller_manager_config.yaml 10 | name: manager-config 11 | apiVersion: kustomize.config.k8s.io/v1beta1 12 | kind: Kustomization 13 | 14 | images: 15 | - name: controller 16 | newName: ghcr.io/nutanix-cloud-native/cluster-api-provider-nutanix/controller 17 | newTag: latest 18 | -------------------------------------------------------------------------------- /templates/failure-domains/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | 4 | namespace: ${NAMESPACE} 5 | 6 | resources: 7 | - ../base/ 8 | - ./failure-domains.yaml 9 | 10 | patches: 11 | - path: ./failure-domains-patch.yaml 12 | - target: 13 | kind: NutanixMachineTemplate 14 | patch: |- 15 | - op: "remove" 16 | path: "/spec/template/spec/cluster" 17 | - op: "remove" 18 | path: "/spec/template/spec/subnet" 19 | -------------------------------------------------------------------------------- /.github/workflows/cilium-without-kubeproxy-conformance-periodic.yaml: -------------------------------------------------------------------------------- 1 | name: Periodic Conformance Test with Cilium without KubeProxy 2 | on: 3 | schedule: 4 | - cron: "0 18 * * *" # 6 PM 5 | jobs: 6 | e2e: 7 | uses: ./.github/workflows/e2e.yaml 8 | with: 9 | e2e-labels: "conformance || cluster-upgrade-conformance" 10 | make-target: "test-e2e-cilium-no-kubeproxy" 11 | secrets: inherit 12 | permissions: 13 | contents: read 14 | checks: write 15 | -------------------------------------------------------------------------------- /templates/image-lookup/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Nutanix. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | apiVersion: kustomize.config.k8s.io/v1beta1 5 | kind: Kustomization 6 | 7 | metadata: 8 | name: nutanix-image-lookup-kustomize 9 | 10 | resources: 11 | - ../base/ 12 | 13 | patches: 14 | - path: lookup-patch.yaml 15 | - target: 16 | kind: NutanixMachineTemplate 17 | patch: |- 18 | - op: "remove" 19 | path: "/spec/template/spec/image" 20 | -------------------------------------------------------------------------------- /config/rbac/nutanixcluster_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view nutanixclusters. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: nutanixcluster-viewer-role 6 | rules: 7 | - apiGroups: 8 | - infrastructure.cluster.x-k8s.io 9 | resources: 10 | - nutanixclusters 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - infrastructure.cluster.x-k8s.io 17 | resources: 18 | - nutanixclusters/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /config/rbac/nutanixmachine_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view nutanixmachines. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: nutanixmachine-viewer-role 6 | rules: 7 | - apiGroups: 8 | - infrastructure.cluster.x-k8s.io 9 | resources: 10 | - nutanixmachines 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - infrastructure.cluster.x-k8s.io 17 | resources: 18 | - nutanixmachines/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /templates/testdata/clusterctl-init.yaml: -------------------------------------------------------------------------------- 1 | CLUSTERCTL_LOG_LEVEL: 10 2 | EXP_CLUSTER_RESOURCE_SET: 'true' 3 | CLUSTER_TOPOLOGY: 'true' 4 | NUTANIX_ENDPOINT: '' # IP or FQDN of Prism Central 5 | NUTANIX_USER: '' # Prism Central user 6 | NUTANIX_PASSWORD: '' # Prism Central password 7 | providers: 8 | # add a custom provider 9 | - name: "nutanix" 10 | url: "file://${HOME}/.cluster-api/overrides/infrastructure-nutanix/${LOCAL_PROVIDER_VERSION}/infrastructure-components.yaml" 11 | type: "InfrastructureProvider" 12 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1.7.1/base/crs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: "cni-${CLUSTER_NAME}-crs-cni" 5 | data: ${CNI_RESOURCES} 6 | --- 7 | apiVersion: addons.cluster.x-k8s.io/v1beta1 8 | kind: ClusterResourceSet 9 | metadata: 10 | name: "${CLUSTER_NAME}-crs-cni" 11 | spec: 12 | strategy: ApplyOnce 13 | clusterSelector: 14 | matchLabels: 15 | cni: "${CLUSTER_NAME}-crs-cni" 16 | resources: 17 | - name: "cni-${CLUSTER_NAME}-crs-cni" 18 | kind: ConfigMap 19 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/base/crs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: "cni-${CLUSTER_NAME}-crs-cni" 5 | data: ${CNI_RESOURCES} 6 | --- 7 | apiVersion: addons.cluster.x-k8s.io/v1beta1 8 | kind: ClusterResourceSet 9 | metadata: 10 | name: "${CLUSTER_NAME}-crs-cni" 11 | spec: 12 | strategy: ApplyOnce 13 | clusterSelector: 14 | matchLabels: 15 | cni: "${CLUSTER_NAME}-crs-cni" 16 | resources: 17 | - name: "cni-${CLUSTER_NAME}-crs-cni" 18 | kind: ConfigMap 19 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_nutanixclusters.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: nutanixclusters.infrastructure.cluster.x-k8s.io 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: ["v1", "v1beta1"] 16 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_nutanixmachines.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: nutanixmachines.infrastructure.cluster.x-k8s.io 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: ["v1", "v1beta1"] 16 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_nutanixclustertemplates.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: nutanixclustertemplates.infrastructure.cluster.x-k8s.io 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: 16 | - v1 17 | -------------------------------------------------------------------------------- /config/crd/patches/webhook_in_nutanixmachinetemplates.yaml: -------------------------------------------------------------------------------- 1 | # The following patch enables a conversion webhook for the CRD 2 | apiVersion: apiextensions.k8s.io/v1 3 | kind: CustomResourceDefinition 4 | metadata: 5 | name: nutanixmachinetemplates.infrastructure.cluster.x-k8s.io 6 | spec: 7 | conversion: 8 | strategy: Webhook 9 | webhook: 10 | clientConfig: 11 | service: 12 | namespace: system 13 | name: webhook-service 14 | path: /convert 15 | conversionReviewVersions: ["v1", "v1beta1"] 16 | -------------------------------------------------------------------------------- /templates/ccm/nutanix-ccm-crs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: addons.cluster.x-k8s.io/v1beta1 2 | kind: ClusterResourceSet 3 | metadata: 4 | name: nutanix-ccm-crs 5 | spec: 6 | clusterSelector: 7 | matchLabels: 8 | ccm: nutanix 9 | resources: 10 | - kind: ConfigMap 11 | name: nutanix-ccm 12 | - kind: Secret 13 | name: nutanix-ccm-secret 14 | - kind: ConfigMap 15 | name: nutanix-ccm-pc-trusted-ca-bundle 16 | strategy: ApplyOnce 17 | --- 18 | apiVersion: v1 19 | kind: ConfigMap 20 | metadata: 21 | name: nutanix-ccm 22 | data: 23 | -------------------------------------------------------------------------------- /config/rbac/nutanixmachinetemplate_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view nutanixmachinetemplates. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: nutanixmachinetemplate-viewer-role 6 | rules: 7 | - apiGroups: 8 | - infrastructure.cluster.x-k8s.io 9 | resources: 10 | - nutanixmachinetemplates 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - apiGroups: 16 | - infrastructure.cluster.x-k8s.io 17 | resources: 18 | - nutanixmachinetemplates/status 19 | verbs: 20 | - get 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature enhancement request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | /kind feature 8 | 9 | **Describe the solution you'd like** 10 | [A clear and concise description of what you want to happen.] 11 | 12 | 13 | **Anything else you would like to add:** 14 | [Miscellaneous information that will assist in solving the issue.] 15 | 16 | 17 | **Environment:** 18 | 19 | - Cluster-api-provider-nutanix version: 20 | - Kubernetes version: (use `kubectl version`): 21 | - OS (e.g. from `/etc/os-release`): -------------------------------------------------------------------------------- /config/rbac/nutanixcluster_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit nutanixclusters. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: nutanixcluster-editor-role 6 | rules: 7 | - apiGroups: 8 | - infrastructure.cluster.x-k8s.io 9 | resources: 10 | - nutanixclusters 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - infrastructure.cluster.x-k8s.io 21 | resources: 22 | - nutanixclusters/status 23 | verbs: 24 | - get 25 | -------------------------------------------------------------------------------- /config/rbac/nutanixmachine_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit nutanixmachines. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: nutanixmachine-editor-role 6 | rules: 7 | - apiGroups: 8 | - infrastructure.cluster.x-k8s.io 9 | resources: 10 | - nutanixmachines 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - infrastructure.cluster.x-k8s.io 21 | resources: 22 | - nutanixmachines/status 23 | verbs: 24 | - get 25 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-csi/kct.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 3 | kind: KubeadmConfigTemplate 4 | metadata: 5 | name: "${CLUSTER_NAME}-kcfg-0" 6 | namespace: "${NAMESPACE}" 7 | spec: 8 | template: 9 | spec: 10 | preKubeadmCommands: 11 | - echo "before kubeadm call" > /var/log/prekubeadm.log 12 | - hostnamectl set-hostname "{{ ds.meta_data.hostname }}" 13 | - apt update 14 | - apt install -y nfs-common open-iscsi lvm2 xfsprogs 15 | - systemctl enable --now iscsid 16 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-csi3/kct.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 3 | kind: KubeadmConfigTemplate 4 | metadata: 5 | name: "${CLUSTER_NAME}-kcfg-0" 6 | namespace: "${NAMESPACE}" 7 | spec: 8 | template: 9 | spec: 10 | preKubeadmCommands: 11 | - echo "before kubeadm call" > /var/log/prekubeadm.log 12 | - hostnamectl set-hostname "{{ ds.meta_data.hostname }}" 13 | - apt update 14 | - apt install -y nfs-common open-iscsi lvm2 xfsprogs 15 | - systemctl enable --now iscsid 16 | -------------------------------------------------------------------------------- /.github/release.yaml: -------------------------------------------------------------------------------- 1 | # .github/release.yml 2 | 3 | changelog: 4 | exclude: 5 | labels: 6 | - ignore-for-release 7 | categories: 8 | - title: Breaking Changes 🛠 9 | labels: 10 | - Semver-Major 11 | - breaking-change 12 | - title: Exciting New Features 🎉 13 | labels: 14 | - Semver-Minor 15 | - enhancement 16 | - title: Bug Fixes 🐛 17 | labels: 18 | - bug 19 | - title: Documentation 📖 20 | labels: 21 | - documentation 22 | - title: Other Changes 23 | labels: 24 | - "*" 25 | -------------------------------------------------------------------------------- /config/prometheus/monitor.yaml: -------------------------------------------------------------------------------- 1 | # Prometheus Monitor Service (Metrics) 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: ServiceMonitor 4 | metadata: 5 | labels: 6 | control-plane: controller-manager 7 | name: controller-manager-metrics-monitor 8 | namespace: system 9 | spec: 10 | endpoints: 11 | - path: /metrics 12 | port: https 13 | scheme: https 14 | bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token 15 | tlsConfig: 16 | insecureSkipVerify: true 17 | selector: 18 | matchLabels: 19 | control-plane: controller-manager 20 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/no-kubeproxy.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 3 | kind: KubeadmControlPlane 4 | metadata: 5 | name: "${CLUSTER_NAME}-kcp" 6 | spec: 7 | kubeadmConfigSpec: 8 | initConfiguration: 9 | skipPhases: 10 | - addon/kube-proxy 11 | --- 12 | apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 13 | kind: KubeadmConfigTemplate 14 | metadata: 15 | name: "${CLUSTER_NAME}-kcfg-0" 16 | spec: 17 | template: 18 | spec: 19 | initConfiguration: 20 | skipPhases: 21 | - addon/kube-proxy 22 | -------------------------------------------------------------------------------- /config/default/manager_config_patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: controller-manager 5 | namespace: system 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: manager 11 | args: 12 | - "--config=controller_manager_config.yaml" 13 | volumeMounts: 14 | - name: manager-config 15 | mountPath: /controller_manager_config.yaml 16 | subPath: controller_manager_config.yaml 17 | volumes: 18 | - name: manager-config 19 | configMap: 20 | name: manager-config 21 | -------------------------------------------------------------------------------- /config/crd/kustomizeconfig.yaml: -------------------------------------------------------------------------------- 1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD 2 | nameReference: 3 | - kind: Service 4 | version: v1 5 | fieldSpecs: 6 | - kind: CustomResourceDefinition 7 | version: v1 8 | group: apiextensions.k8s.io 9 | path: spec/conversion/webhook/clientConfig/service/name 10 | 11 | namespace: 12 | - kind: CustomResourceDefinition 13 | version: v1 14 | group: apiextensions.k8s.io 15 | path: spec/conversion/webhook/clientConfig/service/namespace 16 | create: false 17 | 18 | varReference: 19 | - path: metadata/annotations 20 | -------------------------------------------------------------------------------- /config/rbac/nutanixmachinetemplate_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit nutanixmachinetemplates. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: nutanixmachinetemplate-editor-role 6 | rules: 7 | - apiGroups: 8 | - infrastructure.cluster.x-k8s.io 9 | resources: 10 | - nutanixmachinetemplates 11 | verbs: 12 | - create 13 | - delete 14 | - get 15 | - list 16 | - patch 17 | - update 18 | - watch 19 | - apiGroups: 20 | - infrastructure.cluster.x-k8s.io 21 | resources: 22 | - nutanixmachinetemplates/status 23 | verbs: 24 | - get 25 | -------------------------------------------------------------------------------- /templates/base/nutanix-cluster.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 2 | kind: NutanixCluster 3 | metadata: 4 | name: "${CLUSTER_NAME}" 5 | spec: 6 | prismCentral: 7 | address: "${NUTANIX_ENDPOINT}" 8 | port: ${NUTANIX_PORT=9440} 9 | insecure: ${NUTANIX_INSECURE=false} 10 | credentialRef: 11 | name: "${CLUSTER_NAME}" 12 | kind: Secret 13 | additionalTrustBundle: 14 | name: ${CLUSTER_NAME}-pc-trusted-ca-bundle 15 | kind: ConfigMap 16 | controlPlaneEndpoint: 17 | host: "${CONTROL_PLANE_ENDPOINT_IP}" 18 | port: ${CONTROL_PLANE_ENDPOINT_PORT=6443} 19 | -------------------------------------------------------------------------------- /hack/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-image-lookup/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Nutanix. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | apiVersion: kustomize.config.k8s.io/v1beta1 5 | kind: Kustomization 6 | 7 | metadata: 8 | name: nutanix-image-lookup-kustomize 9 | 10 | resources: 11 | - ../../../../../../templates/base/ 12 | - ../base/crs.yaml 13 | 14 | patches: 15 | - path: ../base/cni-patch.yaml 16 | - path: lookup-patch.yaml 17 | - target: 18 | kind: NutanixMachineTemplate 19 | patch: |- 20 | - op: "remove" 21 | path: "/spec/template/spec/image" 22 | -------------------------------------------------------------------------------- /templates/csi3/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Nutanix. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | apiVersion: kustomize.config.k8s.io/v1beta1 5 | kind: Kustomization 6 | 7 | metadata: 8 | name: nutanix-csi-kustomize 9 | 10 | namespace: kube-system 11 | 12 | configMapGenerator: 13 | - behavior: merge 14 | files: 15 | - nutanix-csi-storage.yaml 16 | - nutanix-csi-snapshot.yaml 17 | - nutanix-csi-webhook.yaml 18 | name: nutanix-csi 19 | 20 | resources: 21 | - ../base/ 22 | - nutanix-csi.yaml 23 | - nutanix-csi-crs.yaml 24 | - nutanix-csi-secret.yaml 25 | 26 | patches: 27 | - path: csi-patch.yaml 28 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/no-kubeproxy/no-kubeproxy-clusterclass.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 2 | kind: KubeadmControlPlaneTemplate 3 | metadata: 4 | name: "nutanix-quick-start-kcpt" 5 | spec: 6 | template: 7 | spec: 8 | kubeadmConfigSpec: 9 | initConfiguration: 10 | skipPhases: 11 | - addon/kube-proxy 12 | --- 13 | apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 14 | kind: KubeadmConfigTemplate 15 | metadata: 16 | name: "nutanix-quick-start-kcfg-0" 17 | spec: 18 | template: 19 | spec: 20 | initConfiguration: 21 | skipPhases: 22 | - addon/kube-proxy 23 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-additional-categories/nmt.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 3 | kind: NutanixMachineTemplate 4 | metadata: 5 | name: "${CLUSTER_NAME}-mt-0" 6 | namespace: "${NAMESPACE}" 7 | spec: 8 | template: 9 | spec: 10 | additionalCategories: 11 | # Use System category Apptype:Kubernetes 12 | - key: AppType 13 | value: Kubernetes 14 | # Use System category Environment:Dev 15 | - key: Environment 16 | value: Dev 17 | # Use System category Environment:Testing 18 | - key: Environment 19 | value: Testing 20 | -------------------------------------------------------------------------------- /config/rbac/leader_election_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions to do leader election. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: Role 4 | metadata: 5 | name: leader-election-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - configmaps 11 | verbs: 12 | - get 13 | - list 14 | - watch 15 | - create 16 | - update 17 | - patch 18 | - delete 19 | - apiGroups: 20 | - coordination.k8s.io 21 | resources: 22 | - leases 23 | verbs: 24 | - get 25 | - list 26 | - watch 27 | - create 28 | - update 29 | - patch 30 | - delete 31 | - apiGroups: 32 | - "" 33 | resources: 34 | - events 35 | verbs: 36 | - create 37 | - patch 38 | -------------------------------------------------------------------------------- /tools/imagebuilder/terraform/variables.tf: -------------------------------------------------------------------------------- 1 | variable "password" { 2 | type = string 3 | } 4 | variable "endpoint" { 5 | type = string 6 | } 7 | variable "user" { 8 | type = string 9 | } 10 | 11 | variable "image_url" { 12 | default = "https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img" 13 | } 14 | 15 | variable "cluster_name" { 16 | type = string 17 | } 18 | variable "vm_name" { 19 | type = string 20 | } 21 | variable "vm_user" { 22 | type = string 23 | } 24 | variable "subnet_name" { 25 | type = string 26 | } 27 | variable "public_key_file_path" { 28 | type = string 29 | } 30 | variable "private_key_file_path" { 31 | type = string 32 | } 33 | -------------------------------------------------------------------------------- /templates/base/cluster-without-topology.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | cluster.x-k8s.io/cluster-name: "${CLUSTER_NAME}" 6 | name: "${CLUSTER_NAME}" 7 | spec: 8 | clusterNetwork: 9 | services: 10 | cidrBlocks: ["172.19.0.0/16"] 11 | pods: 12 | cidrBlocks: ["172.20.0.0/16"] 13 | serviceDomain: "cluster.local" 14 | controlPlaneRef: 15 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 16 | kind: KubeadmControlPlane 17 | name: "${CLUSTER_NAME}-kcp" 18 | infrastructureRef: 19 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 20 | kind: NutanixCluster 21 | name: "${CLUSTER_NAME}" 22 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | # Enable version updates for Go modules 9 | - package-ecosystem: "gomod" 10 | directory: "/" 11 | schedule: 12 | interval: "daily" 13 | 14 | # Enable version updates for GitHub Actions 15 | - package-ecosystem: "github-actions" 16 | directory: "/" 17 | schedule: 18 | interval: "daily" 19 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | run: 3 | concurrency: 4 4 | build-tags: 5 | - e2e 6 | linters: 7 | enable: 8 | - gocognit 9 | - nolintlint 10 | settings: 11 | nolintlint: 12 | require-explanation: true 13 | require-specific: true 14 | exclusions: 15 | generated: lax 16 | presets: 17 | - comments 18 | - common-false-positives 19 | - legacy 20 | - std-error-handling 21 | paths: 22 | - third_party$ 23 | - builtin$ 24 | - examples$ 25 | formatters: 26 | enable: 27 | - gofmt 28 | - gofumpt 29 | exclusions: 30 | generated: lax 31 | paths: 32 | - third_party$ 33 | - builtin$ 34 | - examples$ 35 | -------------------------------------------------------------------------------- /api/v1beta1/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package v1beta1 contains the v1beta1 API implementation. 18 | package v1beta1 19 | -------------------------------------------------------------------------------- /templates/ccm/nutanix-ccm-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nutanix-ccm-secret 5 | type: addons.cluster.x-k8s.io/resource-set 6 | stringData: 7 | nutanix-ccm-secret.yaml: | 8 | apiVersion: v1 9 | kind: Secret 10 | metadata: 11 | name: nutanix-creds 12 | namespace: kube-system 13 | stringData: 14 | credentials: | 15 | [ 16 | { 17 | "type": "basic_auth", 18 | "data": { 19 | "prismCentral":{ 20 | "username": "${NUTANIX_USER}", 21 | "password": "${NUTANIX_PASSWORD}" 22 | }, 23 | "prismElements": null 24 | } 25 | } 26 | ] 27 | -------------------------------------------------------------------------------- /tools/imagebuilder/delete_image_build_vm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2022 Nutanix 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | pushd ./terraform 17 | terraform destroy 18 | popd -------------------------------------------------------------------------------- /templates/csi3/nutanix-csi-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: nutanix-csi-secret 5 | type: addons.cluster.x-k8s.io/resource-set 6 | stringData: 7 | nutanix-csi-secret.yaml: | 8 | apiVersion: v1 9 | stringData: 10 | key: ${NUTANIX_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD} 11 | kind: Secret 12 | metadata: 13 | name: ntnx-pc-secret 14 | namespace: ntnx-system 15 | type: Opaque 16 | --- 17 | apiVersion: v1 18 | stringData: 19 | key: ${NUTANIX_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD} 20 | kind: Secret 21 | metadata: 22 | name: nutanix-csi-credentials 23 | namespace: ntnx-system 24 | type: Opaque 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Tell us about a problem you are experiencing 4 | 5 | --- 6 | 7 | /kind bug 8 | 9 | **What steps did you take and what happened:** 10 | 11 | _A clear and concise description of what the bug is and how has this been tested. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration_ 12 | 13 | 14 | **What did you expect to happen:** 15 | 16 | 17 | **Anything else you would like to add:** 18 | 19 | _Miscellaneous information that will assist in solving the issue._ 20 | 21 | 22 | **Environment:** 23 | 24 | - Cluster-api-provider-nutanix version: 25 | - Kubernetes version: (use `kubectl version`): 26 | - OS (e.g. from `/etc/os-release`): -------------------------------------------------------------------------------- /config/rbac/nutanixclustertemplate_viewer_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to view nutanixclustertemplates. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: nutanixclustertemplate-viewer-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: cluster-api-provider-nutanix 10 | app.kubernetes.io/part-of: cluster-api-provider-nutanix 11 | app.kubernetes.io/managed-by: kustomize 12 | name: nutanixclustertemplate-viewer-role 13 | rules: 14 | - apiGroups: 15 | - infrastructure.cluster.x-k8s.io 16 | resources: 17 | - nutanixclustertemplates 18 | verbs: 19 | - get 20 | - list 21 | - watch 22 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-failure-domains/failure-domain-nmt.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 3 | kind: NutanixMachineTemplate 4 | metadata: 5 | name: "${CLUSTER_NAME}-mt-0" 6 | namespace: "${NAMESPACE}" 7 | spec: 8 | template: 9 | spec: 10 | providerID: "nutanix://${CLUSTER_NAME}-m1" 11 | bootType: ${NUTANIX_MACHINE_BOOT_TYPE=legacy} 12 | vcpusPerSocket: ${NUTANIX_MACHINE_VCPU_PER_SOCKET=1} 13 | vcpuSockets: ${NUTANIX_MACHINE_VCPU_SOCKET=2} 14 | memorySize: "${NUTANIX_MACHINE_MEMORY_SIZE=4Gi}" 15 | systemDiskSize: "${NUTANIX_SYSTEMDISK_SIZE=40Gi}" 16 | image: 17 | type: name 18 | name: "${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME}" 19 | -------------------------------------------------------------------------------- /devbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "bash@latest", 4 | "coreutils@latest", 5 | "clusterctl@latest", 6 | "envsubst@latest", 7 | "fping@latest", 8 | "gnumake@latest", 9 | "ginkgo@latest", 10 | "go@latest", 11 | "golangci-lint@latest", 12 | "gotestsum@latest", 13 | "kubernetes-helm@latest", 14 | "kind@latest", 15 | "ko@latest", 16 | "kubectl@latest", 17 | "kubernetes-code-generator@latest", 18 | "kubernetes-controller-tools@latest", 19 | "kustomize@latest", 20 | "mockgen@latest", 21 | "yamllint@latest", 22 | "path:./hack/flakes#go-apidiff", 23 | "path:./hack/flakes#go-mod-upgrade", 24 | "path:./hack/flakes#yamllint-checkstyle", 25 | "path:./hack/flakes#setup-envtest" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-failure-domains-migration/failure-domain-nmt.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 3 | kind: NutanixMachineTemplate 4 | metadata: 5 | name: "${CLUSTER_NAME}-mt-0" 6 | namespace: "${NAMESPACE}" 7 | spec: 8 | template: 9 | spec: 10 | providerID: "nutanix://${CLUSTER_NAME}-m1" 11 | bootType: ${NUTANIX_MACHINE_BOOT_TYPE=legacy} 12 | vcpusPerSocket: ${NUTANIX_MACHINE_VCPU_PER_SOCKET=1} 13 | vcpuSockets: ${NUTANIX_MACHINE_VCPU_SOCKET=2} 14 | memorySize: "${NUTANIX_MACHINE_MEMORY_SIZE=4Gi}" 15 | systemDiskSize: "${NUTANIX_SYSTEMDISK_SIZE=40Gi}" 16 | image: 17 | type: name 18 | name: "${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME}" 19 | -------------------------------------------------------------------------------- /test/e2e/README.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | This document describes the steps to test CAPX end-to-end. 4 | 5 | ### Requirements 6 | 7 | TBD 8 | 9 | ### Environment variables 10 | 11 | TBD 12 | 13 | ### Running the e2e tests 14 | 15 | Run the following command to execute the CAPX e2e tests: 16 | 17 | ```shell 18 | make test-e2e 19 | ``` 20 | 21 | The above command should build the CAPX manager image locally and use that image with the e2e test suite. 22 | 23 | Running e2e with other CNIs can be done by invoking following command: 24 | ```shell 25 | #run e2e with Calico: 26 | make test-e2e-calico 27 | 28 | #run e2e with Flannel: 29 | make test-e2e-flannel 30 | 31 | #run e2e with Cilium: 32 | make test-e2e-cilium 33 | 34 | #run e2e tests with every CNI: 35 | make test-e2e-all-cni 36 | ``` 37 | -------------------------------------------------------------------------------- /test/e2e/data/shared/metadata.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3 2 | kind: Metadata 3 | releaseSeries: 4 | - major: 0 5 | minor: 3 6 | contract: v1alpha3 7 | - major: 0 8 | minor: 4 9 | contract: v1alpha4 10 | - major: 0 11 | minor: 5 12 | contract: v1beta1 13 | - major: 1 14 | minor: 3 15 | contract: v1beta1 16 | - major: 1 17 | minor: 4 18 | contract: v1beta1 19 | - major: 1 20 | minor: 5 21 | contract: v1beta1 22 | - major: 1 23 | minor: 6 24 | contract: v1beta1 25 | - major: 1 26 | minor: 7 27 | contract: v1beta1 28 | - major: 1 29 | minor: 8 30 | contract: v1beta1 31 | - major: 1 32 | minor: 9 33 | contract: v1beta1 34 | - major: 1 35 | minor: 10 36 | contract: v1beta1 37 | -------------------------------------------------------------------------------- /config/rbac/nutanixclustertemplate_editor_role.yaml: -------------------------------------------------------------------------------- 1 | # permissions for end users to edit nutanixclustertemplates. 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | labels: 6 | app.kubernetes.io/name: clusterrole 7 | app.kubernetes.io/instance: nutanixclustertemplate-editor-role 8 | app.kubernetes.io/component: rbac 9 | app.kubernetes.io/created-by: cluster-api-provider-nutanix 10 | app.kubernetes.io/part-of: cluster-api-provider-nutanix 11 | app.kubernetes.io/managed-by: kustomize 12 | name: nutanixclustertemplate-editor-role 13 | rules: 14 | - apiGroups: 15 | - infrastructure.cluster.x-k8s.io 16 | resources: 17 | - nutanixclustertemplates 18 | verbs: 19 | - create 20 | - delete 21 | - get 22 | - list 23 | - patch 24 | - update 25 | - watch 26 | -------------------------------------------------------------------------------- /tools/imagebuilder/create_image_build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2022 Nutanix 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | pushd ./terraform 17 | terraform init 18 | terraform validate 19 | terraform plan 20 | terraform apply 21 | terraform show 22 | popd 23 | -------------------------------------------------------------------------------- /templates/base/mhc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: MachineHealthCheck 3 | metadata: 4 | name: "${CLUSTER_NAME}-mhc" 5 | spec: 6 | clusterName: "${CLUSTER_NAME}" 7 | maxUnhealthy: 40% 8 | nodeStartupTimeout: 10m0s 9 | selector: 10 | matchLabels: 11 | cluster.x-k8s.io/cluster-name: "${CLUSTER_NAME}" 12 | unhealthyConditions: 13 | - type: Ready 14 | status: "False" 15 | timeout: 5m0s 16 | - type: Ready 17 | status: Unknown 18 | timeout: 5m0s 19 | - type: MemoryPressure 20 | status: "True" 21 | timeout: 5m0s 22 | - type: DiskPressure 23 | status: "True" 24 | timeout: 5m0s 25 | - type: PIDPressure 26 | status: "True" 27 | timeout: 5m0s 28 | - type: NetworkUnavailable 29 | status: "True" 30 | timeout: 5m0s 31 | -------------------------------------------------------------------------------- /config/default/manager_auth_proxy_patch.yaml: -------------------------------------------------------------------------------- 1 | # This patch modifies the manager deployment to expose the metrics port securely 2 | # using controller-runtime's built-in authentication and authorization 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: controller-manager 7 | namespace: system 8 | spec: 9 | template: 10 | spec: 11 | containers: 12 | - name: manager 13 | args: 14 | - "--health-probe-bind-address=:8081" 15 | - "--diagnostics-address=:8443" 16 | - "--leader-elect" 17 | - "--zap-log-level=${NUTANIX_LOG_LEVEL=info}" 18 | - "--zap-devel=${NUTANIX_LOG_DEVELOPMENT=true}" 19 | - "--zap-stacktrace-level=${NUTANIX_LOG_STACKTRACE_LEVEL=panic}" 20 | ports: 21 | - containerPort: 8443 22 | name: https 23 | protocol: TCP 24 | -------------------------------------------------------------------------------- /config/rbac/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # All RBAC will be applied under this service account in 2 | # the deployment namespace. You may comment out this resource 3 | # if your manager will use a service account that exists at 4 | # runtime. Be sure to update RoleBinding and ClusterRoleBinding 5 | # subjects if changing service account names. 6 | # Comment the following 4 lines if you want to disable 7 | # the auth proxy (https://github.com/brancz/kube-rbac-proxy) 8 | # which protects your /metrics endpoint. 9 | resources: 10 | - service_account.yaml 11 | - role.yaml 12 | - role_binding.yaml 13 | - leader_election_role.yaml 14 | - leader_election_role_binding.yaml 15 | - auth_proxy_service.yaml 16 | - auth_proxy_role.yaml 17 | - auth_proxy_role_binding.yaml 18 | - auth_proxy_client_clusterrole.yaml 19 | apiVersion: kustomize.config.k8s.io/v1beta1 20 | kind: Kustomization 21 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-md-remediation/mhc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Source: https://github.com/kubernetes-sigs/cluster-api/blob/main/test/e2e/data/infrastructure-docker/v1beta1/cluster-template-md-remediation/mhc.yaml 3 | 4 | # MachineHealthCheck object with 5 | # - a selector that targets all the machines with label e2e.remediation.label="" 6 | # - unhealthyConditions triggering remediation after 10s the condition is set 7 | apiVersion: cluster.x-k8s.io/v1beta1 8 | kind: MachineHealthCheck 9 | metadata: 10 | name: "${CLUSTER_NAME}-mhc-0" 11 | namespace: "${NAMESPACE}" 12 | spec: 13 | clusterName: "${CLUSTER_NAME}" 14 | maxUnhealthy: 100% 15 | selector: 16 | matchLabels: 17 | e2e.remediation.label: "" 18 | unhealthyConditions: 19 | - type: e2e.remediation.condition 20 | status: "False" 21 | timeout: 10s 22 | -------------------------------------------------------------------------------- /api/v1beta1/nutanixcluster_conversion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1beta1 18 | 19 | // Hub marks NutanixCluster as a conversion hub. 20 | func (*NutanixCluster) Hub() {} 21 | 22 | // Hub marks NutanixClusterList as a conversion hub. 23 | func (*NutanixClusterList) Hub() {} 24 | -------------------------------------------------------------------------------- /api/v1beta1/nutanixmachine_conversion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1beta1 18 | 19 | // Hub marks NutanixMachine as a conversion hub. 20 | func (*NutanixMachine) Hub() {} 21 | 22 | // Hub marks NutanixMachineList as a conversion hub. 23 | func (*NutanixMachineList) Hub() {} 24 | -------------------------------------------------------------------------------- /templates/failure-domains/failure-domains-patch.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 3 | kind: NutanixCluster 4 | metadata: 5 | name: ${CLUSTER_NAME} 6 | spec: 7 | controlPlaneFailureDomains: 8 | - name: ${NUTANIX_FAILURE_DOMAIN_1_NAME} 9 | - name: ${NUTANIX_FAILURE_DOMAIN_2_NAME} 10 | - name: ${NUTANIX_FAILURE_DOMAIN_3_NAME} 11 | --- 12 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 13 | kind: KubeadmControlPlane 14 | metadata: 15 | name: ${CLUSTER_NAME}-kcp 16 | spec: 17 | replicas: 3 18 | --- 19 | apiVersion: cluster.x-k8s.io/v1beta1 20 | kind: MachineDeployment 21 | metadata: 22 | labels: 23 | cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} 24 | name: ${CLUSTER_NAME}-wmd 25 | spec: 26 | replicas: ${WORKER_MACHINE_COUNT=3} 27 | template: 28 | spec: 29 | failureDomain: ${NUTANIX_FAILURE_DOMAIN_1_NAME} 30 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-kcp-remediation/mhc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Source: https://github.com/kubernetes-sigs/cluster-api/blob/main/test/e2e/data/infrastructure-docker/v1beta1/cluster-template-kcp-remediation/mhc.yaml 3 | 4 | # MachineHealthCheck object with 5 | # - a selector that targets all the machines with label cluster.x-k8s.io/control-plane="" 6 | # - unhealthyConditions triggering remediation after 10s the condition is set 7 | apiVersion: cluster.x-k8s.io/v1beta1 8 | kind: MachineHealthCheck 9 | metadata: 10 | name: "${CLUSTER_NAME}-mhc-0" 11 | namespace: "${NAMESPACE}" 12 | spec: 13 | clusterName: "${CLUSTER_NAME}" 14 | maxUnhealthy: 100% 15 | selector: 16 | matchLabels: 17 | cluster.x-k8s.io/control-plane: "" 18 | unhealthyConditions: 19 | - type: e2e.remediation.condition 20 | status: "False" 21 | timeout: 10s 22 | -------------------------------------------------------------------------------- /hooks/build-finalize.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2022 Nutanix 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -x 17 | set -e 18 | 19 | BUILD_DIR=~/project/package/docker 20 | cp -r ~/project/api $BUILD_DIR 21 | cp -r ~/project/controllers $BUILD_DIR 22 | cp -r ~/project/pkg $BUILD_DIR 23 | cp go.mod go.sum main.go $BUILD_DIR 24 | 25 | -------------------------------------------------------------------------------- /tools/imagebuilder/terraform/scripts/build_os_image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2022 Nutanix 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | git clone https://github.com/kubernetes-sigs/image-builder.git 17 | export PATH=$PATH:~/.local/bin 18 | cd ~/image-builder/images/capi 19 | chmod +x hack/* 20 | make deps-raw 21 | make build-qemu-ubuntu-2004 -------------------------------------------------------------------------------- /api/v1beta1/nutanixmachinetemplate_conversion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1beta1 18 | 19 | // Hub marks NutanixMachineTemplate as a conversion hub. 20 | func (*NutanixMachineTemplate) Hub() {} 21 | 22 | // Hub marks NutanixMachineTemplateList as a conversion hub. 23 | func (*NutanixMachineTemplateList) Hub() {} 24 | -------------------------------------------------------------------------------- /templates/base/md.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: MachineDeployment 3 | metadata: 4 | labels: 5 | cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} 6 | name: "${CLUSTER_NAME}-wmd" 7 | spec: 8 | clusterName: "${CLUSTER_NAME}" 9 | replicas: ${WORKER_MACHINE_COUNT} 10 | selector: 11 | matchLabels: {} 12 | template: 13 | metadata: 14 | labels: 15 | cluster.x-k8s.io/cluster-name: "${CLUSTER_NAME}" 16 | spec: 17 | bootstrap: 18 | configRef: 19 | apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 20 | kind: KubeadmConfigTemplate 21 | name: "${CLUSTER_NAME}-kcfg-0" 22 | clusterName: "${CLUSTER_NAME}" 23 | infrastructureRef: 24 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 25 | kind: NutanixMachineTemplate 26 | name: "${CLUSTER_NAME}-mt-0" 27 | version: "${KUBERNETES_VERSION}" 28 | -------------------------------------------------------------------------------- /.github/workflows/conventional-pr-title.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2025 Nutanix. All rights reserved. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | name: "conventional-pr-title" 5 | permissions: 6 | contents: read 7 | pull-requests: read 8 | on: 9 | pull_request: 10 | types: 11 | - opened 12 | - edited 13 | - synchronize 14 | pull_request_target: 15 | types: 16 | - opened 17 | - edited 18 | - synchronize 19 | jobs: 20 | check: 21 | runs-on: ubuntu-24.04 22 | steps: 23 | - uses: amannn/action-semantic-pull-request@v6 24 | with: 25 | types: | 26 | build 27 | chore 28 | ci 29 | docs 30 | feat 31 | fix 32 | perf 33 | refactor 34 | revert 35 | style 36 | test 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | -------------------------------------------------------------------------------- /docs/vscode-integration/README.md: -------------------------------------------------------------------------------- 1 | # VSCode Integration 2 | 3 | Some of the unit tests use the [envtest package](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest) from the controller-runtime project to create a temporary Kubernetes API server. 4 | 5 | Envtest reads the location of the necessary binaries, i.e. etcd and kube-apiserver, from an environment variable. This environment variable is initialized by our make targets, but VSCode does not run tests using make. 6 | 7 | We can use a VSCode task to write the location to a file, and configure vscode-go, which runs the tests, to initialize its environment from this file. 8 | 9 | To run envtest-based tests from VSCode, follow these steps: 10 | 11 | 1. Install setup-envtest (and other build/test dependencies) by running `devbox install`. 12 | 2. Copy `settings.json` and `tasks.json` in this directory into the `.vscode` folder at the root of the repository. 13 | 3. Restart VSCode. 14 | -------------------------------------------------------------------------------- /templates/image-lookup/lookup-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 2 | kind: NutanixMachineTemplate 3 | metadata: 4 | name: "${CLUSTER_NAME}-mt-0" 5 | spec: 6 | template: 7 | spec: 8 | providerID: "nutanix://${CLUSTER_NAME}-m1" 9 | # Supported options for boot type: legacy and uefi 10 | # Defaults to legacy if not set 11 | bootType: ${NUTANIX_MACHINE_BOOT_TYPE=legacy} 12 | vcpusPerSocket: ${NUTANIX_MACHINE_VCPU_PER_SOCKET=1} 13 | vcpuSockets: ${NUTANIX_MACHINE_VCPU_SOCKET=2} 14 | memorySize: "${NUTANIX_MACHINE_MEMORY_SIZE=4Gi}" 15 | systemDiskSize: "${NUTANIX_SYSTEMDISK_SIZE=40Gi}" 16 | cluster: 17 | type: name 18 | name: "${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME}" 19 | subnet: 20 | - type: name 21 | name: "${NUTANIX_SUBNET_NAME}" 22 | imageLookup: 23 | baseOS: "${IMAGE_LOOKUP_BASE_OS}" 24 | format: "${IMAGE_LOOKUP_FORMAT}" 25 | -------------------------------------------------------------------------------- /package/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build the manager binary 2 | FROM golang:1.24 as builder 3 | 4 | WORKDIR /workspace 5 | # Copy the Go Modules manifests 6 | COPY go.mod go.mod 7 | COPY go.sum go.sum 8 | # cache deps before building and copying source so that we don't need to re-download as much 9 | # and so that source changes don't invalidate our downloaded layer 10 | RUN go mod download 11 | 12 | # Copy the go source 13 | COPY main.go main.go 14 | COPY api/ api/ 15 | COPY controllers/ controllers/ 16 | COPY pkg/ pkg/ 17 | 18 | # Build 19 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go 20 | 21 | # Use distroless as minimal base image to package the manager binary 22 | # Refer to https://github.com/GoogleContainerTools/distroless for more details 23 | #FROM gcr.io/distroless/static:nonroot 24 | FROM gcr.io/distroless/static:debug 25 | WORKDIR / 26 | COPY --from=builder /workspace/manager . 27 | USER 65532:65532 28 | 29 | ENTRYPOINT ["/manager"] 30 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-no-nmt/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/base/nutanix-cluster.yaml 5 | - ../../../../../../templates/base/cluster-without-topology.yaml 6 | - ../../../../../../templates/base/kcp.yaml 7 | - ../../../../../../templates/base/kct.yaml 8 | - ../../../../../../templates/base/secret.yaml 9 | - ../../../../../../templates/base/cm.yaml 10 | - ../../../../../../templates/base/md.yaml 11 | - ../../../../../../templates/base/mhc.yaml 12 | - ../../../../../../templates/ccm/nutanix-ccm-crs.yaml 13 | - ../../../../../../templates/ccm/nutanix-ccm-secret.yaml 14 | - ../base/crs.yaml 15 | patches: 16 | - path: ../base/cni-patch.yaml 17 | - path: ../../../../../../templates/base/ccm-patch.yaml 18 | configMapGenerator: 19 | - behavior: merge 20 | files: 21 | - ../../../../../../templates/ccm/nutanix-ccm.yaml 22 | name: nutanix-ccm 23 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-no-secret/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/base/nutanix-cluster.yaml 5 | - ../../../../../../templates/base/cluster-without-topology.yaml 6 | - ../../../../../../templates/base/kct.yaml 7 | - ../../../../../../templates/base/kcp.yaml 8 | - ../../../../../../templates/base/nmt.yaml 9 | - ../../../../../../templates/base/md.yaml 10 | - ../../../../../../templates/base/mhc.yaml 11 | - ../../../../../../templates/ccm/nutanix-ccm-crs.yaml 12 | - ../../../../../../templates/ccm/nutanix-ccm-secret.yaml 13 | - ../../../../../../templates/base/cm.yaml 14 | - ../base/crs.yaml 15 | patches: 16 | - path: ../base/cni-patch.yaml 17 | - path: ../../../../../../templates/base/ccm-patch.yaml 18 | configMapGenerator: 19 | - behavior: merge 20 | files: 21 | - ../../../../../../templates/ccm/nutanix-ccm.yaml 22 | name: nutanix-ccm 23 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-upgrades/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/base/nutanix-cluster.yaml 5 | - ../../../../../../templates/base/cluster-without-topology.yaml 6 | - ../../../../../../templates/base/kcp.yaml 7 | - ../../../../../../templates/base/kct.yaml 8 | - ../../../../../../templates/base/secret.yaml 9 | - ../../../../../../templates/base/cm.yaml 10 | - ../../../../../../templates/base/md.yaml 11 | - ../../../../../../templates/base/mhc.yaml 12 | - ../../../../../../templates/ccm/nutanix-ccm-crs.yaml 13 | - ../../../../../../templates/ccm/nutanix-ccm-secret.yaml 14 | - ../base/crs.yaml 15 | - ./nmt.yaml 16 | patches: 17 | - path: ../base/cni-patch.yaml 18 | - path: ../../../../../../templates/base/ccm-patch.yaml 19 | configMapGenerator: 20 | - behavior: merge 21 | files: 22 | - ../../../../../../templates/ccm/nutanix-ccm.yaml 23 | name: nutanix-ccm 24 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-image-lookup/lookup-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 2 | kind: NutanixMachineTemplate 3 | metadata: 4 | name: "${CLUSTER_NAME}-mt-0" 5 | spec: 6 | template: 7 | spec: 8 | providerID: "nutanix://${CLUSTER_NAME}-m1" 9 | # Supported options for boot type: legacy and uefi 10 | # Defaults to legacy if not set 11 | bootType: ${NUTANIX_MACHINE_BOOT_TYPE=legacy} 12 | vcpusPerSocket: ${NUTANIX_MACHINE_VCPU_PER_SOCKET=1} 13 | vcpuSockets: ${NUTANIX_MACHINE_VCPU_SOCKET=2} 14 | memorySize: "${NUTANIX_MACHINE_MEMORY_SIZE=4Gi}" 15 | systemDiskSize: "${NUTANIX_SYSTEMDISK_SIZE=40Gi}" 16 | cluster: 17 | type: name 18 | name: "${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME}" 19 | subnet: 20 | - type: name 21 | name: "${NUTANIX_SUBNET_NAME}" 22 | imageLookup: 23 | baseOS: "${IMAGE_LOOKUP_BASE_OS}" 24 | format: "${IMAGE_LOOKUP_FORMAT}" 25 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-kcp-remediation/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/base/nutanix-cluster.yaml 5 | - ../../../../../../templates/base/cluster-without-topology.yaml 6 | - ../../../../../../templates/base/kcp.yaml 7 | - ../../../../../../templates/base/kct.yaml 8 | - ../../../../../../templates/base/secret.yaml 9 | - ../../../../../../templates/base/cm.yaml 10 | - ../../../../../../templates/base/nmt.yaml 11 | - ../../../../../../templates/base/md.yaml 12 | - ../../../../../../templates/ccm/nutanix-ccm-crs.yaml 13 | - ../../../../../../templates/ccm/nutanix-ccm-secret.yaml 14 | - ../base/crs.yaml 15 | - ./mhc.yaml 16 | patches: 17 | - path: ../base/cni-patch.yaml 18 | - path: ../../../../../../templates/base/ccm-patch.yaml 19 | configMapGenerator: 20 | - behavior: merge 21 | files: 22 | - ../../../../../../templates/ccm/nutanix-ccm.yaml 23 | name: nutanix-ccm 24 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-no-nutanix-cluster/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/base/nutanix-cluster.yaml 5 | - ../../../../../../templates/base/cluster-without-topology.yaml 6 | - ../../../../../../templates/base/kcp.yaml 7 | - ../../../../../../templates/base/kct.yaml 8 | - ../../../../../../templates/base/nmt.yaml 9 | - ../../../../../../templates/base/cm.yaml 10 | - ../../../../../../templates/base/md.yaml 11 | - ../../../../../../templates/base/mhc.yaml 12 | - ../../../../../../templates/ccm/nutanix-ccm-crs.yaml 13 | - ../../../../../../templates/ccm/nutanix-ccm-secret.yaml 14 | - ../base/crs.yaml 15 | patches: 16 | - path: ../base/cni-patch.yaml 17 | - path: ./nc.yaml 18 | - path: ../../../../../../templates/base/ccm-patch.yaml 19 | configMapGenerator: 20 | - behavior: merge 21 | files: 22 | - ../../../../../../templates/ccm/nutanix-ccm.yaml 23 | name: nutanix-ccm 24 | -------------------------------------------------------------------------------- /templates/base/ccm-patch.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 2 | kind: KubeadmControlPlane 3 | metadata: 4 | name: "${CLUSTER_NAME}-kcp" 5 | spec: 6 | kubeadmConfigSpec: 7 | clusterConfiguration: 8 | controllerManager: 9 | extraArgs: 10 | cloud-provider: external 11 | initConfiguration: 12 | nodeRegistration: 13 | kubeletExtraArgs: 14 | cloud-provider: external 15 | joinConfiguration: 16 | nodeRegistration: 17 | kubeletExtraArgs: 18 | cloud-provider: external 19 | --- 20 | apiVersion: cluster.x-k8s.io/v1beta1 21 | kind: Cluster 22 | metadata: 23 | labels: 24 | ccm: "nutanix" 25 | name: "${CLUSTER_NAME}" 26 | --- 27 | apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 28 | kind: KubeadmConfigTemplate 29 | metadata: 30 | name: "${CLUSTER_NAME}-kcfg-0" 31 | spec: 32 | template: 33 | spec: 34 | joinConfiguration: 35 | nodeRegistration: 36 | kubeletExtraArgs: 37 | cloud-provider: external 38 | -------------------------------------------------------------------------------- /templates/clusterclass/kct.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 2 | kind: KubeadmConfigTemplate 3 | metadata: 4 | name: "nutanix-quick-start-kcfg-0" 5 | spec: 6 | template: 7 | spec: 8 | joinConfiguration: 9 | nodeRegistration: 10 | kubeletExtraArgs: 11 | cloud-provider: external 12 | eviction-hard: nodefs.available<10%,nodefs.inodesFree<5%,imagefs.available<15%,memory.available<100Mi,imagefs.inodesFree<10% 13 | tls-cipher-suites: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 14 | postKubeadmCommands: 15 | - echo "after kubeadm call" > /var/log/postkubeadm.log 16 | preKubeadmCommands: 17 | - echo "before kubeadm call" > /var/log/prekubeadm.log 18 | - hostnamectl set-hostname "{{ ds.meta_data.hostname }}" 19 | verbosity: 10 20 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-md-remediation/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/base/nutanix-cluster.yaml 5 | - ../../../../../../templates/base/cluster-without-topology.yaml 6 | - ../../../../../../templates/base/kcp.yaml 7 | - ../../../../../../templates/base/kct.yaml 8 | - ../../../../../../templates/base/secret.yaml 9 | - ../../../../../../templates/base/cm.yaml 10 | - ../../../../../../templates/base/nmt.yaml 11 | - ../../../../../../templates/base/md.yaml 12 | - ../../../../../../templates/ccm/nutanix-ccm-crs.yaml 13 | - ../../../../../../templates/ccm/nutanix-ccm-secret.yaml 14 | - ../base/crs.yaml 15 | - ./mhc.yaml 16 | patches: 17 | - path: ../base/cni-patch.yaml 18 | - path: ./md.yaml 19 | - path: ../../../../../../templates/base/ccm-patch.yaml 20 | configMapGenerator: 21 | - behavior: merge 22 | files: 23 | - ../../../../../../templates/ccm/nutanix-ccm.yaml 24 | name: nutanix-ccm 25 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-project/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/base/nutanix-cluster.yaml 5 | - ../../../../../../templates/base/cluster-without-topology.yaml 6 | - ../../../../../../templates/base/kcp.yaml 7 | - ../../../../../../templates/base/kct.yaml 8 | - ../../../../../../templates/base/secret.yaml 9 | - ../../../../../../templates/base/cm.yaml 10 | - ../../../../../../templates/base/nmt.yaml 11 | - ../../../../../../templates/base/md.yaml 12 | - ../../../../../../templates/base/mhc.yaml 13 | - ../../../../../../templates/ccm/nutanix-ccm-crs.yaml 14 | - ../../../../../../templates/ccm/nutanix-ccm-secret.yaml 15 | - ../base/crs.yaml 16 | patches: 17 | - path: ../base/cni-patch.yaml 18 | - path: ./nmt.yaml 19 | - path: ../../../../../../templates/base/ccm-patch.yaml 20 | configMapGenerator: 21 | - behavior: merge 22 | files: 23 | - ../../../../../../templates/ccm/nutanix-ccm.yaml 24 | name: nutanix-ccm 25 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-failure-domains/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/base/nutanix-cluster.yaml 5 | - ../../../../../../templates/base/cluster-without-topology.yaml 6 | - ../../../../../../templates/base/kcp.yaml 7 | - ../../../../../../templates/base/kct.yaml 8 | - ../../../../../../templates/base/secret.yaml 9 | - ../../../../../../templates/base/cm.yaml 10 | - ../../../../../../templates/base/md.yaml 11 | - ../../../../../../templates/base/mhc.yaml 12 | - ../../../../../../templates/ccm/nutanix-ccm-crs.yaml 13 | - ../../../../../../templates/ccm/nutanix-ccm-secret.yaml 14 | - ../base/crs.yaml 15 | - failure-domain-nmt.yaml 16 | patches: 17 | - path: ../base/cni-patch.yaml 18 | - path: failure-domain-patch.yaml 19 | - path: ../../../../../../templates/base/ccm-patch.yaml 20 | configMapGenerator: 21 | - behavior: merge 22 | files: 23 | - ../../../../../../templates/ccm/nutanix-ccm.yaml 24 | name: nutanix-ccm 25 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-failure-domains-migration/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - ../../../../../../templates/base/nutanix-cluster.yaml 5 | - ../../../../../../templates/base/cluster-without-topology.yaml 6 | - ../../../../../../templates/base/kcp.yaml 7 | - ../../../../../../templates/base/kct.yaml 8 | - ../../../../../../templates/base/secret.yaml 9 | - ../../../../../../templates/base/cm.yaml 10 | - ../../../../../../templates/base/md.yaml 11 | - ../../../../../../templates/base/mhc.yaml 12 | - ../../../../../../templates/ccm/nutanix-ccm-crs.yaml 13 | - ../../../../../../templates/ccm/nutanix-ccm-secret.yaml 14 | - ../base/crs.yaml 15 | - failure-domain-nmt.yaml 16 | patches: 17 | - path: ../base/cni-patch.yaml 18 | - path: failure-domain-patch.yaml 19 | - path: ../../../../../../templates/base/ccm-patch.yaml 20 | configMapGenerator: 21 | - behavior: merge 22 | files: 23 | - ../../../../../../templates/ccm/nutanix-ccm.yaml 24 | name: nutanix-ccm 25 | -------------------------------------------------------------------------------- /tools/imagebuilder/terraform/scripts/install_prerequisites.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2022 Nutanix 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # https://image-builder.sigs.k8s.io/capi/providers/raw.html 17 | sudo apt-get -y update 18 | sudo apt install -y git unzip make python3-pip qemu-kvm libvirt-daemon-system libvirt-clients virtinst cpu-checker libguestfs-tools libosinfo-bin 19 | sudo usermod -a -G kvm ${USER} 20 | sudo chown root:kvm /dev/kvm 21 | # exit and log back in to make the change take place. 22 | exit 0 -------------------------------------------------------------------------------- /docs/vscode-integration/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "type": "shell", 8 | "label": "Prepare vscode to run envtest-based tests", 9 | "detail": "Install envtest and configure the vscode-go test environment.", 10 | "group": { 11 | "kind": "test", 12 | "isDefault": true 13 | }, 14 | "command": [ 15 | "echo $(make print-envtest) > ${workspaceFolder}/.vscode/test.env", 16 | ], 17 | "presentation": { 18 | "echo": true, 19 | "reveal": "silent", 20 | "focus": false, 21 | "panel": "shared", 22 | "showReuseMessage": false, 23 | "clear": false 24 | }, 25 | "runOptions": { 26 | "runOn": "folderOpen", 27 | "instanceLimit": 1, 28 | }, 29 | "promptOnClose": true, 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /templates/clusterclass/nmt-cp.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 2 | kind: NutanixMachineTemplate 3 | metadata: 4 | name: "nutanix-quick-start-cp-nmt" 5 | spec: 6 | template: 7 | spec: 8 | # Supported options for boot type: legacy and uefi 9 | # Defaults to legacy if not set 10 | bootType: legacy 11 | vcpusPerSocket: 1 12 | vcpuSockets: 2 13 | memorySize: 4Gi 14 | systemDiskSize: 40Gi 15 | image: 16 | type: name 17 | name: "placeholder-image" 18 | # Adds additional categories to the virtual machines. 19 | # Note: Categories must already be present in Prism Central 20 | # additionalCategories: 21 | # - key: AppType 22 | # value: Kubernetes 23 | # Adds the cluster virtual machines to a project defined in Prism Central. 24 | # Replace NUTANIX_PROJECT_NAME with the correct project defined in Prism Central 25 | # Note: Project must already be present in Prism Central. 26 | # project: 27 | # type: name 28 | # name: "NUTANIX_PROJECT_NAME" 29 | # gpus: 30 | # - type: name 31 | # name: "GPU NAME" 32 | -------------------------------------------------------------------------------- /templates/clusterclass/nmt-md.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 2 | kind: NutanixMachineTemplate 3 | metadata: 4 | name: "nutanix-quick-start-md-nmt" 5 | spec: 6 | template: 7 | spec: 8 | # Supported options for boot type: legacy and uefi 9 | # Defaults to legacy if not set 10 | bootType: legacy 11 | vcpusPerSocket: 1 12 | vcpuSockets: 2 13 | memorySize: 4Gi 14 | systemDiskSize: 40Gi 15 | image: 16 | type: name 17 | name: "placeholder-image" 18 | # Adds additional categories to the virtual machines. 19 | # Note: Categories must already be present in Prism Central 20 | # additionalCategories: 21 | # - key: AppType 22 | # value: Kubernetes 23 | # Adds the cluster virtual machines to a project defined in Prism Central. 24 | # Replace NUTANIX_PROJECT_NAME with the correct project defined in Prism Central 25 | # Note: Project must already be present in Prism Central. 26 | # project: 27 | # type: name 28 | # name: "NUTANIX_PROJECT_NAME" 29 | # gpus: 30 | # - type: name 31 | # name: "GPU NAME" 32 | -------------------------------------------------------------------------------- /tools/imagebuilder/README.md: -------------------------------------------------------------------------------- 1 | # Steps to create raw OS image for NutanixMachineTemplate 2 | 3 | ## To create build vm on Nutanix Cloud Infrastructure 4 | Create terraform/terraform.tfvars file with following information and assiging appropriate values 5 |
 6 | endpoint     = ""
 7 | password     = ""
 8 | user         = ""
 9 | image_url    = "https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img"
10 | cluster_name = ""
11 | vm_name      = "capi_build_vm"
12 | vm_user      = "ubuntu"
13 | subnet_name  = ""
14 | public_key_file_path   = ""
15 | private_key_file_path  = ""
16 | 
17 | 18 | Then run following command 19 |
20 | ./create_image_build.sh
21 | 
22 | 23 | This will create a ubuntu build vm, build the image and copy it to local output directory from remote vm. 24 | You can find the os image in following dir ./terraform/output/ on your local machine 25 | 26 | Upload this image into Nutanix Image Service and use it for creating cluster by specifying it in NutanixMachineTemplate under image section. 27 | 28 | ## To destroy the build vm 29 | Destroy build vm by running following command 30 |
31 | ./delete_image_build_vm.sh
32 | 
-------------------------------------------------------------------------------- /templates/base/kct.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 2 | kind: KubeadmConfigTemplate 3 | metadata: 4 | name: "${CLUSTER_NAME}-kcfg-0" 5 | spec: 6 | template: 7 | spec: 8 | joinConfiguration: 9 | nodeRegistration: 10 | kubeletExtraArgs: 11 | cloud-provider: external 12 | eviction-hard: nodefs.available<10%,nodefs.inodesFree<5%,imagefs.available<15%,memory.available<100Mi,imagefs.inodesFree<10% 13 | tls-cipher-suites: ${TLS_CIPHER_SUITES=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256} 14 | postKubeadmCommands: 15 | - echo "after kubeadm call" > /var/log/postkubeadm.log 16 | preKubeadmCommands: 17 | - echo "before kubeadm call" > /var/log/prekubeadm.log 18 | - hostnamectl set-hostname "{{ ds.meta_data.hostname }}" 19 | users: 20 | - lockPassword: false 21 | name: capiuser 22 | sshAuthorizedKeys: 23 | - ${NUTANIX_SSH_AUTHORIZED_KEY} 24 | sudo: ALL=(ALL) NOPASSWD:ALL 25 | verbosity: 10 26 | -------------------------------------------------------------------------------- /templates/failure-domains/failure-domains.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 3 | kind: NutanixFailureDomain 4 | metadata: 5 | name: "${NUTANIX_FAILURE_DOMAIN_1_NAME}" 6 | namespace: "${NAMESPACE}" 7 | spec: 8 | prismElementCluster: 9 | type: name 10 | name: "${NUTANIX_FAILURE_DOMAIN_1_PRISM_ELEMENT_NAME}" 11 | subnets: 12 | - type: name 13 | name: "${NUTANIX_FAILURE_DOMAIN_1_SUBNET_NAME}" 14 | --- 15 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 16 | kind: NutanixFailureDomain 17 | metadata: 18 | name: "${NUTANIX_FAILURE_DOMAIN_2_NAME}" 19 | namespace: "${NAMESPACE}" 20 | spec: 21 | prismElementCluster: 22 | type: name 23 | name: "${NUTANIX_FAILURE_DOMAIN_2_PRISM_ELEMENT_NAME}" 24 | subnets: 25 | - type: name 26 | name: "${NUTANIX_FAILURE_DOMAIN_2_SUBNET_NAME}" 27 | --- 28 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 29 | kind: NutanixFailureDomain 30 | metadata: 31 | name: "${NUTANIX_FAILURE_DOMAIN_3_NAME}" 32 | namespace: "${NAMESPACE}" 33 | spec: 34 | prismElementCluster: 35 | type: name 36 | name: "${NUTANIX_FAILURE_DOMAIN_3_PRISM_ELEMENT_NAME}" 37 | subnets: 38 | - type: name 39 | name: "${NUTANIX_FAILURE_DOMAIN_3_SUBNET_NAME}" 40 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-csi/kcp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 3 | kind: KubeadmControlPlane 4 | metadata: 5 | name: "${CLUSTER_NAME}-kcp" 6 | namespace: "${NAMESPACE}" 7 | spec: 8 | kubeadmConfigSpec: 9 | preKubeadmCommands: 10 | - echo "before kubeadm call" > /var/log/prekubeadm.log 11 | - hostnamectl set-hostname "{{ ds.meta_data.hostname }}" 12 | - apt update 13 | - apt install -y nfs-common open-iscsi lvm2 xfsprogs 14 | - systemctl enable --now iscsid 15 | - echo "::1 ipv6-localhost ipv6-loopback" >/etc/hosts 16 | - echo "127.0.0.1 localhost" >>/etc/hosts 17 | - echo "127.0.0.1 kubernetes" >>/etc/hosts 18 | - echo "127.0.0.1 {{ ds.meta_data.hostname }}" >> /etc/hosts 19 | - | 20 | KUBERNETES_VERSION_NO_V=${KUBERNETES_VERSION#v} 21 | VERSION_TO_COMPARE=1.29.0 22 | if [ "$(printf '%s\n' "$KUBERNETES_VERSION_NO_V" "$VERSION_TO_COMPARE" | sort -V | head -n1)" != "$KUBERNETES_VERSION_NO_V" ]; then 23 | if [ -f /run/kubeadm/kubeadm.yaml ]; then 24 | sed -i 's#path: /etc/kubernetes/admin.conf#path: /etc/kubernetes/super-admin.conf#' /etc/kubernetes/manifests/kube-vip.yaml; 25 | fi 26 | fi 27 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-csi3/kcp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 3 | kind: KubeadmControlPlane 4 | metadata: 5 | name: "${CLUSTER_NAME}-kcp" 6 | namespace: "${NAMESPACE}" 7 | spec: 8 | kubeadmConfigSpec: 9 | preKubeadmCommands: 10 | - echo "before kubeadm call" > /var/log/prekubeadm.log 11 | - hostnamectl set-hostname "{{ ds.meta_data.hostname }}" 12 | - apt update 13 | - apt install -y nfs-common open-iscsi lvm2 xfsprogs 14 | - systemctl enable --now iscsid 15 | - echo "::1 ipv6-localhost ipv6-loopback" >/etc/hosts 16 | - echo "127.0.0.1 localhost" >>/etc/hosts 17 | - echo "127.0.0.1 kubernetes" >>/etc/hosts 18 | - echo "127.0.0.1 {{ ds.meta_data.hostname }}" >> /etc/hosts 19 | - | 20 | KUBERNETES_VERSION_NO_V=${KUBERNETES_VERSION#v} 21 | VERSION_TO_COMPARE=1.29.0 22 | if [ "$(printf '%s\n' "$KUBERNETES_VERSION_NO_V" "$VERSION_TO_COMPARE" | sort -V | head -n1)" != "$KUBERNETES_VERSION_NO_V" ]; then 23 | if [ -f /run/kubeadm/kubeadm.yaml ]; then 24 | sed -i 's#path: /etc/kubernetes/admin.conf#path: /etc/kubernetes/super-admin.conf#' /etc/kubernetes/manifests/kube-vip.yaml; 25 | fi 26 | fi 27 | -------------------------------------------------------------------------------- /scripts/csi_nutanix_update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2021 Nutanix. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | NUTANIX_CSI_SNAPSHOT_VERSION=6.3.3 17 | NUTANIX_CSI_STORAGE_VERSION=2.6.10 18 | 19 | helm repo add nutanix https://nutanix.github.io/helm/ --force-update && helm repo update 20 | 21 | helm template -n ntnx-system nutanix-snapshot nutanix/nutanix-csi-snapshot --set tls.source=secret > templates/csi/nutanix-csi-snapshot.yaml 22 | 23 | ex templates/csi/nutanix-csi-snapshot.yaml < templates/csi/nutanix-csi-storage.yaml 29 | -------------------------------------------------------------------------------- /test/e2e/k8s_conformance_test.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | /* 4 | Copyright 2022 Nutanix, Inc 5 | Copyright 2020 The Kubernetes Authors. 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package e2e 18 | 19 | import ( 20 | . "github.com/onsi/ginkgo/v2" 21 | 22 | capi_e2e "sigs.k8s.io/cluster-api/test/e2e" 23 | ) 24 | 25 | var _ = Describe("When testing K8S conformance", Label("conformance"), func() { 26 | capi_e2e.K8SConformanceSpec(ctx, func() capi_e2e.K8SConformanceSpecInput { 27 | return capi_e2e.K8SConformanceSpecInput{ 28 | E2EConfig: e2eConfig, 29 | ClusterctlConfigPath: clusterctlConfigPath, 30 | BootstrapClusterProxy: bootstrapClusterProxy, 31 | ArtifactFolder: artifactFolder, 32 | SkipCleanup: skipCleanup, 33 | } 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /metadata.yaml: -------------------------------------------------------------------------------- 1 | # maps release series of major.minor to cluster-api contract version 2 | # the contract version may change between minor or major versions, but *not* 3 | # between patch versions. 4 | # 5 | # TODO(release-blocker): update this file only when a new major or minor version is released 6 | 7 | apiVersion: clusterctl.cluster.x-k8s.io/v1alpha3 8 | kind: Metadata 9 | releaseSeries: 10 | - major: 0 11 | minor: 1 12 | contract: v1alpha4 13 | - major: 0 14 | minor: 2 15 | contract: v1beta1 16 | - major: 0 17 | minor: 3 18 | contract: v1beta1 19 | - major: 0 20 | minor: 4 21 | contract: v1beta1 22 | - major: 0 23 | minor: 5 24 | contract: v1beta1 25 | - major: 1 26 | minor: 0 27 | contract: v1beta1 28 | - major: 1 29 | minor: 1 30 | contract: v1beta1 31 | - major: 1 32 | minor: 2 33 | contract: v1beta1 34 | - major: 1 35 | minor: 3 36 | contract: v1beta1 37 | - major: 1 38 | minor: 4 39 | contract: v1beta1 40 | - major: 1 41 | minor: 5 42 | contract: v1beta1 43 | - major: 1 44 | minor: 6 45 | contract: v1beta1 46 | - major: 1 47 | minor: 7 48 | contract: v1beta1 49 | - major: 1 50 | minor: 8 51 | contract: v1beta1 52 | - major: 0 53 | minor: 0 54 | contract: v1beta1 55 | -------------------------------------------------------------------------------- /pkg/client/testdata/validTestCA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx 3 | GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds 4 | b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV 5 | BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD 6 | VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa 7 | DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc 8 | THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb 9 | Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP 10 | c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX 11 | gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV 12 | HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF 13 | AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj 14 | Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG 15 | j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH 16 | hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC 17 | X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== 18 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /scripts/ccm_nutanix_update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2022 Nutanix. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | NUTANIX_CCM_VERSION=0.6.0 17 | NUTANIX_CCM_REPO=ghcr.io/nutanix-cloud-native/cloud-provider-nutanix/controller 18 | 19 | helm repo add nutanix https://nutanix.github.io/helm/ --force-update && helm repo update 20 | 21 | helm template -n kube-system nutanix-cloud-provider nutanix/nutanix-cloud-provider --version ${NUTANIX_CCM_VERSION} \ 22 | --set prismCentralEndPoint='${NUTANIX_ENDPOINT}',prismCentralPort='${NUTANIX_PORT=9440}',prismCentralInsecure='${NUTANIX_INSECURE=false}' \ 23 | --set image.repository="\${CCM_REPO=$NUTANIX_CCM_REPO}",image.tag="\${CCM_TAG=v$NUTANIX_CCM_VERSION}" \ 24 | --set createSecret=false \ 25 | > templates/ccm/nutanix-ccm.yaml 26 | -------------------------------------------------------------------------------- /test/e2e/md_rollout_test.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | /* 4 | Copyright 2020 The Kubernetes Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package e2e 20 | 21 | import ( 22 | . "github.com/onsi/ginkgo/v2" 23 | 24 | capi_e2e "sigs.k8s.io/cluster-api/test/e2e" 25 | ) 26 | 27 | var _ = Describe("When testing MachineDeployment rolling upgrades", Label("scaling", "md-rolling-upgrades"), func() { 28 | capi_e2e.MachineDeploymentRolloutSpec(ctx, func() capi_e2e.MachineDeploymentRolloutSpecInput { 29 | return capi_e2e.MachineDeploymentRolloutSpecInput{ 30 | E2EConfig: e2eConfig, 31 | ClusterctlConfigPath: clusterctlConfigPath, 32 | BootstrapClusterProxy: bootstrapClusterProxy, 33 | ArtifactFolder: artifactFolder, 34 | SkipCleanup: skipCleanup, 35 | } 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /test/e2e/mhc_remediations_test.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | /* 4 | Copyright 2020 The Kubernetes Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package e2e 20 | 21 | import ( 22 | . "github.com/onsi/ginkgo/v2" 23 | 24 | capi_e2e "sigs.k8s.io/cluster-api/test/e2e" 25 | ) 26 | 27 | var _ = Describe("When testing unhealthy machines remediation", Label("scaling", "machine-health-remediation"), func() { 28 | capi_e2e.MachineDeploymentRemediationSpec(ctx, func() capi_e2e.MachineDeploymentRemediationSpecInput { 29 | return capi_e2e.MachineDeploymentRemediationSpecInput{ 30 | E2EConfig: e2eConfig, 31 | ClusterctlConfigPath: clusterctlConfigPath, 32 | BootstrapClusterProxy: bootstrapClusterProxy, 33 | ArtifactFolder: artifactFolder, 34 | SkipCleanup: skipCleanup, 35 | } 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /PROJECT: -------------------------------------------------------------------------------- 1 | # Code generated by tool. DO NOT EDIT. 2 | # This file is used to track the info used to scaffold your project 3 | # and allow the plugins properly work. 4 | # More info: https://book.kubebuilder.io/reference/project-config.html 5 | domain: cluster.x-k8s.io 6 | layout: 7 | - go.kubebuilder.io/v3 8 | projectName: cluster-api-provider-nutanix 9 | repo: github.com/nutanix-cloud-native/cluster-api-provider-nutanix 10 | resources: 11 | - api: 12 | crdVersion: v1 13 | namespaced: true 14 | controller: true 15 | domain: cluster.x-k8s.io 16 | group: infrastructure 17 | kind: NutanixCluster 18 | path: github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1 19 | version: v1beta1 20 | - api: 21 | crdVersion: v1 22 | namespaced: true 23 | controller: true 24 | domain: cluster.x-k8s.io 25 | group: infrastructure 26 | kind: NutanixMachine 27 | path: github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1 28 | version: v1beta1 29 | - api: 30 | crdVersion: v1 31 | namespaced: true 32 | domain: cluster.x-k8s.io 33 | group: infrastructure 34 | kind: NutanixMachineTemplate 35 | path: github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1 36 | version: v1beta1 37 | - api: 38 | crdVersion: v1 39 | namespaced: true 40 | domain: cluster.x-k8s.io 41 | group: infrastructure 42 | kind: NutanixClusterTemplate 43 | path: github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1 44 | version: v1beta1 45 | version: "3" 46 | -------------------------------------------------------------------------------- /templates/base/nmt.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 3 | kind: NutanixMachineTemplate 4 | metadata: 5 | name: "${CLUSTER_NAME}-mt-0" 6 | spec: 7 | template: 8 | spec: 9 | providerID: "nutanix://${CLUSTER_NAME}-m1" 10 | # Supported options for boot type: legacy and uefi 11 | # Defaults to legacy if not set 12 | bootType: ${NUTANIX_MACHINE_BOOT_TYPE=legacy} 13 | vcpusPerSocket: ${NUTANIX_MACHINE_VCPU_PER_SOCKET=1} 14 | vcpuSockets: ${NUTANIX_MACHINE_VCPU_SOCKET=2} 15 | memorySize: "${NUTANIX_MACHINE_MEMORY_SIZE=4Gi}" 16 | systemDiskSize: "${NUTANIX_SYSTEMDISK_SIZE=40Gi}" 17 | image: 18 | type: name 19 | name: "${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME}" 20 | cluster: 21 | type: name 22 | name: "${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME}" 23 | subnet: 24 | - type: name 25 | name: "${NUTANIX_SUBNET_NAME}" 26 | # Adds additional categories to the virtual machines. 27 | # Note: Categories must already be present in Prism Central 28 | # additionalCategories: 29 | # - key: AppType 30 | # value: Kubernetes 31 | # Adds the cluster virtual machines to a project defined in Prism Central. 32 | # Replace NUTANIX_PROJECT_NAME with the correct project defined in Prism Central 33 | # Note: Project must already be present in Prism Central. 34 | # project: 35 | # type: name 36 | # name: "NUTANIX_PROJECT_NAME" 37 | # gpus: 38 | # - type: name 39 | # name: "GPU NAME" 40 | -------------------------------------------------------------------------------- /pkg/client/testdata/validTestManagerCA.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u 3 | ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp 4 | bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV 5 | BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx 6 | NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 7 | d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl 8 | MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u 9 | ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A 10 | MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL 11 | Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr 12 | hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW 13 | nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi 14 | VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E 15 | BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ 16 | KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy 17 | T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf 18 | zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT 19 | J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e 20 | nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= 21 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /pkg/client/cache.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | v4Converged "github.com/nutanix-cloud-native/prism-go-client/converged/v4" 5 | "github.com/nutanix-cloud-native/prism-go-client/environment/types" 6 | v3 "github.com/nutanix-cloud-native/prism-go-client/v3" 7 | v4 "github.com/nutanix-cloud-native/prism-go-client/v4" 8 | 9 | "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" 10 | ) 11 | 12 | // NutanixClientCache is the cache of prism clients to be shared across the different controllers 13 | var NutanixClientCache = v3.NewClientCache(v3.WithSessionAuth(true)) 14 | 15 | // NutanixClientCacheV4 is the cache of prism clients to be shared across the different controllers 16 | var NutanixClientCacheV4 = v4.NewClientCache(v4.WithSessionAuth(true)) 17 | 18 | // NutanixConvergedClientV4Cache is the cache of prism clients to be shared across the different controllers 19 | var NutanixConvergedClientV4Cache = v4Converged.NewClientCache(v4.WithSessionAuth(true)) 20 | 21 | // CacheParams is the struct that implements ClientCacheParams interface from prism-go-client 22 | type CacheParams struct { 23 | NutanixCluster *v1beta1.NutanixCluster 24 | PrismManagementEndpoint *types.ManagementEndpoint 25 | } 26 | 27 | // Key is the namespace/name of te NutanixCluster CR 28 | func (c *CacheParams) Key() string { 29 | return c.NutanixCluster.GetNamespacedName() 30 | } 31 | 32 | // ManagementEndpoint returns the management endpoint of the NutanixCluster CR 33 | func (c *CacheParams) ManagementEndpoint() types.ManagementEndpoint { 34 | return *c.PrismManagementEndpoint 35 | } 36 | -------------------------------------------------------------------------------- /api/v1beta1/groupversion_info.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package v1beta1 contains API Schema definitions for the infrastructure v1beta1 API group 18 | // +kubebuilder:object:generate=true 19 | // +groupName=infrastructure.cluster.x-k8s.io 20 | package v1beta1 21 | 22 | import ( 23 | "k8s.io/apimachinery/pkg/runtime/schema" 24 | "sigs.k8s.io/controller-runtime/pkg/scheme" 25 | ) 26 | 27 | const ( 28 | // Version is the API version. 29 | Version = "v1beta1" 30 | 31 | // GroupName is the name of the API group. 32 | GroupName = "infrastructure.cluster.x-k8s.io" 33 | ) 34 | 35 | var ( 36 | // GroupVersion is group version used to register these objects 37 | GroupVersion = schema.GroupVersion{Group: GroupName, Version: Version} 38 | 39 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme 40 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} 41 | 42 | // AddToScheme adds the types in this group-version to the given scheme. 43 | AddToScheme = SchemeBuilder.AddToScheme 44 | ) 45 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-failure-domains/failure-domain-patch.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 3 | kind: NutanixCluster 4 | metadata: 5 | name: ${CLUSTER_NAME} 6 | spec: 7 | failureDomains: 8 | - name: ${NUTANIX_FAILURE_DOMAIN_1_NAME} 9 | controlPlane: true 10 | cluster: 11 | name: ${NUTANIX_FAILURE_DOMAIN_1_PRISM_ELEMENT_NAME} 12 | type: name 13 | subnets: 14 | - name: ${NUTANIX_FAILURE_DOMAIN_1_SUBNET_NAME} 15 | type: name 16 | - name: ${NUTANIX_FAILURE_DOMAIN_2_NAME} 17 | controlPlane: true 18 | cluster: 19 | name: ${NUTANIX_FAILURE_DOMAIN_2_PRISM_ELEMENT_NAME} 20 | type: name 21 | subnets: 22 | - name: ${NUTANIX_FAILURE_DOMAIN_2_SUBNET_NAME} 23 | type: name 24 | - name: ${NUTANIX_FAILURE_DOMAIN_3_NAME} 25 | controlPlane: true 26 | cluster: 27 | name: ${NUTANIX_FAILURE_DOMAIN_3_PRISM_ELEMENT_NAME} 28 | type: name 29 | subnets: 30 | - name: ${NUTANIX_FAILURE_DOMAIN_3_SUBNET_NAME} 31 | type: name 32 | --- 33 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 34 | kind: KubeadmControlPlane 35 | metadata: 36 | name: ${CLUSTER_NAME}-kcp 37 | spec: 38 | replicas: 3 39 | --- 40 | apiVersion: cluster.x-k8s.io/v1beta1 41 | kind: MachineDeployment 42 | metadata: 43 | labels: 44 | cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} 45 | name: ${CLUSTER_NAME}-wmd 46 | spec: 47 | replicas: 0 48 | template: 49 | spec: 50 | failureDomain: ${NUTANIX_FAILURE_DOMAIN_1_NAME} 51 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-failure-domains-migration/failure-domain-patch.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 3 | kind: NutanixCluster 4 | metadata: 5 | name: ${CLUSTER_NAME} 6 | spec: 7 | failureDomains: 8 | - name: ${NUTANIX_FAILURE_DOMAIN_1_NAME} 9 | controlPlane: true 10 | cluster: 11 | name: ${NUTANIX_FAILURE_DOMAIN_1_PRISM_ELEMENT_NAME} 12 | type: name 13 | subnets: 14 | - name: ${NUTANIX_FAILURE_DOMAIN_1_SUBNET_NAME} 15 | type: name 16 | - name: ${NUTANIX_FAILURE_DOMAIN_2_NAME} 17 | controlPlane: true 18 | cluster: 19 | name: ${NUTANIX_FAILURE_DOMAIN_2_PRISM_ELEMENT_NAME} 20 | type: name 21 | subnets: 22 | - name: ${NUTANIX_FAILURE_DOMAIN_2_SUBNET_NAME} 23 | type: name 24 | - name: ${NUTANIX_FAILURE_DOMAIN_3_NAME} 25 | controlPlane: true 26 | cluster: 27 | name: ${NUTANIX_FAILURE_DOMAIN_3_PRISM_ELEMENT_NAME} 28 | type: name 29 | subnets: 30 | - name: ${NUTANIX_FAILURE_DOMAIN_3_SUBNET_NAME} 31 | type: name 32 | --- 33 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 34 | kind: KubeadmControlPlane 35 | metadata: 36 | name: ${CLUSTER_NAME}-kcp 37 | spec: 38 | replicas: 3 39 | --- 40 | apiVersion: cluster.x-k8s.io/v1beta1 41 | kind: MachineDeployment 42 | metadata: 43 | labels: 44 | cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} 45 | name: ${CLUSTER_NAME}-wmd 46 | spec: 47 | replicas: 1 48 | template: 49 | spec: 50 | failureDomain: ${NUTANIX_FAILURE_DOMAIN_1_NAME} 51 | -------------------------------------------------------------------------------- /controllers/options.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "errors" 5 | 6 | "k8s.io/client-go/util/workqueue" 7 | "sigs.k8s.io/controller-runtime/pkg/reconcile" 8 | ) 9 | 10 | // ControllerConfig is the configuration for cluster and machine controllers 11 | type ControllerConfig struct { 12 | MaxConcurrentReconciles int 13 | RateLimiter workqueue.TypedRateLimiter[reconcile.Request] 14 | SkipNameValidation bool 15 | } 16 | 17 | // ControllerConfigOpts is a function that can be used to configure the controller config 18 | type ControllerConfigOpts func(*ControllerConfig) error 19 | 20 | // WithMaxConcurrentReconciles sets the maximum number of concurrent reconciles 21 | func WithMaxConcurrentReconciles(max int) ControllerConfigOpts { 22 | return func(c *ControllerConfig) error { 23 | if max < 1 { 24 | return errors.New("max concurrent reconciles must be greater than 0") 25 | } 26 | c.MaxConcurrentReconciles = max 27 | return nil 28 | } 29 | } 30 | 31 | // WithRateLimiter sets the rate limiter for the controller 32 | func WithRateLimiter(rateLimiter workqueue.TypedRateLimiter[reconcile.Request]) ControllerConfigOpts { 33 | return func(c *ControllerConfig) error { 34 | if rateLimiter == nil { 35 | return errors.New("rate limiter cannot be nil") 36 | } 37 | c.RateLimiter = rateLimiter 38 | return nil 39 | } 40 | } 41 | 42 | // WithSkipNameValidation sets whether to skip name validation in controller options 43 | func WithSkipNameValidation(skip bool) ControllerConfigOpts { 44 | return func(c *ControllerConfig) error { 45 | c.SkipNameValidation = skip 46 | return nil 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.github/workflows/trivy-scan.yaml: -------------------------------------------------------------------------------- 1 | name: Trivy Scan 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: "17 17 * * *" 7 | 8 | permissions: 9 | contents: read 10 | 11 | jobs: 12 | build: 13 | permissions: 14 | contents: read 15 | security-events: write 16 | name: Scan 17 | runs-on: "ubuntu-latest" 18 | steps: 19 | - name: Checkout Code 20 | uses: actions/checkout@v4 21 | 22 | - name: Get repository name 23 | run: echo "REPOSITORY_NAME=${GITHUB_REPOSITORY#*/}" >> $GITHUB_ENV 24 | - name: Install devbox 25 | run: curl -fsSL https://get.jetpack.io/devbox | bash -s -- -f 26 | - name: Install devbox deps 27 | run: devbox install 28 | 29 | - name: Prepare build 30 | run: devbox run -- make manifests generate 31 | 32 | - name: Build container 33 | env: 34 | KO_DOCKER_REPO: ko.local 35 | PLATFORMS: linux/amd64,linux/arm64,linux/arm 36 | run: | 37 | export SOURCE_DATE_EPOCH=$(date +%s) 38 | devbox run -- ko build -B -t ${{ github.sha }} --platform=$PLATFORMS . 39 | 40 | - name: Run Trivy vulnerability scanner 41 | uses: aquasecurity/trivy-action@0.16.1 42 | with: 43 | image-ref: "ko.local/${{ env.REPOSITORY_NAME }}:${{ github.sha }}" 44 | format: "sarif" 45 | output: "trivy-results.sarif" 46 | severity: "CRITICAL,HIGH" 47 | 48 | - name: Upload Trivy scan results to GitHub Security tab 49 | uses: github/codeql-action/upload-sarif@v3 50 | with: 51 | sarif_file: "trivy-results.sarif" 52 | -------------------------------------------------------------------------------- /config/rbac/role.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRole 4 | metadata: 5 | name: manager-role 6 | rules: 7 | - apiGroups: 8 | - "" 9 | resources: 10 | - configmaps 11 | - secrets 12 | verbs: 13 | - delete 14 | - get 15 | - list 16 | - update 17 | - watch 18 | - apiGroups: 19 | - "" 20 | resources: 21 | - nodes 22 | verbs: 23 | - get 24 | - list 25 | - patch 26 | - watch 27 | - apiGroups: 28 | - bootstrap.cluster.x-k8s.io 29 | resources: 30 | - kubeadmconfigs 31 | verbs: 32 | - get 33 | - list 34 | - patch 35 | - update 36 | - watch 37 | - apiGroups: 38 | - cluster.x-k8s.io 39 | resources: 40 | - clusters 41 | verbs: 42 | - get 43 | - list 44 | - patch 45 | - update 46 | - watch 47 | - apiGroups: 48 | - cluster.x-k8s.io 49 | resources: 50 | - clusters/status 51 | - machines 52 | - machines/status 53 | verbs: 54 | - get 55 | - list 56 | - watch 57 | - apiGroups: 58 | - infrastructure.cluster.x-k8s.io 59 | resources: 60 | - nutanixclusters 61 | - nutanixfailuredomains 62 | - nutanixmachines 63 | verbs: 64 | - create 65 | - delete 66 | - get 67 | - list 68 | - patch 69 | - update 70 | - watch 71 | - apiGroups: 72 | - infrastructure.cluster.x-k8s.io 73 | resources: 74 | - nutanixclusters/finalizers 75 | - nutanixmachines/finalizers 76 | verbs: 77 | - update 78 | - apiGroups: 79 | - infrastructure.cluster.x-k8s.io 80 | resources: 81 | - nutanixclusters/status 82 | - nutanixfailuredomains/finalizers 83 | - nutanixfailuredomains/status 84 | - nutanixmachines/status 85 | verbs: 86 | - get 87 | - patch 88 | - update 89 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "Code Scanning - Action" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - 'release-*' 8 | pull_request: 9 | schedule: 10 | - cron: '30 1 * * 0' 11 | 12 | jobs: 13 | CodeQL-Build: 14 | runs-on: ubuntu-latest 15 | 16 | permissions: 17 | # required for all workflows 18 | security-events: write 19 | 20 | # only required for workflows in private repositories 21 | actions: read 22 | contents: read 23 | 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@v4 27 | 28 | # Initializes the CodeQL tools for scanning. 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v3 31 | # Override language selection by uncommenting this and choosing your languages 32 | # with: 33 | # languages: go, javascript, csharp, python, cpp, java 34 | 35 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 36 | # If this step fails, then you should remove it and run the build manually (see below). 37 | - name: Autobuild 38 | uses: github/codeql-action/autobuild@v3 39 | 40 | # ℹ️ Command-line programs to run using the OS shell. 41 | # 📚 https://git.io/JvXDl 42 | 43 | # ✏️ If the Autobuild fails above, remove it and uncomment the following 44 | # three lines and modify them (or add more) to build your code if your 45 | # project uses a compiled language 46 | 47 | #- run: | 48 | # make bootstrap 49 | # make release 50 | 51 | - name: Perform CodeQL Analysis 52 | uses: github/codeql-action/analyze@v3 53 | -------------------------------------------------------------------------------- /test/e2e/log/log.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | // +build e2e 3 | 4 | /* 5 | Copyright 2022 Nutanix 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package log 21 | 22 | import ( 23 | "fmt" 24 | 25 | ginkgov2 "github.com/onsi/ginkgo/v2" 26 | ) 27 | 28 | const ( 29 | // Debug log level 30 | LogDebug = "DEBUG" 31 | 32 | // Info log level 33 | LogInfo = "INFO" 34 | 35 | // Warn log level 36 | LogWarn = "WARN" 37 | 38 | // Error log level 39 | LogError = "ERROR" 40 | ) 41 | 42 | // Debugf logs a debug message 43 | func Debugf(format string, a ...interface{}) { 44 | Logf(LogDebug, format, a...) 45 | } 46 | 47 | // Infof logs an info message 48 | func Infof(format string, a ...interface{}) { 49 | Logf(LogInfo, format, a...) 50 | } 51 | 52 | // Warnf logs a warning message 53 | func Warnf(format string, a ...interface{}) { 54 | Logf(LogWarn, format, a...) 55 | } 56 | 57 | // Errorf logs an error message 58 | func Errorf(format string, a ...interface{}) { 59 | Logf(LogError, format, a...) 60 | } 61 | 62 | // Logf logs a message with the given level 63 | func Logf(level string, format string, a ...interface{}) { 64 | msg := level + ": " + format + "\n" 65 | fmt.Fprintf(ginkgov2.GinkgoWriter, msg, a...) 66 | } 67 | -------------------------------------------------------------------------------- /package/certs/digicertca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh 3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 4 | d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD 5 | QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT 6 | MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg 7 | U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB 8 | ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83 9 | nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd 10 | KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f 11 | /ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX 12 | kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0 13 | /RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C 14 | AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY 15 | aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6 16 | Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1 17 | oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD 18 | QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v 19 | d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh 20 | xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB 21 | CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl 22 | 5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA 23 | 8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC 24 | 2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit 25 | c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0 26 | j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz 27 | -----END CERTIFICATE----- 28 | -------------------------------------------------------------------------------- /hack/flakes/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1710146030, 9 | "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1725983898, 24 | "narHash": "sha256-4b3A9zPpxAxLnkF9MawJNHDtOOl6ruL0r6Og1TEDGCE=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "1355a0cbfeac61d785b7183c0caaec1f97361b43", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "NixOS", 32 | "ref": "nixos-unstable", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /api/v1beta1/suite_test.go: -------------------------------------------------------------------------------- 1 | package v1beta1_test 2 | 3 | import ( 4 | "context" 5 | "path/filepath" 6 | "testing" 7 | 8 | . "github.com/onsi/ginkgo/v2" 9 | . "github.com/onsi/gomega" 10 | "k8s.io/client-go/kubernetes/scheme" 11 | clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 12 | "sigs.k8s.io/controller-runtime/pkg/client" 13 | "sigs.k8s.io/controller-runtime/pkg/envtest" 14 | logf "sigs.k8s.io/controller-runtime/pkg/log" 15 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 16 | 17 | infrav1 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" 18 | ) 19 | 20 | var ( 21 | k8sClient client.Client 22 | testEnv *envtest.Environment 23 | ctx = context.Background() 24 | ) 25 | 26 | func TestV1beta1CELValidation(t *testing.T) { 27 | RegisterFailHandler(Fail) 28 | RunSpecs(t, "CEL Validation Suite") 29 | } 30 | 31 | var _ = BeforeSuite(func() { 32 | logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) 33 | 34 | By("bootstrapping test environment") 35 | testEnv = &envtest.Environment{ 36 | CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, 37 | ErrorIfCRDPathMissing: true, 38 | } 39 | 40 | cfg, err := testEnv.Start() 41 | Expect(err).NotTo(HaveOccurred()) 42 | Expect(cfg).NotTo(BeNil()) 43 | 44 | err = infrav1.AddToScheme(scheme.Scheme) 45 | Expect(err).NotTo(HaveOccurred()) 46 | 47 | err = clusterv1.AddToScheme(scheme.Scheme) 48 | Expect(err).NotTo(HaveOccurred()) 49 | 50 | k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) 51 | Expect(err).NotTo(HaveOccurred()) 52 | Expect(k8sClient).NotTo(BeNil()) 53 | }) 54 | 55 | var _ = AfterSuite(func() { 56 | By("tearing down the test environment") 57 | err := testEnv.Stop() 58 | Expect(err).NotTo(HaveOccurred()) 59 | }) 60 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1beta1/cluster-template-upgrades/nmt.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 3 | kind: NutanixMachineTemplate 4 | metadata: 5 | name: "${CLUSTER_NAME}-mt-0" 6 | namespace: "${NAMESPACE}" 7 | spec: 8 | template: 9 | spec: 10 | providerID: "nutanix://${CLUSTER_NAME}-m1" 11 | bootType: ${NUTANIX_MACHINE_BOOT_TYPE=legacy} 12 | vcpusPerSocket: ${NUTANIX_MACHINE_VCPU_PER_SOCKET=1} 13 | vcpuSockets: ${NUTANIX_MACHINE_VCPU_SOCKET=2} 14 | memorySize: "${NUTANIX_MACHINE_MEMORY_SIZE=4Gi}" 15 | systemDiskSize: "${NUTANIX_SYSTEMDISK_SIZE=40Gi}" 16 | image: 17 | type: name 18 | name: "${NUTANIX_MACHINE_TEMPLATE_IMAGE_UPGRADE_FROM}" 19 | cluster: 20 | type: name 21 | name: "${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME}" 22 | subnet: 23 | - type: name 24 | name: "${NUTANIX_SUBNET_NAME}" 25 | 26 | --- 27 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 28 | kind: NutanixMachineTemplate 29 | metadata: 30 | name: "cluster-upgrade-conformance" 31 | namespace: "${NAMESPACE}" 32 | spec: 33 | template: 34 | spec: 35 | providerID: "nutanix://cluster-upgrade-conformance" 36 | bootType: ${NUTANIX_MACHINE_BOOT_TYPE=legacy} 37 | vcpusPerSocket: ${NUTANIX_MACHINE_VCPU_PER_SOCKET=1} 38 | vcpuSockets: ${NUTANIX_MACHINE_VCPU_SOCKET=2} 39 | memorySize: "${NUTANIX_MACHINE_MEMORY_SIZE=4Gi}" 40 | systemDiskSize: "${NUTANIX_SYSTEMDISK_SIZE=40Gi}" 41 | image: 42 | type: name 43 | name: "${NUTANIX_MACHINE_TEMPLATE_IMAGE_UPGRADE_TO}" 44 | cluster: 45 | type: name 46 | name: "${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME}" 47 | subnet: 48 | - type: name 49 | name: "${NUTANIX_SUBNET_NAME}" 50 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | **What this PR does / why we need it**: 10 | 11 | **Which issue(s) this PR fixes** *(optional, in `fixes #(, fixes #, ...)` format, will close the issue(s) when PR gets merged)*: 12 | Fixes # 13 | 14 | **How Has This Been Tested?**: 15 | 16 | _Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration and test output_ 17 | 18 | 19 | **Special notes for your reviewer**: 20 | 21 | _Please confirm that if this PR changes any image versions, then that's the sole change this PR makes._ 22 | 23 | **Release note**: 24 | 28 | ```release-note 29 | 30 | ``` -------------------------------------------------------------------------------- /pkg/client/cache_test.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "net/url" 5 | "testing" 6 | 7 | v4Converged "github.com/nutanix-cloud-native/prism-go-client/converged/v4" 8 | "github.com/nutanix-cloud-native/prism-go-client/environment/types" 9 | v3 "github.com/nutanix-cloud-native/prism-go-client/v3" 10 | v4 "github.com/nutanix-cloud-native/prism-go-client/v4" 11 | "github.com/stretchr/testify/assert" 12 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 | 14 | "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" 15 | ) 16 | 17 | func TestCacheParamsKey(t *testing.T) { 18 | cluster := &v1beta1.NutanixCluster{ 19 | ObjectMeta: metav1.ObjectMeta{ 20 | Name: "test-cluster", 21 | Namespace: "test-namespace", 22 | }, 23 | } 24 | 25 | params := CacheParams{ 26 | NutanixCluster: cluster, 27 | } 28 | 29 | expectedKey := "test-namespace/test-cluster" 30 | assert.Equal(t, expectedKey, params.Key()) 31 | } 32 | 33 | func TestCacheParamsManagementEndpoint(t *testing.T) { 34 | endpoint := &types.ManagementEndpoint{ 35 | Address: &url.URL{ 36 | Scheme: "https", 37 | Host: "prismcentral.nutanix.com:9440", 38 | }, 39 | } 40 | 41 | params := &CacheParams{ 42 | PrismManagementEndpoint: endpoint, 43 | } 44 | 45 | assert.Equal(t, *endpoint, params.ManagementEndpoint()) 46 | } 47 | 48 | func TestNutanixClientCache(t *testing.T) { 49 | assert.NotNil(t, NutanixClientCache) 50 | assert.IsType(t, &v3.ClientCache{}, NutanixClientCache) 51 | } 52 | 53 | func TestNutanixClientCacheV4(t *testing.T) { 54 | assert.NotNil(t, NutanixClientCacheV4) 55 | assert.IsType(t, &v4.ClientCache{}, NutanixClientCacheV4) 56 | } 57 | 58 | func TestNutanixConvergedClientV4Cache(t *testing.T) { 59 | assert.NotNil(t, NutanixConvergedClientV4Cache) 60 | assert.IsType(t, &v4Converged.ClientCache{}, NutanixConvergedClientV4Cache) 61 | } 62 | -------------------------------------------------------------------------------- /templates/testdata/cluster-with-control-plane-endpoint.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | ccm: nutanix 6 | cluster.x-k8s.io/cluster-name: cluster-with-control-plane-endpoint 7 | name: cluster-with-control-plane-endpoint 8 | spec: 9 | topology: 10 | class: nutanix-quick-start 11 | controlPlane: 12 | metadata: {} 13 | replicas: 1 14 | variables: 15 | - name: sshKey 16 | value: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMe61GqA9gqeX3zDCiwuU8zEDt3ckLnfVm8ZxN7UuFyL user@host 17 | - name: controlPlaneEndpoint 18 | value: 19 | IP: 1.2.3.4 20 | port: 6443 21 | - name: prismCentralEndpoint 22 | value: 23 | address: prismcentral.fake 24 | credentialSecret: nutanix-quick-start-pc-creds 25 | insecure: false 26 | port: 9440 27 | - name: controlPlaneMachineDetails 28 | value: 29 | bootType: legacy 30 | clusterName: fake-cluster 31 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 32 | memorySize: 4Gi 33 | subnets: 34 | - type: name 35 | name: fake-subnet 36 | systemDiskSize: 40Gi 37 | vcpuSockets: 2 38 | vcpusPerSocket: 1 39 | - name: workerMachineDetails 40 | value: 41 | bootType: legacy 42 | clusterName: fake-cluster 43 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 44 | memorySize: 4Gi 45 | subnets: 46 | - type: name 47 | name: fake-subnet 48 | systemDiskSize: 40Gi 49 | vcpuSockets: 2 50 | vcpusPerSocket: 1 51 | version: v1.29.2 52 | workers: 53 | machineDeployments: 54 | - class: nutanix-quick-start-worker 55 | name: md-0 56 | replicas: 2 57 | -------------------------------------------------------------------------------- /templates/testdata/cluster-with-project-name.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | ccm: nutanix 6 | cluster.x-k8s.io/cluster-name: cluster-with-project-name 7 | name: cluster-with-project-name 8 | spec: 9 | topology: 10 | class: nutanix-quick-start 11 | controlPlane: 12 | metadata: {} 13 | replicas: 1 14 | variables: 15 | - name: sshKey 16 | value: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMe61GqA9gqeX3zDCiwuU8zEDt3ckLnfVm8ZxN7UuFyL user@host 17 | - name: controlPlaneEndpoint 18 | value: 19 | IP: 1.2.3.4 20 | port: 6443 21 | - name: prismCentralEndpoint 22 | value: 23 | address: prismcentral.fake 24 | credentialSecret: nutanix-quick-start-pc-creds 25 | insecure: false 26 | port: 9440 27 | - name: controlPlaneMachineDetails 28 | value: 29 | bootType: legacy 30 | clusterName: fake-cluster 31 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 32 | memorySize: 4Gi 33 | subnets: 34 | - type: name 35 | name: fake-subnet 36 | systemDiskSize: 40Gi 37 | vcpuSockets: 2 38 | vcpusPerSocket: 1 39 | - name: workerMachineDetails 40 | value: 41 | bootType: legacy 42 | clusterName: fake-cluster 43 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 44 | memorySize: 4Gi 45 | subnets: 46 | - type: name 47 | name: fake-subnet 48 | systemDiskSize: 40Gi 49 | vcpuSockets: 2 50 | vcpusPerSocket: 1 51 | - name: project 52 | value: 53 | type: name 54 | name: fake-project 55 | version: v1.29.2 56 | workers: 57 | machineDeployments: 58 | - class: nutanix-quick-start-worker 59 | name: md-0 60 | replicas: 2 61 | -------------------------------------------------------------------------------- /test/helpers/prism-go-client/v3/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v3 18 | 19 | import ( 20 | "fmt" 21 | "net/http" 22 | "net/http/httptest" 23 | "path" 24 | 25 | prismgoclient "github.com/nutanix-cloud-native/prism-go-client" 26 | nutanixClientV3 "github.com/nutanix-cloud-native/prism-go-client/v3" 27 | ) 28 | 29 | const ( 30 | baseURLPath = "/api/nutanix/v3/" 31 | ) 32 | 33 | type TestClient struct { 34 | *nutanixClientV3.Client 35 | 36 | mux *http.ServeMux 37 | server *httptest.Server 38 | } 39 | 40 | func NewTestClient() (*TestClient, error) { 41 | mux := http.NewServeMux() 42 | server := httptest.NewServer(mux) 43 | 44 | cred := prismgoclient.Credentials{ 45 | URL: server.URL, 46 | Username: "username", 47 | Password: "password", 48 | Endpoint: "0.0.0.0", 49 | } 50 | 51 | client, err := nutanixClientV3.NewV3Client(cred) 52 | if err != nil { 53 | return nil, fmt.Errorf("error creating Nutanix test client: %w", err) 54 | } 55 | return &TestClient{client, mux, server}, nil 56 | } 57 | 58 | func (c *TestClient) Close() { 59 | c.server.Close() 60 | } 61 | 62 | func (c *TestClient) AddMockHandler(pattern string, handler func(w http.ResponseWriter, r *http.Request)) { 63 | c.mux.HandleFunc(pattern, handler) 64 | } 65 | 66 | func GetTaskURLPath(uuid string) string { 67 | return path.Join(baseURLPath, "tasks", uuid) 68 | } 69 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are always welcome. Before contributing please search the [issue tracker](../../issues). Your issue may have already been discussed or fixed in `main`. To contribute, [fork](https://help.github.com/articles/fork-a-repo/) this repository, commit your changes, and [send a Pull Request](https://help.github.com/articles/using-pull-requests/). 4 | 5 | ## Feature requests 6 | 7 | Feature requests should be submitted in the [issue tracker](../../issues), with a description of the expected behavior & use case, where they'll remain closed until sufficient interest, [e.g. :+1: reactions](https://help.github.com/articles/about-discussions-in-issues-and-pull-requests/), has been [shown by the community](../../issues?q=label%3A%22votes+needed%22+sort%3Areactions-%2B1-desc). 8 | 9 | Before submitting an issue, please search for similar ones in the [closed issues](../../issues?q=is%3Aissue+is%3Aclosed+label%3Aenhancement). 10 | 11 | ## Pull requests 12 | 13 | ### Approval and release process 14 | 15 | Pull requests approvals go through the following steps: 16 | 17 | 1. A GitHub action may be triggered to lint and test. 18 | 2. A maintainer reviews the changes. Any change requires at least one review. 19 | 3. The pull request can be merged when at least one maintainer approves it. 20 | 21 | ## Contributor License Agreement 22 | 23 | Before you submit your pull request, you'll need to sign the [Nutanix Contributor License Agreement (CLA)](https://www.nutanix.dev/cla/). The CLA must be agreed to by all contributors who are not Nutanix Full-time Employees (FTE) or interns prior to the contribution being merged into the project codebase. The CLA is substantially similar to the Apache Contributor License Agreement, which is the industry standard CLA. 24 | 25 | For more information about CLAs, please check out Alex Russell's excellent post, 26 | ["Why Do I Need to Sign This?"](https://infrequently.org/2008/06/why-do-i-need-to-sign-this/). -------------------------------------------------------------------------------- /templates/testdata/cluster-with-project-uuid.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | ccm: nutanix 6 | cluster.x-k8s.io/cluster-name: cluster-with-project-uuid 7 | name: cluster-with-project-uuid 8 | spec: 9 | topology: 10 | class: nutanix-quick-start 11 | controlPlane: 12 | metadata: {} 13 | replicas: 1 14 | variables: 15 | - name: sshKey 16 | value: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMe61GqA9gqeX3zDCiwuU8zEDt3ckLnfVm8ZxN7UuFyL user@host 17 | - name: controlPlaneEndpoint 18 | value: 19 | IP: 1.2.3.4 20 | port: 6443 21 | - name: prismCentralEndpoint 22 | value: 23 | address: prismcentral.fake 24 | credentialSecret: nutanix-quick-start-pc-creds 25 | insecure: false 26 | port: 9440 27 | - name: controlPlaneMachineDetails 28 | value: 29 | bootType: legacy 30 | clusterName: fake-cluster 31 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 32 | memorySize: 4Gi 33 | subnets: 34 | - type: name 35 | name: fake-subnet 36 | systemDiskSize: 40Gi 37 | vcpuSockets: 2 38 | vcpusPerSocket: 1 39 | - name: workerMachineDetails 40 | value: 41 | bootType: legacy 42 | clusterName: fake-cluster 43 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 44 | memorySize: 4Gi 45 | subnets: 46 | - type: name 47 | name: fake-subnet 48 | systemDiskSize: 40Gi 49 | vcpuSockets: 2 50 | vcpusPerSocket: 1 51 | - name: project 52 | value: 53 | type: uuid 54 | uuid: 00000000-0000-0000-0000-000000000001 55 | version: v1.29.2 56 | workers: 57 | machineDeployments: 58 | - class: nutanix-quick-start-worker 59 | name: md-0 60 | replicas: 2 61 | -------------------------------------------------------------------------------- /templates/testdata/cluster-with-subnets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | ccm: nutanix 6 | cluster.x-k8s.io/cluster-name: cluster-with-subnets 7 | name: cluster-with-subnets 8 | spec: 9 | topology: 10 | class: nutanix-quick-start 11 | controlPlane: 12 | metadata: {} 13 | replicas: 1 14 | variables: 15 | - name: sshKey 16 | value: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMe61GqA9gqeX3zDCiwuU8zEDt3ckLnfVm8ZxN7UuFyL user@host 17 | - name: controlPlaneEndpoint 18 | value: 19 | IP: 1.2.3.4 20 | port: 6443 21 | - name: prismCentralEndpoint 22 | value: 23 | address: prismcentral.fake 24 | credentialSecret: nutanix-quick-start-pc-creds 25 | insecure: false 26 | port: 9440 27 | - name: controlPlaneMachineDetails 28 | value: 29 | bootType: legacy 30 | clusterName: fake-cluster 31 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 32 | memorySize: 4Gi 33 | subnets: 34 | - type: name 35 | name: shared-subnet 36 | - type: name 37 | name: controlplane-subnet 38 | systemDiskSize: 40Gi 39 | vcpuSockets: 2 40 | vcpusPerSocket: 1 41 | - name: workerMachineDetails 42 | value: 43 | bootType: legacy 44 | clusterName: fake-cluster 45 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 46 | memorySize: 4Gi 47 | subnets: 48 | - type: name 49 | name: shared-subnet 50 | - type: name 51 | name: worker-subnet 52 | systemDiskSize: 40Gi 53 | vcpuSockets: 2 54 | vcpusPerSocket: 1 55 | version: v1.29.2 56 | workers: 57 | machineDeployments: 58 | - class: nutanix-quick-start-worker 59 | name: md-0 60 | replicas: 2 61 | -------------------------------------------------------------------------------- /templates/testdata/cluster-with-gpu.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | ccm: nutanix 6 | cluster.x-k8s.io/cluster-name: cluster-with-gpu 7 | name: cluster-with-gpu 8 | spec: 9 | topology: 10 | class: nutanix-quick-start 11 | controlPlane: 12 | metadata: {} 13 | replicas: 1 14 | variables: 15 | - name: sshKey 16 | value: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMe61GqA9gqeX3zDCiwuU8zEDt3ckLnfVm8ZxN7UuFyL user@host 17 | - name: controlPlaneEndpoint 18 | value: 19 | IP: 1.2.3.4 20 | port: 6443 21 | - name: prismCentralEndpoint 22 | value: 23 | address: prismcentral.fake 24 | credentialSecret: nutanix-quick-start-pc-creds 25 | insecure: false 26 | port: 9440 27 | - name: controlPlaneMachineDetails 28 | value: 29 | bootType: legacy 30 | clusterName: fake-cluster 31 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 32 | memorySize: 4Gi 33 | subnets: 34 | - type: name 35 | name: fake-subnet 36 | systemDiskSize: 40Gi 37 | vcpuSockets: 2 38 | vcpusPerSocket: 1 39 | gpus: 40 | - type: deviceID 41 | deviceID: 42 42 | - name: workerMachineDetails 43 | value: 44 | bootType: legacy 45 | clusterName: fake-cluster 46 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 47 | memorySize: 4Gi 48 | subnets: 49 | - type: name 50 | name: fake-subnet 51 | systemDiskSize: 40Gi 52 | vcpuSockets: 2 53 | vcpusPerSocket: 1 54 | gpus: 55 | - type: name 56 | name: fake-gpu 57 | version: v1.29.2 58 | workers: 59 | machineDeployments: 60 | - class: nutanix-quick-start-worker 61 | name: md-0 62 | replicas: 2 63 | -------------------------------------------------------------------------------- /api/v1beta1/nutanixclustertemplate_types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1beta1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | ) 22 | 23 | // NutanixClusterTemplateSpec defines the desired state of NutanixClusterTemplate 24 | type NutanixClusterTemplateSpec struct { 25 | Template NutanixClusterTemplateResource `json:"template"` 26 | } 27 | 28 | //+kubebuilder:object:root=true 29 | //+kubebuilder:resource:categories=cluster-api 30 | 31 | // NutanixClusterTemplate is the Schema for the nutanixclustertemplates API 32 | type NutanixClusterTemplate struct { 33 | metav1.TypeMeta `json:",inline"` 34 | metav1.ObjectMeta `json:"metadata,omitempty"` 35 | 36 | Spec NutanixClusterTemplateSpec `json:"spec,omitempty"` 37 | } 38 | 39 | //+kubebuilder:object:root=true 40 | 41 | // NutanixClusterTemplateList contains a list of NutanixClusterTemplate 42 | type NutanixClusterTemplateList struct { 43 | metav1.TypeMeta `json:",inline"` 44 | metav1.ListMeta `json:"metadata,omitempty"` 45 | Items []NutanixClusterTemplate `json:"items"` 46 | } 47 | 48 | func init() { 49 | SchemeBuilder.Register(&NutanixClusterTemplate{}, &NutanixClusterTemplateList{}) 50 | } 51 | 52 | // NutanixClusterTemplateResource describes the data needed to create a NutanixCluster from a template. 53 | type NutanixClusterTemplateResource struct { 54 | Spec NutanixClusterSpec `json:"spec"` 55 | } 56 | -------------------------------------------------------------------------------- /scripts/csi3_nutanix_update.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2021 Nutanix. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | NUTANIX_CSI_SNAPSHOT_VERSION=6.3.3 17 | NUTANIX_CSI_STORAGE_VERSION=3.3.4 18 | 19 | helm repo add nutanix-helm-releases https://nutanix.github.io/helm-releases/ --force-update && helm repo update 20 | 21 | helm template -n ntnx-system nutanix-snapshot nutanix-helm-releases/nutanix-csi-snapshot --set tls.source=secret > templates/csi3/nutanix-csi-snapshot.yaml 22 | 23 | ex templates/csi3/nutanix-csi-snapshot.yaml < templates/csi3/nutanix-csi-storage.yaml 29 | 30 | # Fix 1: Add namespace to nutanix-storage-precheck-job 31 | # Helm generates the Job without a namespace field, but it needs one for proper deployment 32 | ex templates/csi3/nutanix-csi-storage.yaml <> ${tmpdir}/server.conf 26 | [req] 27 | req_extensions = v3_req 28 | distinguished_name = req_distinguished_name 29 | [req_distinguished_name] 30 | [ v3_req ] 31 | basicConstraints = CA:FALSE 32 | keyUsage = nonRepudiation, digitalSignature, keyEncipherment 33 | extendedKeyUsage = clientAuth, serverAuth 34 | subjectAltName = DNS:${title}, DNS:${title}.${namespace}, DNS:${title}.${namespace}.svc 35 | [alt_names] 36 | DNS.1 = ${title} 37 | DNS.2 = ${title}.${namespace} 38 | DNS.3 = ${title}.${namespace}.svc 39 | EOF 40 | 41 | openssl genrsa -out ${tmpdir}/server.key 2048 42 | openssl req -new -key ${tmpdir}/server.key -out ${tmpdir}/server.csr -subj "/CN=${title}.${namespace}.svc" -config ${tmpdir}/server.conf 43 | 44 | openssl x509 -req -in ${tmpdir}/server.csr -CA ${tmpdir}/ca.crt -CAkey ${tmpdir}/ca.key -CAcreateserial -out ${tmpdir}/server.crt -days 100000 -extensions v3_req -extfile ${tmpdir}/server.conf 45 | 46 | 47 | export WEBHOOK_KEY=`cat ${tmpdir}/server.key | base64 | tr -d '\n'` 48 | export WEBHOOK_CERT=`cat ${tmpdir}/server.crt | base64 | tr -d '\n'` 49 | export WEBHOOK_CA=`cat ${tmpdir}/ca.crt | base64 | tr -d '\n'` 50 | -------------------------------------------------------------------------------- /make/test-cluster-without-topology.mk: -------------------------------------------------------------------------------- 1 | TEST_NAMESPACE=ns-without-topology 2 | TEST_CLUSTER_NAME=mycluster-without-topology 3 | 4 | .PHONY: test-cluster-create 5 | test-cluster-create: ## Create a workload cluster without topology 6 | clusterctl version 7 | clusterctl config repositories | grep nutanix 8 | clusterctl generate cluster ${TEST_CLUSTER_NAME} -i nutanix:${LOCAL_PROVIDER_VERSION} --target-namespace ${TEST_NAMESPACE} --list-variables -v 10 9 | clusterctl generate cluster ${TEST_CLUSTER_NAME} -i nutanix:${LOCAL_PROVIDER_VERSION} --target-namespace ${TEST_NAMESPACE} -v 10 > ./${TEST_CLUSTER_NAME}.yaml 10 | kubectl create ns $(TEST_NAMESPACE) --dry-run=client -oyaml | kubectl apply --server-side -f - 11 | kubectl apply --server-side -f ./${TEST_CLUSTER_NAME}.yaml 12 | 13 | .PHONY: test-cluster-delete 14 | test-cluster-delete: ## Delete workload cluster without topology 15 | kubectl -n ${TEST_NAMESPACE} delete cluster ${TEST_CLUSTER_NAME} --ignore-not-found 16 | 17 | .PHONY: generate-cluster-kubeconfig 18 | generate-cluster-kubeconfig: ## generate kubeconfig of workload cluster without topology 19 | kubectl -n $(TEST_NAMESPACE) get secret 20 | kubectl -n ${TEST_NAMESPACE} get secret ${TEST_CLUSTER_NAME}-kubeconfig -o json | jq -r .data.value | base64 --decode > ${TEST_CLUSTER_NAME}.workload.kubeconfig 21 | 22 | .PHONY: test-cluster-install-cni 23 | test-cluster-install-cni: generate-cluster-kubeconfig ## install cni on workload cluster without topology 24 | kubectl --kubeconfig ./${TEST_CLUSTER_NAME}.workload.kubeconfig apply -f https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/main/test/e2e/data/cni/calico/calico.yaml 25 | 26 | .PHONY: list-bootstrap-resources 27 | list-bootstrap-resources: ## List resources of bootstrap/management cluster 28 | kubectl get ns 29 | kubectl get all --all-namespaces 30 | kubectl -n capx-system get all 31 | kubectl -n $(TEST_NAMESPACE) get Cluster,NutanixCluster,Machine,NutanixMachine,KubeAdmControlPlane,MachineHealthCheck,nodes 32 | kubectl -n capx-system get pod 33 | 34 | .PHONY: list-workload-resources 35 | list-workload-resources: ## List resources of workload cluster 36 | kubectl --kubeconfig ./${TEST_CLUSTER_NAME}.workload.kubeconfig get nodes,ns 37 | -------------------------------------------------------------------------------- /test/e2e/clusterclass_changes_test.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | // +build e2e 3 | 4 | /* 5 | Copyright 2020 The Kubernetes Authors. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package e2e 21 | 22 | import ( 23 | . "github.com/onsi/ginkgo/v2" 24 | 25 | capi_e2e "sigs.k8s.io/cluster-api/test/e2e" 26 | ) 27 | 28 | var _ = Describe("When mutating ClusterClass fields", Label("clusterclass"), func() { 29 | capi_e2e.ClusterClassChangesSpec(ctx, func() capi_e2e.ClusterClassChangesSpecInput { 30 | return capi_e2e.ClusterClassChangesSpecInput{ 31 | E2EConfig: e2eConfig, 32 | ClusterctlConfigPath: clusterctlConfigPath, 33 | BootstrapClusterProxy: bootstrapClusterProxy, 34 | ArtifactFolder: artifactFolder, 35 | SkipCleanup: skipCleanup, 36 | Flavor: "topology", 37 | // ModifyControlPlaneFields are the ControlPlane fields which will be set on the 38 | // ControlPlaneTemplate of the ClusterClass after the initial Cluster creation. 39 | // The test verifies that these fields are rolled out to the ControlPlane. 40 | ModifyControlPlaneFields: map[string]interface{}{ 41 | "spec.machineTemplate.nodeDrainTimeout": "10s", 42 | }, 43 | // ModifyMachineDeploymentBootstrapConfigTemplateFields are the fields which will be set on the 44 | // BootstrapConfigTemplate of all MachineDeploymentClasses of the ClusterClass after the initial Cluster creation. 45 | // The test verifies that these fields are rolled out to the MachineDeployments. 46 | ModifyMachineDeploymentBootstrapConfigTemplateFields: map[string]interface{}{ 47 | "spec.template.spec.verbosity": int64(4), 48 | }, 49 | ModifyMachineDeploymentInfrastructureMachineTemplateFields: map[string]interface{}{ 50 | "spec.template.spec.vcpuSockets": int64(1), 51 | }, 52 | } 53 | }) 54 | }) 55 | -------------------------------------------------------------------------------- /controllers/suite_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package controllers 18 | 19 | import ( 20 | "path/filepath" 21 | "testing" 22 | 23 | . "github.com/onsi/ginkgo/v2" 24 | . "github.com/onsi/gomega" 25 | "k8s.io/client-go/kubernetes/scheme" 26 | "sigs.k8s.io/controller-runtime/pkg/client" 27 | "sigs.k8s.io/controller-runtime/pkg/envtest" 28 | logf "sigs.k8s.io/controller-runtime/pkg/log" 29 | "sigs.k8s.io/controller-runtime/pkg/log/zap" 30 | 31 | infrav1 "github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" 32 | //+kubebuilder:scaffold:imports 33 | ) 34 | 35 | // These tests use Ginkgo (BDD-style Go testing framework). Refer to 36 | // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. 37 | 38 | var ( 39 | k8sClient client.Client 40 | testEnv *envtest.Environment 41 | ) 42 | 43 | func TestAPIs(t *testing.T) { 44 | RegisterFailHandler(Fail) 45 | RunSpecs(t, "capx-e2e") 46 | } 47 | 48 | var _ = BeforeSuite(func() { 49 | logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) 50 | 51 | By("bootstrapping test environment") 52 | testEnv = &envtest.Environment{ 53 | CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")}, 54 | ErrorIfCRDPathMissing: true, 55 | } 56 | 57 | cfg, err := testEnv.Start() 58 | Expect(err).NotTo(HaveOccurred()) 59 | Expect(cfg).NotTo(BeNil()) 60 | 61 | err = infrav1.AddToScheme(scheme.Scheme) 62 | Expect(err).NotTo(HaveOccurred()) 63 | 64 | //+kubebuilder:scaffold:scheme 65 | 66 | k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) 67 | Expect(err).NotTo(HaveOccurred()) 68 | Expect(k8sClient).NotTo(BeNil()) 69 | }) 70 | 71 | var _ = AfterSuite(func() { 72 | By("tearing down the test environment") 73 | err := testEnv.Stop() 74 | Expect(err).NotTo(HaveOccurred()) 75 | }) 76 | -------------------------------------------------------------------------------- /pkg/client/status.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package client 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "time" 23 | 24 | nutanixClientV3 "github.com/nutanix-cloud-native/prism-go-client/v3" 25 | "k8s.io/apimachinery/pkg/util/wait" 26 | "k8s.io/utils/ptr" 27 | ctrl "sigs.k8s.io/controller-runtime" 28 | ) 29 | 30 | const ( 31 | pollingInterval = time.Second * 2 32 | statusSucceeded = "SUCCEEDED" 33 | ) 34 | 35 | // WaitForTaskToSucceed will poll every 2 seconds for the task with uuid to have status of "SUCCEEDED". 36 | // The polling will stop if the ctx is cancelled, it's used for HTTP requests in the client and to control the polling. 37 | // WaitForTaskToSucceed will exit immediately on an error getting the task. 38 | func WaitForTaskToSucceed(ctx context.Context, conn *nutanixClientV3.Client, uuid string) error { 39 | return wait.PollUntilContextCancel(ctx, pollingInterval, true, func(ctx context.Context) (done bool, err error) { 40 | status, getErr := GetTaskStatus(ctx, conn, uuid) 41 | return status == statusSucceeded, getErr 42 | }) 43 | } 44 | 45 | func GetTaskStatus(ctx context.Context, client *nutanixClientV3.Client, uuid string) (string, error) { 46 | log := ctrl.LoggerFrom(ctx) 47 | log.V(1).Info(fmt.Sprintf("Getting task with UUID %s", uuid)) 48 | v, err := client.V3.GetTask(ctx, uuid) 49 | if err != nil { 50 | log.Error(err, fmt.Sprintf("error occurred while waiting for task with UUID %s", uuid)) 51 | return "", err 52 | } 53 | 54 | if *v.Status == "INVALID_UUID" || *v.Status == "FAILED" { 55 | return *v.Status, 56 | fmt.Errorf("error_detail: %s, progress_message: %s", ptr.Deref(v.ErrorDetail, ""), ptr.Deref(v.ProgressMessage, "")) 57 | } 58 | taskStatus := *v.Status 59 | log.V(1).Info(fmt.Sprintf("Status for task with UUID %s: %s", uuid, taskStatus)) 60 | return taskStatus, nil 61 | } 62 | -------------------------------------------------------------------------------- /templates/topology/cluster-with-topology.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | name: "${CLUSTER_NAME}" 5 | labels: 6 | cluster.x-k8s.io/cluster-name: "${CLUSTER_NAME}" 7 | spec: 8 | clusterNetwork: 9 | services: 10 | cidrBlocks: ["172.19.0.0/16"] 11 | pods: 12 | cidrBlocks: ["172.20.0.0/16"] 13 | serviceDomain: "cluster.local" 14 | topology: 15 | class: "nutanix-quick-start" 16 | version: ${KUBERNETES_VERSION} 17 | controlPlane: 18 | replicas: ${CONTROL_PLANE_MACHINE_COUNT} 19 | metadata: {} 20 | workers: 21 | machineDeployments: 22 | - class: nutanix-quick-start-worker 23 | name: md-0 24 | replicas: ${WORKER_MACHINE_COUNT} 25 | metadata: {} 26 | variables: 27 | - name: sshKey 28 | value: '${NUTANIX_SSH_AUTHORIZED_KEY}' 29 | - name: controlPlaneEndpoint 30 | value: 31 | IP: "${CONTROL_PLANE_ENDPOINT_IP}" 32 | port: ${CONTROL_PLANE_ENDPOINT_PORT=6443} 33 | - name: prismCentralEndpoint 34 | value: 35 | address: "${NUTANIX_ENDPOINT}" 36 | port: ${NUTANIX_PORT=9440} 37 | insecure: ${NUTANIX_INSECURE=false} 38 | credentialSecret: ${CLUSTER_NAME}-pc-creds 39 | additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle 40 | - name: controlPlaneMachineDetails 41 | value: 42 | bootType: ${NUTANIX_MACHINE_BOOT_TYPE=legacy} 43 | vcpusPerSocket: ${NUTANIX_MACHINE_VCPU_PER_SOCKET=1} 44 | vcpuSockets: ${NUTANIX_MACHINE_VCPU_SOCKET=2} 45 | memorySize: "${NUTANIX_MACHINE_MEMORY_SIZE=4Gi}" 46 | systemDiskSize: "${NUTANIX_SYSTEMDISK_SIZE=40Gi}" 47 | imageName: "${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME}" 48 | clusterName: "${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME}" 49 | subnets: 50 | - type: name 51 | name: "${NUTANIX_SUBNET_NAME}" 52 | - name: workerMachineDetails 53 | value: 54 | bootType: ${NUTANIX_MACHINE_BOOT_TYPE=legacy} 55 | vcpusPerSocket: ${NUTANIX_MACHINE_VCPU_PER_SOCKET=1} 56 | vcpuSockets: ${NUTANIX_MACHINE_VCPU_SOCKET=2} 57 | memorySize: "${NUTANIX_MACHINE_MEMORY_SIZE=4Gi}" 58 | systemDiskSize: "${NUTANIX_SYSTEMDISK_SIZE=40Gi}" 59 | imageName: "${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME}" 60 | clusterName: "${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME}" 61 | subnets: 62 | - type: name 63 | name: "${NUTANIX_SUBNET_NAME}" 64 | -------------------------------------------------------------------------------- /config/crd/kustomization.yaml: -------------------------------------------------------------------------------- 1 | # This kustomization.yaml is not intended to be run by itself, 2 | # since it depends on service name and namespace that are out of this kustomize package. 3 | # It should be run by config/default 4 | resources: 5 | - bases/infrastructure.cluster.x-k8s.io_nutanixclusters.yaml 6 | - bases/infrastructure.cluster.x-k8s.io_nutanixmachines.yaml 7 | - bases/infrastructure.cluster.x-k8s.io_nutanixmachinetemplates.yaml 8 | - bases/infrastructure.cluster.x-k8s.io_nutanixclustertemplates.yaml 9 | - bases/infrastructure.cluster.x-k8s.io_nutanixfailuredomains.yaml 10 | #+kubebuilder:scaffold:crdkustomizeresource 11 | 12 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. 13 | # patches here are for enabling the conversion webhook for each CRD 14 | #- patches/webhook_in_nutanixclusters.yaml 15 | #- patches/webhook_in_nutanixmachines.yaml 16 | #- patches/webhook_in_nutanixmachinetemplates.yaml 17 | #- patches/webhook_in_nutanixclustertemplates.yaml 18 | #+kubebuilder:scaffold:crdkustomizewebhookpatch 19 | 20 | # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. 21 | # patches here are for enabling the CA injection for each CRD 22 | #- patches/cainjection_in_nutanixclusters.yaml 23 | #- patches/cainjection_in_nutanixmachines.yaml 24 | #- patches/cainjection_in_nutanixmachinetemplates.yaml 25 | #- patches/cainjection_in_nutanixclustertemplates.yaml 26 | #+kubebuilder:scaffold:crdkustomizecainjectionpatch 27 | 28 | # controller-gen doesn't allow for complex anyOf declarations in CRD generation code markers so we have to add these 29 | # via a JSON patch instead. 30 | # 31 | # This enforces the Prism Central address to be either a hostname or an IP address without resorting to complex 32 | # regular expressions. 33 | 34 | # the following config is for teaching kustomize how to do kustomization for CRDs. 35 | configurations: 36 | - kustomizeconfig.yaml 37 | 38 | apiVersion: kustomize.config.k8s.io/v1beta1 39 | kind: Kustomization 40 | labels: 41 | - includeSelectors: true 42 | pairs: 43 | cluster.x-k8s.io/v1beta1: v1beta1 44 | patches: 45 | - patch: |- 46 | - op: add 47 | path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/prismCentral/properties/address/anyOf 48 | value: 49 | - format: hostname 50 | - format: ipv4 51 | - format: ipv6 52 | target: 53 | group: apiextensions.k8s.io 54 | kind: CustomResourceDefinition 55 | name: nutanixclusters.infrastructure.cluster.x-k8s.io 56 | version: v1 57 | -------------------------------------------------------------------------------- /hack/flakes/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Useful flakes for golang and Kubernetes projects"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | flake-utils.url = "github:numtide/flake-utils"; 7 | }; 8 | 9 | outputs = inputs @ { self, nixpkgs, flake-utils }: 10 | flake-utils.lib.eachDefaultSystem (system: 11 | with nixpkgs.legacyPackages.${system}; rec { 12 | packages = rec { 13 | go-apidiff = buildGo121Module { 14 | name = "go-apidiff"; 15 | src = fetchFromGitHub { 16 | owner = "joelanford"; 17 | repo = "go-apidiff"; 18 | rev = "v0.8.2"; 19 | hash = "sha256-YxxOemAvseRJSeCDdwuBnzjpmK3tUXt6BJGjJx5t4zQ"; 20 | }; 21 | doCheck = false; 22 | subPackages = [ "." ]; 23 | vendorHash = "sha256-AOIOjfQldAsINbcGkpM/fnyTVEZzzOXM0JnqAVwwdm8="; 24 | }; 25 | 26 | go-mod-upgrade = buildGo121Module { 27 | name = "go-mod-upgrade"; 28 | src = fetchFromGitHub { 29 | owner = "oligot"; 30 | repo = "go-mod-upgrade"; 31 | rev = "v0.9.1"; 32 | hash = "sha256-+C0IMb7MU1fq/P0/tTUNmzznZ1q5M69491pO5yBZlVs="; 33 | }; 34 | doCheck = false; 35 | subPackages = [ "." ]; 36 | vendorHash = "sha256-8rbRxtOiKmnf68kjsUCXaZf+MHI1n5aXa91Aneq9SKo="; 37 | }; 38 | 39 | yamllint-checkstyle = buildGo121Module { 40 | pname = "yamllint-checkstyle"; 41 | name = "yamllint-checkstyle"; 42 | src = fetchFromGitHub { 43 | owner = "thomaspoignant"; 44 | repo = "yamllint-checkstyle"; 45 | rev = "v1.0.2"; 46 | sha256 = "jdgzR+q7IiEpZid0/L6rtkKD8d6DvN48rfJZ+EN+xB0="; 47 | }; 48 | vendorHash = "sha256-LHRd8Q/v3ceFOqULsTtphfd4xBsz3XBG4Rkmn3Ty6CE="; 49 | }; 50 | 51 | setup-envtest = buildGo121Module { 52 | name = "setup-envtest"; 53 | src = fetchFromGitHub { 54 | owner = "kubernetes-sigs"; 55 | repo = "controller-runtime"; 56 | rev = "v0.16.3"; 57 | hash = "sha256-X4YM4A63UxD650S3lxbxRtZaHOyF7LY6d5eVJe91+5c="; 58 | } + "/tools/setup-envtest"; 59 | doCheck = false; 60 | subPackages = [ "." ]; 61 | vendorHash = "sha256-ISVGxhFQh4e0eag9Sw0Zj4u1cG0tudZLhJcGdH5tDo4="; 62 | }; 63 | }; 64 | 65 | formatter = alejandra; 66 | } 67 | ); 68 | } 69 | -------------------------------------------------------------------------------- /api/v1beta1/nutanixmachinetemplate_types.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 Nutanix 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package v1beta1 18 | 19 | import ( 20 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 | capiv1 "sigs.k8s.io/cluster-api/api/v1beta1" 22 | ) 23 | 24 | // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. 25 | 26 | const ( 27 | // NutanixMachineTemplateKind represents the Kind of NutanixMachineTemplate 28 | NutanixMachineTemplateKind = "NutanixMachineTemplate" 29 | ) 30 | 31 | // NutanixMachineTemplateSpec defines the desired state of NutanixMachineTemplate 32 | type NutanixMachineTemplateSpec struct { 33 | Template NutanixMachineTemplateResource `json:"template"` 34 | } 35 | 36 | //+kubebuilder:object:root=true 37 | //+kubebuilder:resource:path=nutanixmachinetemplates,shortName=nmtmpl,scope=Namespaced,categories=cluster-api 38 | //+kubebuilder:storageversion 39 | 40 | // NutanixMachineTemplate is the Schema for the nutanixmachinetemplates API 41 | type NutanixMachineTemplate struct { 42 | metav1.TypeMeta `json:",inline"` 43 | metav1.ObjectMeta `json:"metadata,omitempty"` 44 | 45 | Spec NutanixMachineTemplateSpec `json:"spec,omitempty"` 46 | } 47 | 48 | //+kubebuilder:object:root=true 49 | 50 | // NutanixMachineTemplateList contains a list of NutanixMachineTemplate 51 | type NutanixMachineTemplateList struct { 52 | metav1.TypeMeta `json:",inline"` 53 | metav1.ListMeta `json:"metadata,omitempty"` 54 | Items []NutanixMachineTemplate `json:"items"` 55 | } 56 | 57 | func init() { 58 | SchemeBuilder.Register(&NutanixMachineTemplate{}, &NutanixMachineTemplateList{}) 59 | } 60 | 61 | // NutanixMachineTemplateResource describes the data needed to create a NutanixMachine from a template 62 | type NutanixMachineTemplateResource struct { 63 | // Standard object metadata. 64 | // Ref: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata 65 | // +optional 66 | ObjectMeta capiv1.ObjectMeta `json:"metadata,omitempty"` 67 | // Spec is the specification of the desired behavior of the machine. 68 | Spec NutanixMachineSpec `json:"spec"` 69 | } 70 | -------------------------------------------------------------------------------- /templates/testdata/cluster-with-failure-domain.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: cluster.x-k8s.io/v1beta1 2 | kind: Cluster 3 | metadata: 4 | labels: 5 | ccm: nutanix 6 | cluster.x-k8s.io/cluster-name: cluster-with-failure-domains 7 | name: cluster-with-failure-domains 8 | spec: 9 | topology: 10 | class: nutanix-quick-start 11 | controlPlane: 12 | metadata: {} 13 | replicas: 1 14 | variables: 15 | - name: sshKey 16 | value: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMe61GqA9gqeX3zDCiwuU8zEDt3ckLnfVm8ZxN7UuFyL user@host 17 | - name: controlPlaneEndpoint 18 | value: 19 | IP: 1.2.3.4 20 | port: 6443 21 | - name: prismCentralEndpoint 22 | value: 23 | additionalTrustBundle: cluster-with-failure-domains-pc-trusted-ca-bundle 24 | address: prismcentral.fake 25 | credentialSecret: nutanix-quick-start-pc-creds 26 | insecure: false 27 | port: 9440 28 | - name: controlPlaneMachineDetails 29 | value: 30 | bootType: legacy 31 | clusterName: fake 32 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 33 | memorySize: 4Gi 34 | subnets: 35 | - type: name 36 | name: fake-subnet 37 | systemDiskSize: 40Gi 38 | vcpuSockets: 2 39 | vcpusPerSocket: 1 40 | - name: workerMachineDetails 41 | value: 42 | bootType: legacy 43 | clusterName: fake 44 | imageName: ubuntu-2204-kube-v1.29.2.qcow2 45 | memorySize: 4Gi 46 | subnets: 47 | - type: name 48 | name: fake-subnet 49 | systemDiskSize: 40Gi 50 | vcpuSockets: 2 51 | vcpusPerSocket: 1 52 | - name: failureDomains 53 | value: 54 | - cluster: 55 | name: cluster1 56 | type: name 57 | controlPlane: true 58 | name: cluster1 59 | subnets: 60 | - name: subnet1 61 | type: name 62 | - cluster: 63 | name: cluster2 64 | type: name 65 | controlPlane: true 66 | name: cluster2 67 | subnets: 68 | - name: subnet2 69 | type: name 70 | - cluster: 71 | uuid: 00000000-0000-0000-0000-000000000001 72 | type: uuid 73 | controlPlane: true 74 | name: cluster3 75 | subnets: 76 | - uuid: 00000000-0000-0000-0000-000000000001 77 | type: uuid 78 | version: v1.29.2 79 | workers: 80 | machineDeployments: 81 | - class: nutanix-quick-start-worker 82 | name: md-0 83 | replicas: 2 84 | -------------------------------------------------------------------------------- /test/e2e/data/infrastructure-nutanix/v1.7.1/base/controlplane-vip.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 2 | kind: NutanixCluster 3 | metadata: 4 | name: "${CLUSTER_NAME}" 5 | namespace: "${NAMESPACE}" 6 | spec: 7 | controlPlaneEndpoint: 8 | host: ${CONTROL_PLANE_ENDPOINT_IP_WORKLOAD_CLUSTER} 9 | --- 10 | apiVersion: controlplane.cluster.x-k8s.io/v1beta1 11 | kind: KubeadmControlPlane 12 | metadata: 13 | name: "${CLUSTER_NAME}-kcp" 14 | namespace: "${NAMESPACE}" 15 | spec: 16 | kubeadmConfigSpec: 17 | files: 18 | - content: | 19 | apiVersion: v1 20 | kind: Pod 21 | metadata: 22 | name: kube-vip 23 | namespace: kube-system 24 | spec: 25 | containers: 26 | - name: kube-vip 27 | image: ghcr.io/kube-vip/kube-vip:v0.9.2 28 | imagePullPolicy: IfNotPresent 29 | args: 30 | - manager 31 | env: 32 | - name: vip_arp 33 | value: "true" 34 | - name: address 35 | value: "${CONTROL_PLANE_ENDPOINT_IP_WORKLOAD_CLUSTER}" 36 | - name: port 37 | value: "${CONTROL_PLANE_ENDPOINT_PORT=6443}" 38 | - name: vip_subnet 39 | value: "32" 40 | - name: cp_enable 41 | value: "true" 42 | - name: cp_namespace 43 | value: kube-system 44 | - name: vip_ddns 45 | value: "false" 46 | - name: vip_leaderelection 47 | value: "true" 48 | - name: vip_leaseduration 49 | value: "15" 50 | - name: vip_renewdeadline 51 | value: "10" 52 | - name: vip_retryperiod 53 | value: "2" 54 | - name: svc_enable 55 | value: "${KUBEVIP_SVC_ENABLE=false}" 56 | - name: lb_enable 57 | value: "${KUBEVIP_LB_ENABLE=false}" 58 | - name: enableServicesElection 59 | value: "${KUBEVIP_SVC_ELECTION=false}" 60 | securityContext: 61 | capabilities: 62 | add: 63 | - NET_ADMIN 64 | - SYS_TIME 65 | - NET_RAW 66 | volumeMounts: 67 | - mountPath: /etc/kubernetes/admin.conf 68 | name: kubeconfig 69 | resources: {} 70 | hostNetwork: true 71 | volumes: 72 | - name: kubeconfig 73 | hostPath: 74 | type: FileOrCreate 75 | path: /etc/kubernetes/admin.conf 76 | status: {} 77 | owner: root:root 78 | path: /etc/kubernetes/manifests/kube-vip.yaml 79 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | bin 9 | testbin/* 10 | *.tmp 11 | 12 | # Test binary, build with `go test -c` 13 | *.test 14 | 15 | # auto-generated e2e cluster-template yaml files 16 | test/e2e/data/infrastructure-nutanix/*/cluster-template*.yaml 17 | test/e2e/data/infrastructure-nutanix/*/clusterclass-*.yaml 18 | 19 | # Output of the go coverage tool, specifically when used with LiteIDE 20 | *.out 21 | 22 | # Kubernetes Generated files - skip generated files, except for vendored files 23 | 24 | !vendor/**/zz_generated.* 25 | 26 | # editor and IDE paraphernalia 27 | .idea 28 | *.swp 29 | *.swo 30 | *~ 31 | 32 | ### macOS ### 33 | # General 34 | .DS_Store 35 | .AppleDouble 36 | .LSOverride 37 | 38 | # Icon must end with two \r 39 | Icon 40 | 41 | 42 | # Thumbnails 43 | ._* 44 | 45 | # Files that might appear in the root of a volume 46 | .DocumentRevisions-V100 47 | .fseventsd 48 | .Spotlight-V100 49 | .TemporaryItems 50 | .Trashes 51 | .VolumeIcon.icns 52 | .com.apple.timemachine.donotpresent 53 | 54 | # Directories potentially created on remote AFP share 55 | .AppleDB 56 | .AppleDesktop 57 | Network Trash Folder 58 | Temporary Items 59 | .apdisk 60 | 61 | ### Terraform ### 62 | # Local .terraform directories 63 | **/.terraform/* 64 | 65 | # .tfstate files 66 | **/*.tfstate 67 | **/*.tfstate.* 68 | 69 | # Crash log files 70 | **/crash.log 71 | **/crash.*.log 72 | 73 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as 74 | # password, private keys, and other secrets. These should not be part of version 75 | # control as they are data points which are potentially sensitive and subject 76 | # to change depending on the environment. 77 | **/*.tfvars 78 | **/*.tfvars.json 79 | 80 | # Ignore override files as they are usually used to override resources locally and so 81 | # are not checked in 82 | **/override.tf 83 | **/override.tf.json 84 | **/*_override.tf 85 | **/*_override.tf.json 86 | 87 | # Include override files you do wish to add to version control using negated pattern 88 | # !example_override.tf 89 | 90 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 91 | # example: *tfplan* 92 | 93 | # Ignore CLI configuration files 94 | **/.terraformrc 95 | **/terraform.rc 96 | 97 | # Global log files 98 | **/*.log 99 | 100 | # build generated directories and files 101 | _artifacts 102 | 103 | # vscode directories 104 | .vscode 105 | 106 | # Makefile default RELEASE_DIR 107 | out 108 | 109 | # github.com 110 | github.com 111 | profile.cov 112 | coverage.xml 113 | 114 | # env files that usually contain secrets or local config 115 | .env 116 | .envrc 117 | 118 | # local dev files 119 | clusterctl.yaml 120 | cluster.yaml 121 | *.workload.kubeconfig 122 | /.local/ 123 | /.devbox/ 124 | mycluster-without-topology.yaml 125 | yamllint-checkstyle.xml 126 | -------------------------------------------------------------------------------- /test/e2e/capx_quick_start_test.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | /* 4 | Copyright 2020 The Kubernetes Authors. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package e2e 20 | 21 | import ( 22 | . "github.com/onsi/ginkgo/v2" 23 | "k8s.io/utils/ptr" 24 | capi_e2e "sigs.k8s.io/cluster-api/test/e2e" 25 | ) 26 | 27 | var _ = Describe("When following the Cluster API quick-start", Label("quickstart", "capx-feature-test"), func() { 28 | capi_e2e.QuickStartSpec(ctx, func() capi_e2e.QuickStartSpecInput { 29 | return capi_e2e.QuickStartSpecInput{ 30 | E2EConfig: e2eConfig, 31 | ClusterctlConfigPath: clusterctlConfigPath, 32 | BootstrapClusterProxy: bootstrapClusterProxy, 33 | ArtifactFolder: artifactFolder, 34 | SkipCleanup: skipCleanup, 35 | } 36 | }) 37 | }) 38 | 39 | var _ = Describe("When following the Cluster API quick-start with ClusterClass", Label("quickstart", "clusterclass", "capx-feature-test"), func() { 40 | capi_e2e.QuickStartSpec(ctx, func() capi_e2e.QuickStartSpecInput { 41 | return capi_e2e.QuickStartSpecInput{ 42 | E2EConfig: e2eConfig, 43 | ClusterctlConfigPath: clusterctlConfigPath, 44 | BootstrapClusterProxy: bootstrapClusterProxy, 45 | ArtifactFolder: artifactFolder, 46 | SkipCleanup: skipCleanup, 47 | Flavor: ptr.To("topology"), 48 | } 49 | }) 50 | }) 51 | 52 | // // NOTE: This test requires an IPv6 management cluster (can be configured via IP_FAMILY=IPv6). 53 | // var _ = Describe("When following the Cluster API quick-start with IPv6 [IPv6] [PR-Informing]", func() { 54 | // QuickStartSpec(ctx, func() QuickStartSpecInput { 55 | // return QuickStartSpecInput{ 56 | // E2EConfig: e2eConfig, 57 | // ClusterctlConfigPath: clusterctlConfigPath, 58 | // BootstrapClusterProxy: bootstrapClusterProxy, 59 | // ArtifactFolder: artifactFolder, 60 | // SkipCleanup: skipCleanup, 61 | // Flavor: ptr.To("ipv6"), 62 | // } 63 | // }) 64 | // }) 65 | 66 | // var _ = Describe("When following the Cluster API quick-start with Ignition", func() { 67 | // QuickStartSpec(ctx, func() QuickStartSpecInput { 68 | // return QuickStartSpecInput{ 69 | // E2EConfig: e2eConfig, 70 | // ClusterctlConfigPath: clusterctlConfigPath, 71 | // BootstrapClusterProxy: bootstrapClusterProxy, 72 | // ArtifactFolder: artifactFolder, 73 | // SkipCleanup: skipCleanup, 74 | // Flavor: ptr.To("ignition"), 75 | // } 76 | // }) 77 | // }) 78 | -------------------------------------------------------------------------------- /make/test-cluster-with-topology.mk: -------------------------------------------------------------------------------- 1 | TEST_NAMESPACE=ns-topology 2 | TEST_CLUSTER_CLASS_NAME=my-clusterclass 3 | TEST_TOPOLOGY_CLUSTER_NAME=mycluster-with-topology 4 | 5 | .PHONY: test-cc-cluster-create 6 | test-cc-cluster-create: cluster-templates ## Create a workload cluster with topology (which uses clusterclass) 7 | clusterctl generate cluster ${TEST_CLUSTER_CLASS_NAME} --from ./templates/cluster-template-clusterclass.yaml -n $(TEST_NAMESPACE) > ${TEST_CLUSTER_CLASS_NAME}.yaml 8 | clusterctl generate cluster ${TEST_TOPOLOGY_CLUSTER_NAME} --from ./templates/cluster-template-topology.yaml -n $(TEST_NAMESPACE) > ${TEST_TOPOLOGY_CLUSTER_NAME}.yaml 9 | kubectl create ns $(TEST_NAMESPACE) --dry-run=client -oyaml | kubectl apply --server-side -f - 10 | kubectl apply --server-side -f ./${TEST_CLUSTER_CLASS_NAME}.yaml 11 | kubectl apply --server-side -f ./${TEST_TOPOLOGY_CLUSTER_NAME}.yaml 12 | 13 | .PHONY: test-cc-cluster-upgrade 14 | test-cc-cluster-upgrade: ## Upgrade K8S version of cluster with topology (which uses clusterclass) 15 | clusterctl generate cluster ${TEST_TOPOLOGY_CLUSTER_NAME} --from ./templates/cluster-template-topology.yaml -n $(TEST_NAMESPACE) --kubernetes-version=${UPGRADE_K8S_VERSION_TO} > ${TEST_TOPOLOGY_CLUSTER_NAME}.yaml 16 | kubectl apply --server-side -f ./${TEST_TOPOLOGY_CLUSTER_NAME}.yaml 17 | 18 | .PHONY: test-cc-cluster-delete 19 | test-cc-cluster-delete: ## Delete workload cluster with topology 20 | kubectl -n $(TEST_NAMESPACE) delete cluster ${TEST_TOPOLOGY_CLUSTER_NAME} --ignore-not-found 21 | kubectl -n $(TEST_NAMESPACE) delete secret ${TEST_TOPOLOGY_CLUSTER_NAME} --ignore-not-found 22 | kubectl -n $(TEST_NAMESPACE) delete cm ${TEST_TOPOLOGY_CLUSTER_NAME}-pc-trusted-ca-bundle --ignore-not-found 23 | rm -f ${TEST_TOPOLOGY_CLUSTER_NAME}.yaml 24 | rm -f ${TEST_CLUSTER_CLASS_NAME}.yaml 25 | 26 | .PHONY: generate-cc-cluster-kubeconfig 27 | generate-cc-cluster-kubeconfig: ## generate kubeconfig of workload cluster with topology 28 | kubectl -n ${TEST_NAMESPACE} get secret ${TEST_TOPOLOGY_CLUSTER_NAME}-kubeconfig -o json | jq -r .data.value | base64 --decode > ${TEST_TOPOLOGY_CLUSTER_NAME}.workload.kubeconfig 29 | 30 | .PHONY: test-cc-cluster-install-cni 31 | test-cc-cluster-install-cni: generate-cc-cluster-kubeconfig ## install cni on workload cluster with topology 32 | kubectl --kubeconfig ./${TEST_TOPOLOGY_CLUSTER_NAME}.workload.kubeconfig apply -f https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/main/test/e2e/data/cni/calico/calico.yaml 33 | 34 | .PHONY: list-cc-cluster-resources 35 | list-cc-cluster-resources: generate-cc-cluster-kubeconfig ## list resources of workload cluster with topology 36 | kubectl -n capx-system get endpoints 37 | kubectl get crd | grep nutanix 38 | kubectl get cluster-api -A 39 | clusterctl describe cluster ${TEST_TOPOLOGY_CLUSTER_NAME} -n ${TEST_NAMESPACE} 40 | kubectl -n $(TEST_NAMESPACE) get Cluster,NutanixCluster,Machine,NutanixMachine,KubeAdmControlPlane,machinedeployments,MachineHealthCheck,nodes 41 | kubectl get ValidatingWebhookConfiguration,MutatingWebhookConfiguration -A 42 | kubectl --kubeconfig ./${TEST_TOPOLOGY_CLUSTER_NAME}.workload.kubeconfig get nodes,ns 43 | kubectl --kubeconfig ./${TEST_TOPOLOGY_CLUSTER_NAME}.workload.kubeconfig get pods -A -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Generate release artefact 2 | 3 | on: 4 | push: 5 | tags: 6 | - "v*.*.*" 7 | 8 | jobs: 9 | build_release: 10 | name: Build Release 11 | runs-on: ubuntu-22.04 12 | defaults: 13 | run: 14 | shell: bash 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Install devbox 22 | run: curl -fsSL https://get.jetpack.io/devbox | bash -s -- -f 23 | 24 | - name: Install devbox deps 25 | run: devbox install 26 | 27 | - name: Login to GHCR 28 | uses: docker/login-action@v3 29 | with: 30 | registry: ghcr.io 31 | username: ${{ github.actor }} 32 | password: ${{ secrets.GITHUB_TOKEN }} 33 | 34 | - name: Docker meta 35 | id: meta 36 | uses: docker/metadata-action@v5 37 | with: 38 | images: capi-nutanix 39 | sep-tags: "," 40 | sep-labels: "," 41 | tags: | 42 | type=semver,pattern=v{{version}} 43 | type=semver,pattern=v{{major}}.{{minor}} 44 | type=semver,pattern=v{{major}} 45 | type=sha 46 | 47 | - name: Prepare build 48 | run: devbox run -- make manifests generate 49 | 50 | - name: Build container 51 | env: 52 | KO_DOCKER_REPO: ghcr.io/${{ github.repository }}/controller 53 | TAGS: ${{ steps.meta.outputs.tags }} 54 | LABELS: ${{ steps.meta.outputs.labels }} 55 | PLATFORMS: linux/amd64,linux/arm64,linux/arm 56 | run: | 57 | PTAGS=`echo $TAGS | sed 's/capi-nutanix://g'` 58 | export SOURCE_DATE_EPOCH=$(date +%s) 59 | devbox run -- ko build --bare --image-label "$LABELS" -t "$PTAGS" --platform=$PLATFORMS . 60 | 61 | - name: parse semver 62 | id: semver 63 | env: 64 | SEMVER: ${{ steps.meta.outputs.version }} 65 | run: | 66 | n=${SEMVER//[!0-9]/ } 67 | a=(${n//\./ }) 68 | echo "::set-output name=major::${a[0]}" 69 | echo "::set-output name=minor::${a[1]}" 70 | 71 | - name: build template 72 | env: 73 | NEW_IMG: ghcr.io/${{ github.repository }}/controller:${{ steps.meta.outputs.version }} 74 | run: | 75 | (cd config/manager && kustomize edit set image controller=$NEW_IMG) 76 | devbox run -- make release-manifests 77 | 78 | - name: generate image info 79 | env: 80 | NEW_IMG: ghcr.io/${{ github.repository }}/controller:${{ steps.meta.outputs.version }} 81 | run: | 82 | echo "## Images" >> ${{ github.workspace }}-CHANGELOG.txt 83 | echo "|Name|Link|" >> ${{ github.workspace }}-CHANGELOG.txt 84 | echo "|-|-|" >> ${{ github.workspace }}-CHANGELOG.txt 85 | echo "|CAPX|[$NEW_IMG](https://$NEW_IMG)|" >> ${{ github.workspace }}-CHANGELOG.txt 86 | 87 | - name: create release 88 | uses: softprops/action-gh-release@v1 89 | with: 90 | draft: false 91 | prerelease: false 92 | body_path: ${{ github.workspace }}-CHANGELOG.txt 93 | generate_release_notes: true 94 | append_body: true 95 | files: | 96 | out/infrastructure-components.yaml 97 | out/metadata.yaml 98 | out/cluster-template*.yaml 99 | -------------------------------------------------------------------------------- /test/e2e/cluster_topology_k8s_configs.go: -------------------------------------------------------------------------------- 1 | //go:build e2e 2 | 3 | /* 4 | Copyright 2024 Nutanix 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package e2e 20 | 21 | // NOTE: 22 | // 1. To support a new k8s version, 23 | // - add a new function NewE2eConfigK8SVersion similar to 24 | // NewE2eConfigK8SVersion127 with respective var names 25 | // - add a new row in SupportedK8STargetConfigs and 26 | // 2. To remove a supported version, 27 | // - delete a row from SupportedK8STargetConfigs array. 28 | // - delete respective version's NewE2eConfigK8SVersion function 29 | // All the tests iterating over this array will will use newer configs 30 | 31 | // E2eConfigK8SVersion holds K8s version specific e2e config variables 32 | type E2eConfigK8SVersion struct { 33 | E2eConfigK8sVersionEnvVar string 34 | E2eConfigK8sVersionImageEnvVar string 35 | } 36 | 37 | // returns E2eConfigK8SVersion with Kube127 specific e2e config vars 38 | func NewE2eConfigK8SVersion127() *E2eConfigK8SVersion { 39 | return &E2eConfigK8SVersion{ 40 | E2eConfigK8sVersionEnvVar: "KUBERNETES_VERSION_v1_27", 41 | E2eConfigK8sVersionImageEnvVar: "NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME_v1_27", 42 | } 43 | } 44 | 45 | // returns E2eConfigK8SVersion with Kube128 specific e2e config vars 46 | func NewE2eConfigK8SVersion128() *E2eConfigK8SVersion { 47 | return &E2eConfigK8SVersion{ 48 | E2eConfigK8sVersionEnvVar: "KUBERNETES_VERSION_v1_28", 49 | E2eConfigK8sVersionImageEnvVar: "NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME_v1_28", 50 | } 51 | } 52 | 53 | // returns E2eConfigK8SVersion with Kube129 specific e2e config vars 54 | func NewE2eConfigK8SVersion129() *E2eConfigK8SVersion { 55 | return &E2eConfigK8SVersion{ 56 | E2eConfigK8sVersionEnvVar: "KUBERNETES_VERSION_v1_29", 57 | E2eConfigK8sVersionImageEnvVar: "NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME_v1_29", 58 | } 59 | } 60 | 61 | // returns E2eConfigK8SVersion with Kube130 specific e2e config vars 62 | func NewE2eConfigK8SVersion130() *E2eConfigK8SVersion { 63 | return &E2eConfigK8SVersion{ 64 | E2eConfigK8sVersionEnvVar: "KUBERNETES_VERSION_v1_30", 65 | E2eConfigK8sVersionImageEnvVar: "NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME_v1_30", 66 | } 67 | } 68 | 69 | // TestConfig holds required parameters for each supported k8s target config 70 | type TestConfig struct { 71 | targetKube *E2eConfigK8SVersion 72 | targetLabels []string 73 | } 74 | 75 | // SupportedK8STargetConfigs holds all the supported k8s versions and respective labels for 76 | // each version speficic test 77 | var SupportedK8STargetConfigs = []TestConfig{ 78 | {targetKube: NewE2eConfigK8SVersion127(), targetLabels: []string{"Kube127"}}, 79 | {targetKube: NewE2eConfigK8SVersion128(), targetLabels: []string{"Kube128"}}, 80 | {targetKube: NewE2eConfigK8SVersion129(), targetLabels: []string{"Kube129"}}, 81 | {targetKube: NewE2eConfigK8SVersion130(), targetLabels: []string{"Kube130"}}, 82 | } 83 | --------------------------------------------------------------------------------