From 6c53bb1c39c880cf5db1cda6aa2fc7f195ef9f4c Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Thu, 21 Mar 2024 12:30:14 +0000 Subject: [PATCH 01/87] build: Remove unused example kustomizations Missed when reorganising example kustomizations in previous PR. --- .../bases/aws/kustomization.yaml.tmpl | 155 ------------------ .../bases/docker/kustomization.yaml.tmpl | 69 -------- 2 files changed, 224 deletions(-) delete mode 100644 hack/examples/bases/aws/kustomization.yaml.tmpl delete mode 100644 hack/examples/bases/docker/kustomization.yaml.tmpl diff --git a/hack/examples/bases/aws/kustomization.yaml.tmpl b/hack/examples/bases/aws/kustomization.yaml.tmpl deleted file mode 100644 index 11a33741f..000000000 --- a/hack/examples/bases/aws/kustomization.yaml.tmpl +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2023 D2iQ, Inc. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- ./calico/crs -- ./calico/helm-addon -- ./cilium/crs -- ./cilium/helm-addon - -namePrefix: aws- - -labels: -- includeSelectors: false - pairs: - cluster.x-k8s.io/provider: aws - -patches: -- target: - group: cluster.x-k8s.io - kind: Cluster - patch: |- - - op: "add" - path: "/spec/topology/class" - value: "aws-quick-start" - - op: "remove" - path: "/metadata/labels/cni" - - op: "add" - path: "/spec/topology/variables/0/value/aws" - value: - region: us-west-2 - - op: "add" - path: "/spec/topology/variables/0/value/controlPlane" - value: - aws: - ami: - lookup: - format: "$${AMI_LOOKUP_FORMAT}" - org: "$${AMI_LOOKUP_ORG}" - baseOS: "$${AMI_LOOKUP_BASEOS}" - - op: "add" - path: "/spec/topology/variables/-" - value: - name: "workerConfig" - value: - aws: - ami: - lookup: - format: "$${AMI_LOOKUP_FORMAT}" - org: "$${AMI_LOOKUP_ORG}" - baseOS: "$${AMI_LOOKUP_BASEOS}" - - op: "add" - path: "/spec/topology/variables/0/value/addons/cpi" - value: {} - - op: "add" - path: "/spec/topology/variables/0/value/addons/csi" - value: - providers: - - name: aws-ebs -- target: - group: cluster.x-k8s.io - kind: ClusterClass - patch: |- - - op: "add" - path: "/spec/controlPlane/machineInfrastructure/ref/name" - value: "aws-quick-start-control-plane" - - op: "add" - path: "/spec/controlPlane/ref/name" - value: "aws-quick-start-control-plane" - - op: "add" - path: "/spec/infrastructure/ref/name" - value: "aws-quick-start" - - op: "add" - path: "/spec/workers/machineDeployments/0/template/bootstrap/ref/name" - value: "aws-quick-start-worker-bootstraptemplate" - - op: "add" - path: "/spec/workers/machineDeployments/0/template/infrastructure/ref/name" - value: "aws-quick-start-worker-machinetemplate" - - op: "add" - path: "/spec/patches" - value: - - name: "cluster-config" - external: - generateExtension: "awsclusterconfigpatch.cluster-api-runtime-extensions-nutanix" - discoverVariablesExtension: "awsclusterconfigvars.cluster-api-runtime-extensions-nutanix" - - name: "worker-config" - external: - generateExtension: "awsworkerconfigpatch.cluster-api-runtime-extensions-nutanix" - discoverVariablesExtension: "awsworkerconfigvars.cluster-api-runtime-extensions-nutanix" - - name: identityRef - definitions: - - jsonPatches: - - op: add - path: /spec/template/spec/identityRef - value: - kind: AWSClusterControllerIdentity - name: default - selector: - apiVersion: infrastructure.cluster.x-k8s.io/v1beta2 - kind: AWSClusterTemplate - matchResources: - infrastructureCluster: true - description: AWSClusterStaticIdentity identityRef to use when creating the cluster - - op: "remove" - path: "/spec/variables" -- target: - group: infrastructure.cluster.x-k8s.io - kind: AWSMachineTemplate - name: quick-start-worker-machinetemplate - patch: |- - - op: "add" - path: "/spec/template/spec/instanceType" - value: "m5.2xlarge" -- target: - group: infrastructure.cluster.x-k8s.io - kind: AWSMachineTemplate - name: quick-start-control-plane - patch: |- - - op: "add" - path: "/spec/template/spec/instanceType" - value: "m5.xlarge" -- target: - group: infrastructure.cluster.x-k8s.io - kind: AWSMachineTemplate - name: quick-start-worker-machinetemplate - patch: |- - - op: "add" - path: "/spec/template/spec/sshKeyName" - value: "" -- target: - group: infrastructure.cluster.x-k8s.io - kind: AWSMachineTemplate - name: quick-start-control-plane - patch: |- - - op: "add" - path: "/spec/template/spec/sshKeyName" - value: "" -- target: - kind: ConfigMap - patch: | - $$patch: delete - apiVersion: v1 - kind: ConfigMap - metadata: - name: aws-cni-$${CLUSTER_NAME}-crs-0 -- target: - kind: ClusterResourceSet - patch: | - $$patch: delete - apiVersion: addons.cluster.x-k8s.io/v1beta1 - kind: ConfigMap - metadata: - name: aws-$${CLUSTER_NAME}-crs-0 diff --git a/hack/examples/bases/docker/kustomization.yaml.tmpl b/hack/examples/bases/docker/kustomization.yaml.tmpl deleted file mode 100644 index e8b14cc6c..000000000 --- a/hack/examples/bases/docker/kustomization.yaml.tmpl +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2023 D2iQ, Inc. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: -- ./cilium/crs -- ./cilium/helm-addon -- ./calico/crs -- ./calico/helm-addon -- https://github.com/kubernetes-sigs/cluster-api/releases/download/${CLUSTERCTL_VERSION}/clusterclass-quick-start.yaml - -namePrefix: docker- - -labels: -- includeSelectors: false - pairs: - cluster.x-k8s.io/provider: docker - -patches: -- target: - group: cluster.x-k8s.io - kind: Cluster - patch: |- - - op: "remove" - path: "/metadata/namespace" - - op: "add" - path: "/spec/topology/class" - value: "docker-quick-start" - - op: "add" - path: "/spec/topology/variables/0/value/docker" - value: {} - - op: "remove" - path: "/spec/topology/workers/machinePools" -- target: - group: cluster.x-k8s.io - kind: ClusterClass - patch: |- - - op: "add" - path: "/spec/controlPlane/machineInfrastructure/ref/name" - value: "docker-quick-start-control-plane" - - op: "add" - path: "/spec/controlPlane/ref/name" - value: "docker-quick-start-control-plane" - - op: "add" - path: "/spec/infrastructure/ref/name" - value: "docker-quick-start-cluster" - - op: "add" - path: "/spec/workers/machineDeployments/0/template/bootstrap/ref/name" - value: "docker-quick-start-default-worker-bootstraptemplate" - - op: "add" - path: "/spec/workers/machineDeployments/0/template/infrastructure/ref/name" - value: "docker-quick-start-default-worker-machinetemplate" - - op: "add" - path: "/spec/patches" - value: - - name: "cluster-config" - external: - generateExtension: "dockerclusterconfigpatch.cluster-api-runtime-extensions-nutanix" - discoverVariablesExtension: "dockerclusterconfigvars.cluster-api-runtime-extensions-nutanix" - - name: "worker-config" - external: - generateExtension: "dockerworkerconfigpatch.cluster-api-runtime-extensions-nutanix" - discoverVariablesExtension: "dockerworkerconfigvars.cluster-api-runtime-extensions-nutanix" - - op: "remove" - path: "/spec/variables" - - op: "remove" - path: "/spec/workers/machinePools" From 9f56b561258d5696ca9952d35e79f67b479577fa Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Mon, 18 Mar 2024 09:46:56 -0700 Subject: [PATCH 02/87] feat: Add user configuration for all providers - Defines a cluster-level variable for defining one or more users - Patches bootstrap templates for control plane and worker node pools with user configuration --- api/v1alpha1/clusterconfig_types.go | 64 ++++++++ api/v1alpha1/zz_generated.deepcopy.go | 58 +++++++ .../aws/mutation/metapatch_handler_test.go | 9 ++ .../docker/mutation/metapatch_handler_test.go | 9 ++ pkg/handlers/generic/mutation/handlers.go | 2 + pkg/handlers/generic/mutation/users/doc.go | 5 + pkg/handlers/generic/mutation/users/inject.go | 142 ++++++++++++++++++ .../mutation/users/tests/generate_patches.go | 98 ++++++++++++ .../generic/mutation/users/variables_test.go | 44 ++++++ 9 files changed, 431 insertions(+) create mode 100644 pkg/handlers/generic/mutation/users/doc.go create mode 100644 pkg/handlers/generic/mutation/users/inject.go create mode 100644 pkg/handlers/generic/mutation/users/tests/generate_patches.go create mode 100644 pkg/handlers/generic/mutation/users/variables_test.go diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index 17e5b119e..8b2f7d901 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -98,6 +98,9 @@ type GenericClusterConfig struct { // +optional Addons *Addons `json:"addons,omitempty"` + + // +optional + Users Users `json:"users,omitempty"` } func (s GenericClusterConfig) VariableSchema() clusterv1.VariableSchema { //nolint:gocritic,lll // Passed by value for no potential side-effect. @@ -116,6 +119,7 @@ func (s GenericClusterConfig) VariableSchema() clusterv1.VariableSchema { //noli OpenAPIV3Schema, "imageRegistries": ImageRegistries{}.VariableSchema().OpenAPIV3Schema, "globalImageRegistryMirror": GlobalImageRegistryMirror{}.VariableSchema().OpenAPIV3Schema, + "users": Users{}.VariableSchema().OpenAPIV3Schema, }, }, } @@ -344,6 +348,66 @@ func (ImageRegistries) VariableSchema() clusterv1.VariableSchema { } } +type Users []User + +func (Users) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Description: "Users to add to the machine", + Type: "array", + Items: ptr.To(User{}.VariableSchema().OpenAPIV3Schema), + }, + } +} + +// User defines the input for a generated user in cloud-init. +type User struct { + // Name specifies the user name + Name string `json:"name"` + + // Passwd specifies a hashed password for the user + // +optional + Passwd *string `json:"passwd,omitempty"` + + // SSHAuthorizedKeys specifies a list of ssh authorized keys for the user + // +optional + SSHAuthorizedKeys []string `json:"sshAuthorizedKeys,omitempty"` + + // Sudo specifies a sudo role for the user + // +optional + Sudo *string `json:"sudo,omitempty"` +} + +func (User) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "name": { + Description: "The username", + Type: "string", + }, + "passwd": { + Description: "The hashed password for the user", + Type: "string", + }, + "sshAuthorizedKeys": { + Description: "A list of SSH authorized keys for this user", + Type: "array", + Items: &clusterv1.JSONSchemaProps{ + // No description, because the one for the parent array is enough. + Type: "string", + }, + }, + "sudo": { + Description: "The sudo rule that applies to this user", + Type: "string", + }, + }, + }, + } +} + func init() { SchemeBuilder.Register(&ClusterConfig{}) } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 5af92e536..e9bd1198d 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -472,6 +472,13 @@ func (in *GenericClusterConfig) DeepCopyInto(out *GenericClusterConfig) { *out = new(Addons) (*in).DeepCopyInto(*out) } + if in.Users != nil { + in, out := &in.Users, &out.Users + *out = make(Users, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericClusterConfig. @@ -764,6 +771,57 @@ func (in Subnets) DeepCopy() Subnets { return *out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *User) DeepCopyInto(out *User) { + *out = *in + if in.Passwd != nil { + in, out := &in.Passwd, &out.Passwd + *out = new(string) + **out = **in + } + if in.SSHAuthorizedKeys != nil { + in, out := &in.SSHAuthorizedKeys, &out.SSHAuthorizedKeys + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Sudo != nil { + in, out := &in.Sudo, &out.Sudo + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. +func (in *User) DeepCopy() *User { + if in == nil { + return nil + } + out := new(User) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Users) DeepCopyInto(out *Users) { + { + in := &in + *out = make(Users, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Users. +func (in Users) DeepCopy() Users { + if in == nil { + return nil + } + out := new(Users) + in.DeepCopyInto(out) + return *out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VPC) DeepCopyInto(out *VPC) { *out = *in diff --git a/pkg/handlers/aws/mutation/metapatch_handler_test.go b/pkg/handlers/aws/mutation/metapatch_handler_test.go index e09beec54..f8c7f1c0f 100644 --- a/pkg/handlers/aws/mutation/metapatch_handler_test.go +++ b/pkg/handlers/aws/mutation/metapatch_handler_test.go @@ -37,6 +37,8 @@ import ( kubernetesimagerepositorytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository/tests" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors" globalimageregistrymirrortests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/users" + userstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/users/tests" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" ) @@ -188,4 +190,11 @@ func TestGeneratePatches(t *testing.T) { v1alpha1.AWSVariableName, controlplaneloadbalancer.VariableName, ) + + userstests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + clusterconfig.MetaVariableName, + users.VariableName, + ) } diff --git a/pkg/handlers/docker/mutation/metapatch_handler_test.go b/pkg/handlers/docker/mutation/metapatch_handler_test.go index 0004da3b2..cdcd81994 100644 --- a/pkg/handlers/docker/mutation/metapatch_handler_test.go +++ b/pkg/handlers/docker/mutation/metapatch_handler_test.go @@ -27,6 +27,8 @@ import ( kubernetesimagerepositorytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository/tests" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors" globalimageregistrymirrortests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/users" + userstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/users/tests" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" ) @@ -112,4 +114,11 @@ func TestGeneratePatches(t *testing.T) { clusterconfig.MetaVariableName, mirrors.GlobalMirrorVariableName, ) + + userstests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + clusterconfig.MetaVariableName, + users.VariableName, + ) } diff --git a/pkg/handlers/generic/mutation/handlers.go b/pkg/handlers/generic/mutation/handlers.go index 087582b0f..bd71c8caa 100644 --- a/pkg/handlers/generic/mutation/handlers.go +++ b/pkg/handlers/generic/mutation/handlers.go @@ -15,6 +15,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/imageregistries/credentials" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/users" ) // MetaMutators returns all generic patch handlers. @@ -28,5 +29,6 @@ func MetaMutators(mgr manager.Manager) []mutation.MetaMutator { credentials.NewPatch(mgr.GetClient()), mirrors.NewPatch(mgr.GetClient()), calico.NewPatch(), + users.NewPatch(), } } diff --git a/pkg/handlers/generic/mutation/users/doc.go b/pkg/handlers/generic/mutation/users/doc.go new file mode 100644 index 000000000..d652aaae3 --- /dev/null +++ b/pkg/handlers/generic/mutation/users/doc.go @@ -0,0 +1,5 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters,verbs=watch;list;get +package users diff --git a/pkg/handlers/generic/mutation/users/inject.go b/pkg/handlers/generic/mutation/users/inject.go new file mode 100644 index 000000000..facec1f78 --- /dev/null +++ b/pkg/handlers/generic/mutation/users/inject.go @@ -0,0 +1,142 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package users + +import ( + "context" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/utils/ptr" + bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" + controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches/selectors" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +const ( + // VariableName is the external patch variable name. + VariableName = "users" +) + +type usersPatchHandler struct { + variableName string + variableFieldPath []string +} + +func NewPatch() *usersPatchHandler { + return newUsersPatchHandler( + clusterconfig.MetaVariableName, + VariableName) +} + +func newUsersPatchHandler( + variableName string, + variableFieldPath ...string, +) *usersPatchHandler { + return &usersPatchHandler{ + variableName: variableName, + variableFieldPath: variableFieldPath, + } +} + +func (h *usersPatchHandler) Mutate( + ctx context.Context, + obj *unstructured.Unstructured, + vars map[string]apiextensionsv1.JSON, + holderRef runtimehooksv1.HolderReference, + _ ctrlclient.ObjectKey, +) error { + log := ctrl.LoggerFrom(ctx, "holderRef", holderRef) + + usersVariable, found, err := variables.Get[v1alpha1.Users]( + vars, + h.variableName, + h.variableFieldPath..., + ) + if err != nil { + return err + } + if !found { + log.V(5).Info("users variable not defined") + return nil + } + + log = log.WithValues( + "variableName", + h.variableName, + "variableFieldPath", + h.variableFieldPath, + "variableValue", + usersVariable, + ) + + if err := patches.MutateIfApplicable( + obj, vars, &holderRef, selectors.ControlPlane(), log, + func(obj *controlplanev1.KubeadmControlPlaneTemplate) error { + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", ctrlclient.ObjectKeyFromObject(obj), + ).Info("setting users in control plane kubeadm config template") + bootstrapUsers := []bootstrapv1.User{} + for _, userFromVariable := range usersVariable { + bootstrapUsers = append(bootstrapUsers, generateBootstrapUser(userFromVariable)) + } + obj.Spec.Template.Spec.KubeadmConfigSpec.Users = bootstrapUsers + return nil + }); err != nil { + return err + } + + if err := patches.MutateIfApplicable( + obj, vars, &holderRef, selectors.WorkersKubeadmConfigTemplateSelector(), log, + func(obj *bootstrapv1.KubeadmConfigTemplate) error { + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", ctrlclient.ObjectKeyFromObject(obj), + ).Info("setting users in worker node kubeadm config template") + bootstrapUsers := []bootstrapv1.User{} + for _, userFromVariable := range usersVariable { + bootstrapUsers = append(bootstrapUsers, generateBootstrapUser(userFromVariable)) + } + obj.Spec.Template.Spec.Users = bootstrapUsers + return nil + }); err != nil { + return err + } + + return nil +} + +func generateBootstrapUser(userFromVariable v1alpha1.User) bootstrapv1.User { + bootstrapUser := bootstrapv1.User{ + Name: userFromVariable.Name, + Passwd: userFromVariable.Passwd, + SSHAuthorizedKeys: userFromVariable.SSHAuthorizedKeys, + Sudo: userFromVariable.Sudo, + } + + // LockPassword is not part of our API, because we can derive its value + // for the use cases our API supports. + // + // We do not support the edge cases where a password is defined, but + // password authentication is disabled, or where no password is defined, but + // password authentication is enabled. + // + // We disable password authentication by default. + bootstrapUser.LockPassword = ptr.To[bool](true) + if userFromVariable.Passwd != nil { + // We enable password authentication only if a password is defined. + bootstrapUser.LockPassword = ptr.To[bool](true) + } + + return bootstrapUser +} diff --git a/pkg/handlers/generic/mutation/users/tests/generate_patches.go b/pkg/handlers/generic/mutation/users/tests/generate_patches.go new file mode 100644 index 000000000..61bd69ba1 --- /dev/null +++ b/pkg/handlers/generic/mutation/users/tests/generate_patches.go @@ -0,0 +1,98 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package tests + +import ( + "testing" + + "github.com/onsi/gomega" + "k8s.io/apiserver/pkg/storage/names" + "k8s.io/utils/ptr" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" +) + +var ( + testUser1 = v1alpha1.User{ + Name: "complete", + Passwd: ptr.To[string]("password"), + SSHAuthorizedKeys: []string{ + "key1", + "key2", + }, + Sudo: ptr.To[string]("ALL=(ALL) NOPASSWD:ALL"), + } + testUser2 = v1alpha1.User{ + Name: "onlyname", + } +) + +func TestGeneratePatches( + t *testing.T, + generatorFunc func() mutation.GeneratePatches, + variableName string, + variablePath ...string, +) { + t.Helper() + + capitest.ValidateGeneratePatches( + t, + generatorFunc, + capitest.PatchTestDef{ + Name: "unset variable", + }, + capitest.PatchTestDef{ + Name: "users set for KubeadmControlPlaneTemplate", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + []v1alpha1.User{testUser1, testUser2}, + variablePath..., + ), + }, + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/users", + ValueMatcher: gomega.HaveLen(2), + }}, + }, + ) + + capitest.ValidateGeneratePatches( + t, + generatorFunc, + capitest.PatchTestDef{ + Name: "unset variable", + }, + capitest.PatchTestDef{ + Name: "users set for KubeadmConfigTemplate generic worker", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + []v1alpha1.User{testUser1, testUser2}, + variablePath..., + ), + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": names.SimpleNameGenerator.GenerateName("worker-"), + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/users", + ValueMatcher: gomega.HaveLen(2), + }}, + }, + ) +} diff --git a/pkg/handlers/generic/mutation/users/variables_test.go b/pkg/handlers/generic/mutation/users/variables_test.go new file mode 100644 index 000000000..f4ab8c6a0 --- /dev/null +++ b/pkg/handlers/generic/mutation/users/variables_test.go @@ -0,0 +1,44 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package users + +import ( + "testing" + + "k8s.io/utils/ptr" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +func TestVariableValidation(t *testing.T) { + capitest.ValidateDiscoverVariables( + t, + clusterconfig.MetaVariableName, + ptr.To(v1alpha1.GenericClusterConfig{}.VariableSchema()), + false, + clusterconfig.NewVariable, + // HTTPProxy + capitest.VariableTestDef{ + Name: "valid users", + Vals: v1alpha1.GenericClusterConfig{ + Users: []v1alpha1.User{ + { + Name: "complete", + Passwd: ptr.To[string]("password"), + SSHAuthorizedKeys: []string{ + "key1", + "key2", + }, + Sudo: ptr.To[string]("ALL=(ALL) NOPASSWD:ALL"), + }, + { + Name: "onlyname", + }, + }, + }, + }, + ) +} From 08457eb7999710e2f25eead164e19693d7f68d2b Mon Sep 17 00:00:00 2001 From: deepakm-ntnx Date: Tue, 20 Feb 2024 11:24:21 -0800 Subject: [PATCH 03/87] [WIP] added nutanix support --- .../bases/nutanix/kustomization.yaml.tmpl | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 hack/examples/bases/nutanix/kustomization.yaml.tmpl diff --git a/hack/examples/bases/nutanix/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/kustomization.yaml.tmpl new file mode 100644 index 000000000..96cca51e3 --- /dev/null +++ b/hack/examples/bases/nutanix/kustomization.yaml.tmpl @@ -0,0 +1,51 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + # - ./cilium/crs + # - ./cilium/helm-addon + # - ./calico/crs + # - ./calico/helm-addon + - https://github.com/nutanix-cloud-native/cluster-api-provider-nutanix/releases/download/v1.4.0-alpha.1/cluster-template-clusterclass.yaml + +namePrefix: + +labels: + - includeSelectors: false + pairs: + cluster.x-k8s.io/provider: infrastructure-nutanix + +patches: + - target: + group: cluster.x-k8s.io + kind: Cluster + patch: |- + - op: "remove" + path: "/metadata/namespace" + - op: "add" + path: "/spec/topology/class" + value: "${CLUSTER_CLASS_NAME}" + - target: + group: cluster.x-k8s.io + kind: ClusterClass + patch: |- + - op: "add" + path: "/spec/controlPlane/machineInfrastructure/ref/name" + value: "${CLUSTER_CLASS_NAME}-cp-nmt" + - op: "add" + path: "/spec/controlPlane/ref/name" + value: "${CLUSTER_CLASS_NAME}-kcpt" + - op: "add" + path: "/spec/infrastructure/ref/name" + value: "${CLUSTER_CLASS_NAME}-nct" + - op: "add" + path: "/spec/workers/machineDeployments/0/template/bootstrap/ref/name" + value: "${CLUSTER_CLASS_NAME}-kcfg-0" + - op: "add" + path: "/spec/workers/machineDeployments/0/template/infrastructure/ref/name" + value: "${CLUSTER_CLASS_NAME}-md-nmt" + - op: "remove" + path: "/spec/variables" From e00083a646a7616c980a4990695216af9b3da387 Mon Sep 17 00:00:00 2001 From: Deepak Muley Date: Thu, 21 Mar 2024 11:50:26 -0700 Subject: [PATCH 04/87] added nutanix examples for clusterclass and cluster --- .../nutanix-cluster-class.yaml | 305 ++++++++++++++ .../nutanix-cluster-calico-crs.yaml | 384 ++++++++++++++++++ .../nutanix-cluster-calico-helm-addon.yaml | 384 ++++++++++++++++++ .../nutanix-cluster-cilium-crs.yaml | 384 ++++++++++++++++++ .../nutanix-cluster-cilium-helm-addon.yaml | 384 ++++++++++++++++++ .../nutanix/cluster/kustomization.yaml.tmpl | 30 ++ .../clusterclass/kustomization.yaml.tmpl | 31 ++ .../nutanix/clusterclass/kustomizeconfig.yaml | 22 + .../bases/nutanix/kustomization.yaml.tmpl | 51 --- .../nutanix/kustomization.yaml.tmpl | 27 ++ .../calico/crs/kustomization.yaml.tmpl | 19 + .../calico/helm-addon/kustomization.yaml.tmpl | 19 + .../cilium/crs/kustomization.yaml.tmpl | 19 + .../cilium/helm-addon/kustomization.yaml.tmpl | 19 + .../patches/nutanix/initialize-variables.yaml | 62 +++ hack/examples/sync.sh | 4 +- 16 files changed, 2091 insertions(+), 53 deletions(-) create mode 100644 charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml create mode 100644 examples/capi-quick-start/nutanix-cluster-calico-crs.yaml create mode 100644 examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml create mode 100644 examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml create mode 100644 examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml create mode 100644 hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl create mode 100644 hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl create mode 100644 hack/examples/bases/nutanix/clusterclass/kustomizeconfig.yaml delete mode 100644 hack/examples/bases/nutanix/kustomization.yaml.tmpl create mode 100644 hack/examples/overlays/clusterclasses/nutanix/kustomization.yaml.tmpl create mode 100644 hack/examples/overlays/clusters/nutanix/calico/crs/kustomization.yaml.tmpl create mode 100644 hack/examples/overlays/clusters/nutanix/calico/helm-addon/kustomization.yaml.tmpl create mode 100644 hack/examples/overlays/clusters/nutanix/cilium/crs/kustomization.yaml.tmpl create mode 100644 hack/examples/overlays/clusters/nutanix/cilium/helm-addon/kustomization.yaml.tmpl create mode 100644 hack/examples/patches/nutanix/initialize-variables.yaml diff --git a/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml new file mode 100644 index 000000000..58e511c35 --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml @@ -0,0 +1,305 @@ +apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 +kind: KubeadmConfigTemplate +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-quick-start-kcfg-0 +spec: + template: + spec: + joinConfiguration: + nodeRegistration: + kubeletExtraArgs: + cloud-provider: external + eviction-hard: nodefs.available<10%,nodefs.inodesFree<5%,imagefs.available<15%,memory.available<100Mi,imagefs.inodesFree<10% + 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 + postKubeadmCommands: + - echo "after kubeadm call" > /var/log/postkubeadm.log + preKubeadmCommands: + - echo "before kubeadm call" > /var/log/prekubeadm.log + - hostnamectl set-hostname "{{ ds.meta_data.hostname }}" + verbosity: 10 +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: ClusterClass +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-quick-start +spec: + controlPlane: + machineHealthCheck: + maxUnhealthy: 40% + nodeStartupTimeout: 10m + unhealthyConditions: + - status: "False" + timeout: 300s + type: Ready + - status: Unknown + timeout: 300s + type: Ready + - status: "True" + timeout: 300s + type: MemoryPressure + - status: "True" + timeout: 300s + type: DiskPressure + - status: "True" + timeout: 300s + type: PIDPressure + - status: "True" + timeout: 300s + type: NetworkUnavailable + machineInfrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: NutanixMachineTemplate + name: nutanix-quick-start-cp-nmt + ref: + apiVersion: controlplane.cluster.x-k8s.io/v1beta1 + kind: KubeadmControlPlaneTemplate + name: nutanix-quick-start-kcpt + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: NutanixClusterTemplate + name: nutanix-quick-start-nct + patches: + - external: + discoverVariablesExtension: nutanixclusterconfigvars.cluster-api-runtime-extensions-nutanix + generateExtension: nutanixclusterconfigpatch.cluster-api-runtime-extensions-nutanix + name: cluster-config + - external: + discoverVariablesExtension: nutanixworkerconfigvars.cluster-api-runtime-extensions-nutanix + generateExtension: nutanixworkerconfigpatch.cluster-api-runtime-extensions-nutanix + name: worker-config + workers: + machineDeployments: + - class: nutanix-quick-start-worker + machineHealthCheck: + maxUnhealthy: 40% + nodeStartupTimeout: 10m + unhealthyConditions: + - status: "False" + timeout: 300s + type: Ready + - status: Unknown + timeout: 300s + type: Ready + - status: "True" + timeout: 300s + type: MemoryPressure + - status: "True" + timeout: 300s + type: DiskPressure + - status: "True" + timeout: 300s + type: PIDPressure + - status: "True" + timeout: 300s + type: NetworkUnavailable + template: + bootstrap: + ref: + apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 + kind: KubeadmConfigTemplate + name: nutanix-quick-start-kcfg-0 + infrastructure: + ref: + apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 + kind: NutanixMachineTemplate + name: nutanix-quick-start-md-nmt +--- +apiVersion: controlplane.cluster.x-k8s.io/v1beta1 +kind: KubeadmControlPlaneTemplate +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-quick-start-kcpt +spec: + template: + spec: + kubeadmConfigSpec: + clusterConfiguration: + apiServer: + certSANs: + - localhost + - 127.0.0.1 + - 0.0.0.0 + extraArgs: + cloud-provider: external + 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 + controllerManager: + extraArgs: + cloud-provider: external + 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 + scheduler: + extraArgs: + 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 + files: + - content: | + apiVersion: v1 + kind: Pod + metadata: + name: kube-vip + namespace: kube-system + spec: + containers: + - name: kube-vip + image: ghcr.io/kube-vip/kube-vip:v0.6.4 + imagePullPolicy: IfNotPresent + args: + - manager + env: + - name: vip_arp + value: "true" + - name: address + value: "${CONTROL_PLANE_ENDPOINT_IP}" + - name: port + value: "${CONTROL_PLANE_ENDPOINT_PORT=6443}" + - name: vip_cidr + value: "32" + - name: cp_enable + value: "true" + - name: cp_namespace + value: kube-system + - name: vip_ddns + value: "false" + - name: vip_leaderelection + value: "true" + - name: vip_leaseduration + value: "15" + - name: vip_renewdeadline + value: "10" + - name: vip_retryperiod + value: "2" + - name: svc_enable + value: "${KUBEVIP_SVC_ENABLE=false}" + - name: lb_enable + value: "${KUBEVIP_LB_ENABLE=false}" + - name: enableServicesElection + value: "${KUBEVIP_SVC_ELECTION=false}" + securityContext: + capabilities: + add: + - NET_ADMIN + - SYS_TIME + - NET_RAW + volumeMounts: + - mountPath: /etc/kubernetes/admin.conf + name: kubeconfig + resources: {} + hostNetwork: true + hostAliases: + - hostnames: + - kubernetes + ip: 127.0.0.1 + volumes: + - name: kubeconfig + hostPath: + type: FileOrCreate + path: /etc/kubernetes/admin.conf + status: {} + owner: root:root + path: /etc/kubernetes/manifests/kube-vip.yaml + initConfiguration: + nodeRegistration: + kubeletExtraArgs: + cloud-provider: external + eviction-hard: nodefs.available<10%,nodefs.inodesFree<5%,imagefs.available<15%,memory.available<100Mi,imagefs.inodesFree<10% + 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 + joinConfiguration: + nodeRegistration: + kubeletExtraArgs: + cloud-provider: external + eviction-hard: nodefs.available<10%,nodefs.inodesFree<5%,imagefs.available<15%,memory.available<100Mi,imagefs.inodesFree<10% + 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 + postKubeadmCommands: + - echo export KUBECONFIG=/etc/kubernetes/admin.conf >> /root/.bashrc + - | + KUBERNETES_VERSION_NO_V=${KUBERNETES_VERSION#v} + VERSION_TO_COMPARE=1.29.0 + if [ "$(printf '%s\n' "$KUBERNETES_VERSION_NO_V" "$VERSION_TO_COMPARE" | sort -V | head -n1)" != "$KUBERNETES_VERSION_NO_V" ]; then + if [ -f /run/kubeadm/kubeadm.yaml ]; then + sed -i 's#path: /etc/kubernetes/super-admin.conf#path: /etc/kubernetes/admin.conf#' /etc/kubernetes/manifests/kube-vip.yaml; + fi + fi + - echo "after kubeadm call" > /var/log/postkubeadm.log + preKubeadmCommands: + - echo "before kubeadm call" > /var/log/prekubeadm.log + - hostnamectl set-hostname "{{ ds.meta_data.hostname }}" + - echo "::1 ipv6-localhost ipv6-loopback" >/etc/hosts + - echo "127.0.0.1 localhost" >>/etc/hosts + - echo "127.0.0.1 kubernetes" >>/etc/hosts + - echo "127.0.0.1 {{ ds.meta_data.hostname }}" >> /etc/hosts + - | + KUBERNETES_VERSION_NO_V=${KUBERNETES_VERSION#v} + VERSION_TO_COMPARE=1.29.0 + if [ "$(printf '%s\n' "$KUBERNETES_VERSION_NO_V" "$VERSION_TO_COMPARE" | sort -V | head -n1)" != "$KUBERNETES_VERSION_NO_V" ]; then + if [ -f /run/kubeadm/kubeadm.yaml ]; then + sed -i 's#path: /etc/kubernetes/admin.conf#path: /etc/kubernetes/super-admin.conf#' /etc/kubernetes/manifests/kube-vip.yaml; + fi + fi + useExperimentalRetryJoin: true + verbosity: 10 +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: NutanixClusterTemplate +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-quick-start-nct +spec: + template: + spec: + failureDomains: [] +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: NutanixMachineTemplate +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-quick-start-cp-nmt +spec: + template: + spec: + bootType: legacy + cluster: + name: "" + type: name + image: + name: "" + type: name + memorySize: 4Gi + providerID: nutanix://vm-uuid + subnet: + - name: "" + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 +--- +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: NutanixMachineTemplate +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-quick-start-md-nmt +spec: + template: + spec: + bootType: legacy + cluster: + name: "" + type: name + image: + name: "" + type: name + memorySize: 4Gi + providerID: nutanix://vm-uuid + subnet: + - name: "" + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml new file mode 100644 index 000000000..9d453da93 --- /dev/null +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -0,0 +1,384 @@ +apiVersion: v1 +binaryData: + ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} +kind: ConfigMap +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-trusted-ca-bundle +--- +apiVersion: v1 +data: + nutanix-ccm.yaml: | + --- + apiVersion: v1 + kind: ConfigMap + metadata: + name: nutanix-ccm-pc-trusted-ca-bundle + namespace: kube-system + binaryData: + ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: cloud-controller-manager + namespace: kube-system + --- + # Source: nutanix-cloud-provider/templates/cm.yaml + kind: ConfigMap + apiVersion: v1 + metadata: + name: nutanix-config + namespace: kube-system + data: + nutanix_config.json: |- + { + "prismCentral": { + "address": "${NUTANIX_ENDPOINT}", + "port": ${NUTANIX_PORT=9440}, + "insecure": ${NUTANIX_INSECURE=false}, + "credentialRef": { + "kind": "secret", + "name": "nutanix-creds", + "namespace": "kube-system" + }, + "additionalTrustBundle": { + "kind": "ConfigMap", + "name": "nutanix-ccm-pc-trusted-ca-bundle", + "namespace": "kube-system" + } + }, + "enableCustomLabeling": ${CCM_CUSTOM_LABEL=false}, + "topologyDiscovery": { + "type": "Prism" + } + } + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:cloud-controller-manager + rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - update + - apiGroups: + - "" + resources: + - nodes + verbs: + - "*" + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch + - apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - apiGroups: + - "" + resources: + - endpoints + verbs: + - create + - get + - list + - watch + - update + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + kind: ClusterRoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + metadata: + name: system:cloud-controller-manager + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:cloud-controller-manager + subjects: + - kind: ServiceAccount + name: cloud-controller-manager + namespace: kube-system + --- + # Source: nutanix-cloud-provider/templates/cloud-provider-nutanix-deployment.yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + k8s-app: nutanix-cloud-controller-manager + name: nutanix-cloud-controller-manager + namespace: kube-system + spec: + replicas: 1 + selector: + matchLabels: + k8s-app: nutanix-cloud-controller-manager + strategy: + type: Recreate + template: + metadata: + labels: + k8s-app: nutanix-cloud-controller-manager + spec: + hostNetwork: true + priorityClassName: system-cluster-critical + nodeSelector: + node-role.kubernetes.io/control-plane: "" + serviceAccountName: cloud-controller-manager + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + k8s-app: nutanix-cloud-controller-manager + topologyKey: kubernetes.io/hostname + dnsPolicy: Default + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + operator: Exists + - effect: NoExecute + key: node.kubernetes.io/unreachable + operator: Exists + tolerationSeconds: 120 + - effect: NoExecute + key: node.kubernetes.io/not-ready + operator: Exists + tolerationSeconds: 120 + - effect: NoSchedule + key: node.cloudprovider.kubernetes.io/uninitialized + operator: Exists + - effect: NoSchedule + key: node.kubernetes.io/not-ready + operator: Exists + containers: + - image: "${CCM_REPO=ghcr.io/nutanix-cloud-native/cloud-provider-nutanix/controller}:${CCM_TAG=v0.3.2}" + imagePullPolicy: IfNotPresent + name: nutanix-cloud-controller-manager + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + args: + - "--leader-elect=true" + - "--cloud-config=/etc/cloud/nutanix_config.json" + resources: + requests: + cpu: 100m + memory: 50Mi + volumeMounts: + - mountPath: /etc/cloud + name: nutanix-config-volume + readOnly: true + volumes: + - name: nutanix-config-volume + configMap: + name: nutanix-config +kind: ConfigMap +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-creds +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm-secret +stringData: + nutanix-ccm-secret.yaml: | + apiVersion: v1 + kind: Secret + metadata: + name: nutanix-creds + namespace: kube-system + stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + }, + "prismElements": null + } + } + ] +type: addons.cluster.x-k8s.io/resource-set +--- +apiVersion: addons.cluster.x-k8s.io/v1beta1 +kind: ClusterResourceSet +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm-crs +spec: + clusterSelector: + matchLabels: + ccm: nutanix + resources: + - kind: ConfigMap + name: nutanix-ccm + - kind: Secret + name: nutanix-ccm-secret + - kind: ConfigMap + name: nutanix-ccm-pc-trusted-ca-bundle + strategy: ApplyOnce +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + labels: + ccm: nutanix + cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME} +spec: + clusterNetwork: + pods: + cidrBlocks: + - ${POD_CIDR:-192.168.0.0/16} + serviceDomain: ${SERVICE_DOMAIN:="cluster.local"} + services: + cidrBlocks: + - ${SERVICE_CIDR:-10.128.0.0/12} + topology: + class: nutanix-quick-start + controlPlane: + metadata: {} + replicas: ${CONTROL_PLANE_MACHINE_COUNT} + variables: + - name: clusterConfig + value: + addons: + clusterAutoscaler: + strategy: ClusterResourceSet + cni: + provider: Calico + strategy: ClusterResourceSet + nfd: + strategy: ClusterResourceSet + controlPlane: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + memorySize: 4Gi + subnet: + - name: $${NUTANIX_SUBNET_NAME} + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 + nutanix: + controlPlaneEndpoint: + host: $${CONTROL_PLANE_ENDPOINT_IP} + port: $${CONTROL_PLANE_ENDPOINT_PORT} + prismCentralEndpoint: + additionalTrustBundle: $${CLUSTER_NAME}-pc-trusted-ca-bundle + credentialSecret: $${CLUSTER_NAME}-pc-creds + host: $${NUTANIX_ENDPOINT} + insecure: $${NUTANIX_INSECURE} + port: 9440 + - name: workerConfig + value: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + memorySize: 4Gi + subnet: + - name: $${NUTANIX_SUBNET_NAME} + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 + version: ${KUBERNETES_VERSION} + workers: + machineDeployments: + - class: nutanix-quick-start-worker + metadata: + annotations: + cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size: "${WORKER_MACHINE_COUNT}" + cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size: "${WORKER_MACHINE_COUNT}" + name: md-0 diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml new file mode 100644 index 000000000..cc1aa98f2 --- /dev/null +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -0,0 +1,384 @@ +apiVersion: v1 +binaryData: + ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} +kind: ConfigMap +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-trusted-ca-bundle +--- +apiVersion: v1 +data: + nutanix-ccm.yaml: | + --- + apiVersion: v1 + kind: ConfigMap + metadata: + name: nutanix-ccm-pc-trusted-ca-bundle + namespace: kube-system + binaryData: + ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: cloud-controller-manager + namespace: kube-system + --- + # Source: nutanix-cloud-provider/templates/cm.yaml + kind: ConfigMap + apiVersion: v1 + metadata: + name: nutanix-config + namespace: kube-system + data: + nutanix_config.json: |- + { + "prismCentral": { + "address": "${NUTANIX_ENDPOINT}", + "port": ${NUTANIX_PORT=9440}, + "insecure": ${NUTANIX_INSECURE=false}, + "credentialRef": { + "kind": "secret", + "name": "nutanix-creds", + "namespace": "kube-system" + }, + "additionalTrustBundle": { + "kind": "ConfigMap", + "name": "nutanix-ccm-pc-trusted-ca-bundle", + "namespace": "kube-system" + } + }, + "enableCustomLabeling": ${CCM_CUSTOM_LABEL=false}, + "topologyDiscovery": { + "type": "Prism" + } + } + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:cloud-controller-manager + rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - update + - apiGroups: + - "" + resources: + - nodes + verbs: + - "*" + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch + - apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - apiGroups: + - "" + resources: + - endpoints + verbs: + - create + - get + - list + - watch + - update + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + kind: ClusterRoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + metadata: + name: system:cloud-controller-manager + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:cloud-controller-manager + subjects: + - kind: ServiceAccount + name: cloud-controller-manager + namespace: kube-system + --- + # Source: nutanix-cloud-provider/templates/cloud-provider-nutanix-deployment.yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + k8s-app: nutanix-cloud-controller-manager + name: nutanix-cloud-controller-manager + namespace: kube-system + spec: + replicas: 1 + selector: + matchLabels: + k8s-app: nutanix-cloud-controller-manager + strategy: + type: Recreate + template: + metadata: + labels: + k8s-app: nutanix-cloud-controller-manager + spec: + hostNetwork: true + priorityClassName: system-cluster-critical + nodeSelector: + node-role.kubernetes.io/control-plane: "" + serviceAccountName: cloud-controller-manager + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + k8s-app: nutanix-cloud-controller-manager + topologyKey: kubernetes.io/hostname + dnsPolicy: Default + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + operator: Exists + - effect: NoExecute + key: node.kubernetes.io/unreachable + operator: Exists + tolerationSeconds: 120 + - effect: NoExecute + key: node.kubernetes.io/not-ready + operator: Exists + tolerationSeconds: 120 + - effect: NoSchedule + key: node.cloudprovider.kubernetes.io/uninitialized + operator: Exists + - effect: NoSchedule + key: node.kubernetes.io/not-ready + operator: Exists + containers: + - image: "${CCM_REPO=ghcr.io/nutanix-cloud-native/cloud-provider-nutanix/controller}:${CCM_TAG=v0.3.2}" + imagePullPolicy: IfNotPresent + name: nutanix-cloud-controller-manager + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + args: + - "--leader-elect=true" + - "--cloud-config=/etc/cloud/nutanix_config.json" + resources: + requests: + cpu: 100m + memory: 50Mi + volumeMounts: + - mountPath: /etc/cloud + name: nutanix-config-volume + readOnly: true + volumes: + - name: nutanix-config-volume + configMap: + name: nutanix-config +kind: ConfigMap +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-creds +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm-secret +stringData: + nutanix-ccm-secret.yaml: | + apiVersion: v1 + kind: Secret + metadata: + name: nutanix-creds + namespace: kube-system + stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + }, + "prismElements": null + } + } + ] +type: addons.cluster.x-k8s.io/resource-set +--- +apiVersion: addons.cluster.x-k8s.io/v1beta1 +kind: ClusterResourceSet +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm-crs +spec: + clusterSelector: + matchLabels: + ccm: nutanix + resources: + - kind: ConfigMap + name: nutanix-ccm + - kind: Secret + name: nutanix-ccm-secret + - kind: ConfigMap + name: nutanix-ccm-pc-trusted-ca-bundle + strategy: ApplyOnce +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + labels: + ccm: nutanix + cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME} +spec: + clusterNetwork: + pods: + cidrBlocks: + - ${POD_CIDR:-192.168.0.0/16} + serviceDomain: ${SERVICE_DOMAIN:="cluster.local"} + services: + cidrBlocks: + - ${SERVICE_CIDR:-10.128.0.0/12} + topology: + class: nutanix-quick-start + controlPlane: + metadata: {} + replicas: ${CONTROL_PLANE_MACHINE_COUNT} + variables: + - name: clusterConfig + value: + addons: + clusterAutoscaler: + strategy: HelmAddon + cni: + provider: Calico + strategy: HelmAddon + nfd: + strategy: HelmAddon + controlPlane: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + memorySize: 4Gi + subnet: + - name: $${NUTANIX_SUBNET_NAME} + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 + nutanix: + controlPlaneEndpoint: + host: $${CONTROL_PLANE_ENDPOINT_IP} + port: $${CONTROL_PLANE_ENDPOINT_PORT} + prismCentralEndpoint: + additionalTrustBundle: $${CLUSTER_NAME}-pc-trusted-ca-bundle + credentialSecret: $${CLUSTER_NAME}-pc-creds + host: $${NUTANIX_ENDPOINT} + insecure: $${NUTANIX_INSECURE} + port: 9440 + - name: workerConfig + value: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + memorySize: 4Gi + subnet: + - name: $${NUTANIX_SUBNET_NAME} + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 + version: ${KUBERNETES_VERSION} + workers: + machineDeployments: + - class: nutanix-quick-start-worker + metadata: + annotations: + cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size: "${WORKER_MACHINE_COUNT}" + cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size: "${WORKER_MACHINE_COUNT}" + name: md-0 diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml new file mode 100644 index 000000000..b0f59d3d3 --- /dev/null +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -0,0 +1,384 @@ +apiVersion: v1 +binaryData: + ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} +kind: ConfigMap +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-trusted-ca-bundle +--- +apiVersion: v1 +data: + nutanix-ccm.yaml: | + --- + apiVersion: v1 + kind: ConfigMap + metadata: + name: nutanix-ccm-pc-trusted-ca-bundle + namespace: kube-system + binaryData: + ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: cloud-controller-manager + namespace: kube-system + --- + # Source: nutanix-cloud-provider/templates/cm.yaml + kind: ConfigMap + apiVersion: v1 + metadata: + name: nutanix-config + namespace: kube-system + data: + nutanix_config.json: |- + { + "prismCentral": { + "address": "${NUTANIX_ENDPOINT}", + "port": ${NUTANIX_PORT=9440}, + "insecure": ${NUTANIX_INSECURE=false}, + "credentialRef": { + "kind": "secret", + "name": "nutanix-creds", + "namespace": "kube-system" + }, + "additionalTrustBundle": { + "kind": "ConfigMap", + "name": "nutanix-ccm-pc-trusted-ca-bundle", + "namespace": "kube-system" + } + }, + "enableCustomLabeling": ${CCM_CUSTOM_LABEL=false}, + "topologyDiscovery": { + "type": "Prism" + } + } + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:cloud-controller-manager + rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - update + - apiGroups: + - "" + resources: + - nodes + verbs: + - "*" + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch + - apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - apiGroups: + - "" + resources: + - endpoints + verbs: + - create + - get + - list + - watch + - update + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + kind: ClusterRoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + metadata: + name: system:cloud-controller-manager + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:cloud-controller-manager + subjects: + - kind: ServiceAccount + name: cloud-controller-manager + namespace: kube-system + --- + # Source: nutanix-cloud-provider/templates/cloud-provider-nutanix-deployment.yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + k8s-app: nutanix-cloud-controller-manager + name: nutanix-cloud-controller-manager + namespace: kube-system + spec: + replicas: 1 + selector: + matchLabels: + k8s-app: nutanix-cloud-controller-manager + strategy: + type: Recreate + template: + metadata: + labels: + k8s-app: nutanix-cloud-controller-manager + spec: + hostNetwork: true + priorityClassName: system-cluster-critical + nodeSelector: + node-role.kubernetes.io/control-plane: "" + serviceAccountName: cloud-controller-manager + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + k8s-app: nutanix-cloud-controller-manager + topologyKey: kubernetes.io/hostname + dnsPolicy: Default + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + operator: Exists + - effect: NoExecute + key: node.kubernetes.io/unreachable + operator: Exists + tolerationSeconds: 120 + - effect: NoExecute + key: node.kubernetes.io/not-ready + operator: Exists + tolerationSeconds: 120 + - effect: NoSchedule + key: node.cloudprovider.kubernetes.io/uninitialized + operator: Exists + - effect: NoSchedule + key: node.kubernetes.io/not-ready + operator: Exists + containers: + - image: "${CCM_REPO=ghcr.io/nutanix-cloud-native/cloud-provider-nutanix/controller}:${CCM_TAG=v0.3.2}" + imagePullPolicy: IfNotPresent + name: nutanix-cloud-controller-manager + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + args: + - "--leader-elect=true" + - "--cloud-config=/etc/cloud/nutanix_config.json" + resources: + requests: + cpu: 100m + memory: 50Mi + volumeMounts: + - mountPath: /etc/cloud + name: nutanix-config-volume + readOnly: true + volumes: + - name: nutanix-config-volume + configMap: + name: nutanix-config +kind: ConfigMap +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-creds +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm-secret +stringData: + nutanix-ccm-secret.yaml: | + apiVersion: v1 + kind: Secret + metadata: + name: nutanix-creds + namespace: kube-system + stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + }, + "prismElements": null + } + } + ] +type: addons.cluster.x-k8s.io/resource-set +--- +apiVersion: addons.cluster.x-k8s.io/v1beta1 +kind: ClusterResourceSet +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm-crs +spec: + clusterSelector: + matchLabels: + ccm: nutanix + resources: + - kind: ConfigMap + name: nutanix-ccm + - kind: Secret + name: nutanix-ccm-secret + - kind: ConfigMap + name: nutanix-ccm-pc-trusted-ca-bundle + strategy: ApplyOnce +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + labels: + ccm: nutanix + cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME} +spec: + clusterNetwork: + pods: + cidrBlocks: + - ${POD_CIDR:-192.168.0.0/16} + serviceDomain: ${SERVICE_DOMAIN:="cluster.local"} + services: + cidrBlocks: + - ${SERVICE_CIDR:-10.128.0.0/12} + topology: + class: nutanix-quick-start + controlPlane: + metadata: {} + replicas: ${CONTROL_PLANE_MACHINE_COUNT} + variables: + - name: clusterConfig + value: + addons: + clusterAutoscaler: + strategy: ClusterResourceSet + cni: + provider: Cilium + strategy: ClusterResourceSet + nfd: + strategy: ClusterResourceSet + controlPlane: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + memorySize: 4Gi + subnet: + - name: $${NUTANIX_SUBNET_NAME} + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 + nutanix: + controlPlaneEndpoint: + host: $${CONTROL_PLANE_ENDPOINT_IP} + port: $${CONTROL_PLANE_ENDPOINT_PORT} + prismCentralEndpoint: + additionalTrustBundle: $${CLUSTER_NAME}-pc-trusted-ca-bundle + credentialSecret: $${CLUSTER_NAME}-pc-creds + host: $${NUTANIX_ENDPOINT} + insecure: $${NUTANIX_INSECURE} + port: 9440 + - name: workerConfig + value: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + memorySize: 4Gi + subnet: + - name: $${NUTANIX_SUBNET_NAME} + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 + version: ${KUBERNETES_VERSION} + workers: + machineDeployments: + - class: nutanix-quick-start-worker + metadata: + annotations: + cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size: "${WORKER_MACHINE_COUNT}" + cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size: "${WORKER_MACHINE_COUNT}" + name: md-0 diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml new file mode 100644 index 000000000..59a5b19be --- /dev/null +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -0,0 +1,384 @@ +apiVersion: v1 +binaryData: + ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} +kind: ConfigMap +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-trusted-ca-bundle +--- +apiVersion: v1 +data: + nutanix-ccm.yaml: | + --- + apiVersion: v1 + kind: ConfigMap + metadata: + name: nutanix-ccm-pc-trusted-ca-bundle + namespace: kube-system + binaryData: + ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + apiVersion: v1 + kind: ServiceAccount + metadata: + name: cloud-controller-manager + namespace: kube-system + --- + # Source: nutanix-cloud-provider/templates/cm.yaml + kind: ConfigMap + apiVersion: v1 + metadata: + name: nutanix-config + namespace: kube-system + data: + nutanix_config.json: |- + { + "prismCentral": { + "address": "${NUTANIX_ENDPOINT}", + "port": ${NUTANIX_PORT=9440}, + "insecure": ${NUTANIX_INSECURE=false}, + "credentialRef": { + "kind": "secret", + "name": "nutanix-creds", + "namespace": "kube-system" + }, + "additionalTrustBundle": { + "kind": "ConfigMap", + "name": "nutanix-ccm-pc-trusted-ca-bundle", + "namespace": "kube-system" + } + }, + "enableCustomLabeling": ${CCM_CUSTOM_LABEL=false}, + "topologyDiscovery": { + "type": "Prism" + } + } + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + annotations: + rbac.authorization.kubernetes.io/autoupdate: "true" + name: system:cloud-controller-manager + rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + - update + - apiGroups: + - "" + resources: + - nodes + verbs: + - "*" + - apiGroups: + - "" + resources: + - nodes/status + verbs: + - patch + - apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - apiGroups: + - "" + resources: + - endpoints + verbs: + - create + - get + - list + - watch + - update + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + --- + # Source: nutanix-cloud-provider/templates/rbac.yaml + kind: ClusterRoleBinding + apiVersion: rbac.authorization.k8s.io/v1 + metadata: + name: system:cloud-controller-manager + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:cloud-controller-manager + subjects: + - kind: ServiceAccount + name: cloud-controller-manager + namespace: kube-system + --- + # Source: nutanix-cloud-provider/templates/cloud-provider-nutanix-deployment.yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + labels: + k8s-app: nutanix-cloud-controller-manager + name: nutanix-cloud-controller-manager + namespace: kube-system + spec: + replicas: 1 + selector: + matchLabels: + k8s-app: nutanix-cloud-controller-manager + strategy: + type: Recreate + template: + metadata: + labels: + k8s-app: nutanix-cloud-controller-manager + spec: + hostNetwork: true + priorityClassName: system-cluster-critical + nodeSelector: + node-role.kubernetes.io/control-plane: "" + serviceAccountName: cloud-controller-manager + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + k8s-app: nutanix-cloud-controller-manager + topologyKey: kubernetes.io/hostname + dnsPolicy: Default + tolerations: + - effect: NoSchedule + key: node-role.kubernetes.io/master + operator: Exists + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + operator: Exists + - effect: NoExecute + key: node.kubernetes.io/unreachable + operator: Exists + tolerationSeconds: 120 + - effect: NoExecute + key: node.kubernetes.io/not-ready + operator: Exists + tolerationSeconds: 120 + - effect: NoSchedule + key: node.cloudprovider.kubernetes.io/uninitialized + operator: Exists + - effect: NoSchedule + key: node.kubernetes.io/not-ready + operator: Exists + containers: + - image: "${CCM_REPO=ghcr.io/nutanix-cloud-native/cloud-provider-nutanix/controller}:${CCM_TAG=v0.3.2}" + imagePullPolicy: IfNotPresent + name: nutanix-cloud-controller-manager + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + args: + - "--leader-elect=true" + - "--cloud-config=/etc/cloud/nutanix_config.json" + resources: + requests: + cpu: 100m + memory: 50Mi + volumeMounts: + - mountPath: /etc/cloud + name: nutanix-config-volume + readOnly: true + volumes: + - name: nutanix-config-volume + configMap: + name: nutanix-config +kind: ConfigMap +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pc-creds +stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + } + } + } + ] +--- +apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm-secret +stringData: + nutanix-ccm-secret.yaml: | + apiVersion: v1 + kind: Secret + metadata: + name: nutanix-creds + namespace: kube-system + stringData: + credentials: | + [ + { + "type": "basic_auth", + "data": { + "prismCentral":{ + "username": "${NUTANIX_USER}", + "password": "${NUTANIX_PASSWORD}" + }, + "prismElements": null + } + } + ] +type: addons.cluster.x-k8s.io/resource-set +--- +apiVersion: addons.cluster.x-k8s.io/v1beta1 +kind: ClusterResourceSet +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: nutanix-ccm-crs +spec: + clusterSelector: + matchLabels: + ccm: nutanix + resources: + - kind: ConfigMap + name: nutanix-ccm + - kind: Secret + name: nutanix-ccm-secret + - kind: ConfigMap + name: nutanix-ccm-pc-trusted-ca-bundle + strategy: ApplyOnce +--- +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + labels: + ccm: nutanix + cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME} +spec: + clusterNetwork: + pods: + cidrBlocks: + - ${POD_CIDR:-192.168.0.0/16} + serviceDomain: ${SERVICE_DOMAIN:="cluster.local"} + services: + cidrBlocks: + - ${SERVICE_CIDR:-10.128.0.0/12} + topology: + class: nutanix-quick-start + controlPlane: + metadata: {} + replicas: ${CONTROL_PLANE_MACHINE_COUNT} + variables: + - name: clusterConfig + value: + addons: + clusterAutoscaler: + strategy: HelmAddon + cni: + provider: Cilium + strategy: HelmAddon + nfd: + strategy: HelmAddon + controlPlane: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + memorySize: 4Gi + subnet: + - name: $${NUTANIX_SUBNET_NAME} + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 + nutanix: + controlPlaneEndpoint: + host: $${CONTROL_PLANE_ENDPOINT_IP} + port: $${CONTROL_PLANE_ENDPOINT_PORT} + prismCentralEndpoint: + additionalTrustBundle: $${CLUSTER_NAME}-pc-trusted-ca-bundle + credentialSecret: $${CLUSTER_NAME}-pc-creds + host: $${NUTANIX_ENDPOINT} + insecure: $${NUTANIX_INSECURE} + port: 9440 + - name: workerConfig + value: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + memorySize: 4Gi + subnet: + - name: $${NUTANIX_SUBNET_NAME} + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 + version: ${KUBERNETES_VERSION} + workers: + machineDeployments: + - class: nutanix-quick-start-worker + metadata: + annotations: + cluster.x-k8s.io/cluster-api-autoscaler-node-group-max-size: "${WORKER_MACHINE_COUNT}" + cluster.x-k8s.io/cluster-api-autoscaler-node-group-min-size: "${WORKER_MACHINE_COUNT}" + name: md-0 diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl new file mode 100644 index 000000000..d4454cc70 --- /dev/null +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -0,0 +1,30 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/main/templates/cluster-template-topology.yaml + +sortOptions: + order: fifo + +labels: +- includeSelectors: false + pairs: + cluster.x-k8s.io/provider: nutanix + +patches: +- target: + kind: Cluster + path: ../../../patches/initialize-variables.yaml +- target: + kind: Cluster + path: ../../../patches/cluster-network.yaml +- target: + kind: Cluster + path: ../../../patches/cluster-autoscaler.yaml +- target: + kind: Cluster + path: ../../../patches/nutanix/initialize-variables.yaml \ No newline at end of file diff --git a/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl new file mode 100644 index 000000000..77a0718f4 --- /dev/null +++ b/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl @@ -0,0 +1,31 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/main/templates/cluster-template-clusterclass.yaml + +configurations: + - kustomizeconfig.yaml + +sortOptions: + order: fifo + +namePrefix: + +labels: +- includeSelectors: false + pairs: + cluster.x-k8s.io/provider: nutanix + +patches: +# Delete the patch and variable definitions. +- target: + kind: ClusterClass + patch: |- + - op: "remove" + path: "/spec/patches" + - op: "remove" + path: "/spec/variables" \ No newline at end of file diff --git a/hack/examples/bases/nutanix/clusterclass/kustomizeconfig.yaml b/hack/examples/bases/nutanix/clusterclass/kustomizeconfig.yaml new file mode 100644 index 000000000..97b1f3955 --- /dev/null +++ b/hack/examples/bases/nutanix/clusterclass/kustomizeconfig.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +nameReference: + - kind: NutanixMachineTemplate + fieldSpecs: + - kind: ClusterClass + path: spec/controlPlane/machineInfrastructure/ref/name + - kind: ClusterClass + path: spec/workers/machineDeployments/template/infrastructure/ref/name + - kind: KubeadmControlPlaneTemplate + fieldSpecs: + - kind: ClusterClass + path: spec/controlPlane/ref/name + - kind: NutanixClusterTemplate + fieldSpecs: + - kind: ClusterClass + path: spec/infrastructure/ref/name + - kind: KubeadmConfigTemplate + fieldSpecs: + - kind: ClusterClass + path: spec/workers/machineDeployments/template/bootstrap/ref/name diff --git a/hack/examples/bases/nutanix/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/kustomization.yaml.tmpl deleted file mode 100644 index 96cca51e3..000000000 --- a/hack/examples/bases/nutanix/kustomization.yaml.tmpl +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2023 D2iQ, Inc. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -resources: - # - ./cilium/crs - # - ./cilium/helm-addon - # - ./calico/crs - # - ./calico/helm-addon - - https://github.com/nutanix-cloud-native/cluster-api-provider-nutanix/releases/download/v1.4.0-alpha.1/cluster-template-clusterclass.yaml - -namePrefix: - -labels: - - includeSelectors: false - pairs: - cluster.x-k8s.io/provider: infrastructure-nutanix - -patches: - - target: - group: cluster.x-k8s.io - kind: Cluster - patch: |- - - op: "remove" - path: "/metadata/namespace" - - op: "add" - path: "/spec/topology/class" - value: "${CLUSTER_CLASS_NAME}" - - target: - group: cluster.x-k8s.io - kind: ClusterClass - patch: |- - - op: "add" - path: "/spec/controlPlane/machineInfrastructure/ref/name" - value: "${CLUSTER_CLASS_NAME}-cp-nmt" - - op: "add" - path: "/spec/controlPlane/ref/name" - value: "${CLUSTER_CLASS_NAME}-kcpt" - - op: "add" - path: "/spec/infrastructure/ref/name" - value: "${CLUSTER_CLASS_NAME}-nct" - - op: "add" - path: "/spec/workers/machineDeployments/0/template/bootstrap/ref/name" - value: "${CLUSTER_CLASS_NAME}-kcfg-0" - - op: "add" - path: "/spec/workers/machineDeployments/0/template/infrastructure/ref/name" - value: "${CLUSTER_CLASS_NAME}-md-nmt" - - op: "remove" - path: "/spec/variables" diff --git a/hack/examples/overlays/clusterclasses/nutanix/kustomization.yaml.tmpl b/hack/examples/overlays/clusterclasses/nutanix/kustomization.yaml.tmpl new file mode 100644 index 000000000..2c27d69fb --- /dev/null +++ b/hack/examples/overlays/clusterclasses/nutanix/kustomization.yaml.tmpl @@ -0,0 +1,27 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../../bases/nutanix/clusterclass + +sortOptions: + order: fifo + +patches: + - target: + kind: ClusterClass + patch: |- + - op: "add" + path: "/spec/patches" + value: + - name: "cluster-config" + external: + generateExtension: "nutanixclusterconfigpatch.cluster-api-runtime-extensions-nutanix" + discoverVariablesExtension: "nutanixclusterconfigvars.cluster-api-runtime-extensions-nutanix" + - name: "worker-config" + external: + generateExtension: "nutanixworkerconfigpatch.cluster-api-runtime-extensions-nutanix" + discoverVariablesExtension: "nutanixworkerconfigvars.cluster-api-runtime-extensions-nutanix" diff --git a/hack/examples/overlays/clusters/nutanix/calico/crs/kustomization.yaml.tmpl b/hack/examples/overlays/clusters/nutanix/calico/crs/kustomization.yaml.tmpl new file mode 100644 index 000000000..467d830d9 --- /dev/null +++ b/hack/examples/overlays/clusters/nutanix/calico/crs/kustomization.yaml.tmpl @@ -0,0 +1,19 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../../../../bases/nutanix/cluster + +sortOptions: + order: fifo + +patches: + - target: + kind: Cluster + path: ../../../../../patches/calico.yaml + - target: + kind: Cluster + path: ../../../../../patches/crs-strategy.yaml diff --git a/hack/examples/overlays/clusters/nutanix/calico/helm-addon/kustomization.yaml.tmpl b/hack/examples/overlays/clusters/nutanix/calico/helm-addon/kustomization.yaml.tmpl new file mode 100644 index 000000000..580fb8325 --- /dev/null +++ b/hack/examples/overlays/clusters/nutanix/calico/helm-addon/kustomization.yaml.tmpl @@ -0,0 +1,19 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../../../../bases/nutanix/cluster + +sortOptions: + order: fifo + +patches: + - target: + kind: Cluster + path: ../../../../../patches/calico.yaml + - target: + kind: Cluster + path: ../../../../../patches/helm-addon-strategy.yaml diff --git a/hack/examples/overlays/clusters/nutanix/cilium/crs/kustomization.yaml.tmpl b/hack/examples/overlays/clusters/nutanix/cilium/crs/kustomization.yaml.tmpl new file mode 100644 index 000000000..8583a6ab4 --- /dev/null +++ b/hack/examples/overlays/clusters/nutanix/cilium/crs/kustomization.yaml.tmpl @@ -0,0 +1,19 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../../../../bases/nutanix/cluster + +sortOptions: + order: fifo + +patches: + - target: + kind: Cluster + path: ../../../../../patches/cilium.yaml + - target: + kind: Cluster + path: ../../../../../patches/crs-strategy.yaml diff --git a/hack/examples/overlays/clusters/nutanix/cilium/helm-addon/kustomization.yaml.tmpl b/hack/examples/overlays/clusters/nutanix/cilium/helm-addon/kustomization.yaml.tmpl new file mode 100644 index 000000000..2c5917713 --- /dev/null +++ b/hack/examples/overlays/clusters/nutanix/cilium/helm-addon/kustomization.yaml.tmpl @@ -0,0 +1,19 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- ../../../../../bases/nutanix/cluster + +sortOptions: + order: fifo + +patches: + - target: + kind: Cluster + path: ../../../../../patches/cilium.yaml + - target: + kind: Cluster + path: ../../../../../patches/helm-addon-strategy.yaml diff --git a/hack/examples/patches/nutanix/initialize-variables.yaml b/hack/examples/patches/nutanix/initialize-variables.yaml new file mode 100644 index 000000000..23a28aac8 --- /dev/null +++ b/hack/examples/patches/nutanix/initialize-variables.yaml @@ -0,0 +1,62 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +- op: "add" + path: "/spec/topology/class" + value: "nutanix-quick-start" +- op: "add" + path: "/spec/topology/variables" + value: + - name: "clusterConfig" + value: + addons: + cni: + clusterAutoscaler: + strategy: + nfd: + strategy: + nutanix: + controlPlaneEndpoint: + host: $${CONTROL_PLANE_ENDPOINT_IP} + port: $${CONTROL_PLANE_ENDPOINT_PORT} + prismCentralEndpoint: + additionalTrustBundle: $${CLUSTER_NAME}-pc-trusted-ca-bundle + host: $${NUTANIX_ENDPOINT} + insecure: $${NUTANIX_INSECURE} + port: 9440 + credentialSecret: $${CLUSTER_NAME}-pc-creds + controlPlane: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + subnet: + - name: $${NUTANIX_SUBNET_NAME} + type: name + memorySize: 4Gi + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 + - name: "workerConfig" + value: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + memorySize: 4Gi + subnet: + - name: $${NUTANIX_SUBNET_NAME} + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 diff --git a/hack/examples/sync.sh b/hack/examples/sync.sh index 4d11c0e70..b656cabc9 100755 --- a/hack/examples/sync.sh +++ b/hack/examples/sync.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env bash -x # Copyright 2023 D2iQ, Inc. All rights reserved. # SPDX-License-Identifier: Apache-2.0 @@ -21,7 +21,7 @@ mkdir -p "${EXAMPLE_CLUSTERCLASSES_DIR}" readonly EXAMPLE_CLUSTERS_DIR=examples/capi-quick-start mkdir -p "${EXAMPLE_CLUSTERS_DIR}" -for provider in "aws" "docker"; do +for provider in "aws" "docker" "nutanix"; do kustomize build --load-restrictor LoadRestrictionsNone \ ./hack/examples/overlays/clusterclasses/"${provider}" >"${EXAMPLE_CLUSTERCLASSES_DIR}"/"${provider}"-cluster-class.yaml From 1d132978a2f81cd82832b87625e5da769d391df2 Mon Sep 17 00:00:00 2001 From: Deepak Muley Date: Thu, 21 Mar 2024 13:22:32 -0700 Subject: [PATCH 05/87] removed extra $ sign from all the variables --- devbox.lock | 1092 ----------------- .../nutanix-cluster-calico-crs.yaml | 24 +- .../nutanix-cluster-calico-helm-addon.yaml | 24 +- .../nutanix-cluster-cilium-crs.yaml | 24 +- .../nutanix-cluster-cilium-helm-addon.yaml | 24 +- .../patches/nutanix/initialize-variables.yaml | 24 +- 6 files changed, 60 insertions(+), 1152 deletions(-) diff --git a/devbox.lock b/devbox.lock index 73b569425..59ee0c2bb 100644 --- a/devbox.lock +++ b/devbox.lock @@ -8,43 +8,15 @@ "version": "1.6.27", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nnhjp60w14pdy1hjgxn9dfsg4nbfs93v-actionlint-1.6.27", - "default": true - } - ], "store_path": "/nix/store/nnhjp60w14pdy1hjgxn9dfsg4nbfs93v-actionlint-1.6.27" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/p8rc44x83sld3wk1m4y27za9n1mjyk48-actionlint-1.6.27", - "default": true - } - ], "store_path": "/nix/store/p8rc44x83sld3wk1m4y27za9n1mjyk48-actionlint-1.6.27" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7v1lh7c3pwlax5fy7pw233czn4hs89hl-actionlint-1.6.27", - "default": true - } - ], "store_path": "/nix/store/7v1lh7c3pwlax5fy7pw233czn4hs89hl-actionlint-1.6.27" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/56xxvs3yijdmhhxbfvps38nz95xdxgyl-actionlint-1.6.27", - "default": true - } - ], "store_path": "/nix/store/56xxvs3yijdmhhxbfvps38nz95xdxgyl-actionlint-1.6.27" } } @@ -56,43 +28,15 @@ "version": "3.10.1", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/5lygcps2ly736k0dvk2w4mx6yy8dzz6s-chart-testing-3.10.1", - "default": true - } - ], "store_path": "/nix/store/5lygcps2ly736k0dvk2w4mx6yy8dzz6s-chart-testing-3.10.1" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/103km469ldwrzs525m57bj409vxjlniw-chart-testing-3.10.1", - "default": true - } - ], "store_path": "/nix/store/103km469ldwrzs525m57bj409vxjlniw-chart-testing-3.10.1" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/c4qgh783pvhzqpv7skimzfs75pklbz4f-chart-testing-3.10.1", - "default": true - } - ], "store_path": "/nix/store/c4qgh783pvhzqpv7skimzfs75pklbz4f-chart-testing-3.10.1" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/wzscgl31rzxws05y7vxkl0f65fsiydmm-chart-testing-3.10.1", - "default": true - } - ], "store_path": "/nix/store/wzscgl31rzxws05y7vxkl0f65fsiydmm-chart-testing-3.10.1" } } @@ -104,43 +48,15 @@ "version": "1.6.3", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/6hsi8bj8ddbrv29jff467q1rqcfgs964-clusterctl-1.6.3", - "default": true - } - ], "store_path": "/nix/store/6hsi8bj8ddbrv29jff467q1rqcfgs964-clusterctl-1.6.3" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/jysji089cqrygcwl2ryvbb0sa3cjj8vv-clusterctl-1.6.3", - "default": true - } - ], "store_path": "/nix/store/jysji089cqrygcwl2ryvbb0sa3cjj8vv-clusterctl-1.6.3" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/gbch3dp061am97j79b56pp07121j781k-clusterctl-1.6.3", - "default": true - } - ], "store_path": "/nix/store/gbch3dp061am97j79b56pp07121j781k-clusterctl-1.6.3" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1xy66gcyxaqjhb5h15slyxzw64d920c6-clusterctl-1.6.3", - "default": true - } - ], "store_path": "/nix/store/1xy66gcyxaqjhb5h15slyxzw64d920c6-clusterctl-1.6.3" } } @@ -152,67 +68,15 @@ "version": "9.4", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/vinxz6lkrilb72dkzr3ny02nnvql6z50-coreutils-9.4", - "default": true - }, - { - "name": "info", - "path": "/nix/store/mgvngj0x370glcix9wfaripy3bx5j3s0-coreutils-9.4-info" - } - ], "store_path": "/nix/store/vinxz6lkrilb72dkzr3ny02nnvql6z50-coreutils-9.4" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/77fyfwmz29cz9j5x6yw2wrlm4rvasldv-coreutils-9.4", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/fkfnrbg62vbsdagml1c9vld3wpk3079n-coreutils-9.4-debug" - }, - { - "name": "info", - "path": "/nix/store/x14ppijm82bac50bgf2varjvdm0mr28f-coreutils-9.4-info" - } - ], "store_path": "/nix/store/77fyfwmz29cz9j5x6yw2wrlm4rvasldv-coreutils-9.4" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/spm5vvna0wwkknavwfgxdsbq48r5374a-coreutils-9.4", - "default": true - }, - { - "name": "info", - "path": "/nix/store/mpgbpc0iyn2wy1668b1f2lzw2b967zsh-coreutils-9.4-info" - } - ], "store_path": "/nix/store/spm5vvna0wwkknavwfgxdsbq48r5374a-coreutils-9.4" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/mb488rr560vq1xnl10hinnyfflcrd51n-coreutils-9.4", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/cgw6a9mc6v28dfbxjgprwv9dam57djsd-coreutils-9.4-debug" - }, - { - "name": "info", - "path": "/nix/store/m2zz2awv8a8118axl7qliq6dwpwb7q0v-coreutils-9.4-info" - } - ], "store_path": "/nix/store/mb488rr560vq1xnl10hinnyfflcrd51n-coreutils-9.4" } } @@ -224,43 +88,15 @@ "version": "1.4.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7lwyjdf9bhyihfdr9gm7ajhjbliphv34-envsubst-1.4.2", - "default": true - } - ], "store_path": "/nix/store/7lwyjdf9bhyihfdr9gm7ajhjbliphv34-envsubst-1.4.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/qsly6czilaakclr57zlaxl0y574f6lj3-envsubst-1.4.2", - "default": true - } - ], "store_path": "/nix/store/qsly6czilaakclr57zlaxl0y574f6lj3-envsubst-1.4.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/i5kjf63ns7b1scw1k3jvwlj6m5lpz3mi-envsubst-1.4.2", - "default": true - } - ], "store_path": "/nix/store/i5kjf63ns7b1scw1k3jvwlj6m5lpz3mi-envsubst-1.4.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/vgglbbxi4wa85g3fzb71jxbddkklhpvg-envsubst-1.4.2", - "default": true - } - ], "store_path": "/nix/store/vgglbbxi4wa85g3fzb71jxbddkklhpvg-envsubst-1.4.2" } } @@ -272,75 +108,15 @@ "version": "4.9.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/46ilsgv2hj073d3ghqv209bl95djki8q-findutils-4.9.0", - "default": true - }, - { - "name": "info", - "path": "/nix/store/a5bp80lnmw0cbmfqjxhkz1p5h825ii3p-findutils-4.9.0-info" - }, - { - "name": "locate", - "path": "/nix/store/af9i1zykrns1ha3rhzkpdvyxa1kkhg1z-findutils-4.9.0-locate" - } - ], "store_path": "/nix/store/46ilsgv2hj073d3ghqv209bl95djki8q-findutils-4.9.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ry6g1kym7g3i8813msq7b0gzqbdj1rfk-findutils-4.9.0", - "default": true - }, - { - "name": "info", - "path": "/nix/store/fi8k5nm1279ag30y5ghgzhadcqp00mrn-findutils-4.9.0-info" - }, - { - "name": "locate", - "path": "/nix/store/m17gn49zqfg4z43816p77fzpxlqrlk8d-findutils-4.9.0-locate" - } - ], "store_path": "/nix/store/ry6g1kym7g3i8813msq7b0gzqbdj1rfk-findutils-4.9.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/iqka9ifkjwwz0cf5dz8w7fl9p41p142p-findutils-4.9.0", - "default": true - }, - { - "name": "info", - "path": "/nix/store/r2p9iavm6ypdijwdm96c2jfhl8krs0xx-findutils-4.9.0-info" - }, - { - "name": "locate", - "path": "/nix/store/qwsfnln108rys79d8fnfa3qrajz03h39-findutils-4.9.0-locate" - } - ], "store_path": "/nix/store/iqka9ifkjwwz0cf5dz8w7fl9p41p142p-findutils-4.9.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/rr5pqqck5f6fjkv7agwjyhaljvh27ncn-findutils-4.9.0", - "default": true - }, - { - "name": "info", - "path": "/nix/store/9c6pyndcn1lr2wm210zylp3wv37b04g0-findutils-4.9.0-info" - }, - { - "name": "locate", - "path": "/nix/store/jsyyg8i8rbxj1gaki1szcl66cj93z8xk-findutils-4.9.0-locate" - } - ], "store_path": "/nix/store/rr5pqqck5f6fjkv7agwjyhaljvh27ncn-findutils-4.9.0" } } @@ -352,43 +128,15 @@ "version": "2.45.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ijbvh0hln26a39q5m7iavyvyj83adja9-gh-2.45.0", - "default": true - } - ], "store_path": "/nix/store/ijbvh0hln26a39q5m7iavyvyj83adja9-gh-2.45.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/33v7d9a7x91lzvyr8d76mzb5022glay4-gh-2.45.0", - "default": true - } - ], "store_path": "/nix/store/33v7d9a7x91lzvyr8d76mzb5022glay4-gh-2.45.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/snd8ridf0apgbk7ngyf4waqdk72mr9pm-gh-2.45.0", - "default": true - } - ], "store_path": "/nix/store/snd8ridf0apgbk7ngyf4waqdk72mr9pm-gh-2.45.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1krwa1i8qyxapbp6n02r4niwiqhhnaln-gh-2.45.0", - "default": true - } - ], "store_path": "/nix/store/1krwa1i8qyxapbp6n02r4niwiqhhnaln-gh-2.45.0" } } @@ -400,43 +148,15 @@ "version": "2.17.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/lxq0cx9km60yjwf63pmf1j3rbfr82q7x-ginkgo-2.17.0", - "default": true - } - ], "store_path": "/nix/store/lxq0cx9km60yjwf63pmf1j3rbfr82q7x-ginkgo-2.17.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1bf8v0b9k0pmmrs06h6zw13cxl0pmd9q-ginkgo-2.17.0", - "default": true - } - ], "store_path": "/nix/store/1bf8v0b9k0pmmrs06h6zw13cxl0pmd9q-ginkgo-2.17.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7qyd3jfipsx9gj0wbkms245hkidlfb0f-ginkgo-2.17.0", - "default": true - } - ], "store_path": "/nix/store/7qyd3jfipsx9gj0wbkms245hkidlfb0f-ginkgo-2.17.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/bavqnxdhcvlpmkjvd0hcnhj3dlrrysmc-ginkgo-2.17.0", - "default": true - } - ], "store_path": "/nix/store/bavqnxdhcvlpmkjvd0hcnhj3dlrrysmc-ginkgo-2.17.0" } } @@ -448,67 +168,15 @@ "version": "2.43.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/4zyn11089z9i567c84d3628bq2k56q8r-git-2.43.2", - "default": true - }, - { - "name": "doc", - "path": "/nix/store/0vaafk5p4hh797n28w4nx1c5ykjq1kxc-git-2.43.2-doc" - } - ], "store_path": "/nix/store/4zyn11089z9i567c84d3628bq2k56q8r-git-2.43.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/6dmwwsmj6bp9ss0bsw5j042zjzx5p2kw-git-2.43.2", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/yx6wsnivlrbwajqbf933pj733ypj4bbd-git-2.43.2-debug" - }, - { - "name": "doc", - "path": "/nix/store/bxyy779y05dkvbzvpic3knycd3iyx8m4-git-2.43.2-doc" - } - ], "store_path": "/nix/store/6dmwwsmj6bp9ss0bsw5j042zjzx5p2kw-git-2.43.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ffnl9nk43qffalwvmb0bnhz3j2glkk1h-git-2.43.2", - "default": true - }, - { - "name": "doc", - "path": "/nix/store/8vpr8jl73k5m2cqbz4d16a6i3nw7x82s-git-2.43.2-doc" - } - ], "store_path": "/nix/store/ffnl9nk43qffalwvmb0bnhz3j2glkk1h-git-2.43.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/fmx804pc0bs1966xq5bb67kark2mww9r-git-2.43.2", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/sga5blm5fi6ad5hj4kg5m9m4gxgqmciv-git-2.43.2-debug" - }, - { - "name": "doc", - "path": "/nix/store/z9784jl4061n5bnbwjz2qd93c50r98m9-git-2.43.2-doc" - } - ], "store_path": "/nix/store/fmx804pc0bs1966xq5bb67kark2mww9r-git-2.43.2" } } @@ -520,87 +188,15 @@ "version": "4.4.1", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/b4jbbx01f3n4r97g49jnxw3clf4p1szv-gnumake-4.4.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/maj11ssnlx9lqd3vfmpfh45l6p5bxvv4-gnumake-4.4.1-man", - "default": true - }, - { - "name": "info", - "path": "/nix/store/rp5gi5y0dd2hzww57x7gkya7g2qg6rrq-gnumake-4.4.1-info" - } - ], "store_path": "/nix/store/b4jbbx01f3n4r97g49jnxw3clf4p1szv-gnumake-4.4.1" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/hfyyfn6h7cw2fvdc0jmpfigwi3rp7d2x-gnumake-4.4.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/z20ifgpnah4nnls4ylkij1gmrhg6bv10-gnumake-4.4.1-man", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/m8zg8w7m00hxjwxwcj1apcra1lh58j50-gnumake-4.4.1-debug" - }, - { - "name": "info", - "path": "/nix/store/sk9zc9r371pcpj5hhjck79h8a2i726qv-gnumake-4.4.1-info" - } - ], "store_path": "/nix/store/hfyyfn6h7cw2fvdc0jmpfigwi3rp7d2x-gnumake-4.4.1" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ry772inn49ra4vmns2vg67bjpqv29j0k-gnumake-4.4.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/dbd3dygcpky1s2yls12wzy8rsh0dzjbr-gnumake-4.4.1-man", - "default": true - }, - { - "name": "info", - "path": "/nix/store/4yi8y2v3h62jz3jia5zi60nrxgfbn05w-gnumake-4.4.1-info" - } - ], "store_path": "/nix/store/ry772inn49ra4vmns2vg67bjpqv29j0k-gnumake-4.4.1" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/0pkbh7939p7npr02ayama32pa389m5p7-gnumake-4.4.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/h420v4pzqavirmna1fz0r5cz3nbq65xq-gnumake-4.4.1-man", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/l8523cnr1cn189yzchcq30iml87dr5a4-gnumake-4.4.1-debug" - }, - { - "name": "info", - "path": "/nix/store/bnjzmbm99sgviynsqxhz831cc9gvidnl-gnumake-4.4.1-info" - } - ], "store_path": "/nix/store/0pkbh7939p7npr02ayama32pa389m5p7-gnumake-4.4.1" } } @@ -612,59 +208,15 @@ "version": "4.9", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/zmmrhy50wsyg5k9wrmbpcnjz6swdsk58-gnused-4.9", - "default": true - }, - { - "name": "info", - "path": "/nix/store/bbq8l0cn5rsbf3nmfl4sxkynwzjwzxk4-gnused-4.9-info" - } - ], "store_path": "/nix/store/zmmrhy50wsyg5k9wrmbpcnjz6swdsk58-gnused-4.9" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/jcpl9xd17v9c8aqkdwakhw3mymmagshp-gnused-4.9", - "default": true - }, - { - "name": "info", - "path": "/nix/store/8jz40706yyf04dwbm1nl0mc4z905iq17-gnused-4.9-info" - } - ], "store_path": "/nix/store/jcpl9xd17v9c8aqkdwakhw3mymmagshp-gnused-4.9" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/wjlj4v79x8zxnx5ylfgmiqp36vm28ii6-gnused-4.9", - "default": true - }, - { - "name": "info", - "path": "/nix/store/75dy9xdcnfj9j0z7wd8jrlrgb0n96mb1-gnused-4.9-info" - } - ], "store_path": "/nix/store/wjlj4v79x8zxnx5ylfgmiqp36vm28ii6-gnused-4.9" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/q7kq0naays5251ihghw0ccsz39id7kk5-gnused-4.9", - "default": true - }, - { - "name": "info", - "path": "/nix/store/a81qmwij2v1pjwsq739l482fxkkn4s07-gnused-4.9-info" - } - ], "store_path": "/nix/store/q7kq0naays5251ihghw0ccsz39id7kk5-gnused-4.9" } } @@ -676,43 +228,15 @@ "version": "1.22.1", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/k9srp8ngvblscg68fdpcyqkydh86429k-go-1.22.1", - "default": true - } - ], "store_path": "/nix/store/k9srp8ngvblscg68fdpcyqkydh86429k-go-1.22.1" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/i604lwmgw1s8w3bdvsiz4332rx7fsb87-go-1.22.1", - "default": true - } - ], "store_path": "/nix/store/i604lwmgw1s8w3bdvsiz4332rx7fsb87-go-1.22.1" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/5dyp491ka5hx1g788dvnvadzk9kn92bp-go-1.22.1", - "default": true - } - ], "store_path": "/nix/store/5dyp491ka5hx1g788dvnvadzk9kn92bp-go-1.22.1" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/wkbckbd30nlhq4dxzg64q6y4vm1xx4fk-go-1.22.1", - "default": true - } - ], "store_path": "/nix/store/wkbckbd30nlhq4dxzg64q6y4vm1xx4fk-go-1.22.1" } } @@ -724,43 +248,15 @@ "version": "0.12.14", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/yzkh6mg18q5c2dxlrsdi750imm41div4-gojq-0.12.14", - "default": true - } - ], "store_path": "/nix/store/yzkh6mg18q5c2dxlrsdi750imm41div4-gojq-0.12.14" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/xb0b2ng2m3xdm5iah0cjbqsaqiz87qza-gojq-0.12.14", - "default": true - } - ], "store_path": "/nix/store/xb0b2ng2m3xdm5iah0cjbqsaqiz87qza-gojq-0.12.14" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1y68nsm5nx450lnvc6gr8as7231sfbhz-gojq-0.12.14", - "default": true - } - ], "store_path": "/nix/store/1y68nsm5nx450lnvc6gr8as7231sfbhz-gojq-0.12.14" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1ivsp6qjrkr3d2gzax6w8iai55qagliv-gojq-0.12.14", - "default": true - } - ], "store_path": "/nix/store/1ivsp6qjrkr3d2gzax6w8iai55qagliv-gojq-0.12.14" } } @@ -772,43 +268,15 @@ "version": "0.12.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/225jl3pgxsgivmvggjbijywn0vfc0nd1-golines-0.12.2", - "default": true - } - ], "store_path": "/nix/store/225jl3pgxsgivmvggjbijywn0vfc0nd1-golines-0.12.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nvfxf1ss0f2kq6cj1apa86yn7sxgxyb2-golines-0.12.2", - "default": true - } - ], "store_path": "/nix/store/nvfxf1ss0f2kq6cj1apa86yn7sxgxyb2-golines-0.12.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/jyyd2n5vbwl95a6jkb3xficbj54p8fj4-golines-0.12.2", - "default": true - } - ], "store_path": "/nix/store/jyyd2n5vbwl95a6jkb3xficbj54p8fj4-golines-0.12.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nach7a7wc17kb36pvfvjcbms2p99kfr5-golines-0.12.2", - "default": true - } - ], "store_path": "/nix/store/nach7a7wc17kb36pvfvjcbms2p99kfr5-golines-0.12.2" } } @@ -820,43 +288,15 @@ "version": "1.24.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/8dd7j0fgivrb62jq43pyvmmwz5q9qgas-goreleaser-1.24.0", - "default": true - } - ], "store_path": "/nix/store/8dd7j0fgivrb62jq43pyvmmwz5q9qgas-goreleaser-1.24.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/d0z2c8vwijna7cfdp28r5kj6p5f1abzs-goreleaser-1.24.0", - "default": true - } - ], "store_path": "/nix/store/d0z2c8vwijna7cfdp28r5kj6p5f1abzs-goreleaser-1.24.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/4rnps0ylkz2jaw1qdp29m0pyx62mkv93-goreleaser-1.24.0", - "default": true - } - ], "store_path": "/nix/store/4rnps0ylkz2jaw1qdp29m0pyx62mkv93-goreleaser-1.24.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ys8s2aigrqa8ylsj58wh3qvj61i0lirb-goreleaser-1.24.0", - "default": true - } - ], "store_path": "/nix/store/ys8s2aigrqa8ylsj58wh3qvj61i0lirb-goreleaser-1.24.0" } } @@ -868,43 +308,15 @@ "version": "1.10.1", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/0z0jj1xpcnbgmfymdll7qjggffv6x09f-gotestsum-1.10.1", - "default": true - } - ], "store_path": "/nix/store/0z0jj1xpcnbgmfymdll7qjggffv6x09f-gotestsum-1.10.1" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ii73x40gwzwgm7wp5svkay6k65w722ab-gotestsum-1.10.1", - "default": true - } - ], "store_path": "/nix/store/ii73x40gwzwgm7wp5svkay6k65w722ab-gotestsum-1.10.1" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/glqkgvz7ll2vg7mfm1nlrd49a1dwfpb2-gotestsum-1.10.1", - "default": true - } - ], "store_path": "/nix/store/glqkgvz7ll2vg7mfm1nlrd49a1dwfpb2-gotestsum-1.10.1" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/bydqdbg757r6g5r24bf6s7yb9zdc1q4d-gotestsum-1.10.1", - "default": true - } - ], "store_path": "/nix/store/bydqdbg757r6g5r24bf6s7yb9zdc1q4d-gotestsum-1.10.1" } } @@ -916,43 +328,15 @@ "version": "1.0.4", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/kcqx91mgrw03wgqzzx96xprfjzkkss96-govulncheck-1.0.4", - "default": true - } - ], "store_path": "/nix/store/kcqx91mgrw03wgqzzx96xprfjzkkss96-govulncheck-1.0.4" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/4m6afbm7qm1rq5ql9a0x4xcyzlj5i627-govulncheck-1.0.4", - "default": true - } - ], "store_path": "/nix/store/4m6afbm7qm1rq5ql9a0x4xcyzlj5i627-govulncheck-1.0.4" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nx4dsdypvbvizasrgjhpv82kw0fjlgm4-govulncheck-1.0.4", - "default": true - } - ], "store_path": "/nix/store/nx4dsdypvbvizasrgjhpv82kw0fjlgm4-govulncheck-1.0.4" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/kp3rjfdaxjx0m021nxp0kng5xx26p2j5-govulncheck-1.0.4", - "default": true - } - ], "store_path": "/nix/store/kp3rjfdaxjx0m021nxp0kng5xx26p2j5-govulncheck-1.0.4" } } @@ -964,43 +348,15 @@ "version": "1.11.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/dkky99zsrdkwz9hxprsq5zzha94jsrbj-helm-docs-1.11.2", - "default": true - } - ], "store_path": "/nix/store/dkky99zsrdkwz9hxprsq5zzha94jsrbj-helm-docs-1.11.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/3wamvq5mnmayksx0yy5ch9zb8mq42hd2-helm-docs-1.11.2", - "default": true - } - ], "store_path": "/nix/store/3wamvq5mnmayksx0yy5ch9zb8mq42hd2-helm-docs-1.11.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1pfj5vzrss4xd34hi0b119hpm5ymd9hv-helm-docs-1.11.2", - "default": true - } - ], "store_path": "/nix/store/1pfj5vzrss4xd34hi0b119hpm5ymd9hv-helm-docs-1.11.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/zdzdnhdbqfrm2lczw4h38ziipr4ixs1d-helm-docs-1.11.2", - "default": true - } - ], "store_path": "/nix/store/zdzdnhdbqfrm2lczw4h38ziipr4ixs1d-helm-docs-1.11.2" } } @@ -1012,43 +368,15 @@ "version": "0.124.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/rfkfvwigv0282mw24n3cdym7cyi542jy-hugo-0.124.0", - "default": true - } - ], "store_path": "/nix/store/rfkfvwigv0282mw24n3cdym7cyi542jy-hugo-0.124.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/0rnv4sichypqbprm4nqd0jjc27z5286c-hugo-0.124.0", - "default": true - } - ], "store_path": "/nix/store/0rnv4sichypqbprm4nqd0jjc27z5286c-hugo-0.124.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ip5zhc1rf2li8cmjwffjrj42r7nkkj4a-hugo-0.124.0", - "default": true - } - ], "store_path": "/nix/store/ip5zhc1rf2li8cmjwffjrj42r7nkkj4a-hugo-0.124.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/8syg9xrkp3nbpb1r4b469068kvk8gq2a-hugo-0.124.0", - "default": true - } - ], "store_path": "/nix/store/8syg9xrkp3nbpb1r4b469068kvk8gq2a-hugo-0.124.0" } } @@ -1060,43 +388,15 @@ "version": "0.22.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/87yk9f9zqzl4q6cawsw78l9c872xk3zb-kind-0.22.0", - "default": true - } - ], "store_path": "/nix/store/87yk9f9zqzl4q6cawsw78l9c872xk3zb-kind-0.22.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/hd04jgix5j5dj1grcgh9wwlz636243h6-kind-0.22.0", - "default": true - } - ], "store_path": "/nix/store/hd04jgix5j5dj1grcgh9wwlz636243h6-kind-0.22.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/114mq99ncln9x8h4mxpcjsflbh9qawxs-kind-0.22.0", - "default": true - } - ], "store_path": "/nix/store/114mq99ncln9x8h4mxpcjsflbh9qawxs-kind-0.22.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/d0wmw2i217vak50q2h94wic5ipi11jir-kind-0.22.0", - "default": true - } - ], "store_path": "/nix/store/d0wmw2i217vak50q2h94wic5ipi11jir-kind-0.22.0" } } @@ -1108,43 +408,15 @@ "version": "0.15.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/5d6ri1axxv9cwsac5lg1vz288zk5vf3s-ko-0.15.2", - "default": true - } - ], "store_path": "/nix/store/5d6ri1axxv9cwsac5lg1vz288zk5vf3s-ko-0.15.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/8d62nfbvadkbrqlp20451cm0pgp6zjxg-ko-0.15.2", - "default": true - } - ], "store_path": "/nix/store/8d62nfbvadkbrqlp20451cm0pgp6zjxg-ko-0.15.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/mbikn788gr04c9kkzkdic4w05l8nq7z9-ko-0.15.2", - "default": true - } - ], "store_path": "/nix/store/mbikn788gr04c9kkzkdic4w05l8nq7z9-ko-0.15.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/11h314lbbbj0989drrwc4bi2xrwvxywv-ko-0.15.2", - "default": true - } - ], "store_path": "/nix/store/11h314lbbbj0989drrwc4bi2xrwvxywv-ko-0.15.2" } } @@ -1156,43 +428,15 @@ "version": "3.14.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/yqlqfiab0nglynw6r74inrinbls15620-kubebuilder-3.14.0", - "default": true - } - ], "store_path": "/nix/store/yqlqfiab0nglynw6r74inrinbls15620-kubebuilder-3.14.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/g4nbjgznx6rcrlpg3xn4ynyyr5wvczjp-kubebuilder-3.14.0", - "default": true - } - ], "store_path": "/nix/store/g4nbjgznx6rcrlpg3xn4ynyyr5wvczjp-kubebuilder-3.14.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/xc309p246h3q5xn9gzkh49qcglhfj6ra-kubebuilder-3.14.0", - "default": true - } - ], "store_path": "/nix/store/xc309p246h3q5xn9gzkh49qcglhfj6ra-kubebuilder-3.14.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/3rzgxlj6msggxpy8zdf6ffk197wnmywr-kubebuilder-3.14.0", - "default": true - } - ], "store_path": "/nix/store/3rzgxlj6msggxpy8zdf6ffk197wnmywr-kubebuilder-3.14.0" } } @@ -1204,79 +448,15 @@ "version": "1.29.3", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/qrfxb19jr53r2kcsvga8wvg25v5dwyjh-kubectl-1.29.3", - "default": true - }, - { - "name": "man", - "path": "/nix/store/2m9dv8cvh6f90di79cmld40hmniw3h0i-kubectl-1.29.3-man", - "default": true - }, - { - "name": "convert", - "path": "/nix/store/j9rqnfgamf15lp5ijnp916hp3hl42xz8-kubectl-1.29.3-convert" - } - ], "store_path": "/nix/store/qrfxb19jr53r2kcsvga8wvg25v5dwyjh-kubectl-1.29.3" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/hmdnw2aivd5ywvg8h2d9sjghpp91jqmm-kubectl-1.29.3", - "default": true - }, - { - "name": "man", - "path": "/nix/store/av4rh67mx52js37csgyhl296bnp0z07s-kubectl-1.29.3-man", - "default": true - }, - { - "name": "convert", - "path": "/nix/store/w3pma5nyyxizibg6pbc6m1lqr0rfamn5-kubectl-1.29.3-convert" - } - ], "store_path": "/nix/store/hmdnw2aivd5ywvg8h2d9sjghpp91jqmm-kubectl-1.29.3" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1xvm25fyz9afncqgjxixjsjxfihvqf9k-kubectl-1.29.3", - "default": true - }, - { - "name": "man", - "path": "/nix/store/351mgjyq1jllp6347v71zpk54j7bws0w-kubectl-1.29.3-man", - "default": true - }, - { - "name": "convert", - "path": "/nix/store/4mf6d3vzql08zkg8rwac6y5nsjkcv6d1-kubectl-1.29.3-convert" - } - ], "store_path": "/nix/store/1xvm25fyz9afncqgjxixjsjxfihvqf9k-kubectl-1.29.3" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/xha7i9pddiz31bm9cr33njwnmzdpd3rf-kubectl-1.29.3", - "default": true - }, - { - "name": "man", - "path": "/nix/store/7alsjj9dc5j2xj28v6c0369wa7v1qgg0-kubectl-1.29.3-man", - "default": true - }, - { - "name": "convert", - "path": "/nix/store/gn5sj2jjwy2fvikgjkc76h8lagyszys0-kubectl-1.29.3-convert" - } - ], "store_path": "/nix/store/xha7i9pddiz31bm9cr33njwnmzdpd3rf-kubectl-1.29.3" } } @@ -1288,43 +468,15 @@ "version": "0.14.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/jblk86f5bi2dwg2w8g42xl9mpw1yrbi4-controller-tools-0.14.0", - "default": true - } - ], "store_path": "/nix/store/jblk86f5bi2dwg2w8g42xl9mpw1yrbi4-controller-tools-0.14.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/sq48wn8yyqkya8as690h61d1dlxwlkbi-controller-tools-0.14.0", - "default": true - } - ], "store_path": "/nix/store/sq48wn8yyqkya8as690h61d1dlxwlkbi-controller-tools-0.14.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nm2vx0f6ajmqpbi2c6z8wani5f1fdqb4-controller-tools-0.14.0", - "default": true - } - ], "store_path": "/nix/store/nm2vx0f6ajmqpbi2c6z8wani5f1fdqb4-controller-tools-0.14.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/f8h9pj08ksm49v980yb0slzrbpqqc98r-controller-tools-0.14.0", - "default": true - } - ], "store_path": "/nix/store/f8h9pj08ksm49v980yb0slzrbpqqc98r-controller-tools-0.14.0" } } @@ -1336,43 +488,15 @@ "version": "3.14.3", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/zy9621qww3klbwkffz2pp9kh3p0hdfs3-kubernetes-helm-3.14.3", - "default": true - } - ], "store_path": "/nix/store/zy9621qww3klbwkffz2pp9kh3p0hdfs3-kubernetes-helm-3.14.3" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ki8zl3ccm68ma3kyjcnzdgfh4wslr2l6-kubernetes-helm-3.14.3", - "default": true - } - ], "store_path": "/nix/store/ki8zl3ccm68ma3kyjcnzdgfh4wslr2l6-kubernetes-helm-3.14.3" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/l6d6j4q4af0dhmjha0c7d010f3hj16b6-kubernetes-helm-3.14.3", - "default": true - } - ], "store_path": "/nix/store/l6d6j4q4af0dhmjha0c7d010f3hj16b6-kubernetes-helm-3.14.3" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/dnnm27a9s71pkgb7wjrdiw8gf9f7a003-kubernetes-helm-3.14.3", - "default": true - } - ], "store_path": "/nix/store/dnnm27a9s71pkgb7wjrdiw8gf9f7a003-kubernetes-helm-3.14.3" } } @@ -1384,43 +508,15 @@ "version": "5.3.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/452i1p4zhmbp0lij399pmlagvvhbz8qa-kustomize-5.3.0", - "default": true - } - ], "store_path": "/nix/store/452i1p4zhmbp0lij399pmlagvvhbz8qa-kustomize-5.3.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/db73m9xy7q4al1ypx3i4nbqw9wi25fpc-kustomize-5.3.0", - "default": true - } - ], "store_path": "/nix/store/db73m9xy7q4al1ypx3i4nbqw9wi25fpc-kustomize-5.3.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/r4kcp37cwrfskcdlk8r0hmwb5y6gh8lc-kustomize-5.3.0", - "default": true - } - ], "store_path": "/nix/store/r4kcp37cwrfskcdlk8r0hmwb5y6gh8lc-kustomize-5.3.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/y6q6p3fv79gahrkp6gz8q9lks4h0zgh8-kustomize-5.3.0", - "default": true - } - ], "store_path": "/nix/store/y6q6p3fv79gahrkp6gz8q9lks4h0zgh8-kustomize-5.3.0" } } @@ -1432,59 +528,15 @@ "version": "3.6.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nwrn3g5v9bsrnd88v84q4q9japllx0jb-pre-commit-3.6.2", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/y3r47sj7njflny4l0x0a96bk24hfh7s4-pre-commit-3.6.2-dist" - } - ], "store_path": "/nix/store/nwrn3g5v9bsrnd88v84q4q9japllx0jb-pre-commit-3.6.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/61bnh53x2c6laq7vd7ssr23wm85zifs6-pre-commit-3.6.2", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/0rdbgni8iyzz32d24adg3rykkp4pc85m-pre-commit-3.6.2-dist" - } - ], "store_path": "/nix/store/61bnh53x2c6laq7vd7ssr23wm85zifs6-pre-commit-3.6.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/dpimv11qs1l3yyzb5nj94p2inpn35yj7-pre-commit-3.6.2", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/y1sav86i99mz03dp988lf1yxgcsdbff1-pre-commit-3.6.2-dist" - } - ], "store_path": "/nix/store/dpimv11qs1l3yyzb5nj94p2inpn35yj7-pre-commit-3.6.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1n78gswil3nq9fdrff4rb2li4y45y5w4-pre-commit-3.6.2", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/ljfxnyrk6l9wpq2n5x79asgcw4pj7ay7-pre-commit-3.6.2-dist" - } - ], "store_path": "/nix/store/1n78gswil3nq9fdrff4rb2li4y45y5w4-pre-commit-3.6.2" } } @@ -1496,43 +548,15 @@ "version": "3.2.7", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/0kmy2vr9hznx2g22bvpavlcyrgjilx4z-rsync-3.2.7", - "default": true - } - ], "store_path": "/nix/store/0kmy2vr9hznx2g22bvpavlcyrgjilx4z-rsync-3.2.7" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/554m9gj7cd3qc7d9yyhvrw6l5gxwsf84-rsync-3.2.7", - "default": true - } - ], "store_path": "/nix/store/554m9gj7cd3qc7d9yyhvrw6l5gxwsf84-rsync-3.2.7" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/3f6wicmglmb803anbavd1gagbq16gqpb-rsync-3.2.7", - "default": true - } - ], "store_path": "/nix/store/3f6wicmglmb803anbavd1gagbq16gqpb-rsync-3.2.7" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/dc65w7qlnzqa9wfbyvyq5d8zv42v8zds-rsync-3.2.7", - "default": true - } - ], "store_path": "/nix/store/dc65w7qlnzqa9wfbyvyq5d8zv42v8zds-rsync-3.2.7" } } @@ -1544,43 +568,15 @@ "version": "3.8.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/6sicjz0jhnsazn34g9hlsjb7a80zm9i5-shfmt-3.8.0", - "default": true - } - ], "store_path": "/nix/store/6sicjz0jhnsazn34g9hlsjb7a80zm9i5-shfmt-3.8.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/l2l4hxcqypaqbp7ia8ig05345yx0sq5m-shfmt-3.8.0", - "default": true - } - ], "store_path": "/nix/store/l2l4hxcqypaqbp7ia8ig05345yx0sq5m-shfmt-3.8.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/6vh95c1bvnxr08ccy3p3gi02gxam5bns-shfmt-3.8.0", - "default": true - } - ], "store_path": "/nix/store/6vh95c1bvnxr08ccy3p3gi02gxam5bns-shfmt-3.8.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/sfdz20anszw4qfgwk71mmmfm0dzp94fv-shfmt-3.8.0", - "default": true - } - ], "store_path": "/nix/store/sfdz20anszw4qfgwk71mmmfm0dzp94fv-shfmt-3.8.0" } } @@ -1592,59 +588,15 @@ "version": "4.0.4", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/78j6khza1gr5zmbcldssr8zm8xxnzwps-python3.11-yamale-4.0.4", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/jfglw0libz2z4a97vnb8lsy1lqyrckvq-python3.11-yamale-4.0.4-dist" - } - ], "store_path": "/nix/store/78j6khza1gr5zmbcldssr8zm8xxnzwps-python3.11-yamale-4.0.4" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/9wdk342n50063l5y9idh4pl9gxvwdfyb-python3.11-yamale-4.0.4", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/4l5axk5c1878qmdpsgyc6kaf26gvvgms-python3.11-yamale-4.0.4-dist" - } - ], "store_path": "/nix/store/9wdk342n50063l5y9idh4pl9gxvwdfyb-python3.11-yamale-4.0.4" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/zy5pwvyhdyrkvgwwagf950pj0rvcdx68-python3.11-yamale-4.0.4", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/77a332bqd0j6xydhsny3xlm6sd5n5g7n-python3.11-yamale-4.0.4-dist" - } - ], "store_path": "/nix/store/zy5pwvyhdyrkvgwwagf950pj0rvcdx68-python3.11-yamale-4.0.4" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/9pzsm66srma437qmn3inib0r40jjawkm-python3.11-yamale-4.0.4", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/yf79fdb3nkb3ihklp9na61c74pnyh9h0-python3.11-yamale-4.0.4-dist" - } - ], "store_path": "/nix/store/9pzsm66srma437qmn3inib0r40jjawkm-python3.11-yamale-4.0.4" } } @@ -1656,59 +608,15 @@ "version": "1.35.1", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/shw3d5hqv1kjsxgs6favbb6icdf5zspz-python3.11-yamllint-1.35.1", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/i9fmwxqhi001mjn1vmmvn2a33fsddlz7-python3.11-yamllint-1.35.1-dist" - } - ], "store_path": "/nix/store/shw3d5hqv1kjsxgs6favbb6icdf5zspz-python3.11-yamllint-1.35.1" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/qhciblsdwcx382ybhv4qy3pv321rprpn-python3.11-yamllint-1.35.1", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/3zx9gj6mma9g28vg9l6778h1la50s5zk-python3.11-yamllint-1.35.1-dist" - } - ], "store_path": "/nix/store/qhciblsdwcx382ybhv4qy3pv321rprpn-python3.11-yamllint-1.35.1" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/0qjkix7ixdmh056zg2w98yqfx31ip722-python3.11-yamllint-1.35.1", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/sbgn6iav52fp759y47h4j9kaxzmbqgkh-python3.11-yamllint-1.35.1-dist" - } - ], "store_path": "/nix/store/0qjkix7ixdmh056zg2w98yqfx31ip722-python3.11-yamllint-1.35.1" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/04jdxm8pyzbsg9vjgs0y1piglnn6bzny-python3.11-yamllint-1.35.1", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/1grzppn23d79mkj9vyf9rs1f4w0xvyd6-python3.11-yamllint-1.35.1-dist" - } - ], "store_path": "/nix/store/04jdxm8pyzbsg9vjgs0y1piglnn6bzny-python3.11-yamllint-1.35.1" } } diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 9d453da93..36688ac95 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -333,27 +333,27 @@ spec: machineDetails: bootType: legacy cluster: - name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} type: name image: - name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi subnet: - - name: $${NUTANIX_SUBNET_NAME} + - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 nutanix: controlPlaneEndpoint: - host: $${CONTROL_PLANE_ENDPOINT_IP} - port: $${CONTROL_PLANE_ENDPOINT_PORT} + host: ${CONTROL_PLANE_ENDPOINT_IP} + port: ${CONTROL_PLANE_ENDPOINT_PORT} prismCentralEndpoint: - additionalTrustBundle: $${CLUSTER_NAME}-pc-trusted-ca-bundle - credentialSecret: $${CLUSTER_NAME}-pc-creds - host: $${NUTANIX_ENDPOINT} - insecure: $${NUTANIX_INSECURE} + additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle + credentialSecret: ${CLUSTER_NAME}-pc-creds + host: ${NUTANIX_ENDPOINT} + insecure: ${NUTANIX_INSECURE} port: 9440 - name: workerConfig value: @@ -361,14 +361,14 @@ spec: machineDetails: bootType: legacy cluster: - name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} type: name image: - name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi subnet: - - name: $${NUTANIX_SUBNET_NAME} + - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi vcpuSockets: 2 diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index cc1aa98f2..19cb1961a 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -333,27 +333,27 @@ spec: machineDetails: bootType: legacy cluster: - name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} type: name image: - name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi subnet: - - name: $${NUTANIX_SUBNET_NAME} + - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 nutanix: controlPlaneEndpoint: - host: $${CONTROL_PLANE_ENDPOINT_IP} - port: $${CONTROL_PLANE_ENDPOINT_PORT} + host: ${CONTROL_PLANE_ENDPOINT_IP} + port: ${CONTROL_PLANE_ENDPOINT_PORT} prismCentralEndpoint: - additionalTrustBundle: $${CLUSTER_NAME}-pc-trusted-ca-bundle - credentialSecret: $${CLUSTER_NAME}-pc-creds - host: $${NUTANIX_ENDPOINT} - insecure: $${NUTANIX_INSECURE} + additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle + credentialSecret: ${CLUSTER_NAME}-pc-creds + host: ${NUTANIX_ENDPOINT} + insecure: ${NUTANIX_INSECURE} port: 9440 - name: workerConfig value: @@ -361,14 +361,14 @@ spec: machineDetails: bootType: legacy cluster: - name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} type: name image: - name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi subnet: - - name: $${NUTANIX_SUBNET_NAME} + - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi vcpuSockets: 2 diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index b0f59d3d3..888cb9e78 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -333,27 +333,27 @@ spec: machineDetails: bootType: legacy cluster: - name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} type: name image: - name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi subnet: - - name: $${NUTANIX_SUBNET_NAME} + - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 nutanix: controlPlaneEndpoint: - host: $${CONTROL_PLANE_ENDPOINT_IP} - port: $${CONTROL_PLANE_ENDPOINT_PORT} + host: ${CONTROL_PLANE_ENDPOINT_IP} + port: ${CONTROL_PLANE_ENDPOINT_PORT} prismCentralEndpoint: - additionalTrustBundle: $${CLUSTER_NAME}-pc-trusted-ca-bundle - credentialSecret: $${CLUSTER_NAME}-pc-creds - host: $${NUTANIX_ENDPOINT} - insecure: $${NUTANIX_INSECURE} + additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle + credentialSecret: ${CLUSTER_NAME}-pc-creds + host: ${NUTANIX_ENDPOINT} + insecure: ${NUTANIX_INSECURE} port: 9440 - name: workerConfig value: @@ -361,14 +361,14 @@ spec: machineDetails: bootType: legacy cluster: - name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} type: name image: - name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi subnet: - - name: $${NUTANIX_SUBNET_NAME} + - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi vcpuSockets: 2 diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 59a5b19be..42ab33cb0 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -333,27 +333,27 @@ spec: machineDetails: bootType: legacy cluster: - name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} type: name image: - name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi subnet: - - name: $${NUTANIX_SUBNET_NAME} + - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi vcpuSockets: 2 vcpusPerSocket: 1 nutanix: controlPlaneEndpoint: - host: $${CONTROL_PLANE_ENDPOINT_IP} - port: $${CONTROL_PLANE_ENDPOINT_PORT} + host: ${CONTROL_PLANE_ENDPOINT_IP} + port: ${CONTROL_PLANE_ENDPOINT_PORT} prismCentralEndpoint: - additionalTrustBundle: $${CLUSTER_NAME}-pc-trusted-ca-bundle - credentialSecret: $${CLUSTER_NAME}-pc-creds - host: $${NUTANIX_ENDPOINT} - insecure: $${NUTANIX_INSECURE} + additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle + credentialSecret: ${CLUSTER_NAME}-pc-creds + host: ${NUTANIX_ENDPOINT} + insecure: ${NUTANIX_INSECURE} port: 9440 - name: workerConfig value: @@ -361,14 +361,14 @@ spec: machineDetails: bootType: legacy cluster: - name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} type: name image: - name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi subnet: - - name: $${NUTANIX_SUBNET_NAME} + - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi vcpuSockets: 2 diff --git a/hack/examples/patches/nutanix/initialize-variables.yaml b/hack/examples/patches/nutanix/initialize-variables.yaml index 23a28aac8..1aa180e34 100644 --- a/hack/examples/patches/nutanix/initialize-variables.yaml +++ b/hack/examples/patches/nutanix/initialize-variables.yaml @@ -17,26 +17,26 @@ strategy: nutanix: controlPlaneEndpoint: - host: $${CONTROL_PLANE_ENDPOINT_IP} - port: $${CONTROL_PLANE_ENDPOINT_PORT} + host: ${CONTROL_PLANE_ENDPOINT_IP} + port: ${CONTROL_PLANE_ENDPOINT_PORT} prismCentralEndpoint: - additionalTrustBundle: $${CLUSTER_NAME}-pc-trusted-ca-bundle - host: $${NUTANIX_ENDPOINT} - insecure: $${NUTANIX_INSECURE} + additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle + host: ${NUTANIX_ENDPOINT} + insecure: ${NUTANIX_INSECURE} port: 9440 - credentialSecret: $${CLUSTER_NAME}-pc-creds + credentialSecret: ${CLUSTER_NAME}-pc-creds controlPlane: nutanix: machineDetails: bootType: legacy cluster: - name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} type: name image: - name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name subnet: - - name: $${NUTANIX_SUBNET_NAME} + - name: ${NUTANIX_SUBNET_NAME} type: name memorySize: 4Gi systemDiskSize: 40Gi @@ -48,14 +48,14 @@ machineDetails: bootType: legacy cluster: - name: $${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} type: name image: - name: $${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi subnet: - - name: $${NUTANIX_SUBNET_NAME} + - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi vcpuSockets: 2 From e20cf321601b990d88e514f9a74b7256e6d0a28c Mon Sep 17 00:00:00 2001 From: Deepak Muley Date: Thu, 21 Mar 2024 13:47:08 -0700 Subject: [PATCH 06/87] Update hack/examples/sync.sh Co-authored-by: Faiq Signed-off-by: Deepak Muley --- hack/examples/sync.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/examples/sync.sh b/hack/examples/sync.sh index b656cabc9..e18f6fbf7 100755 --- a/hack/examples/sync.sh +++ b/hack/examples/sync.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash -x +#!/usr/bin/env bash # Copyright 2023 D2iQ, Inc. All rights reserved. # SPDX-License-Identifier: Apache-2.0 From 601c6a8dd4e43acf338f93f3fe14994c9ea312ba Mon Sep 17 00:00:00 2001 From: Deepak Muley Date: Fri, 22 Mar 2024 12:45:20 -0700 Subject: [PATCH 07/87] added new line to fix precommit lint --- hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl | 2 +- .../examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index d4454cc70..b75eb33cf 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -27,4 +27,4 @@ patches: path: ../../../patches/cluster-autoscaler.yaml - target: kind: Cluster - path: ../../../patches/nutanix/initialize-variables.yaml \ No newline at end of file + path: ../../../patches/nutanix/initialize-variables.yaml diff --git a/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl index 77a0718f4..d3e1ec343 100644 --- a/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl @@ -28,4 +28,4 @@ patches: - op: "remove" path: "/spec/patches" - op: "remove" - path: "/spec/variables" \ No newline at end of file + path: "/spec/variables" From db87f1886568394bacebff5e85cfca8235f24198 Mon Sep 17 00:00:00 2001 From: Deepak Muley Date: Fri, 22 Mar 2024 13:04:14 -0700 Subject: [PATCH 08/87] fix: removed trailing whitespaces --- .../examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl | 2 +- hack/examples/sync.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl index d3e1ec343..24e9683ff 100644 --- a/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl @@ -13,7 +13,7 @@ configurations: sortOptions: order: fifo -namePrefix: +namePrefix: labels: - includeSelectors: false diff --git a/hack/examples/sync.sh b/hack/examples/sync.sh index e18f6fbf7..a03967595 100755 --- a/hack/examples/sync.sh +++ b/hack/examples/sync.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env bash # Copyright 2023 D2iQ, Inc. All rights reserved. # SPDX-License-Identifier: Apache-2.0 From 7e2b6e6052a92f11811de233bddc2034e1a3f356 Mon Sep 17 00:00:00 2001 From: Deepak Muley Date: Tue, 26 Mar 2024 08:55:44 -0700 Subject: [PATCH 09/87] reverted devbox.lock changes --- devbox.lock | 1092 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1092 insertions(+) diff --git a/devbox.lock b/devbox.lock index 59ee0c2bb..73b569425 100644 --- a/devbox.lock +++ b/devbox.lock @@ -8,15 +8,43 @@ "version": "1.6.27", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/nnhjp60w14pdy1hjgxn9dfsg4nbfs93v-actionlint-1.6.27", + "default": true + } + ], "store_path": "/nix/store/nnhjp60w14pdy1hjgxn9dfsg4nbfs93v-actionlint-1.6.27" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/p8rc44x83sld3wk1m4y27za9n1mjyk48-actionlint-1.6.27", + "default": true + } + ], "store_path": "/nix/store/p8rc44x83sld3wk1m4y27za9n1mjyk48-actionlint-1.6.27" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/7v1lh7c3pwlax5fy7pw233czn4hs89hl-actionlint-1.6.27", + "default": true + } + ], "store_path": "/nix/store/7v1lh7c3pwlax5fy7pw233czn4hs89hl-actionlint-1.6.27" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/56xxvs3yijdmhhxbfvps38nz95xdxgyl-actionlint-1.6.27", + "default": true + } + ], "store_path": "/nix/store/56xxvs3yijdmhhxbfvps38nz95xdxgyl-actionlint-1.6.27" } } @@ -28,15 +56,43 @@ "version": "3.10.1", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/5lygcps2ly736k0dvk2w4mx6yy8dzz6s-chart-testing-3.10.1", + "default": true + } + ], "store_path": "/nix/store/5lygcps2ly736k0dvk2w4mx6yy8dzz6s-chart-testing-3.10.1" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/103km469ldwrzs525m57bj409vxjlniw-chart-testing-3.10.1", + "default": true + } + ], "store_path": "/nix/store/103km469ldwrzs525m57bj409vxjlniw-chart-testing-3.10.1" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/c4qgh783pvhzqpv7skimzfs75pklbz4f-chart-testing-3.10.1", + "default": true + } + ], "store_path": "/nix/store/c4qgh783pvhzqpv7skimzfs75pklbz4f-chart-testing-3.10.1" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/wzscgl31rzxws05y7vxkl0f65fsiydmm-chart-testing-3.10.1", + "default": true + } + ], "store_path": "/nix/store/wzscgl31rzxws05y7vxkl0f65fsiydmm-chart-testing-3.10.1" } } @@ -48,15 +104,43 @@ "version": "1.6.3", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/6hsi8bj8ddbrv29jff467q1rqcfgs964-clusterctl-1.6.3", + "default": true + } + ], "store_path": "/nix/store/6hsi8bj8ddbrv29jff467q1rqcfgs964-clusterctl-1.6.3" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/jysji089cqrygcwl2ryvbb0sa3cjj8vv-clusterctl-1.6.3", + "default": true + } + ], "store_path": "/nix/store/jysji089cqrygcwl2ryvbb0sa3cjj8vv-clusterctl-1.6.3" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/gbch3dp061am97j79b56pp07121j781k-clusterctl-1.6.3", + "default": true + } + ], "store_path": "/nix/store/gbch3dp061am97j79b56pp07121j781k-clusterctl-1.6.3" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/1xy66gcyxaqjhb5h15slyxzw64d920c6-clusterctl-1.6.3", + "default": true + } + ], "store_path": "/nix/store/1xy66gcyxaqjhb5h15slyxzw64d920c6-clusterctl-1.6.3" } } @@ -68,15 +152,67 @@ "version": "9.4", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/vinxz6lkrilb72dkzr3ny02nnvql6z50-coreutils-9.4", + "default": true + }, + { + "name": "info", + "path": "/nix/store/mgvngj0x370glcix9wfaripy3bx5j3s0-coreutils-9.4-info" + } + ], "store_path": "/nix/store/vinxz6lkrilb72dkzr3ny02nnvql6z50-coreutils-9.4" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/77fyfwmz29cz9j5x6yw2wrlm4rvasldv-coreutils-9.4", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/fkfnrbg62vbsdagml1c9vld3wpk3079n-coreutils-9.4-debug" + }, + { + "name": "info", + "path": "/nix/store/x14ppijm82bac50bgf2varjvdm0mr28f-coreutils-9.4-info" + } + ], "store_path": "/nix/store/77fyfwmz29cz9j5x6yw2wrlm4rvasldv-coreutils-9.4" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/spm5vvna0wwkknavwfgxdsbq48r5374a-coreutils-9.4", + "default": true + }, + { + "name": "info", + "path": "/nix/store/mpgbpc0iyn2wy1668b1f2lzw2b967zsh-coreutils-9.4-info" + } + ], "store_path": "/nix/store/spm5vvna0wwkknavwfgxdsbq48r5374a-coreutils-9.4" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/mb488rr560vq1xnl10hinnyfflcrd51n-coreutils-9.4", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/cgw6a9mc6v28dfbxjgprwv9dam57djsd-coreutils-9.4-debug" + }, + { + "name": "info", + "path": "/nix/store/m2zz2awv8a8118axl7qliq6dwpwb7q0v-coreutils-9.4-info" + } + ], "store_path": "/nix/store/mb488rr560vq1xnl10hinnyfflcrd51n-coreutils-9.4" } } @@ -88,15 +224,43 @@ "version": "1.4.2", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/7lwyjdf9bhyihfdr9gm7ajhjbliphv34-envsubst-1.4.2", + "default": true + } + ], "store_path": "/nix/store/7lwyjdf9bhyihfdr9gm7ajhjbliphv34-envsubst-1.4.2" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/qsly6czilaakclr57zlaxl0y574f6lj3-envsubst-1.4.2", + "default": true + } + ], "store_path": "/nix/store/qsly6czilaakclr57zlaxl0y574f6lj3-envsubst-1.4.2" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/i5kjf63ns7b1scw1k3jvwlj6m5lpz3mi-envsubst-1.4.2", + "default": true + } + ], "store_path": "/nix/store/i5kjf63ns7b1scw1k3jvwlj6m5lpz3mi-envsubst-1.4.2" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/vgglbbxi4wa85g3fzb71jxbddkklhpvg-envsubst-1.4.2", + "default": true + } + ], "store_path": "/nix/store/vgglbbxi4wa85g3fzb71jxbddkklhpvg-envsubst-1.4.2" } } @@ -108,15 +272,75 @@ "version": "4.9.0", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/46ilsgv2hj073d3ghqv209bl95djki8q-findutils-4.9.0", + "default": true + }, + { + "name": "info", + "path": "/nix/store/a5bp80lnmw0cbmfqjxhkz1p5h825ii3p-findutils-4.9.0-info" + }, + { + "name": "locate", + "path": "/nix/store/af9i1zykrns1ha3rhzkpdvyxa1kkhg1z-findutils-4.9.0-locate" + } + ], "store_path": "/nix/store/46ilsgv2hj073d3ghqv209bl95djki8q-findutils-4.9.0" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ry6g1kym7g3i8813msq7b0gzqbdj1rfk-findutils-4.9.0", + "default": true + }, + { + "name": "info", + "path": "/nix/store/fi8k5nm1279ag30y5ghgzhadcqp00mrn-findutils-4.9.0-info" + }, + { + "name": "locate", + "path": "/nix/store/m17gn49zqfg4z43816p77fzpxlqrlk8d-findutils-4.9.0-locate" + } + ], "store_path": "/nix/store/ry6g1kym7g3i8813msq7b0gzqbdj1rfk-findutils-4.9.0" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/iqka9ifkjwwz0cf5dz8w7fl9p41p142p-findutils-4.9.0", + "default": true + }, + { + "name": "info", + "path": "/nix/store/r2p9iavm6ypdijwdm96c2jfhl8krs0xx-findutils-4.9.0-info" + }, + { + "name": "locate", + "path": "/nix/store/qwsfnln108rys79d8fnfa3qrajz03h39-findutils-4.9.0-locate" + } + ], "store_path": "/nix/store/iqka9ifkjwwz0cf5dz8w7fl9p41p142p-findutils-4.9.0" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/rr5pqqck5f6fjkv7agwjyhaljvh27ncn-findutils-4.9.0", + "default": true + }, + { + "name": "info", + "path": "/nix/store/9c6pyndcn1lr2wm210zylp3wv37b04g0-findutils-4.9.0-info" + }, + { + "name": "locate", + "path": "/nix/store/jsyyg8i8rbxj1gaki1szcl66cj93z8xk-findutils-4.9.0-locate" + } + ], "store_path": "/nix/store/rr5pqqck5f6fjkv7agwjyhaljvh27ncn-findutils-4.9.0" } } @@ -128,15 +352,43 @@ "version": "2.45.0", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ijbvh0hln26a39q5m7iavyvyj83adja9-gh-2.45.0", + "default": true + } + ], "store_path": "/nix/store/ijbvh0hln26a39q5m7iavyvyj83adja9-gh-2.45.0" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/33v7d9a7x91lzvyr8d76mzb5022glay4-gh-2.45.0", + "default": true + } + ], "store_path": "/nix/store/33v7d9a7x91lzvyr8d76mzb5022glay4-gh-2.45.0" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/snd8ridf0apgbk7ngyf4waqdk72mr9pm-gh-2.45.0", + "default": true + } + ], "store_path": "/nix/store/snd8ridf0apgbk7ngyf4waqdk72mr9pm-gh-2.45.0" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/1krwa1i8qyxapbp6n02r4niwiqhhnaln-gh-2.45.0", + "default": true + } + ], "store_path": "/nix/store/1krwa1i8qyxapbp6n02r4niwiqhhnaln-gh-2.45.0" } } @@ -148,15 +400,43 @@ "version": "2.17.0", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/lxq0cx9km60yjwf63pmf1j3rbfr82q7x-ginkgo-2.17.0", + "default": true + } + ], "store_path": "/nix/store/lxq0cx9km60yjwf63pmf1j3rbfr82q7x-ginkgo-2.17.0" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/1bf8v0b9k0pmmrs06h6zw13cxl0pmd9q-ginkgo-2.17.0", + "default": true + } + ], "store_path": "/nix/store/1bf8v0b9k0pmmrs06h6zw13cxl0pmd9q-ginkgo-2.17.0" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/7qyd3jfipsx9gj0wbkms245hkidlfb0f-ginkgo-2.17.0", + "default": true + } + ], "store_path": "/nix/store/7qyd3jfipsx9gj0wbkms245hkidlfb0f-ginkgo-2.17.0" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/bavqnxdhcvlpmkjvd0hcnhj3dlrrysmc-ginkgo-2.17.0", + "default": true + } + ], "store_path": "/nix/store/bavqnxdhcvlpmkjvd0hcnhj3dlrrysmc-ginkgo-2.17.0" } } @@ -168,15 +448,67 @@ "version": "2.43.2", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/4zyn11089z9i567c84d3628bq2k56q8r-git-2.43.2", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/0vaafk5p4hh797n28w4nx1c5ykjq1kxc-git-2.43.2-doc" + } + ], "store_path": "/nix/store/4zyn11089z9i567c84d3628bq2k56q8r-git-2.43.2" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/6dmwwsmj6bp9ss0bsw5j042zjzx5p2kw-git-2.43.2", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/yx6wsnivlrbwajqbf933pj733ypj4bbd-git-2.43.2-debug" + }, + { + "name": "doc", + "path": "/nix/store/bxyy779y05dkvbzvpic3knycd3iyx8m4-git-2.43.2-doc" + } + ], "store_path": "/nix/store/6dmwwsmj6bp9ss0bsw5j042zjzx5p2kw-git-2.43.2" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ffnl9nk43qffalwvmb0bnhz3j2glkk1h-git-2.43.2", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/8vpr8jl73k5m2cqbz4d16a6i3nw7x82s-git-2.43.2-doc" + } + ], "store_path": "/nix/store/ffnl9nk43qffalwvmb0bnhz3j2glkk1h-git-2.43.2" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/fmx804pc0bs1966xq5bb67kark2mww9r-git-2.43.2", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/sga5blm5fi6ad5hj4kg5m9m4gxgqmciv-git-2.43.2-debug" + }, + { + "name": "doc", + "path": "/nix/store/z9784jl4061n5bnbwjz2qd93c50r98m9-git-2.43.2-doc" + } + ], "store_path": "/nix/store/fmx804pc0bs1966xq5bb67kark2mww9r-git-2.43.2" } } @@ -188,15 +520,87 @@ "version": "4.4.1", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/b4jbbx01f3n4r97g49jnxw3clf4p1szv-gnumake-4.4.1", + "default": true + }, + { + "name": "man", + "path": "/nix/store/maj11ssnlx9lqd3vfmpfh45l6p5bxvv4-gnumake-4.4.1-man", + "default": true + }, + { + "name": "info", + "path": "/nix/store/rp5gi5y0dd2hzww57x7gkya7g2qg6rrq-gnumake-4.4.1-info" + } + ], "store_path": "/nix/store/b4jbbx01f3n4r97g49jnxw3clf4p1szv-gnumake-4.4.1" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/hfyyfn6h7cw2fvdc0jmpfigwi3rp7d2x-gnumake-4.4.1", + "default": true + }, + { + "name": "man", + "path": "/nix/store/z20ifgpnah4nnls4ylkij1gmrhg6bv10-gnumake-4.4.1-man", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/m8zg8w7m00hxjwxwcj1apcra1lh58j50-gnumake-4.4.1-debug" + }, + { + "name": "info", + "path": "/nix/store/sk9zc9r371pcpj5hhjck79h8a2i726qv-gnumake-4.4.1-info" + } + ], "store_path": "/nix/store/hfyyfn6h7cw2fvdc0jmpfigwi3rp7d2x-gnumake-4.4.1" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ry772inn49ra4vmns2vg67bjpqv29j0k-gnumake-4.4.1", + "default": true + }, + { + "name": "man", + "path": "/nix/store/dbd3dygcpky1s2yls12wzy8rsh0dzjbr-gnumake-4.4.1-man", + "default": true + }, + { + "name": "info", + "path": "/nix/store/4yi8y2v3h62jz3jia5zi60nrxgfbn05w-gnumake-4.4.1-info" + } + ], "store_path": "/nix/store/ry772inn49ra4vmns2vg67bjpqv29j0k-gnumake-4.4.1" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/0pkbh7939p7npr02ayama32pa389m5p7-gnumake-4.4.1", + "default": true + }, + { + "name": "man", + "path": "/nix/store/h420v4pzqavirmna1fz0r5cz3nbq65xq-gnumake-4.4.1-man", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/l8523cnr1cn189yzchcq30iml87dr5a4-gnumake-4.4.1-debug" + }, + { + "name": "info", + "path": "/nix/store/bnjzmbm99sgviynsqxhz831cc9gvidnl-gnumake-4.4.1-info" + } + ], "store_path": "/nix/store/0pkbh7939p7npr02ayama32pa389m5p7-gnumake-4.4.1" } } @@ -208,15 +612,59 @@ "version": "4.9", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/zmmrhy50wsyg5k9wrmbpcnjz6swdsk58-gnused-4.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/bbq8l0cn5rsbf3nmfl4sxkynwzjwzxk4-gnused-4.9-info" + } + ], "store_path": "/nix/store/zmmrhy50wsyg5k9wrmbpcnjz6swdsk58-gnused-4.9" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/jcpl9xd17v9c8aqkdwakhw3mymmagshp-gnused-4.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/8jz40706yyf04dwbm1nl0mc4z905iq17-gnused-4.9-info" + } + ], "store_path": "/nix/store/jcpl9xd17v9c8aqkdwakhw3mymmagshp-gnused-4.9" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/wjlj4v79x8zxnx5ylfgmiqp36vm28ii6-gnused-4.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/75dy9xdcnfj9j0z7wd8jrlrgb0n96mb1-gnused-4.9-info" + } + ], "store_path": "/nix/store/wjlj4v79x8zxnx5ylfgmiqp36vm28ii6-gnused-4.9" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/q7kq0naays5251ihghw0ccsz39id7kk5-gnused-4.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/a81qmwij2v1pjwsq739l482fxkkn4s07-gnused-4.9-info" + } + ], "store_path": "/nix/store/q7kq0naays5251ihghw0ccsz39id7kk5-gnused-4.9" } } @@ -228,15 +676,43 @@ "version": "1.22.1", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/k9srp8ngvblscg68fdpcyqkydh86429k-go-1.22.1", + "default": true + } + ], "store_path": "/nix/store/k9srp8ngvblscg68fdpcyqkydh86429k-go-1.22.1" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/i604lwmgw1s8w3bdvsiz4332rx7fsb87-go-1.22.1", + "default": true + } + ], "store_path": "/nix/store/i604lwmgw1s8w3bdvsiz4332rx7fsb87-go-1.22.1" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/5dyp491ka5hx1g788dvnvadzk9kn92bp-go-1.22.1", + "default": true + } + ], "store_path": "/nix/store/5dyp491ka5hx1g788dvnvadzk9kn92bp-go-1.22.1" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/wkbckbd30nlhq4dxzg64q6y4vm1xx4fk-go-1.22.1", + "default": true + } + ], "store_path": "/nix/store/wkbckbd30nlhq4dxzg64q6y4vm1xx4fk-go-1.22.1" } } @@ -248,15 +724,43 @@ "version": "0.12.14", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/yzkh6mg18q5c2dxlrsdi750imm41div4-gojq-0.12.14", + "default": true + } + ], "store_path": "/nix/store/yzkh6mg18q5c2dxlrsdi750imm41div4-gojq-0.12.14" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/xb0b2ng2m3xdm5iah0cjbqsaqiz87qza-gojq-0.12.14", + "default": true + } + ], "store_path": "/nix/store/xb0b2ng2m3xdm5iah0cjbqsaqiz87qza-gojq-0.12.14" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/1y68nsm5nx450lnvc6gr8as7231sfbhz-gojq-0.12.14", + "default": true + } + ], "store_path": "/nix/store/1y68nsm5nx450lnvc6gr8as7231sfbhz-gojq-0.12.14" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/1ivsp6qjrkr3d2gzax6w8iai55qagliv-gojq-0.12.14", + "default": true + } + ], "store_path": "/nix/store/1ivsp6qjrkr3d2gzax6w8iai55qagliv-gojq-0.12.14" } } @@ -268,15 +772,43 @@ "version": "0.12.2", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/225jl3pgxsgivmvggjbijywn0vfc0nd1-golines-0.12.2", + "default": true + } + ], "store_path": "/nix/store/225jl3pgxsgivmvggjbijywn0vfc0nd1-golines-0.12.2" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/nvfxf1ss0f2kq6cj1apa86yn7sxgxyb2-golines-0.12.2", + "default": true + } + ], "store_path": "/nix/store/nvfxf1ss0f2kq6cj1apa86yn7sxgxyb2-golines-0.12.2" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/jyyd2n5vbwl95a6jkb3xficbj54p8fj4-golines-0.12.2", + "default": true + } + ], "store_path": "/nix/store/jyyd2n5vbwl95a6jkb3xficbj54p8fj4-golines-0.12.2" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/nach7a7wc17kb36pvfvjcbms2p99kfr5-golines-0.12.2", + "default": true + } + ], "store_path": "/nix/store/nach7a7wc17kb36pvfvjcbms2p99kfr5-golines-0.12.2" } } @@ -288,15 +820,43 @@ "version": "1.24.0", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/8dd7j0fgivrb62jq43pyvmmwz5q9qgas-goreleaser-1.24.0", + "default": true + } + ], "store_path": "/nix/store/8dd7j0fgivrb62jq43pyvmmwz5q9qgas-goreleaser-1.24.0" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/d0z2c8vwijna7cfdp28r5kj6p5f1abzs-goreleaser-1.24.0", + "default": true + } + ], "store_path": "/nix/store/d0z2c8vwijna7cfdp28r5kj6p5f1abzs-goreleaser-1.24.0" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/4rnps0ylkz2jaw1qdp29m0pyx62mkv93-goreleaser-1.24.0", + "default": true + } + ], "store_path": "/nix/store/4rnps0ylkz2jaw1qdp29m0pyx62mkv93-goreleaser-1.24.0" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ys8s2aigrqa8ylsj58wh3qvj61i0lirb-goreleaser-1.24.0", + "default": true + } + ], "store_path": "/nix/store/ys8s2aigrqa8ylsj58wh3qvj61i0lirb-goreleaser-1.24.0" } } @@ -308,15 +868,43 @@ "version": "1.10.1", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/0z0jj1xpcnbgmfymdll7qjggffv6x09f-gotestsum-1.10.1", + "default": true + } + ], "store_path": "/nix/store/0z0jj1xpcnbgmfymdll7qjggffv6x09f-gotestsum-1.10.1" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ii73x40gwzwgm7wp5svkay6k65w722ab-gotestsum-1.10.1", + "default": true + } + ], "store_path": "/nix/store/ii73x40gwzwgm7wp5svkay6k65w722ab-gotestsum-1.10.1" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/glqkgvz7ll2vg7mfm1nlrd49a1dwfpb2-gotestsum-1.10.1", + "default": true + } + ], "store_path": "/nix/store/glqkgvz7ll2vg7mfm1nlrd49a1dwfpb2-gotestsum-1.10.1" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/bydqdbg757r6g5r24bf6s7yb9zdc1q4d-gotestsum-1.10.1", + "default": true + } + ], "store_path": "/nix/store/bydqdbg757r6g5r24bf6s7yb9zdc1q4d-gotestsum-1.10.1" } } @@ -328,15 +916,43 @@ "version": "1.0.4", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/kcqx91mgrw03wgqzzx96xprfjzkkss96-govulncheck-1.0.4", + "default": true + } + ], "store_path": "/nix/store/kcqx91mgrw03wgqzzx96xprfjzkkss96-govulncheck-1.0.4" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/4m6afbm7qm1rq5ql9a0x4xcyzlj5i627-govulncheck-1.0.4", + "default": true + } + ], "store_path": "/nix/store/4m6afbm7qm1rq5ql9a0x4xcyzlj5i627-govulncheck-1.0.4" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/nx4dsdypvbvizasrgjhpv82kw0fjlgm4-govulncheck-1.0.4", + "default": true + } + ], "store_path": "/nix/store/nx4dsdypvbvizasrgjhpv82kw0fjlgm4-govulncheck-1.0.4" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/kp3rjfdaxjx0m021nxp0kng5xx26p2j5-govulncheck-1.0.4", + "default": true + } + ], "store_path": "/nix/store/kp3rjfdaxjx0m021nxp0kng5xx26p2j5-govulncheck-1.0.4" } } @@ -348,15 +964,43 @@ "version": "1.11.2", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/dkky99zsrdkwz9hxprsq5zzha94jsrbj-helm-docs-1.11.2", + "default": true + } + ], "store_path": "/nix/store/dkky99zsrdkwz9hxprsq5zzha94jsrbj-helm-docs-1.11.2" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/3wamvq5mnmayksx0yy5ch9zb8mq42hd2-helm-docs-1.11.2", + "default": true + } + ], "store_path": "/nix/store/3wamvq5mnmayksx0yy5ch9zb8mq42hd2-helm-docs-1.11.2" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/1pfj5vzrss4xd34hi0b119hpm5ymd9hv-helm-docs-1.11.2", + "default": true + } + ], "store_path": "/nix/store/1pfj5vzrss4xd34hi0b119hpm5ymd9hv-helm-docs-1.11.2" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/zdzdnhdbqfrm2lczw4h38ziipr4ixs1d-helm-docs-1.11.2", + "default": true + } + ], "store_path": "/nix/store/zdzdnhdbqfrm2lczw4h38ziipr4ixs1d-helm-docs-1.11.2" } } @@ -368,15 +1012,43 @@ "version": "0.124.0", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/rfkfvwigv0282mw24n3cdym7cyi542jy-hugo-0.124.0", + "default": true + } + ], "store_path": "/nix/store/rfkfvwigv0282mw24n3cdym7cyi542jy-hugo-0.124.0" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/0rnv4sichypqbprm4nqd0jjc27z5286c-hugo-0.124.0", + "default": true + } + ], "store_path": "/nix/store/0rnv4sichypqbprm4nqd0jjc27z5286c-hugo-0.124.0" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ip5zhc1rf2li8cmjwffjrj42r7nkkj4a-hugo-0.124.0", + "default": true + } + ], "store_path": "/nix/store/ip5zhc1rf2li8cmjwffjrj42r7nkkj4a-hugo-0.124.0" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/8syg9xrkp3nbpb1r4b469068kvk8gq2a-hugo-0.124.0", + "default": true + } + ], "store_path": "/nix/store/8syg9xrkp3nbpb1r4b469068kvk8gq2a-hugo-0.124.0" } } @@ -388,15 +1060,43 @@ "version": "0.22.0", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/87yk9f9zqzl4q6cawsw78l9c872xk3zb-kind-0.22.0", + "default": true + } + ], "store_path": "/nix/store/87yk9f9zqzl4q6cawsw78l9c872xk3zb-kind-0.22.0" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/hd04jgix5j5dj1grcgh9wwlz636243h6-kind-0.22.0", + "default": true + } + ], "store_path": "/nix/store/hd04jgix5j5dj1grcgh9wwlz636243h6-kind-0.22.0" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/114mq99ncln9x8h4mxpcjsflbh9qawxs-kind-0.22.0", + "default": true + } + ], "store_path": "/nix/store/114mq99ncln9x8h4mxpcjsflbh9qawxs-kind-0.22.0" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/d0wmw2i217vak50q2h94wic5ipi11jir-kind-0.22.0", + "default": true + } + ], "store_path": "/nix/store/d0wmw2i217vak50q2h94wic5ipi11jir-kind-0.22.0" } } @@ -408,15 +1108,43 @@ "version": "0.15.2", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/5d6ri1axxv9cwsac5lg1vz288zk5vf3s-ko-0.15.2", + "default": true + } + ], "store_path": "/nix/store/5d6ri1axxv9cwsac5lg1vz288zk5vf3s-ko-0.15.2" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/8d62nfbvadkbrqlp20451cm0pgp6zjxg-ko-0.15.2", + "default": true + } + ], "store_path": "/nix/store/8d62nfbvadkbrqlp20451cm0pgp6zjxg-ko-0.15.2" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/mbikn788gr04c9kkzkdic4w05l8nq7z9-ko-0.15.2", + "default": true + } + ], "store_path": "/nix/store/mbikn788gr04c9kkzkdic4w05l8nq7z9-ko-0.15.2" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/11h314lbbbj0989drrwc4bi2xrwvxywv-ko-0.15.2", + "default": true + } + ], "store_path": "/nix/store/11h314lbbbj0989drrwc4bi2xrwvxywv-ko-0.15.2" } } @@ -428,15 +1156,43 @@ "version": "3.14.0", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/yqlqfiab0nglynw6r74inrinbls15620-kubebuilder-3.14.0", + "default": true + } + ], "store_path": "/nix/store/yqlqfiab0nglynw6r74inrinbls15620-kubebuilder-3.14.0" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/g4nbjgznx6rcrlpg3xn4ynyyr5wvczjp-kubebuilder-3.14.0", + "default": true + } + ], "store_path": "/nix/store/g4nbjgznx6rcrlpg3xn4ynyyr5wvczjp-kubebuilder-3.14.0" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/xc309p246h3q5xn9gzkh49qcglhfj6ra-kubebuilder-3.14.0", + "default": true + } + ], "store_path": "/nix/store/xc309p246h3q5xn9gzkh49qcglhfj6ra-kubebuilder-3.14.0" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/3rzgxlj6msggxpy8zdf6ffk197wnmywr-kubebuilder-3.14.0", + "default": true + } + ], "store_path": "/nix/store/3rzgxlj6msggxpy8zdf6ffk197wnmywr-kubebuilder-3.14.0" } } @@ -448,15 +1204,79 @@ "version": "1.29.3", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/qrfxb19jr53r2kcsvga8wvg25v5dwyjh-kubectl-1.29.3", + "default": true + }, + { + "name": "man", + "path": "/nix/store/2m9dv8cvh6f90di79cmld40hmniw3h0i-kubectl-1.29.3-man", + "default": true + }, + { + "name": "convert", + "path": "/nix/store/j9rqnfgamf15lp5ijnp916hp3hl42xz8-kubectl-1.29.3-convert" + } + ], "store_path": "/nix/store/qrfxb19jr53r2kcsvga8wvg25v5dwyjh-kubectl-1.29.3" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/hmdnw2aivd5ywvg8h2d9sjghpp91jqmm-kubectl-1.29.3", + "default": true + }, + { + "name": "man", + "path": "/nix/store/av4rh67mx52js37csgyhl296bnp0z07s-kubectl-1.29.3-man", + "default": true + }, + { + "name": "convert", + "path": "/nix/store/w3pma5nyyxizibg6pbc6m1lqr0rfamn5-kubectl-1.29.3-convert" + } + ], "store_path": "/nix/store/hmdnw2aivd5ywvg8h2d9sjghpp91jqmm-kubectl-1.29.3" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/1xvm25fyz9afncqgjxixjsjxfihvqf9k-kubectl-1.29.3", + "default": true + }, + { + "name": "man", + "path": "/nix/store/351mgjyq1jllp6347v71zpk54j7bws0w-kubectl-1.29.3-man", + "default": true + }, + { + "name": "convert", + "path": "/nix/store/4mf6d3vzql08zkg8rwac6y5nsjkcv6d1-kubectl-1.29.3-convert" + } + ], "store_path": "/nix/store/1xvm25fyz9afncqgjxixjsjxfihvqf9k-kubectl-1.29.3" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/xha7i9pddiz31bm9cr33njwnmzdpd3rf-kubectl-1.29.3", + "default": true + }, + { + "name": "man", + "path": "/nix/store/7alsjj9dc5j2xj28v6c0369wa7v1qgg0-kubectl-1.29.3-man", + "default": true + }, + { + "name": "convert", + "path": "/nix/store/gn5sj2jjwy2fvikgjkc76h8lagyszys0-kubectl-1.29.3-convert" + } + ], "store_path": "/nix/store/xha7i9pddiz31bm9cr33njwnmzdpd3rf-kubectl-1.29.3" } } @@ -468,15 +1288,43 @@ "version": "0.14.0", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/jblk86f5bi2dwg2w8g42xl9mpw1yrbi4-controller-tools-0.14.0", + "default": true + } + ], "store_path": "/nix/store/jblk86f5bi2dwg2w8g42xl9mpw1yrbi4-controller-tools-0.14.0" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/sq48wn8yyqkya8as690h61d1dlxwlkbi-controller-tools-0.14.0", + "default": true + } + ], "store_path": "/nix/store/sq48wn8yyqkya8as690h61d1dlxwlkbi-controller-tools-0.14.0" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/nm2vx0f6ajmqpbi2c6z8wani5f1fdqb4-controller-tools-0.14.0", + "default": true + } + ], "store_path": "/nix/store/nm2vx0f6ajmqpbi2c6z8wani5f1fdqb4-controller-tools-0.14.0" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/f8h9pj08ksm49v980yb0slzrbpqqc98r-controller-tools-0.14.0", + "default": true + } + ], "store_path": "/nix/store/f8h9pj08ksm49v980yb0slzrbpqqc98r-controller-tools-0.14.0" } } @@ -488,15 +1336,43 @@ "version": "3.14.3", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/zy9621qww3klbwkffz2pp9kh3p0hdfs3-kubernetes-helm-3.14.3", + "default": true + } + ], "store_path": "/nix/store/zy9621qww3klbwkffz2pp9kh3p0hdfs3-kubernetes-helm-3.14.3" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ki8zl3ccm68ma3kyjcnzdgfh4wslr2l6-kubernetes-helm-3.14.3", + "default": true + } + ], "store_path": "/nix/store/ki8zl3ccm68ma3kyjcnzdgfh4wslr2l6-kubernetes-helm-3.14.3" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/l6d6j4q4af0dhmjha0c7d010f3hj16b6-kubernetes-helm-3.14.3", + "default": true + } + ], "store_path": "/nix/store/l6d6j4q4af0dhmjha0c7d010f3hj16b6-kubernetes-helm-3.14.3" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/dnnm27a9s71pkgb7wjrdiw8gf9f7a003-kubernetes-helm-3.14.3", + "default": true + } + ], "store_path": "/nix/store/dnnm27a9s71pkgb7wjrdiw8gf9f7a003-kubernetes-helm-3.14.3" } } @@ -508,15 +1384,43 @@ "version": "5.3.0", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/452i1p4zhmbp0lij399pmlagvvhbz8qa-kustomize-5.3.0", + "default": true + } + ], "store_path": "/nix/store/452i1p4zhmbp0lij399pmlagvvhbz8qa-kustomize-5.3.0" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/db73m9xy7q4al1ypx3i4nbqw9wi25fpc-kustomize-5.3.0", + "default": true + } + ], "store_path": "/nix/store/db73m9xy7q4al1ypx3i4nbqw9wi25fpc-kustomize-5.3.0" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/r4kcp37cwrfskcdlk8r0hmwb5y6gh8lc-kustomize-5.3.0", + "default": true + } + ], "store_path": "/nix/store/r4kcp37cwrfskcdlk8r0hmwb5y6gh8lc-kustomize-5.3.0" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/y6q6p3fv79gahrkp6gz8q9lks4h0zgh8-kustomize-5.3.0", + "default": true + } + ], "store_path": "/nix/store/y6q6p3fv79gahrkp6gz8q9lks4h0zgh8-kustomize-5.3.0" } } @@ -528,15 +1432,59 @@ "version": "3.6.2", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/nwrn3g5v9bsrnd88v84q4q9japllx0jb-pre-commit-3.6.2", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/y3r47sj7njflny4l0x0a96bk24hfh7s4-pre-commit-3.6.2-dist" + } + ], "store_path": "/nix/store/nwrn3g5v9bsrnd88v84q4q9japllx0jb-pre-commit-3.6.2" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/61bnh53x2c6laq7vd7ssr23wm85zifs6-pre-commit-3.6.2", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/0rdbgni8iyzz32d24adg3rykkp4pc85m-pre-commit-3.6.2-dist" + } + ], "store_path": "/nix/store/61bnh53x2c6laq7vd7ssr23wm85zifs6-pre-commit-3.6.2" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/dpimv11qs1l3yyzb5nj94p2inpn35yj7-pre-commit-3.6.2", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/y1sav86i99mz03dp988lf1yxgcsdbff1-pre-commit-3.6.2-dist" + } + ], "store_path": "/nix/store/dpimv11qs1l3yyzb5nj94p2inpn35yj7-pre-commit-3.6.2" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/1n78gswil3nq9fdrff4rb2li4y45y5w4-pre-commit-3.6.2", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/ljfxnyrk6l9wpq2n5x79asgcw4pj7ay7-pre-commit-3.6.2-dist" + } + ], "store_path": "/nix/store/1n78gswil3nq9fdrff4rb2li4y45y5w4-pre-commit-3.6.2" } } @@ -548,15 +1496,43 @@ "version": "3.2.7", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/0kmy2vr9hznx2g22bvpavlcyrgjilx4z-rsync-3.2.7", + "default": true + } + ], "store_path": "/nix/store/0kmy2vr9hznx2g22bvpavlcyrgjilx4z-rsync-3.2.7" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/554m9gj7cd3qc7d9yyhvrw6l5gxwsf84-rsync-3.2.7", + "default": true + } + ], "store_path": "/nix/store/554m9gj7cd3qc7d9yyhvrw6l5gxwsf84-rsync-3.2.7" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/3f6wicmglmb803anbavd1gagbq16gqpb-rsync-3.2.7", + "default": true + } + ], "store_path": "/nix/store/3f6wicmglmb803anbavd1gagbq16gqpb-rsync-3.2.7" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/dc65w7qlnzqa9wfbyvyq5d8zv42v8zds-rsync-3.2.7", + "default": true + } + ], "store_path": "/nix/store/dc65w7qlnzqa9wfbyvyq5d8zv42v8zds-rsync-3.2.7" } } @@ -568,15 +1544,43 @@ "version": "3.8.0", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/6sicjz0jhnsazn34g9hlsjb7a80zm9i5-shfmt-3.8.0", + "default": true + } + ], "store_path": "/nix/store/6sicjz0jhnsazn34g9hlsjb7a80zm9i5-shfmt-3.8.0" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/l2l4hxcqypaqbp7ia8ig05345yx0sq5m-shfmt-3.8.0", + "default": true + } + ], "store_path": "/nix/store/l2l4hxcqypaqbp7ia8ig05345yx0sq5m-shfmt-3.8.0" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/6vh95c1bvnxr08ccy3p3gi02gxam5bns-shfmt-3.8.0", + "default": true + } + ], "store_path": "/nix/store/6vh95c1bvnxr08ccy3p3gi02gxam5bns-shfmt-3.8.0" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/sfdz20anszw4qfgwk71mmmfm0dzp94fv-shfmt-3.8.0", + "default": true + } + ], "store_path": "/nix/store/sfdz20anszw4qfgwk71mmmfm0dzp94fv-shfmt-3.8.0" } } @@ -588,15 +1592,59 @@ "version": "4.0.4", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/78j6khza1gr5zmbcldssr8zm8xxnzwps-python3.11-yamale-4.0.4", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/jfglw0libz2z4a97vnb8lsy1lqyrckvq-python3.11-yamale-4.0.4-dist" + } + ], "store_path": "/nix/store/78j6khza1gr5zmbcldssr8zm8xxnzwps-python3.11-yamale-4.0.4" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/9wdk342n50063l5y9idh4pl9gxvwdfyb-python3.11-yamale-4.0.4", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/4l5axk5c1878qmdpsgyc6kaf26gvvgms-python3.11-yamale-4.0.4-dist" + } + ], "store_path": "/nix/store/9wdk342n50063l5y9idh4pl9gxvwdfyb-python3.11-yamale-4.0.4" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/zy5pwvyhdyrkvgwwagf950pj0rvcdx68-python3.11-yamale-4.0.4", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/77a332bqd0j6xydhsny3xlm6sd5n5g7n-python3.11-yamale-4.0.4-dist" + } + ], "store_path": "/nix/store/zy5pwvyhdyrkvgwwagf950pj0rvcdx68-python3.11-yamale-4.0.4" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/9pzsm66srma437qmn3inib0r40jjawkm-python3.11-yamale-4.0.4", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/yf79fdb3nkb3ihklp9na61c74pnyh9h0-python3.11-yamale-4.0.4-dist" + } + ], "store_path": "/nix/store/9pzsm66srma437qmn3inib0r40jjawkm-python3.11-yamale-4.0.4" } } @@ -608,15 +1656,59 @@ "version": "1.35.1", "systems": { "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/shw3d5hqv1kjsxgs6favbb6icdf5zspz-python3.11-yamllint-1.35.1", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/i9fmwxqhi001mjn1vmmvn2a33fsddlz7-python3.11-yamllint-1.35.1-dist" + } + ], "store_path": "/nix/store/shw3d5hqv1kjsxgs6favbb6icdf5zspz-python3.11-yamllint-1.35.1" }, "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/qhciblsdwcx382ybhv4qy3pv321rprpn-python3.11-yamllint-1.35.1", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/3zx9gj6mma9g28vg9l6778h1la50s5zk-python3.11-yamllint-1.35.1-dist" + } + ], "store_path": "/nix/store/qhciblsdwcx382ybhv4qy3pv321rprpn-python3.11-yamllint-1.35.1" }, "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/0qjkix7ixdmh056zg2w98yqfx31ip722-python3.11-yamllint-1.35.1", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/sbgn6iav52fp759y47h4j9kaxzmbqgkh-python3.11-yamllint-1.35.1-dist" + } + ], "store_path": "/nix/store/0qjkix7ixdmh056zg2w98yqfx31ip722-python3.11-yamllint-1.35.1" }, "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/04jdxm8pyzbsg9vjgs0y1piglnn6bzny-python3.11-yamllint-1.35.1", + "default": true + }, + { + "name": "dist", + "path": "/nix/store/1grzppn23d79mkj9vyf9rs1f4w0xvyd6-python3.11-yamllint-1.35.1-dist" + } + ], "store_path": "/nix/store/04jdxm8pyzbsg9vjgs0y1piglnn6bzny-python3.11-yamllint-1.35.1" } } From c1695ce0bca6238dec428e657d880423f9bac506 Mon Sep 17 00:00:00 2001 From: Deepak Muley Date: Tue, 26 Mar 2024 09:23:16 -0700 Subject: [PATCH 10/87] fix: updated patches to use existing variable --- .../patches/nutanix/initialize-variables.yaml | 101 ++++++++---------- 1 file changed, 47 insertions(+), 54 deletions(-) diff --git a/hack/examples/patches/nutanix/initialize-variables.yaml b/hack/examples/patches/nutanix/initialize-variables.yaml index 1aa180e34..9429272bd 100644 --- a/hack/examples/patches/nutanix/initialize-variables.yaml +++ b/hack/examples/patches/nutanix/initialize-variables.yaml @@ -5,58 +5,51 @@ path: "/spec/topology/class" value: "nutanix-quick-start" - op: "add" - path: "/spec/topology/variables" + path: "/spec/topology/variables/0/value/nutanix" value: - - name: "clusterConfig" - value: - addons: - cni: - clusterAutoscaler: - strategy: - nfd: - strategy: - nutanix: - controlPlaneEndpoint: - host: ${CONTROL_PLANE_ENDPOINT_IP} - port: ${CONTROL_PLANE_ENDPOINT_PORT} - prismCentralEndpoint: - additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle - host: ${NUTANIX_ENDPOINT} - insecure: ${NUTANIX_INSECURE} - port: 9440 - credentialSecret: ${CLUSTER_NAME}-pc-creds - controlPlane: - nutanix: - machineDetails: - bootType: legacy - cluster: - name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} - type: name - image: - name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} - type: name - subnet: - - name: ${NUTANIX_SUBNET_NAME} - type: name - memorySize: 4Gi - systemDiskSize: 40Gi - vcpuSockets: 2 - vcpusPerSocket: 1 - - name: "workerConfig" - value: - nutanix: - machineDetails: - bootType: legacy - cluster: - name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} - type: name - image: - name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} - type: name - memorySize: 4Gi - subnet: - - name: ${NUTANIX_SUBNET_NAME} - type: name - systemDiskSize: 40Gi - vcpuSockets: 2 - vcpusPerSocket: 1 + controlPlaneEndpoint: + host: ${CONTROL_PLANE_ENDPOINT_IP} + port: ${CONTROL_PLANE_ENDPOINT_PORT} + prismCentralEndpoint: + additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle + host: ${NUTANIX_ENDPOINT} + insecure: ${NUTANIX_INSECURE} + port: 9440 + credentialSecret: ${CLUSTER_NAME}-pc-creds +- op: "add" + path: "/spec/topology/variables/0/value/controlPlane" + value: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + subnet: + - name: ${NUTANIX_SUBNET_NAME} + type: name + memorySize: 4Gi + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 +- op: "add" + path: "/spec/topology/variables/1/value/nutanix" + value: + machineDetails: + bootType: legacy + cluster: + name: ${NUTANIX_PRISM_ELEMENT_CLUSTER_NAME} + type: name + image: + name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} + type: name + memorySize: 4Gi + subnet: + - name: ${NUTANIX_SUBNET_NAME} + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 From d6f54fb5c0cdb935ed438130418358b003d8ff70 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Wed, 27 Mar 2024 09:28:51 +0000 Subject: [PATCH 11/87] test(e2e): Rename config for CAREN rather than CRE --- .gitignore | 2 +- make/go.mk | 4 ++-- metadata.yaml | 3 +++ test/e2e/config/{cre.yaml => caren.yaml} | 8 ++++---- .../shared/{v1beta1-helm => v1beta1-caaph}/metadata.yaml | 0 .../shared/{v1beta1-cre => v1beta1-caren}/metadata.yaml | 0 test/e2e/e2e_suite_test.go | 4 ++-- 7 files changed, 12 insertions(+), 9 deletions(-) rename test/e2e/config/{cre.yaml => caren.yaml} (97%) rename test/e2e/data/shared/{v1beta1-helm => v1beta1-caaph}/metadata.yaml (100%) rename test/e2e/data/shared/{v1beta1-cre => v1beta1-caren}/metadata.yaml (100%) diff --git a/.gitignore b/.gitignore index 05f2f7183..a50624695 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,4 @@ node_modules/ /cluster.yaml /runtime-extension-components.yaml /_artifacts/ -test/e2e/config/cre-envsubst.yaml +test/e2e/config/caren-envsubst.yaml diff --git a/make/go.mk b/make/go.mk index 25d799efb..8b7903c53 100644 --- a/make/go.mk +++ b/make/go.mk @@ -74,8 +74,8 @@ bench.%: ; $(info $(M) running benchmarks$(if $(GOTEST_RUN), matching "$(GOTEST_ E2E_PARALLEL_NODES ?= $(shell nproc --ignore=1) E2E_FLAKE_ATTEMPTS ?= 1 -E2E_CONF_FILE ?= $(REPO_ROOT)/test/e2e/config/cre.yaml -E2E_CONF_FILE_ENVSUBST ?= $(REPO_ROOT)/test/e2e/config/cre-envsubst.yaml +E2E_CONF_FILE ?= $(REPO_ROOT)/test/e2e/config/caren.yaml +E2E_CONF_FILE_ENVSUBST ?= $(basename $(E2E_CONF_FILE))-envsubst.yaml ARTIFACTS ?= ${REPO_ROOT}/_artifacts .PHONY: e2e-test diff --git a/metadata.yaml b/metadata.yaml index 79bb8b1e5..cd6638adc 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -16,3 +16,6 @@ releaseSeries: - major: 0 minor: 5 contract: v1beta1 +- major: 0 + minor: 6 + contract: v1beta1 diff --git a/test/e2e/config/cre.yaml b/test/e2e/config/caren.yaml similarity index 97% rename from test/e2e/config/cre.yaml rename to test/e2e/config/caren.yaml index b5ae76a0e..45ac1a554 100644 --- a/test/e2e/config/cre.yaml +++ b/test/e2e/config/caren.yaml @@ -1,7 +1,7 @@ # Copyright 2024 D2iQ, Inc. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -managementClusterName: cre-e2e +managementClusterName: caren-e2e images: - name: ko.local/cluster-api-runtime-extensions-nutanix:${E2E_IMAGE_TAG} @@ -101,12 +101,12 @@ providers: type: "url" contract: v1beta1 files: - - sourcePath: "../data/shared/v1beta1-helm/metadata.yaml" + - sourcePath: "../data/shared/v1beta1-caaph/metadata.yaml" replacements: - old: --metrics-addr=127.0.0.1:8080 new: --metrics-addr=:8080 -- name: cre +- name: caren type: RuntimeExtensionProvider versions: - name: "{go://github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix@v0.5}" @@ -125,7 +125,7 @@ providers: type: "url" contract: v1beta1 files: - - sourcePath: "../data/shared/v1beta1-cre/metadata.yaml" + - sourcePath: "../data/shared/v1beta1-caren/metadata.yaml" replacements: - old: "--v=0" new: "--v=8" diff --git a/test/e2e/data/shared/v1beta1-helm/metadata.yaml b/test/e2e/data/shared/v1beta1-caaph/metadata.yaml similarity index 100% rename from test/e2e/data/shared/v1beta1-helm/metadata.yaml rename to test/e2e/data/shared/v1beta1-caaph/metadata.yaml diff --git a/test/e2e/data/shared/v1beta1-cre/metadata.yaml b/test/e2e/data/shared/v1beta1-caren/metadata.yaml similarity index 100% rename from test/e2e/data/shared/v1beta1-cre/metadata.yaml rename to test/e2e/data/shared/v1beta1-caren/metadata.yaml diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index d41f1c440..a47770158 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -75,7 +75,7 @@ func init() { //nolint:gochecknoinits // Idiomatically used to set up flags. func TestE2E(t *testing.T) { ctrl.SetLogger(klog.Background()) RegisterFailHandler(Fail) - RunSpecs(t, "cre-e2e") + RunSpecs(t, "caren-e2e") } // Using a SynchronizedBeforeSuite for controlling how to create resources shared across ParallelNodes (~ginkgo @@ -238,7 +238,7 @@ func setupBootstrapCluster( } else { // Loading image for already created cluster imagesInput := capibootstrap.LoadImagesToKindClusterInput{ - Name: "cre-e2e", + Name: "caren-e2e", Images: config.Images, } err := capibootstrap.LoadImagesToKindCluster(context.TODO(), imagesInput) From 650c3cf58f65921fe332f28ce8801026ce12986c Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Wed, 27 Mar 2024 09:29:16 -0700 Subject: [PATCH 12/87] fixup! feat: Add user configuration for all providers Address review comments --- api/v1alpha1/clusterconfig_types.go | 7 ++++--- api/v1alpha1/zz_generated.deepcopy.go | 5 ----- pkg/handlers/generic/mutation/users/doc.go | 1 - pkg/handlers/generic/mutation/users/inject.go | 16 ++++++++-------- .../mutation/users/tests/generate_patches.go | 6 +++--- .../generic/mutation/users/variables_test.go | 6 +++--- 6 files changed, 18 insertions(+), 23 deletions(-) diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index 8b2f7d901..59e44bbea 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -365,9 +365,10 @@ type User struct { // Name specifies the user name Name string `json:"name"` - // Passwd specifies a hashed password for the user + // HashedPassword specifies a hashed password for the user. + // An empty string is not marshalled, because it is not a valid value. // +optional - Passwd *string `json:"passwd,omitempty"` + HashedPassword string `json:"hashedPassword,omitempty"` // SSHAuthorizedKeys specifies a list of ssh authorized keys for the user // +optional @@ -387,7 +388,7 @@ func (User) VariableSchema() clusterv1.VariableSchema { Description: "The username", Type: "string", }, - "passwd": { + "hashedPassword": { Description: "The hashed password for the user", Type: "string", }, diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index e9bd1198d..36a2ff9ca 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -774,11 +774,6 @@ func (in Subnets) DeepCopy() Subnets { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *User) DeepCopyInto(out *User) { *out = *in - if in.Passwd != nil { - in, out := &in.Passwd, &out.Passwd - *out = new(string) - **out = **in - } if in.SSHAuthorizedKeys != nil { in, out := &in.SSHAuthorizedKeys, &out.SSHAuthorizedKeys *out = make([]string, len(*in)) diff --git a/pkg/handlers/generic/mutation/users/doc.go b/pkg/handlers/generic/mutation/users/doc.go index d652aaae3..4584d2d23 100644 --- a/pkg/handlers/generic/mutation/users/doc.go +++ b/pkg/handlers/generic/mutation/users/doc.go @@ -1,5 +1,4 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// +kubebuilder:rbac:groups=cluster.x-k8s.io,resources=clusters,verbs=watch;list;get package users diff --git a/pkg/handlers/generic/mutation/users/inject.go b/pkg/handlers/generic/mutation/users/inject.go index facec1f78..8549bbdd7 100644 --- a/pkg/handlers/generic/mutation/users/inject.go +++ b/pkg/handlers/generic/mutation/users/inject.go @@ -119,7 +119,7 @@ func (h *usersPatchHandler) Mutate( func generateBootstrapUser(userFromVariable v1alpha1.User) bootstrapv1.User { bootstrapUser := bootstrapv1.User{ Name: userFromVariable.Name, - Passwd: userFromVariable.Passwd, + Passwd: ptr.To(userFromVariable.HashedPassword), SSHAuthorizedKeys: userFromVariable.SSHAuthorizedKeys, Sudo: userFromVariable.Sudo, } @@ -127,15 +127,15 @@ func generateBootstrapUser(userFromVariable v1alpha1.User) bootstrapv1.User { // LockPassword is not part of our API, because we can derive its value // for the use cases our API supports. // - // We do not support the edge cases where a password is defined, but - // password authentication is disabled, or where no password is defined, but - // password authentication is enabled. + // We do not support these edge cases: + // (a) Hashed password is defined, password authentication is not enabled. + // (b) Hashed password is not defined, password authentication is enabled. // // We disable password authentication by default. - bootstrapUser.LockPassword = ptr.To[bool](true) - if userFromVariable.Passwd != nil { - // We enable password authentication only if a password is defined. - bootstrapUser.LockPassword = ptr.To[bool](true) + bootstrapUser.LockPassword = ptr.To(true) + if userFromVariable.HashedPassword != "" { + // We enable password authentication only if a hashed password is defined. + bootstrapUser.LockPassword = ptr.To(true) } return bootstrapUser diff --git a/pkg/handlers/generic/mutation/users/tests/generate_patches.go b/pkg/handlers/generic/mutation/users/tests/generate_patches.go index 61bd69ba1..adedc8580 100644 --- a/pkg/handlers/generic/mutation/users/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/users/tests/generate_patches.go @@ -19,13 +19,13 @@ import ( var ( testUser1 = v1alpha1.User{ - Name: "complete", - Passwd: ptr.To[string]("password"), + Name: "complete", + HashedPassword: "password", SSHAuthorizedKeys: []string{ "key1", "key2", }, - Sudo: ptr.To[string]("ALL=(ALL) NOPASSWD:ALL"), + Sudo: ptr.To("ALL=(ALL) NOPASSWD:ALL"), } testUser2 = v1alpha1.User{ Name: "onlyname", diff --git a/pkg/handlers/generic/mutation/users/variables_test.go b/pkg/handlers/generic/mutation/users/variables_test.go index f4ab8c6a0..741a5b3d1 100644 --- a/pkg/handlers/generic/mutation/users/variables_test.go +++ b/pkg/handlers/generic/mutation/users/variables_test.go @@ -26,13 +26,13 @@ func TestVariableValidation(t *testing.T) { Vals: v1alpha1.GenericClusterConfig{ Users: []v1alpha1.User{ { - Name: "complete", - Passwd: ptr.To[string]("password"), + Name: "complete", + HashedPassword: "password", SSHAuthorizedKeys: []string{ "key1", "key2", }, - Sudo: ptr.To[string]("ALL=(ALL) NOPASSWD:ALL"), + Sudo: ptr.To("ALL=(ALL) NOPASSWD:ALL"), }, { Name: "onlyname", From 27072c6b2a18c341ec1391b1deb9cfac51f3af8b Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Wed, 27 Mar 2024 10:31:23 -0700 Subject: [PATCH 13/87] fixup! feat: Add user configuration for all providers Expand comments --- api/v1alpha1/clusterconfig_types.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index 59e44bbea..b888f83d2 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -365,12 +365,16 @@ type User struct { // Name specifies the user name Name string `json:"name"` - // HashedPassword specifies a hashed password for the user. + // HashedPassword specifies a hashed password for the user. See your + // distribution's documentation for instructions to create a hashed + // password. // An empty string is not marshalled, because it is not a valid value. // +optional HashedPassword string `json:"hashedPassword,omitempty"` - // SSHAuthorizedKeys specifies a list of ssh authorized keys for the user + // SSHAuthorizedKeys specifies a list of public SSH keys to write to the + // machine. Use the corresponding private SSH keys to authenticate. See SSH + // documentation for instructions to create a key pair. // +optional SSHAuthorizedKeys []string `json:"sshAuthorizedKeys,omitempty"` From 5656042199b1a5b23a830b1e6ee8c19077d7ed30 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Thu, 28 Mar 2024 10:05:04 +0000 Subject: [PATCH 14/87] test: Ensure defaults from JSON schema are respected Without this, defaults declared in the JSON schema are not included in validation steps, which can lead to invalid failures, while also not allowing for tests that target defaults. --- common/go.mod | 1 + common/pkg/testutils/openapi/convert.go | 2 +- common/pkg/testutils/openapi/validate.go | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/common/go.mod b/common/go.mod index 7e97d6d90..d65da65ec 100644 --- a/common/go.mod +++ b/common/go.mod @@ -63,6 +63,7 @@ require ( golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.14.0 // indirect + golang.org/x/sync v0.5.0 // indirect golang.org/x/sys v0.16.0 // indirect golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/common/pkg/testutils/openapi/convert.go b/common/pkg/testutils/openapi/convert.go index 922e4f0b5..5eb248617 100644 --- a/common/pkg/testutils/openapi/convert.go +++ b/common/pkg/testutils/openapi/convert.go @@ -14,7 +14,7 @@ import ( clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ) -// convertToAPIExtensionsJSONSchemaProps converts a clusterv1.JSONSchemaProps to apiextensions.JSONSchemaProp. +// ConvertToAPIExtensionsJSONSchemaProps converts a clusterv1.JSONSchemaProps to apiextensions.JSONSchemaProp. // NOTE: This is used whenever we want to use one of the upstream libraries, as they use apiextensions.JSONSchemaProp. // NOTE: If new fields are added to clusterv1.JSONSchemaProps (e.g. to support complex types), the corresponding // schema validation must be added to validateRootSchema too. diff --git a/common/pkg/testutils/openapi/validate.go b/common/pkg/testutils/openapi/validate.go index 9ef8f4ea8..bf776db6d 100644 --- a/common/pkg/testutils/openapi/validate.go +++ b/common/pkg/testutils/openapi/validate.go @@ -10,6 +10,7 @@ import ( "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" structuralschema "k8s.io/apiextensions-apiserver/pkg/apiserver/schema" + "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/defaulting" structuralpruning "k8s.io/apiextensions-apiserver/pkg/apiserver/schema/pruning" "k8s.io/apiextensions-apiserver/pkg/apiserver/validation" "k8s.io/apimachinery/pkg/util/validation/field" @@ -62,6 +63,18 @@ func ValidateClusterVariable( )} } + s, err := structuralschema.NewStructural(apiExtensionsSchema) + if err != nil { + return field.ErrorList{field.InternalError(fldPath, + fmt.Errorf( + "failed to create structural schema for variable %q; ClusterClass should be checked: %v", + value.Name, + err, + ), + )} + } + defaulting.Default(variableValue, s) + // Validate variable against the schema. // NOTE: We're reusing a library func used in CRD validation. if err := validation.ValidateCustomResource(fldPath, variableValue, validator); err != nil { From 9748994feadf320a197abbf514a3637f73525e18 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 28 Mar 2024 08:58:14 -0700 Subject: [PATCH 15/87] fixup! feat: Add user configuration for all providers Fix typo in lockPassword logic, and add unit test --- go.mod | 2 +- pkg/handlers/generic/mutation/users/inject.go | 6 +- .../generic/mutation/users/inject_test.go | 61 +++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 pkg/handlers/generic/mutation/users/inject_test.go diff --git a/go.mod b/go.mod index c1df13beb..c55396282 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api v0.0.0-00010101000000-000000000000 github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common v0.0.0-00010101000000-000000000000 github.com/go-logr/logr v1.4.1 + github.com/google/go-cmp v0.6.0 github.com/onsi/ginkgo/v2 v2.16.0 github.com/onsi/gomega v1.31.1 github.com/spf13/pflag v1.0.5 @@ -71,7 +72,6 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/google/cel-go v0.17.7 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-github/v53 v53.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect diff --git a/pkg/handlers/generic/mutation/users/inject.go b/pkg/handlers/generic/mutation/users/inject.go index 8549bbdd7..0a224b512 100644 --- a/pkg/handlers/generic/mutation/users/inject.go +++ b/pkg/handlers/generic/mutation/users/inject.go @@ -119,7 +119,6 @@ func (h *usersPatchHandler) Mutate( func generateBootstrapUser(userFromVariable v1alpha1.User) bootstrapv1.User { bootstrapUser := bootstrapv1.User{ Name: userFromVariable.Name, - Passwd: ptr.To(userFromVariable.HashedPassword), SSHAuthorizedKeys: userFromVariable.SSHAuthorizedKeys, Sudo: userFromVariable.Sudo, } @@ -133,9 +132,12 @@ func generateBootstrapUser(userFromVariable v1alpha1.User) bootstrapv1.User { // // We disable password authentication by default. bootstrapUser.LockPassword = ptr.To(true) + if userFromVariable.HashedPassword != "" { // We enable password authentication only if a hashed password is defined. - bootstrapUser.LockPassword = ptr.To(true) + bootstrapUser.LockPassword = ptr.To(false) + + bootstrapUser.Passwd = ptr.To(userFromVariable.HashedPassword) } return bootstrapUser diff --git a/pkg/handlers/generic/mutation/users/inject_test.go b/pkg/handlers/generic/mutation/users/inject_test.go new file mode 100644 index 000000000..470555196 --- /dev/null +++ b/pkg/handlers/generic/mutation/users/inject_test.go @@ -0,0 +1,61 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package users + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "k8s.io/utils/ptr" + bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" +) + +func Test_generateBootstrapUser(t *testing.T) { + type args struct { + userFromVariable v1alpha1.User + } + tests := []struct { + name string + args args + want bootstrapv1.User + }{ + { + name: "if user sets hashed password, enable password auth and set passwd", + args: args{ + userFromVariable: v1alpha1.User{ + Name: "example", + HashedPassword: "example", + }, + }, + want: bootstrapv1.User{ + Name: "example", + Passwd: ptr.To("example"), + LockPassword: ptr.To(false), + }, + }, + { + name: "if user does not set hashed password, disable password auth and do not set passwd", + args: args{ + userFromVariable: v1alpha1.User{ + Name: "example", + }, + }, + want: bootstrapv1.User{ + Name: "example", + Passwd: nil, + LockPassword: ptr.To(true), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := generateBootstrapUser(tt.args.userFromVariable) + if diff := cmp.Diff(tt.want, got); diff != "" { + t.Errorf("generateBootstrapUser() mismatch (-want +got):\n%s", diff) + } + }) + } +} From 1205a59fd25afacd8f93c39896b4cc6af6fa6086 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 28 Mar 2024 11:38:35 -0700 Subject: [PATCH 16/87] fixup! feat: Add user configuration for all providers Add unit test for empty hashed password --- pkg/handlers/generic/mutation/users/inject_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pkg/handlers/generic/mutation/users/inject_test.go b/pkg/handlers/generic/mutation/users/inject_test.go index 470555196..c5d71ca53 100644 --- a/pkg/handlers/generic/mutation/users/inject_test.go +++ b/pkg/handlers/generic/mutation/users/inject_test.go @@ -49,6 +49,20 @@ func Test_generateBootstrapUser(t *testing.T) { LockPassword: ptr.To(true), }, }, + { + name: "if user sets empty hashed password, disable password auth and do not set passwd", + args: args{ + userFromVariable: v1alpha1.User{ + Name: "example", + HashedPassword: "", + }, + }, + want: bootstrapv1.User{ + Name: "example", + Passwd: nil, + LockPassword: ptr.To(true), + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From a0cdd4bd8027efd11cce03bf13733d8dec8c37dc Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 28 Mar 2024 11:47:42 -0700 Subject: [PATCH 17/87] fixup! feat: Add user configuration for all providers Change Sudo field from pointer to value The zero value (empty string) is not valid, so the field does not need to be a pointer. --- api/v1alpha1/clusterconfig_types.go | 5 ++- api/v1alpha1/zz_generated.deepcopy.go | 5 --- pkg/handlers/generic/mutation/users/inject.go | 5 ++- .../generic/mutation/users/inject_test.go | 41 +++++++++++++++++++ .../mutation/users/tests/generate_patches.go | 3 +- .../generic/mutation/users/variables_test.go | 2 +- 6 files changed, 50 insertions(+), 11 deletions(-) diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index b888f83d2..e38e3bbc6 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -378,9 +378,10 @@ type User struct { // +optional SSHAuthorizedKeys []string `json:"sshAuthorizedKeys,omitempty"` - // Sudo specifies a sudo role for the user + // Sudo specifies a sudo role for the user. + // An empty string is not marshalled, because it is not a valid value. // +optional - Sudo *string `json:"sudo,omitempty"` + Sudo string `json:"sudo,omitempty"` } func (User) VariableSchema() clusterv1.VariableSchema { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 36a2ff9ca..e555b38fe 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -779,11 +779,6 @@ func (in *User) DeepCopyInto(out *User) { *out = make([]string, len(*in)) copy(*out, *in) } - if in.Sudo != nil { - in, out := &in.Sudo, &out.Sudo - *out = new(string) - **out = **in - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. diff --git a/pkg/handlers/generic/mutation/users/inject.go b/pkg/handlers/generic/mutation/users/inject.go index 0a224b512..9d41e0495 100644 --- a/pkg/handlers/generic/mutation/users/inject.go +++ b/pkg/handlers/generic/mutation/users/inject.go @@ -120,7 +120,6 @@ func generateBootstrapUser(userFromVariable v1alpha1.User) bootstrapv1.User { bootstrapUser := bootstrapv1.User{ Name: userFromVariable.Name, SSHAuthorizedKeys: userFromVariable.SSHAuthorizedKeys, - Sudo: userFromVariable.Sudo, } // LockPassword is not part of our API, because we can derive its value @@ -140,5 +139,9 @@ func generateBootstrapUser(userFromVariable v1alpha1.User) bootstrapv1.User { bootstrapUser.Passwd = ptr.To(userFromVariable.HashedPassword) } + if userFromVariable.Sudo != "" { + bootstrapUser.Sudo = ptr.To(userFromVariable.Sudo) + } + return bootstrapUser } diff --git a/pkg/handlers/generic/mutation/users/inject_test.go b/pkg/handlers/generic/mutation/users/inject_test.go index c5d71ca53..22eb1c812 100644 --- a/pkg/handlers/generic/mutation/users/inject_test.go +++ b/pkg/handlers/generic/mutation/users/inject_test.go @@ -63,6 +63,47 @@ func Test_generateBootstrapUser(t *testing.T) { LockPassword: ptr.To(true), }, }, + { + name: "if user sets sudo, include it in the patch", + args: args{ + userFromVariable: v1alpha1.User{ + Name: "example", + Sudo: "example", + }, + }, + want: bootstrapv1.User{ + Name: "example", + Sudo: ptr.To("example"), + LockPassword: ptr.To(true), + }, + }, + { + name: "if user does not set sudo, do not include in the patch", + args: args{ + userFromVariable: v1alpha1.User{ + Name: "example", + }, + }, + want: bootstrapv1.User{ + Name: "example", + Sudo: nil, + LockPassword: ptr.To(true), + }, + }, + { + name: "if user sets empty sudo, do not include in the patch", + args: args{ + userFromVariable: v1alpha1.User{ + Name: "example", + Sudo: "", + }, + }, + want: bootstrapv1.User{ + Name: "example", + Sudo: nil, + LockPassword: ptr.To(true), + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/handlers/generic/mutation/users/tests/generate_patches.go b/pkg/handlers/generic/mutation/users/tests/generate_patches.go index adedc8580..2eff072f5 100644 --- a/pkg/handlers/generic/mutation/users/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/users/tests/generate_patches.go @@ -8,7 +8,6 @@ import ( "github.com/onsi/gomega" "k8s.io/apiserver/pkg/storage/names" - "k8s.io/utils/ptr" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" @@ -25,7 +24,7 @@ var ( "key1", "key2", }, - Sudo: ptr.To("ALL=(ALL) NOPASSWD:ALL"), + Sudo: "ALL=(ALL) NOPASSWD:ALL", } testUser2 = v1alpha1.User{ Name: "onlyname", diff --git a/pkg/handlers/generic/mutation/users/variables_test.go b/pkg/handlers/generic/mutation/users/variables_test.go index 741a5b3d1..7f09fcf9c 100644 --- a/pkg/handlers/generic/mutation/users/variables_test.go +++ b/pkg/handlers/generic/mutation/users/variables_test.go @@ -32,7 +32,7 @@ func TestVariableValidation(t *testing.T) { "key1", "key2", }, - Sudo: ptr.To("ALL=(ALL) NOPASSWD:ALL"), + Sudo: "ALL=(ALL) NOPASSWD:ALL", }, { Name: "onlyname", From 64b7afcf5727a2012bc44365300c38dcbc789777 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 28 Mar 2024 12:23:42 -0700 Subject: [PATCH 18/87] fixup! feat: Add user configuration for all providers Make username required --- api/v1alpha1/clusterconfig_types.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index e38e3bbc6..29e7d3725 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -362,7 +362,7 @@ func (Users) VariableSchema() clusterv1.VariableSchema { // User defines the input for a generated user in cloud-init. type User struct { - // Name specifies the user name + // Name specifies the user name. Name string `json:"name"` // HashedPassword specifies a hashed password for the user. See your @@ -387,7 +387,8 @@ type User struct { func (User) VariableSchema() clusterv1.VariableSchema { return clusterv1.VariableSchema{ OpenAPIV3Schema: clusterv1.JSONSchemaProps{ - Type: "object", + Type: "object", + Required: []string{"name"}, Properties: map[string]clusterv1.JSONSchemaProps{ "name": { Description: "The username", From 37ec7c9a4195c852afd99894a30061146b979b0c Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 28 Mar 2024 12:28:09 -0700 Subject: [PATCH 19/87] fixup! feat: Add user configuration for all providers Explain why we do not validate hashed password input --- api/v1alpha1/clusterconfig_types.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index 29e7d3725..35c367409 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -395,8 +395,14 @@ func (User) VariableSchema() clusterv1.VariableSchema { Type: "string", }, "hashedPassword": { - Description: "The hashed password for the user", + Description: "The hashed password for the user. Must be in the format of some hash function supported by the OS.", Type: "string", + // The crypt (5) man page lists regexes for supported hash + // functions. We could validate input against a set of + // regexes, but because the set may be different from the + // set supported by the chosen OS, we might return a false + // negative or positive. For this reason, we do not validate + // the input. }, "sshAuthorizedKeys": { Description: "A list of SSH authorized keys for this user", From 0968ea60257b13141cd3486434d7f953ef805c38 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 28 Mar 2024 12:38:48 -0700 Subject: [PATCH 20/87] fixup! feat: Add user configuration for all providers Explain why we do not validate sudo input --- api/v1alpha1/clusterconfig_types.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index 35c367409..f97c9e116 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -415,6 +415,9 @@ func (User) VariableSchema() clusterv1.VariableSchema { "sudo": { Description: "The sudo rule that applies to this user", Type: "string", + // A sudo rule is defined using an EBNF grammar, and must be + // parsed to be validated. We have decided to not integrate + // a sudo rule parser, so we do not validate the input. }, }, }, From f09a28f739ca4dec4ab1bd76be50f636ba43bbe8 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 28 Mar 2024 15:33:57 -0700 Subject: [PATCH 21/87] fixup! feat: Add user configuration for all providers Update type comments --- api/v1alpha1/clusterconfig_types.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index f97c9e116..a167df0d7 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -365,20 +365,21 @@ type User struct { // Name specifies the user name. Name string `json:"name"` - // HashedPassword specifies a hashed password for the user. See your - // distribution's documentation for instructions to create a hashed - // password. + // HashedPassword is a hashed password for the user, formatted as described + // by the crypt(5) man page. See your distribution's documentation for + // instructions to create a hashed password. // An empty string is not marshalled, because it is not a valid value. // +optional HashedPassword string `json:"hashedPassword,omitempty"` - // SSHAuthorizedKeys specifies a list of public SSH keys to write to the + // SSHAuthorizedKeys is a list of public SSH keys to write to the // machine. Use the corresponding private SSH keys to authenticate. See SSH // documentation for instructions to create a key pair. // +optional SSHAuthorizedKeys []string `json:"sshAuthorizedKeys,omitempty"` - // Sudo specifies a sudo role for the user. + // Sudo is a sudo user specification, formatted as described in the sudo + // documentation. // An empty string is not marshalled, because it is not a valid value. // +optional Sudo string `json:"sudo,omitempty"` From 5a73b71e02a974ad47b8d9525c04974e3d03615e Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 28 Mar 2024 15:35:35 -0700 Subject: [PATCH 22/87] fixup! feat: Add user configuration for all providers Remove errant comment --- pkg/handlers/generic/mutation/users/variables_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/handlers/generic/mutation/users/variables_test.go b/pkg/handlers/generic/mutation/users/variables_test.go index 7f09fcf9c..227318484 100644 --- a/pkg/handlers/generic/mutation/users/variables_test.go +++ b/pkg/handlers/generic/mutation/users/variables_test.go @@ -20,7 +20,6 @@ func TestVariableValidation(t *testing.T) { ptr.To(v1alpha1.GenericClusterConfig{}.VariableSchema()), false, clusterconfig.NewVariable, - // HTTPProxy capitest.VariableTestDef{ Name: "valid users", Vals: v1alpha1.GenericClusterConfig{ From b8bcb0e62c61f73593ec815faca98502586b0ad3 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Thu, 28 Mar 2024 15:35:50 -0700 Subject: [PATCH 23/87] fixup! feat: Add user configuration for all providers Add users to the docs site --- docs/content/customization/generic/users.md | 56 +++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 docs/content/customization/generic/users.md diff --git a/docs/content/customization/generic/users.md b/docs/content/customization/generic/users.md new file mode 100644 index 000000000..5226a9cf7 --- /dev/null +++ b/docs/content/customization/generic/users.md @@ -0,0 +1,56 @@ ++++ +title = "Users" ++++ + +Configure users for all machines in the cluster, the user's superuser capabilities using `sudo` user specifications, and the login authentication mechanism. + +> - SSH _authorized keys_ are just public SSH keys that are used to authenticate a login. See the [SSH man page](https://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT) for more information. +> +> - For information on sudo user specifications, see the [sudo documentation](https://www.sudo.ws/docs/man/sudoers.man/#User_specification). +> +> - Local password authentication is disabled for the user by default. It is enabled only when a hashed password is provided. + +## Examples + +### Admin user with SSH public key login + +Creates a user with the name `admin`, grants the user the ability to run any command as the superuser, and allows you to login via SSH using the username and private key corresponding to the authorized public key. + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: +spec: + topology: + variables: + - name: clusterConfig + value: + users: + - name: admin + - sshAuthorizedKeys: + - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAua0lo8BiGWgvIiDCKnQDKL5uERHfnehm0ns5CEJpJw optional-comment" + sudo: "ALL=(ALL) NOPASSWD:ALL" +``` + +### Admin user with serial console password login + +Creates a user with the name `admin,` grants the user the ability to run any command as the superuser, and allows you to login via serial console using the username and password. + +> Note that this does not allow you to login via SSH using the username and password; in most cases, you must also configure the SSH server to allow password authentication. + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: +spec: + topology: + variables: + - name: clusterConfig + value: + users: + - name: admin + hashedPassword: "$y$j9T$UraH8eN4XvapXBmmSaUrP0$Nyxdf1cJDGZcp0WDKu.CFHprrkPG4ubirqSqiD43Ix3" + sudo: "ALL=(ALL) NOPASSWD:ALL" +``` From dfd5cbe48a64d6d3f5ed80292ce514340e8d1bb5 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Fri, 29 Mar 2024 09:53:12 -0700 Subject: [PATCH 24/87] fixup! fixup! feat: Add user configuration for all providers Manually wrap lines in doc --- docs/content/customization/generic/users.md | 23 ++++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/content/customization/generic/users.md b/docs/content/customization/generic/users.md index 5226a9cf7..b7f7c304c 100644 --- a/docs/content/customization/generic/users.md +++ b/docs/content/customization/generic/users.md @@ -2,19 +2,24 @@ title = "Users" +++ -Configure users for all machines in the cluster, the user's superuser capabilities using `sudo` user specifications, and the login authentication mechanism. +Configure users for all machines in the cluster, the user's superuser capabilities using `sudo` user specifications, and +the login authentication mechanism. -> - SSH _authorized keys_ are just public SSH keys that are used to authenticate a login. See the [SSH man page](https://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT) for more information. +> - SSH _authorized keys_ are just public SSH keys that are used to authenticate a login. See the [SSH man +> page](https://www.man7.org/linux/man-pages/man8/sshd.8.html#AUTHORIZED_KEYS_FILE_FORMAT) for more information. > -> - For information on sudo user specifications, see the [sudo documentation](https://www.sudo.ws/docs/man/sudoers.man/#User_specification). +> - For information on sudo user specifications, see the [sudo +> documentation](https://www.sudo.ws/docs/man/sudoers.man/#User_specification). > -> - Local password authentication is disabled for the user by default. It is enabled only when a hashed password is provided. +> - Local password authentication is disabled for the user by default. It is enabled only when a hashed password is +> provided. ## Examples ### Admin user with SSH public key login -Creates a user with the name `admin`, grants the user the ability to run any command as the superuser, and allows you to login via SSH using the username and private key corresponding to the authorized public key. +Creates a user with the name `admin`, grants the user the ability to run any command as the superuser, and allows you to +login via SSH using the username and private key corresponding to the authorized public key. ```yaml apiVersion: cluster.x-k8s.io/v1beta1 @@ -29,15 +34,17 @@ spec: users: - name: admin - sshAuthorizedKeys: - - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAua0lo8BiGWgvIiDCKnQDKL5uERHfnehm0ns5CEJpJw optional-comment" + - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAua0lo8BiGWgvIiDCKnQDKL5uERHfnehm0ns5CEJpJw optionalcomment" sudo: "ALL=(ALL) NOPASSWD:ALL" ``` ### Admin user with serial console password login -Creates a user with the name `admin,` grants the user the ability to run any command as the superuser, and allows you to login via serial console using the username and password. +Creates a user with the name `admin,` grants the user the ability to run any command as the superuser, and allows you to +login via serial console using the username and password. -> Note that this does not allow you to login via SSH using the username and password; in most cases, you must also configure the SSH server to allow password authentication. +> Note that this does not allow you to login via SSH using the username and password; in most cases, you must also +> configure the SSH server to allow password authentication. ```yaml apiVersion: cluster.x-k8s.io/v1beta1 From b0761a7be93b88e394cfbb82c50c9be31e61731b Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Fri, 29 Mar 2024 11:28:54 -0700 Subject: [PATCH 25/87] build: add Nutanix infra provider (#12) Also deploy infra provider versions that match the API. --- .../templates/clusterclass_nutanix.yaml | 6 ++++++ make/clusterctl.mk | 7 ++++++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/clusterclass_nutanix.yaml diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/clusterclass_nutanix.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/clusterclass_nutanix.yaml new file mode 100644 index 000000000..42ee09357 --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/clusterclass_nutanix.yaml @@ -0,0 +1,6 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +{{- if and .Values.deployDefaultClusterClasses (.Capabilities.APIVersions.Has "infrastructure.cluster.x-k8s.io/v1beta1/NutanixClusterTemplate") }} +{{ .Files.Get "defaultclusterclasses/nutanix-cluster-class.yaml" }} +{{- end}} diff --git a/make/clusterctl.mk b/make/clusterctl.mk index 9fd35d427..0409eaa0e 100644 --- a/make/clusterctl.mk +++ b/make/clusterctl.mk @@ -1,6 +1,10 @@ # Copyright 2023 D2iQ, Inc. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +export CAPA_VERSION := $(shell cd hack/third-party/capa && go list -m -f '{{ .Version }}' sigs.k8s.io/cluster-api-provider-aws/v2) +export CAPX_VERSION := $(shell cd hack/third-party/capx && go list -m -f '{{ .Version }}' github.com/nutanix-cloud-native/cluster-api-provider-nutanix) + +# Leave Nutanix credentials empty here and set it when creating the clusters .PHONY: clusterctl.init clusterctl.init: env CLUSTER_TOPOLOGY=true \ @@ -8,9 +12,10 @@ clusterctl.init: EXP_CLUSTER_RESOURCE_SET=true \ EXP_MACHINE_POOL=true \ AWS_B64ENCODED_CREDENTIALS=$$(clusterawsadm bootstrap credentials encode-as-profile) \ + NUTANIX_ENDPOINT="" NUTANIX_PASSWORD="" NUTANIX_USER="" \ clusterctl init \ --kubeconfig=$(KIND_KUBECONFIG) \ - --infrastructure docker,aws \ + --infrastructure docker,aws:${CAPA_VERSION},nutanix:${CAPX_VERSION} \ --addon helm \ --wait-providers From 47e578a14dc9855ab8f76dbfa087c20972fd41db Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Fri, 29 Mar 2024 13:57:12 -0700 Subject: [PATCH 26/87] fix: rename cpi to ccm (#11) CPI is a term unique to the vSphere CCM. Renaming to the more generic "CCM". --- api/v1alpha1/addon_types.go | 10 +-- api/v1alpha1/clusterconfig_types.go | 14 ++--- api/v1alpha1/zz_generated.deepcopy.go | 22 +++---- .../manifests/aws-ccm-v1.27.1-configmap.yaml} | 6 +- .../manifests/aws-ccm-v1.28.1-configmap.yaml} | 6 +- .../aws-cluster-calico-crs.yaml | 2 +- .../aws-cluster-calico-helm-addon.yaml | 2 +- .../aws-cluster-cilium-crs.yaml | 2 +- .../aws-cluster-cilium-helm-addon.yaml | 2 +- .../kustomization.yaml.tmpl | 6 +- .../{update-aws-cpi.sh => update-aws-ccm.sh} | 26 ++++---- .../bases/aws/cluster/kustomization.yaml.tmpl | 2 +- hack/examples/patches/{cpi.yaml => ccm.yaml} | 2 +- make/addons.mk | 18 +++--- .../lifecycle/{cpi => ccm}/aws/handler.go | 62 +++++++++---------- .../{cpi => ccm}/aws/handler_test.go | 16 ++--- .../generic/lifecycle/{cpi => ccm}/doc.go | 2 +- .../generic/lifecycle/{cpi => ccm}/handler.go | 56 ++++++++--------- pkg/handlers/generic/lifecycle/handlers.go | 16 ++--- 19 files changed, 136 insertions(+), 136 deletions(-) rename charts/cluster-api-runtime-extensions-nutanix/templates/{cpi/aws/manifests/aws-cpi-v1.27.1-configmap.yaml => ccm/aws/manifests/aws-ccm-v1.27.1-configmap.yaml} (97%) rename charts/cluster-api-runtime-extensions-nutanix/templates/{cpi/aws/manifests/aws-cpi-v1.28.1-configmap.yaml => ccm/aws/manifests/aws-ccm-v1.28.1-configmap.yaml} (97%) rename hack/addons/kustomize/{aws-cpi => aws-ccm}/kustomization.yaml.tmpl (86%) rename hack/addons/{update-aws-cpi.sh => update-aws-ccm.sh} (60%) rename hack/examples/patches/{cpi.yaml => ccm.yaml} (67%) rename pkg/handlers/generic/lifecycle/{cpi => ccm}/aws/handler.go (56%) rename pkg/handlers/generic/lifecycle/{cpi => ccm}/aws/handler_test.go (89%) rename pkg/handlers/generic/lifecycle/{cpi => ccm}/doc.go (98%) rename pkg/handlers/generic/lifecycle/{cpi => ccm}/handler.go (66%) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 7a0863bbf..c88edf1e7 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -20,7 +20,7 @@ type Addons struct { ClusterAutoscaler *ClusterAutoscaler `json:"clusterAutoscaler,omitempty"` // +optional - CPI *CPI `json:"cpi,omitempty"` + CCM *CCM `json:"ccm,omitempty"` // +optional CSIProviders *CSIProviders `json:"csi,omitempty"` @@ -36,7 +36,7 @@ func (Addons) VariableSchema() clusterv1.VariableSchema { "nfd": NFD{}.VariableSchema().OpenAPIV3Schema, "clusterAutoscaler": ClusterAutoscaler{}.VariableSchema().OpenAPIV3Schema, "csi": CSIProviders{}.VariableSchema().OpenAPIV3Schema, - "cpi": CPI{}.VariableSchema().OpenAPIV3Schema, + "ccm": CCM{}.VariableSchema().OpenAPIV3Schema, }, }, } @@ -173,10 +173,10 @@ func (CSIProviders) VariableSchema() clusterv1.VariableSchema { } } -// CPI tells us to enable or disable the cloud provider interface. -type CPI struct{} +// CCM tells us to enable or disable the cloud provider interface. +type CCM struct{} -func (CPI) VariableSchema() clusterv1.VariableSchema { +func (CCM) VariableSchema() clusterv1.VariableSchema { return clusterv1.VariableSchema{ OpenAPIV3Schema: clusterv1.JSONSchemaProps{ Type: "object", diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index 17e5b119e..7bbbef0d8 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -20,17 +20,17 @@ const ( CSIProviderAWSEBS = "aws-ebs" - CPIProviderAWS = "aws" + CCMProviderAWS = "aws" ) -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // ClusterConfig is the Schema for the clusterconfigs API. type ClusterConfig struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - //+optional + // +optional Spec ClusterConfigSpec `json:"spec,omitempty"` } @@ -43,7 +43,7 @@ type ClusterConfigSpec struct { GenericClusterConfig `json:",inline"` - //+optional + // +optional ControlPlane *NodeConfigSpec `json:"controlPlane,omitempty"` } @@ -140,11 +140,11 @@ func (v KubernetesImageRepository) String() string { type Image struct { // Repository is used to override the image repository to pull from. - //+optional + // +optional Repository string `json:"repository,omitempty"` // Tag is used to override the default image tag. - //+optional + // +optional Tag string `json:"tag,omitempty"` } @@ -170,7 +170,7 @@ func (Image) VariableSchema() clusterv1.VariableSchema { type Etcd struct { // Image required for overriding etcd image details. - //+optional + // +optional Image *Image `json:"image,omitempty"` } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 5af92e536..01692d804 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -199,9 +199,9 @@ func (in *Addons) DeepCopyInto(out *Addons) { *out = new(ClusterAutoscaler) **out = **in } - if in.CPI != nil { - in, out := &in.CPI, &out.CPI - *out = new(CPI) + if in.CCM != nil { + in, out := &in.CCM, &out.CCM + *out = new(CCM) **out = **in } if in.CSIProviders != nil { @@ -222,31 +222,31 @@ func (in *Addons) DeepCopy() *Addons { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CNI) DeepCopyInto(out *CNI) { +func (in *CCM) DeepCopyInto(out *CCM) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNI. -func (in *CNI) DeepCopy() *CNI { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CCM. +func (in *CCM) DeepCopy() *CCM { if in == nil { return nil } - out := new(CNI) + out := new(CCM) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CPI) DeepCopyInto(out *CPI) { +func (in *CNI) DeepCopyInto(out *CNI) { *out = *in } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CPI. -func (in *CPI) DeepCopy() *CPI { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CNI. +func (in *CNI) DeepCopy() *CNI { if in == nil { return nil } - out := new(CPI) + out := new(CNI) in.DeepCopyInto(out) return out } diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/cpi/aws/manifests/aws-cpi-v1.27.1-configmap.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/ccm/aws/manifests/aws-ccm-v1.27.1-configmap.yaml similarity index 97% rename from charts/cluster-api-runtime-extensions-nutanix/templates/cpi/aws/manifests/aws-cpi-v1.27.1-configmap.yaml rename to charts/cluster-api-runtime-extensions-nutanix/templates/ccm/aws/manifests/aws-ccm-v1.27.1-configmap.yaml index 7d34b818e..94f9739ce 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/cpi/aws/manifests/aws-cpi-v1.27.1-configmap.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/ccm/aws/manifests/aws-ccm-v1.27.1-configmap.yaml @@ -3,11 +3,11 @@ #================================================================= # DO NOT EDIT THIS FILE -# IT HAS BEEN GENERATED BY /hack/addons/update-aws-cpi.sh +# IT HAS BEEN GENERATED BY /hack/addons/update-aws-ccm.sh #================================================================= apiVersion: v1 data: - aws-cpi-v1.27.1.yaml: | + aws-ccm-v1.27.1.yaml: | apiVersion: v1 kind: ServiceAccount metadata: @@ -185,4 +185,4 @@ data: kind: ConfigMap metadata: creationTimestamp: null - name: aws-cpi-v1.27.1 + name: aws-ccm-v1.27.1 diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/cpi/aws/manifests/aws-cpi-v1.28.1-configmap.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/ccm/aws/manifests/aws-ccm-v1.28.1-configmap.yaml similarity index 97% rename from charts/cluster-api-runtime-extensions-nutanix/templates/cpi/aws/manifests/aws-cpi-v1.28.1-configmap.yaml rename to charts/cluster-api-runtime-extensions-nutanix/templates/ccm/aws/manifests/aws-ccm-v1.28.1-configmap.yaml index 6a6b0d0f2..593b24c98 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/cpi/aws/manifests/aws-cpi-v1.28.1-configmap.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/ccm/aws/manifests/aws-ccm-v1.28.1-configmap.yaml @@ -3,11 +3,11 @@ #================================================================= # DO NOT EDIT THIS FILE -# IT HAS BEEN GENERATED BY /hack/addons/update-aws-cpi.sh +# IT HAS BEEN GENERATED BY /hack/addons/update-aws-ccm.sh #================================================================= apiVersion: v1 data: - aws-cpi-v1.28.1.yaml: | + aws-ccm-v1.28.1.yaml: | apiVersion: v1 kind: ServiceAccount metadata: @@ -185,4 +185,4 @@ data: kind: ConfigMap metadata: creationTimestamp: null - name: aws-cpi-v1.28.1 + name: aws-ccm-v1.28.1 diff --git a/examples/capi-quick-start/aws-cluster-calico-crs.yaml b/examples/capi-quick-start/aws-cluster-calico-crs.yaml index d0bb44005..847222c10 100644 --- a/examples/capi-quick-start/aws-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/aws-cluster-calico-crs.yaml @@ -21,12 +21,12 @@ spec: - name: clusterConfig value: addons: + ccm: {} clusterAutoscaler: strategy: ClusterResourceSet cni: provider: Calico strategy: ClusterResourceSet - cpi: {} csi: providers: - name: aws-ebs diff --git a/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml index de865c0a2..ac26e8051 100644 --- a/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml @@ -21,12 +21,12 @@ spec: - name: clusterConfig value: addons: + ccm: {} clusterAutoscaler: strategy: HelmAddon cni: provider: Calico strategy: HelmAddon - cpi: {} csi: providers: - name: aws-ebs diff --git a/examples/capi-quick-start/aws-cluster-cilium-crs.yaml b/examples/capi-quick-start/aws-cluster-cilium-crs.yaml index 582498ec8..2fd77b867 100644 --- a/examples/capi-quick-start/aws-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/aws-cluster-cilium-crs.yaml @@ -21,12 +21,12 @@ spec: - name: clusterConfig value: addons: + ccm: {} clusterAutoscaler: strategy: ClusterResourceSet cni: provider: Cilium strategy: ClusterResourceSet - cpi: {} csi: providers: - name: aws-ebs diff --git a/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml index c710fa612..4bd929d2f 100644 --- a/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml @@ -21,12 +21,12 @@ spec: - name: clusterConfig value: addons: + ccm: {} clusterAutoscaler: strategy: HelmAddon cni: provider: Cilium strategy: HelmAddon - cpi: {} csi: providers: - name: aws-ebs diff --git a/hack/addons/kustomize/aws-cpi/kustomization.yaml.tmpl b/hack/addons/kustomize/aws-ccm/kustomization.yaml.tmpl similarity index 86% rename from hack/addons/kustomize/aws-cpi/kustomization.yaml.tmpl rename to hack/addons/kustomize/aws-ccm/kustomization.yaml.tmpl index 3aff2a7e1..e8238d6da 100644 --- a/hack/addons/kustomize/aws-cpi/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/aws-ccm/kustomization.yaml.tmpl @@ -5,13 +5,13 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization metadata: - name: aws-cpi-kustomize + name: aws-ccm-kustomize helmCharts: - name: aws-cloud-controller-manager repo: https://kubernetes.github.io/cloud-provider-aws releaseName: aws-cloud-controller-manager - version: ${AWS_CPI_CHART_VERSION} + version: ${AWS_CCM_CHART_VERSION} includeCRDs: true skipTests: true @@ -25,4 +25,4 @@ patches: images: - name: registry.k8s.io/provider-aws/cloud-controller-manager - newTag: ${AWS_CPI_VERSION} + newTag: ${AWS_CCM_VERSION} diff --git a/hack/addons/update-aws-cpi.sh b/hack/addons/update-aws-ccm.sh similarity index 60% rename from hack/addons/update-aws-cpi.sh rename to hack/addons/update-aws-ccm.sh index 1b00910c0..cee75151d 100755 --- a/hack/addons/update-aws-cpi.sh +++ b/hack/addons/update-aws-ccm.sh @@ -8,13 +8,13 @@ readonly SCRIPT_DIR # shellcheck source=hack/common.sh source "${SCRIPT_DIR}/../common.sh" -AWS_CPI_VERSION=$1 -export AWS_CPI_VERSION -AWS_CPI_CHART_VERSION=$2 -export AWS_CPI_CHART_VERSION +AWS_CCM_VERSION=$1 +export AWS_CCM_VERSION +AWS_CCM_CHART_VERSION=$2 +export AWS_CCM_CHART_VERSION -if [ -z "${AWS_CPI_VERSION:-}" ]; then - echo "Missing argument: AWS_CPI_VERSION" +if [ -z "${AWS_CCM_VERSION:-}" ]; then + echo "Missing argument: AWS_CCM_VERSION" exit 1 fi @@ -22,23 +22,23 @@ ASSETS_DIR="$(mktemp -d -p "${TMPDIR:-/tmp}")" readonly ASSETS_DIR trap_add "rm -rf ${ASSETS_DIR}" EXIT -readonly KUSTOMIZE_BASE_DIR="${SCRIPT_DIR}/kustomize/aws-cpi/" +readonly KUSTOMIZE_BASE_DIR="${SCRIPT_DIR}/kustomize/aws-ccm/" envsubst -no-unset <"${KUSTOMIZE_BASE_DIR}/kustomization.yaml.tmpl" >"${ASSETS_DIR}/kustomization.yaml" -readonly FILE_NAME="aws-cpi-${AWS_CPI_VERSION}.yaml" +readonly FILE_NAME="aws-ccm-${AWS_CCM_VERSION}.yaml" kustomize build --enable-helm "${ASSETS_DIR}" >"${ASSETS_DIR}/${FILE_NAME}" -kubectl create configmap aws-cpi-"${AWS_CPI_VERSION}" --dry-run=client --output yaml \ +kubectl create configmap aws-ccm-"${AWS_CCM_VERSION}" --dry-run=client --output yaml \ --from-file "${ASSETS_DIR}/${FILE_NAME}" \ - >"${ASSETS_DIR}/aws-cpi-${AWS_CPI_VERSION}-configmap.yaml" + >"${ASSETS_DIR}/aws-ccm-${AWS_CCM_VERSION}-configmap.yaml" # add warning not to edit file directly -cat <"${GIT_REPO_ROOT}/charts/cluster-api-runtime-extensions-nutanix/templates/cpi/aws/manifests/aws-cpi-${AWS_CPI_VERSION}-configmap.yaml" +cat <"${GIT_REPO_ROOT}/charts/cluster-api-runtime-extensions-nutanix/templates/ccm/aws/manifests/aws-ccm-${AWS_CCM_VERSION}-configmap.yaml" $(cat "${GIT_REPO_ROOT}/hack/license-header.yaml.txt") #================================================================= # DO NOT EDIT THIS FILE -# IT HAS BEEN GENERATED BY /hack/addons/update-aws-cpi.sh +# IT HAS BEEN GENERATED BY /hack/addons/update-aws-ccm.sh #================================================================= -$(cat "${ASSETS_DIR}/aws-cpi-${AWS_CPI_VERSION}-configmap.yaml") +$(cat "${ASSETS_DIR}/aws-ccm-${AWS_CCM_VERSION}-configmap.yaml") EOF diff --git a/hack/examples/bases/aws/cluster/kustomization.yaml.tmpl b/hack/examples/bases/aws/cluster/kustomization.yaml.tmpl index 10c970d1c..983a38473 100644 --- a/hack/examples/bases/aws/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/aws/cluster/kustomization.yaml.tmpl @@ -35,7 +35,7 @@ patches: path: ../../../patches/cluster-autoscaler.yaml - target: kind: Cluster - path: ../../../patches/cpi.yaml + path: ../../../patches/ccm.yaml - target: kind: Cluster path: ../../../patches/aws/csi.yaml diff --git a/hack/examples/patches/cpi.yaml b/hack/examples/patches/ccm.yaml similarity index 67% rename from hack/examples/patches/cpi.yaml rename to hack/examples/patches/ccm.yaml index dff7b8841..3263fe97b 100644 --- a/hack/examples/patches/cpi.yaml +++ b/hack/examples/patches/ccm.yaml @@ -2,5 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 - op: "add" - path: "/spec/topology/variables/0/value/addons/cpi" + path: "/spec/topology/variables/0/value/addons/ccm" value: {} diff --git a/make/addons.mk b/make/addons.mk index 60c04554f..85ad54575 100644 --- a/make/addons.mk +++ b/make/addons.mk @@ -7,14 +7,14 @@ export NODE_FEATURE_DISCOVERY_VERSION := $(shell goprintconst -file pkg/handlers export CLUSTER_AUTOSCALER_VERSION := 9.35.0 export AWS_CSI_SNAPSHOT_CONTROLLER_VERSION := v6.3.3 export AWS_EBS_CSI_CHART_VERSION := v2.28.1 -# a map of AWS CPI versions -export AWS_CPI_VERSION_127 := v1.27.1 -export AWS_CPI_CHART_VERSION_127 := 0.0.8 -export AWS_CPI_VERSION_128 := v1.28.1 -export AWS_CPI_CHART_VERSION_128 := 0.0.8 +# a map of AWS CCM versions +export AWS_CCM_VERSION_127 := v1.27.1 +export AWS_CCM_CHART_VERSION_127 := 0.0.8 +export AWS_CCM_VERSION_128 := v1.28.1 +export AWS_CCM_CHART_VERSION_128 := 0.0.8 .PHONY: addons.sync -addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler aws-ebs-csi aws-cpi.127 aws-cpi.128) +addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler aws-ebs-csi aws-ccm.127 aws-ccm.128) .PHONY: update-addon.calico update-addon.calico: ; $(info $(M) updating calico manifests) @@ -36,6 +36,6 @@ update-addon.cluster-autoscaler: ; $(info $(M) updating cluster-autoscaler manif update-addon.aws-ebs-csi: ; $(info $(M) updating aws ebs csi manifests) ./hack/addons/update-aws-ebs-csi.sh -.PHONY: update-addon.aws-cpi.% -update-addon.aws-cpi.%: ; $(info $(M) updating aws cpi $* manifests) - ./hack/addons/update-aws-cpi.sh $(AWS_CPI_VERSION_$*) $(AWS_CPI_CHART_VERSION_$*) +.PHONY: update-addon.aws-ccm.% +update-addon.aws-ccm.%: ; $(info $(M) updating aws ccm $* manifests) + ./hack/addons/update-aws-ccm.sh $(AWS_CCM_VERSION_$*) $(AWS_CCM_CHART_VERSION_$*) diff --git a/pkg/handlers/generic/lifecycle/cpi/aws/handler.go b/pkg/handlers/generic/lifecycle/ccm/aws/handler.go similarity index 56% rename from pkg/handlers/generic/lifecycle/cpi/aws/handler.go rename to pkg/handlers/generic/lifecycle/ccm/aws/handler.go index 3490af192..2e0e9225e 100644 --- a/pkg/handlers/generic/lifecycle/cpi/aws/handler.go +++ b/pkg/handlers/generic/lifecycle/ccm/aws/handler.go @@ -19,40 +19,40 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) -type AWSCPIConfig struct { +type AWSCCMConfig struct { *options.GlobalOptions - kubernetesMinorVersionToCPIConfigMapNames map[string]string + kubernetesMinorVersionToCCMConfigMapNames map[string]string } -func (a *AWSCPIConfig) AddFlags(prefix string, flags *pflag.FlagSet) { +func (a *AWSCCMConfig) AddFlags(prefix string, flags *pflag.FlagSet) { flags.StringToStringVar( - &a.kubernetesMinorVersionToCPIConfigMapNames, - prefix+".default-aws-cpi-configmap-names", + &a.kubernetesMinorVersionToCCMConfigMapNames, + prefix+".default-aws-ccm-configmap-names", map[string]string{ - "1.27": "aws-cpi-v1.27.1", - "1.28": "aws-cpi-v1.28.1", + "1.27": "aws-ccm-v1.27.1", + "1.28": "aws-ccm-v1.28.1", }, "map of provider cluster implementation type to default installation ConfigMap name", ) } -type AWSCPI struct { +type AWSCCM struct { client ctrlclient.Client - config *AWSCPIConfig + config *AWSCCMConfig } func New( c ctrlclient.Client, - cfg *AWSCPIConfig, -) *AWSCPI { - return &AWSCPI{ + cfg *AWSCCMConfig, +) *AWSCCM { + return &AWSCCM{ client: c, config: cfg, } } -func (a *AWSCPI) EnsureCPIConfigMapForCluster( +func (a *AWSCCM) EnsureCCMConfigMapForCluster( ctx context.Context, cluster *clusterv1.Cluster, ) (*corev1.ConfigMap, error) { @@ -60,56 +60,56 @@ func (a *AWSCPI) EnsureCPIConfigMapForCluster( "cluster", cluster.Name, ) - log.Info("Creating AWS CPI ConfigMap for Cluster") + log.Info("Creating AWS CCM ConfigMap for Cluster") version, err := semver.ParseTolerant(cluster.Spec.Topology.Version) if err != nil { return nil, fmt.Errorf("failed to parse version from cluster %w", err) } minorVersion := fmt.Sprintf("%d.%d", version.Major, version.Minor) - configMapForMinorVersion := a.config.kubernetesMinorVersionToCPIConfigMapNames[minorVersion] - cpiConfigMapForMinorVersion := &corev1.ConfigMap{ + configMapForMinorVersion := a.config.kubernetesMinorVersionToCCMConfigMapNames[minorVersion] + ccmConfigMapForMinorVersion := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: a.config.DefaultsNamespace(), Name: configMapForMinorVersion, }, } objName := ctrlclient.ObjectKeyFromObject( - cpiConfigMapForMinorVersion, + ccmConfigMapForMinorVersion, ) - err = a.client.Get(ctx, objName, cpiConfigMapForMinorVersion) + err = a.client.Get(ctx, objName, ccmConfigMapForMinorVersion) if err != nil { - log.Error(err, "failed to fetch CPI template for cluster") + log.Error(err, "failed to fetch CCM template for cluster") return nil, fmt.Errorf( - "failed to retrieve default AWS CPI manifests ConfigMap %q: %w", + "failed to retrieve default AWS CCM manifests ConfigMap %q: %w", objName, err, ) } - cpiConfigMap := generateCPIConfigMapForCluster(cpiConfigMapForMinorVersion, cluster) - if err := client.ServerSideApply(ctx, a.client, cpiConfigMap); err != nil { - log.Error(err, "failed to apply CPI configmap for cluster") + ccmConfigMap := generateCCMConfigMapForCluster(ccmConfigMapForMinorVersion, cluster) + if err := client.ServerSideApply(ctx, a.client, ccmConfigMap); err != nil { + log.Error(err, "failed to apply CCM configmap for cluster") return nil, fmt.Errorf( - "failed to apply AWS CPI manifests ConfigMap: %w", + "failed to apply AWS CCM manifests ConfigMap: %w", err, ) } - return cpiConfigMap, nil + return ccmConfigMap, nil } -func generateCPIConfigMapForCluster( - cpiConfigMapForVersion *corev1.ConfigMap, cluster *clusterv1.Cluster, +func generateCCMConfigMapForCluster( + ccmConfigMapForVersion *corev1.ConfigMap, cluster *clusterv1.Cluster, ) *corev1.ConfigMap { - cpiConfigMapForCluster := &corev1.ConfigMap{ + ccmConfigMapForCluster := &corev1.ConfigMap{ TypeMeta: metav1.TypeMeta{ APIVersion: corev1.SchemeGroupVersion.String(), Kind: "ConfigMap", }, ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, - Name: fmt.Sprintf("%s-%s", cpiConfigMapForVersion.Name, cluster.Name), + Name: fmt.Sprintf("%s-%s", ccmConfigMapForVersion.Name, cluster.Name), }, - Data: cpiConfigMapForVersion.Data, + Data: ccmConfigMapForVersion.Data, } - return cpiConfigMapForCluster + return ccmConfigMapForCluster } diff --git a/pkg/handlers/generic/lifecycle/cpi/aws/handler_test.go b/pkg/handlers/generic/lifecycle/ccm/aws/handler_test.go similarity index 89% rename from pkg/handlers/generic/lifecycle/cpi/aws/handler_test.go rename to pkg/handlers/generic/lifecycle/ccm/aws/handler_test.go index 0fd559f5e..de34b4bae 100644 --- a/pkg/handlers/generic/lifecycle/cpi/aws/handler_test.go +++ b/pkg/handlers/generic/lifecycle/ccm/aws/handler_test.go @@ -12,7 +12,7 @@ import ( clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ) -var startAWSCPIConfigMap = ` +var startAWSCCMConfigMap = ` apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: @@ -77,7 +77,7 @@ spec: type: RollingUpdate ` -func Test_generateCPIConfigMapForCluster(t *testing.T) { +func Test_generateCCMConfigMapForCluster(t *testing.T) { tests := []struct { name string startConfigMap *corev1.ConfigMap @@ -87,11 +87,11 @@ func Test_generateCPIConfigMapForCluster(t *testing.T) { name: "Can set cluster name in arguments", startConfigMap: &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: "aws-cpi-v1.27.1", + Name: "aws-ccm-v1.27.1", Namespace: "default", }, Data: map[string]string{ - "aws-cpi-v1.27.1.yaml": startAWSCPIConfigMap, + "aws-ccm-v1.27.1.yaml": startAWSCCMConfigMap, }, }, cluster: &clusterv1.Cluster{ @@ -104,19 +104,19 @@ func Test_generateCPIConfigMapForCluster(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - cm := generateCPIConfigMapForCluster( + cm := generateCCMConfigMapForCluster( test.startConfigMap, test.cluster, ) - cpiConfigMapExpectedName := fmt.Sprintf( + ccmConfigMapExpectedName := fmt.Sprintf( "%s-%s", test.startConfigMap.Name, test.cluster.Name, ) - if cm.Name != cpiConfigMapExpectedName { + if cm.Name != ccmConfigMapExpectedName { t.Errorf( "expected configmap name to be %s. got: %s", - cpiConfigMapExpectedName, + ccmConfigMapExpectedName, cm.Name, ) } diff --git a/pkg/handlers/generic/lifecycle/cpi/doc.go b/pkg/handlers/generic/lifecycle/ccm/doc.go similarity index 98% rename from pkg/handlers/generic/lifecycle/cpi/doc.go rename to pkg/handlers/generic/lifecycle/ccm/doc.go index 10ac8b7f3..8fe9f0035 100644 --- a/pkg/handlers/generic/lifecycle/cpi/doc.go +++ b/pkg/handlers/generic/lifecycle/ccm/doc.go @@ -9,4 +9,4 @@ // // +kubebuilder:rbac:groups=addons.cluster.x-k8s.io,resources=clusterresourcesets,verbs=watch;list;get;create;patch;update;delete // +kubebuilder:rbac:groups="",resources=configmaps,verbs=watch;list;get;create;patch;update;delete -package cpi +package ccm diff --git a/pkg/handlers/generic/lifecycle/cpi/handler.go b/pkg/handlers/generic/lifecycle/ccm/handler.go similarity index 66% rename from pkg/handlers/generic/lifecycle/cpi/handler.go rename to pkg/handlers/generic/lifecycle/ccm/handler.go index e9e1237ed..43360aa1b 100644 --- a/pkg/handlers/generic/lifecycle/cpi/handler.go +++ b/pkg/handlers/generic/lifecycle/ccm/handler.go @@ -1,7 +1,7 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package cpi +package ccm import ( "context" @@ -23,30 +23,30 @@ import ( ) const ( - variableRootName = "cpi" + variableRootName = "ccm" ) -type CPIProvider interface { - EnsureCPIConfigMapForCluster(context.Context, *clusterv1.Cluster) (*corev1.ConfigMap, error) +type CCMProvider interface { + EnsureCCMConfigMapForCluster(context.Context, *clusterv1.Cluster) (*corev1.ConfigMap, error) } -type CPIHandler struct { +type CCMHandler struct { client ctrlclient.Client variableName string variablePath []string - ProviderHandler map[string]CPIProvider + ProviderHandler map[string]CCMProvider } var ( - _ commonhandlers.Named = &CPIHandler{} - _ lifecycle.AfterControlPlaneInitialized = &CPIHandler{} + _ commonhandlers.Named = &CCMHandler{} + _ lifecycle.AfterControlPlaneInitialized = &CCMHandler{} ) func New( c ctrlclient.Client, - handlers map[string]CPIProvider, -) *CPIHandler { - return &CPIHandler{ + handlers map[string]CCMProvider, +) *CCMHandler { + return &CCMHandler{ client: c, variableName: clusterconfig.MetaVariableName, variablePath: []string{"addons", variableRootName}, @@ -54,11 +54,11 @@ func New( } } -func (c *CPIHandler) Name() string { - return "CPIHandler" +func (c *CCMHandler) Name() string { + return "CCMHandler" } -func (c *CPIHandler) AfterControlPlaneInitialized( +func (c *CCMHandler) AfterControlPlaneInitialized( ctx context.Context, req *runtimehooksv1.AfterControlPlaneInitializedRequest, resp *runtimehooksv1.AfterControlPlaneInitializedResponse, @@ -72,43 +72,43 @@ func (c *CPIHandler) AfterControlPlaneInitialized( varMap := variables.ClusterVariablesToVariablesMap(req.Cluster.Spec.Topology.Variables) - _, found, err := variables.Get[v1alpha1.CPI](varMap, c.variableName, c.variablePath...) + _, found, err := variables.Get[v1alpha1.CCM](varMap, c.variableName, c.variablePath...) if err != nil { log.Error( err, - "failed to read CPI from cluster definition", + "failed to read CCM from cluster definition", ) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage( - fmt.Sprintf("failed to read CPI provider from cluster definition: %v", + fmt.Sprintf("failed to read CCM provider from cluster definition: %v", err, ), ) return } if !found { - log.V(4).Info("Skipping CPI handler.") + log.V(4).Info("Skipping CCM handler.") return } infraKind := req.Cluster.Spec.InfrastructureRef.Kind - log.Info(fmt.Sprintf("finding cpi handler for %s", infraKind)) - var handler CPIProvider + log.Info(fmt.Sprintf("finding CCM handler for %s", infraKind)) + var handler CCMProvider switch { - case strings.Contains(strings.ToLower(infraKind), v1alpha1.CPIProviderAWS): - handler = c.ProviderHandler[v1alpha1.CPIProviderAWS] + case strings.Contains(strings.ToLower(infraKind), v1alpha1.CCMProviderAWS): + handler = c.ProviderHandler[v1alpha1.CCMProviderAWS] default: - log.Info(fmt.Sprintf("No CPI handler provided for infra kind %s", infraKind)) + log.Info(fmt.Sprintf("No CCM handler provided for infra kind %s", infraKind)) return } - cm, err := handler.EnsureCPIConfigMapForCluster(ctx, &req.Cluster) + cm, err := handler.EnsureCCMConfigMapForCluster(ctx, &req.Cluster) if err != nil { log.Error( err, - "failed to generate CPI configmap", + "failed to generate CCM configmap", ) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage( - fmt.Sprintf("failed to generate CPI configmap: %v", + fmt.Sprintf("failed to generate CCM configmap: %v", err, ), ) @@ -118,11 +118,11 @@ func (c *CPIHandler) AfterControlPlaneInitialized( if err != nil { log.Error( err, - "failed to generate CPI CRS for cluster", + "failed to generate CCM CRS for cluster", ) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage( - fmt.Sprintf("failed to generate CPI CRS: %v", + fmt.Sprintf("failed to generate CCM CRS: %v", err, ), ) diff --git a/pkg/handlers/generic/lifecycle/handlers.go b/pkg/handlers/generic/lifecycle/handlers.go index fcfc07d10..366e78196 100644 --- a/pkg/handlers/generic/lifecycle/handlers.go +++ b/pkg/handlers/generic/lifecycle/handlers.go @@ -9,11 +9,11 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm" + awsccm "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm/aws" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/clusterautoscaler" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/calico" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/cilium" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cpi" - awscpi "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cpi/aws" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi" awsebs "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/aws-ebs" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/nfd" @@ -27,7 +27,7 @@ type Handlers struct { nfdConfig *nfd.Config clusterAutoscalerConfig *clusterautoscaler.Config ebsConfig *awsebs.AWSEBSConfig - awsCPIConfig *awscpi.AWSCPIConfig + awsccmConfig *awsccm.AWSCCMConfig } func New(globalOptions *options.GlobalOptions) *Handlers { @@ -37,7 +37,7 @@ func New(globalOptions *options.GlobalOptions) *Handlers { nfdConfig: &nfd.Config{GlobalOptions: globalOptions}, clusterAutoscalerConfig: &clusterautoscaler.Config{GlobalOptions: globalOptions}, ebsConfig: &awsebs.AWSEBSConfig{GlobalOptions: globalOptions}, - awsCPIConfig: &awscpi.AWSCPIConfig{GlobalOptions: globalOptions}, + awsccmConfig: &awsccm.AWSCCMConfig{GlobalOptions: globalOptions}, } } @@ -45,8 +45,8 @@ func (h *Handlers) AllHandlers(mgr manager.Manager) []handlers.Named { csiHandlers := map[string]csi.CSIProvider{ v1alpha1.CSIProviderAWSEBS: awsebs.New(mgr.GetClient(), h.ebsConfig), } - cpiHandlers := map[string]cpi.CPIProvider{ - v1alpha1.CPIProviderAWS: awscpi.New(mgr.GetClient(), h.awsCPIConfig), + ccmHandlers := map[string]ccm.CCMProvider{ + v1alpha1.CCMProviderAWS: awsccm.New(mgr.GetClient(), h.awsccmConfig), } return []handlers.Named{ @@ -56,7 +56,7 @@ func (h *Handlers) AllHandlers(mgr manager.Manager) []handlers.Named { clusterautoscaler.New(mgr.GetClient(), h.clusterAutoscalerConfig), servicelbgc.New(mgr.GetClient()), csi.New(mgr.GetClient(), csiHandlers), - cpi.New(mgr.GetClient(), cpiHandlers), + ccm.New(mgr.GetClient(), ccmHandlers), } } @@ -66,5 +66,5 @@ func (h *Handlers) AddFlags(flagSet *pflag.FlagSet) { h.calicoCNIConfig.AddFlags("cni.calico", flagSet) h.ciliumCNIConfig.AddFlags("cni.cilium", flagSet) h.ebsConfig.AddFlags("awsebs", pflag.CommandLine) - h.awsCPIConfig.AddFlags("awscpi", pflag.CommandLine) + h.awsccmConfig.AddFlags("awsccm", pflag.CommandLine) } From 83dbb727e7d98cb0f36f5deb1c295105755dcff9 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Fri, 29 Mar 2024 17:08:38 -0700 Subject: [PATCH 27/87] test: Check for data races in go tests --- make/go.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/make/go.mk b/make/go.mk index 8b7903c53..84afa2988 100644 --- a/make/go.mk +++ b/make/go.mk @@ -26,6 +26,7 @@ define go_test -covermode=atomic \ -coverprofile=coverage.out \ -short \ + -race \ -v \ $(if $(GOTEST_RUN),-run "$(GOTEST_RUN)") \ ./... && \ From 5dba1016ac1365191d93ac515acc712824fe7734 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Fri, 29 Mar 2024 16:43:34 -0700 Subject: [PATCH 28/87] test: Fix data race --- pkg/handlers/aws/mutation/suite_test.go | 11 +++++++---- pkg/handlers/docker/mutation/suite_test.go | 11 +++++++---- test/helpers/envtest.go | 3 --- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pkg/handlers/aws/mutation/suite_test.go b/pkg/handlers/aws/mutation/suite_test.go index 20633d531..5188c91c7 100644 --- a/pkg/handlers/aws/mutation/suite_test.go +++ b/pkg/handlers/aws/mutation/suite_test.go @@ -4,6 +4,7 @@ package mutation import ( + "context" "fmt" "testing" @@ -18,12 +19,13 @@ var ( ) func TestMain(m *testing.M) { - setup() - defer teardown() + setupCtx, cancel := context.WithCancel(ctx) + setup(setupCtx) + defer teardown(cancel) m.Run() } -func setup() { +func setup(ctx context.Context) { testEnvConfig := helpers.NewTestEnvironmentConfiguration() var err error testEnv, err = testEnvConfig.Build() @@ -38,7 +40,8 @@ func setup() { }() } -func teardown() { +func teardown(cancel context.CancelFunc) { + cancel() if err := testEnv.Stop(); err != nil { panic(fmt.Sprintf("Failed to stop envtest: %v", err)) } diff --git a/pkg/handlers/docker/mutation/suite_test.go b/pkg/handlers/docker/mutation/suite_test.go index 20633d531..5188c91c7 100644 --- a/pkg/handlers/docker/mutation/suite_test.go +++ b/pkg/handlers/docker/mutation/suite_test.go @@ -4,6 +4,7 @@ package mutation import ( + "context" "fmt" "testing" @@ -18,12 +19,13 @@ var ( ) func TestMain(m *testing.M) { - setup() - defer teardown() + setupCtx, cancel := context.WithCancel(ctx) + setup(setupCtx) + defer teardown(cancel) m.Run() } -func setup() { +func setup(ctx context.Context) { testEnvConfig := helpers.NewTestEnvironmentConfiguration() var err error testEnv, err = testEnvConfig.Build() @@ -38,7 +40,8 @@ func setup() { }() } -func teardown() { +func teardown(cancel context.CancelFunc) { + cancel() if err := testEnv.Stop(); err != nil { panic(fmt.Sprintf("Failed to stop envtest: %v", err)) } diff --git a/test/helpers/envtest.go b/test/helpers/envtest.go index caaa1186d..26257229d 100644 --- a/test/helpers/envtest.go +++ b/test/helpers/envtest.go @@ -132,14 +132,11 @@ func (t *TestEnvironmentConfiguration) Build() (*TestEnvironment, error) { // StartManager starts the test controller against the local API server. func (t *TestEnvironment) StartManager(ctx context.Context) error { - ctx, cancel := context.WithCancel(ctx) - t.cancel = cancel return t.Manager.Start(ctx) } // Stop stops the test environment. func (t *TestEnvironment) Stop() error { - t.cancel() return t.env.Stop() } From 63bca57a7c1c6e81e6dce04af9dbf2c3f8c0e042 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Mon, 1 Apr 2024 08:22:20 -0700 Subject: [PATCH 29/87] test: Fix false negative in httpproxy test (#17) Other patches can change the slice length, causing the previous check to fail, although all correct patches are present. --- .../mutation/httpproxy/tests/generate_patches.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go b/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go index 79cb4f2e1..f3b437ed5 100644 --- a/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go @@ -53,9 +53,16 @@ func TestGeneratePatches( }, RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/files", - ValueMatcher: gomega.HaveLen(2), + Operation: "add", + Path: "/spec/template/spec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/systemd/system/containerd.service.d/http-proxy.conf", + ), + gomega.HaveKeyWithValue( + "path", "/etc/systemd/system/kubelet.service.d/http-proxy.conf", + ), + ), }}, }, capitest.PatchTestDef{ From cffe77ca5184e8d3e16cf46ffbd3e9c3c5567d42 Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Mon, 1 Apr 2024 08:24:17 -0700 Subject: [PATCH 30/87] test: Fix false negative in auditpolicy test (#16) Other patches can change the slice length, causing the previous check to fail, although all correct patches are present. --- .../mutation/auditpolicy/tests/generate_patches.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/handlers/generic/mutation/auditpolicy/tests/generate_patches.go b/pkg/handlers/generic/mutation/auditpolicy/tests/generate_patches.go index 7d7d78ac7..3380817f2 100644 --- a/pkg/handlers/generic/mutation/auditpolicy/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/auditpolicy/tests/generate_patches.go @@ -25,12 +25,16 @@ func TestGeneratePatches( Name: "unset variable", }, capitest.PatchTestDef{ - Name: "http proxy set for KubeadmControlPlaneTemplate", + Name: "auditpolicy set for KubeadmControlPlaneTemplate", RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/files", - ValueMatcher: gomega.HaveLen(1), + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/audit-policy/apiserver-audit-policy.yaml", + ), + ), }, { Operation: "add", Path: "/spec/template/spec/kubeadmConfigSpec/clusterConfiguration", From 7092a4c3ebfbe08d2f50a9a87209f4b5c14ea186 Mon Sep 17 00:00:00 2001 From: Faiq Date: Mon, 1 Apr 2024 09:24:58 -0600 Subject: [PATCH 31/87] fix: set a new name for the tigera cm for that cluster (#14) --- pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go b/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go index 7faf3ff71..a08a686e2 100644 --- a/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go +++ b/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go @@ -204,7 +204,7 @@ func generateTigeraOperatorConfigMap( }, ObjectMeta: metav1.ObjectMeta{ Namespace: cluster.Namespace, - Name: defaultTigeraOperatorConfigMap.Name, + Name: fmt.Sprintf("%s-%s", defaultTigeraOperatorConfigMap.Name, cluster.Name), }, Data: defaultTigeraOperatorConfigMap.Data, BinaryData: defaultTigeraOperatorConfigMap.BinaryData, From 7662213d84cee3de428b20d2cc307263c7753f08 Mon Sep 17 00:00:00 2001 From: faiq Date: Mon, 18 Mar 2024 16:36:01 -0600 Subject: [PATCH 32/87] feat: adds nutanix csi to api --- api/v1alpha1/addon_types.go | 39 ++++++++++++++++++++++----- api/v1alpha1/clusterconfig_types.go | 3 ++- api/v1alpha1/zz_generated.deepcopy.go | 31 ++++++++++++++++++++- 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index c88edf1e7..ba5bc61af 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -137,16 +137,45 @@ func (ClusterAutoscaler) VariableSchema() clusterv1.VariableSchema { type CSIProviders struct { // +optional Providers []CSIProvider `json:"providers,omitempty"` - // +optional - DefaultClassName string `json:"defaultClassName,omitempty"` } type CSIProvider struct { + // +optional Name string `json:"name,omitempty"` + + // +optional + StorageClassConfig *StorageClassConfig `json:"storageClassConfig,omitempty"` +} + +type StorageClassConfig struct { + // +optional + DefaultClassName string `json:"defaultClassName,omitempty"` + + // +optional + Parameters map[string]string `json:"parameters,omitempty"` +} + +func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { + supportedCSIProviders := []string{CSIProviderAWSEBS, CSIProviderNutanix} + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "defaultClassName": { + Type: "string", + Enum: variables.MustMarshalValuesToEnumJSON(supportedCSIProviders...), + }, + "parameters": { + Type: "object", + XPreserveUnknownFields: true, + }, + }, + }, + } } func (CSIProviders) VariableSchema() clusterv1.VariableSchema { - supportedCSIProviders := []string{CSIProviderAWSEBS} + supportedCSIProviders := []string{CSIProviderAWSEBS, CSIProviderNutanix} return clusterv1.VariableSchema{ OpenAPIV3Schema: clusterv1.JSONSchemaProps{ Type: "object", @@ -164,10 +193,6 @@ func (CSIProviders) VariableSchema() clusterv1.VariableSchema { }, }, }, - "defaultClassName": { - Type: "string", - Enum: variables.MustMarshalValuesToEnumJSON(supportedCSIProviders...), - }, }, }, } diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index 7bbbef0d8..75e02b61c 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -18,7 +18,8 @@ const ( CNIProviderCalico = "Calico" CNIProviderCilium = "Cilium" - CSIProviderAWSEBS = "aws-ebs" + CSIProviderAWSEBS = "aws-ebs" + CSIProviderNutanix = "nutanix" CCMProviderAWS = "aws" ) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 01692d804..ea0b63e27 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -254,6 +254,11 @@ func (in *CNI) DeepCopy() *CNI { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CSIProvider) DeepCopyInto(out *CSIProvider) { *out = *in + if in.StorageClassConfig != nil { + in, out := &in.StorageClassConfig, &out.StorageClassConfig + *out = new(StorageClassConfig) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIProvider. @@ -272,7 +277,9 @@ func (in *CSIProviders) DeepCopyInto(out *CSIProviders) { if in.Providers != nil { in, out := &in.Providers, &out.Providers *out = make([]CSIProvider, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } @@ -730,6 +737,28 @@ func (in *SecurityGroup) DeepCopy() *SecurityGroup { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StorageClassConfig) DeepCopyInto(out *StorageClassConfig) { + *out = *in + if in.Parameters != nil { + in, out := &in.Parameters, &out.Parameters + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageClassConfig. +func (in *StorageClassConfig) DeepCopy() *StorageClassConfig { + if in == nil { + return nil + } + out := new(StorageClassConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SubnetSpec) DeepCopyInto(out *SubnetSpec) { *out = *in From e32da135251827f2bdd5dd343f04ff5db7829dbe Mon Sep 17 00:00:00 2001 From: faiq Date: Tue, 19 Mar 2024 12:56:56 -0600 Subject: [PATCH 33/87] feat: minor API tweaks and adds tooling for chart --- api/v1alpha1/addon_types.go | 70 ++- api/v1alpha1/zz_generated.deepcopy.go | 11 +- .../manifests/helm-addon-installation.yaml | 9 + .../manifests/nutanix-csi-configmap.yaml | 543 ++++++++++++++++++ .../values.yaml | 6 + .../kustomize/nutanix-csi/helm-values.yaml | 1 + .../nutanix-csi/kustomization.yaml.tmpl | 20 + hack/addons/update-nutanix-csi.sh | 42 ++ make/addons.mk | 17 + 9 files changed, 706 insertions(+), 13 deletions(-) create mode 100644 charts/capi-runtime-extensions/templates/csi/nutanix/manifests/helm-addon-installation.yaml create mode 100644 charts/capi-runtime-extensions/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml create mode 100644 hack/addons/kustomize/nutanix-csi/helm-values.yaml create mode 100644 hack/addons/kustomize/nutanix-csi/kustomization.yaml.tmpl create mode 100755 hack/addons/update-nutanix-csi.sh diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index ba5bc61af..025570b9c 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -4,6 +4,7 @@ package v1alpha1 import ( + corev1 "k8s.io/api/core/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables" @@ -137,6 +138,9 @@ func (ClusterAutoscaler) VariableSchema() clusterv1.VariableSchema { type CSIProviders struct { // +optional Providers []CSIProvider `json:"providers,omitempty"` + + // +optional + DefaultStorageClassName string `json:"defaultStorageClassName,omitempty"` } type CSIProvider struct { @@ -144,12 +148,18 @@ type CSIProvider struct { Name string `json:"name,omitempty"` // +optional - StorageClassConfig *StorageClassConfig `json:"storageClassConfig,omitempty"` + StorageClassConfig []StorageClassConfig `json:"storageClassConfig,omitempty"` + + // +optional + Strategy AddonStrategy `json:"strategy,omitempty"` + + // +optional + Credentials *corev1.SecretReference `json:"credentials,omitempty"` } type StorageClassConfig struct { // +optional - DefaultClassName string `json:"defaultClassName,omitempty"` + Name string `json:"name,omitempty"` // +optional Parameters map[string]string `json:"parameters,omitempty"` @@ -161,7 +171,7 @@ func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { OpenAPIV3Schema: clusterv1.JSONSchemaProps{ Type: "object", Properties: map[string]clusterv1.JSONSchemaProps{ - "defaultClassName": { + "name": { Type: "string", Enum: variables.MustMarshalValuesToEnumJSON(supportedCSIProviders...), }, @@ -174,6 +184,44 @@ func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { } } +func (CSIProvider) VariableSchema() clusterv1.VariableSchema { + supportedCSIProviders := []string{CSIProviderAWSEBS, CSIProviderNutanix} + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "name": { + Description: "Name of the CSI Provider", + Type: "string", + Enum: variables.MustMarshalValuesToEnumJSON( + supportedCSIProviders...), + }, + "strategy": { + Description: "Addon strategy used to deploy the CSI provider to the workload cluster", + Type: "string", + Enum: variables.MustMarshalValuesToEnumJSON( + AddonStrategyClusterResourceSet, + AddonStrategyHelmAddon, + ), + }, + "credentials": { + Type: "object", + Description: "The reference to any secret used by the CSI Provider.", + Properties: map[string]clusterv1.JSONSchemaProps{ + "name": { + Type: "string", + }, + "namespace": { + Type: "string", + }, + }, + }, + "storageClassConfig": StorageClassConfig{}.VariableSchema().OpenAPIV3Schema, + }, + }, + } +} + func (CSIProviders) VariableSchema() clusterv1.VariableSchema { supportedCSIProviders := []string{CSIProviderAWSEBS, CSIProviderNutanix} return clusterv1.VariableSchema{ @@ -183,16 +231,16 @@ func (CSIProviders) VariableSchema() clusterv1.VariableSchema { "providers": { Type: "array", Items: &clusterv1.JSONSchemaProps{ - Type: "object", - Properties: map[string]clusterv1.JSONSchemaProps{ - "name": { - Type: "string", - Enum: variables.MustMarshalValuesToEnumJSON( - supportedCSIProviders...), - }, - }, + Type: "object", + Properties: CSIProvider{}.VariableSchema().OpenAPIV3Schema.Properties, }, }, + "defaultStorageClassName": { + Type: "string", + Description: "Storage Class that will be made default for the cluster.", + Enum: variables.MustMarshalValuesToEnumJSON( + supportedCSIProviders...), + }, }, }, } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ea0b63e27..29687e997 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -256,8 +256,15 @@ func (in *CSIProvider) DeepCopyInto(out *CSIProvider) { *out = *in if in.StorageClassConfig != nil { in, out := &in.StorageClassConfig, &out.StorageClassConfig - *out = new(StorageClassConfig) - (*in).DeepCopyInto(*out) + *out = make([]StorageClassConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Credentials != nil { + in, out := &in.Credentials, &out.Credentials + *out = new(v1.SecretReference) + **out = **in } } diff --git a/charts/capi-runtime-extensions/templates/csi/nutanix/manifests/helm-addon-installation.yaml b/charts/capi-runtime-extensions/templates/csi/nutanix/manifests/helm-addon-installation.yaml new file mode 100644 index 000000000..a92e3ff95 --- /dev/null +++ b/charts/capi-runtime-extensions/templates/csi/nutanix/manifests/helm-addon-installation.yaml @@ -0,0 +1,9 @@ +{{- if .Values.hooks.csi.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.create }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: '{{ .Values.hooks.csi.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.name }}' +data: + values.yaml: |- + createSecret: false +{{- end -}} diff --git a/charts/capi-runtime-extensions/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml b/charts/capi-runtime-extensions/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml new file mode 100644 index 000000000..03c2539b2 --- /dev/null +++ b/charts/capi-runtime-extensions/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml @@ -0,0 +1,543 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +#================================================================= +# DO NOT EDIT THIS FILE +# IT HAS BEEN GENERATED BY /hack/addons/update-nutanix-csi.sh +#================================================================= +apiVersion: v1 +data: + nutanix-csi.yaml: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: nutanix-csi-controller + namespace: kube-system + --- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: nutanix-csi-node + namespace: kube-system + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: nutanix-csi-controller-role + namespace: nutanix-system + rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - apiGroups: + - "" + resources: + - persistentvolumes + verbs: + - get + - list + - watch + - create + - delete + - update + - patch + - apiGroups: + - "" + resources: + - persistentvolumeclaims + verbs: + - get + - list + - watch + - update + - apiGroups: + - "" + resources: + - persistentvolumeclaims/status + verbs: + - update + - patch + - apiGroups: + - storage.k8s.io + resources: + - storageclasses + verbs: + - get + - list + - watch + - apiGroups: + - "" + resources: + - events + verbs: + - list + - watch + - create + - update + - patch + - apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshotclasses + verbs: + - get + - list + - watch + - apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshots + verbs: + - get + - list + - watch + - update + - apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshots/status + verbs: + - update + - apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshotcontents + verbs: + - create + - get + - list + - watch + - update + - delete + - patch + - apiGroups: + - snapshot.storage.k8s.io + resources: + - volumesnapshotcontents/status + verbs: + - update + - patch + - apiGroups: + - storage.k8s.io + resources: + - csinodes + verbs: + - get + - list + - watch + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - create + - delete + - update + - patch + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + metadata: + name: nutanix-csi-node-role + namespace: nutanix-system + rules: + - apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - update + - apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - apiGroups: + - "" + resources: + - persistentvolumes + verbs: + - get + - list + - watch + - update + - apiGroups: + - storage.k8s.io + resources: + - volumeattachments + verbs: + - get + - list + - watch + - update + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: nutanix-csi-controller-binding + namespace: nutanix-system + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nutanix-csi-controller-role + subjects: + - kind: ServiceAccount + name: nutanix-csi-controller + namespace: kube-system + --- + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + metadata: + name: nutanix-csi-node-binding + namespace: nutanix-system + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: nutanix-csi-node-role + subjects: + - kind: ServiceAccount + name: nutanix-csi-node + namespace: kube-system + --- + apiVersion: v1 + kind: Service + metadata: + labels: + app: nutanix-csi-metrics + name: nutanix-csi-metrics + namespace: kube-system + spec: + ports: + - name: provisioner + port: 9809 + protocol: TCP + targetPort: 9809 + - name: resizer + port: 9810 + protocol: TCP + targetPort: 9810 + selector: + app: nutanix-csi-controller + type: ClusterIP + --- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: nutanix-csi-controller + namespace: kube-system + spec: + replicas: 2 + selector: + matchLabels: + app: nutanix-csi-controller + strategy: + rollingUpdate: + maxSurge: 0 + maxUnavailable: 1 + type: RollingUpdate + template: + metadata: + labels: + app: nutanix-csi-controller + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - podAffinityTerm: + labelSelector: + matchLabels: + app: nutanix-csi-controller + topologyKey: kubernetes.io/hostname + weight: 100 + containers: + - args: + - --csi-address=$(ADDRESS) + - --timeout=60s + - --worker-threads=16 + - --extra-create-metadata=true + - --default-fstype=ext4 + - --http-endpoint=:9809 + - --v=2 + - --leader-election=true + env: + - name: ADDRESS + value: /var/lib/csi/sockets/pluginproxy/csi.sock + image: registry.k8s.io/sig-storage/csi-provisioner:v3.6.2 + imagePullPolicy: IfNotPresent + name: csi-provisioner + resources: + requests: + cpu: 100m + memory: 200Mi + volumeMounts: + - mountPath: /var/lib/csi/sockets/pluginproxy/ + name: socket-dir + - args: + - --v=2 + - --csi-address=$(ADDRESS) + - --timeout=60s + - --leader-election=true + - --handle-volume-inuse-error=false + - --http-endpoint=:9810 + env: + - name: ADDRESS + value: /var/lib/csi/sockets/pluginproxy/csi.sock + image: registry.k8s.io/sig-storage/csi-resizer:v1.9.2 + imagePullPolicy: IfNotPresent + name: csi-resizer + resources: + requests: + cpu: 5m + memory: 30Mi + volumeMounts: + - mountPath: /var/lib/csi/sockets/pluginproxy/ + name: socket-dir + - args: + - --csi-address=$(ADDRESS) + - --leader-election=true + - --logtostderr=true + - --timeout=300s + env: + - name: ADDRESS + value: /csi/csi.sock + image: registry.k8s.io/sig-storage/csi-snapshotter:v3.0.3 + imagePullPolicy: IfNotPresent + name: csi-snapshotter + resources: + requests: + cpu: 5m + memory: 30Mi + volumeMounts: + - mountPath: /csi + name: socket-dir + - args: + - --endpoint=$(CSI_ENDPOINT) + - --nodeid=$(NODE_ID) + - --drivername=csi.nutanix.com + env: + - name: CSI_ENDPOINT + value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock + - name: NODE_ID + valueFrom: + fieldRef: + fieldPath: spec.nodeName + image: quay.io/karbon/ntnx-csi:v2.6.6 + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: http-endpoint + initialDelaySeconds: 10 + periodSeconds: 2 + timeoutSeconds: 3 + name: nutanix-csi-plugin + ports: + - containerPort: 9807 + name: http-endpoint + protocol: TCP + resources: + requests: + cpu: 100m + memory: 200Mi + securityContext: + allowPrivilegeEscalation: true + privileged: true + volumeMounts: + - mountPath: /var/lib/csi/sockets/pluginproxy/ + name: socket-dir + - mountPath: /host + name: root-dir + - args: + - --csi-address=/csi/csi.sock + - --http-endpoint=:9807 + image: registry.k8s.io/sig-storage/livenessprobe:v2.11.0 + imagePullPolicy: IfNotPresent + name: liveness-probe + resources: + requests: + cpu: 5m + memory: 20Mi + volumeMounts: + - mountPath: /csi + name: socket-dir + hostNetwork: true + priorityClassName: system-cluster-critical + serviceAccount: nutanix-csi-controller + volumes: + - emptyDir: {} + name: socket-dir + - hostPath: + path: / + type: Directory + name: root-dir + --- + apiVersion: apps/v1 + kind: DaemonSet + metadata: + name: nutanix-csi-node + namespace: kube-system + spec: + selector: + matchLabels: + app: nutanix-csi-node + template: + metadata: + labels: + app: nutanix-csi-node + spec: + containers: + - args: + - --v=2 + - --csi-address=$(ADDRESS) + - --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH) + env: + - name: ADDRESS + value: /csi/csi.sock + - name: DRIVER_REG_SOCK_PATH + value: /var/lib/kubelet/plugins/csi.nutanix.com/csi.sock + - name: KUBE_NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + image: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.9.1 + imagePullPolicy: IfNotPresent + name: driver-registrar + resources: + requests: + cpu: 100m + memory: 20Mi + volumeMounts: + - mountPath: /csi/ + name: plugin-dir + - mountPath: /registration + name: registration-dir + - args: + - --endpoint=$(CSI_ENDPOINT) + - --nodeid=$(NODE_ID) + - --drivername=csi.nutanix.com + env: + - name: CSI_ENDPOINT + value: unix:///csi/csi.sock + - name: NODE_ID + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: NODE_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + image: quay.io/karbon/ntnx-csi:v2.6.6 + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /healthz + port: http-endpoint + initialDelaySeconds: 10 + periodSeconds: 2 + timeoutSeconds: 3 + name: nutanix-csi-node + ports: + - containerPort: 9808 + name: http-endpoint + protocol: TCP + resources: + requests: + cpu: 100m + memory: 200Mi + securityContext: + allowPrivilegeEscalation: true + privileged: true + volumeMounts: + - mountPath: /csi + name: plugin-dir + - mountPath: /var/lib/kubelet + mountPropagation: Bidirectional + name: pods-mount-dir + - mountPath: /dev + name: device-dir + - mountPath: /etc/iscsi + name: iscsi-dir + - mountPath: /host + mountPropagation: Bidirectional + name: root-dir + - args: + - --csi-address=/csi/csi.sock + - --http-endpoint=:9808 + image: registry.k8s.io/sig-storage/livenessprobe:v2.11.0 + imagePullPolicy: IfNotPresent + name: liveness-probe + resources: + requests: + cpu: 5m + memory: 20Mi + volumeMounts: + - mountPath: /csi + name: plugin-dir + hostNetwork: true + priorityClassName: system-cluster-critical + serviceAccount: nutanix-csi-node + volumes: + - hostPath: + path: /var/lib/kubelet/plugins_registry/ + type: Directory + name: registration-dir + - hostPath: + path: /var/lib/kubelet/plugins/csi.nutanix.com/ + type: DirectoryOrCreate + name: plugin-dir + - hostPath: + path: /var/lib/kubelet + type: Directory + name: pods-mount-dir + - hostPath: + path: /dev + name: device-dir + - hostPath: + path: /etc/iscsi + type: Directory + name: iscsi-dir + - hostPath: + path: / + type: Directory + name: root-dir + updateStrategy: + rollingUpdate: + maxUnavailable: 10% + type: RollingUpdate + --- + apiVersion: storage.k8s.io/v1 + kind: CSIDriver + metadata: + name: csi.nutanix.com + spec: + attachRequired: false + podInfoOnMount: true +kind: ConfigMap +metadata: + creationTimestamp: null + name: nutanix-csi diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.yaml b/charts/cluster-api-runtime-extensions-nutanix/values.yaml index 81576e8ba..9a2a4d7ba 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/values.yaml @@ -35,6 +35,12 @@ hooks: defaultValueTemplateConfigMap: create: true name: default-cilium-cni-helm-values-template + csi: + nutanix: + helmAddonStrategy: + defaultValueTemplateConfigMap: + create: true + name: default-nutanix-csi-helm-values-template nfd: crsStrategy: defaultInstallationConfigMap: diff --git a/hack/addons/kustomize/nutanix-csi/helm-values.yaml b/hack/addons/kustomize/nutanix-csi/helm-values.yaml new file mode 100644 index 000000000..a16eb51a5 --- /dev/null +++ b/hack/addons/kustomize/nutanix-csi/helm-values.yaml @@ -0,0 +1 @@ +createSecret: false diff --git a/hack/addons/kustomize/nutanix-csi/kustomization.yaml.tmpl b/hack/addons/kustomize/nutanix-csi/kustomization.yaml.tmpl new file mode 100644 index 000000000..bc838e438 --- /dev/null +++ b/hack/addons/kustomize/nutanix-csi/kustomization.yaml.tmpl @@ -0,0 +1,20 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +metadata: + name: nutanix-csi-kustomize + +namespace: kube-system + +helmCharts: +- name: nutanix-csi-storage + repo: https://nutanix.github.io/helm/ + releaseName: nutanix-csi-storage + version: ${NUTANIX_CSI_CHART_VERSION} + valuesFile: helm-values.yaml + includeCRDs: true + skipTests: true + namespace: nutanix-system diff --git a/hack/addons/update-nutanix-csi.sh b/hack/addons/update-nutanix-csi.sh new file mode 100755 index 000000000..5ce837e21 --- /dev/null +++ b/hack/addons/update-nutanix-csi.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly SCRIPT_DIR + +# shellcheck source=hack/common.sh +source "${SCRIPT_DIR}/../common.sh" + +if [ -z "${NUTANIX_CSI_CHART_VERSION:-}" ]; then + echo "Missing environment variable: NUTANIX_CSI_CHART_VERSION" + exit 1 +fi + +ASSETS_DIR="$(mktemp -d -p "${TMPDIR:-/tmp}")" +readonly ASSETS_DIR +trap_add "rm -rf ${ASSETS_DIR}" EXIT + +readonly FILE_NAME="nutanix-csi.yaml" + +readonly KUSTOMIZE_BASE_DIR="${SCRIPT_DIR}/kustomize/nutanix-csi" +mkdir -p "${ASSETS_DIR}/nutanix-csi" +envsubst -no-unset <"${KUSTOMIZE_BASE_DIR}/kustomization.yaml.tmpl" >"${ASSETS_DIR}/nutanix-csi/kustomization.yaml" +cp -r "${KUSTOMIZE_BASE_DIR}"/*.yaml "${ASSETS_DIR}/nutanix-csi/" + +kustomize build --enable-helm "${ASSETS_DIR}/nutanix-csi/" >"${ASSETS_DIR}/${FILE_NAME}" + +kubectl create configmap nutanix-csi --dry-run=client --output yaml \ + --from-file "${ASSETS_DIR}/${FILE_NAME}" \ + >"${ASSETS_DIR}/nutanix-csi-configmap.yaml" + +# add warning not to edit file directly +cat <"${GIT_REPO_ROOT}/charts/capi-runtime-extensions/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml" +$(cat "${GIT_REPO_ROOT}/hack/license-header.yaml.txt") + +#================================================================= +# DO NOT EDIT THIS FILE +# IT HAS BEEN GENERATED BY /hack/addons/update-nutanix-csi.sh +#================================================================= +$(cat "${ASSETS_DIR}/nutanix-csi-configmap.yaml") +EOF diff --git a/make/addons.mk b/make/addons.mk index 85ad54575..4cc4d8f42 100644 --- a/make/addons.mk +++ b/make/addons.mk @@ -7,6 +7,7 @@ export NODE_FEATURE_DISCOVERY_VERSION := $(shell goprintconst -file pkg/handlers export CLUSTER_AUTOSCALER_VERSION := 9.35.0 export AWS_CSI_SNAPSHOT_CONTROLLER_VERSION := v6.3.3 export AWS_EBS_CSI_CHART_VERSION := v2.28.1 +<<<<<<< HEAD # a map of AWS CCM versions export AWS_CCM_VERSION_127 := v1.27.1 export AWS_CCM_CHART_VERSION_127 := 0.0.8 @@ -15,6 +16,17 @@ export AWS_CCM_CHART_VERSION_128 := 0.0.8 .PHONY: addons.sync addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler aws-ebs-csi aws-ccm.127 aws-ccm.128) +======= +export NUTANIX_CSI_CHART_VERSION := v2.6.6 +# a map of AWS CPI versions +export AWS_CPI_VERSION_127 := v1.27.1 +export AWS_CPI_CHART_VERSION_127 := 0.0.8 +export AWS_CPI_VERSION_128 := v1.28.1 +export AWS_CPI_CHART_VERSION_128 := 0.0.8 + +.PHONY: addons.sync +addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler aws-ebs-csi aws-cpi.127 aws-cpi.128 nutanix-csi) +>>>>>>> 625d067 (feat: minor API tweaks and adds tooling for chart) .PHONY: update-addon.calico update-addon.calico: ; $(info $(M) updating calico manifests) @@ -39,3 +51,8 @@ update-addon.aws-ebs-csi: ; $(info $(M) updating aws ebs csi manifests) .PHONY: update-addon.aws-ccm.% update-addon.aws-ccm.%: ; $(info $(M) updating aws ccm $* manifests) ./hack/addons/update-aws-ccm.sh $(AWS_CCM_VERSION_$*) $(AWS_CCM_CHART_VERSION_$*) + +.PHONY: update-addon.nutanix-csi +update-addon.nutanix-csi: ; $(info $(M) updating nutanix csi manifests) + ./hack/addons/update-nutanix-csi.sh + From d9f9e3ed0ee275aab0ab02ea0f31e9bf9b75d34b Mon Sep 17 00:00:00 2001 From: faiq Date: Wed, 20 Mar 2024 17:43:54 -0600 Subject: [PATCH 34/87] feat: more api changes --- api/v1alpha1/addon_types.go | 101 ++++++++++---- api/v1alpha1/zz_generated.deepcopy.go | 20 +++ .../manifests/aws-ebs-csi-configmap.yaml | 10 -- .../kustomize/aws-ebs-csi/helm-values.yaml | 7 - .../generic/lifecycle/csi/aws-ebs/handler.go | 124 ++++++++++++++++-- pkg/handlers/generic/lifecycle/csi/handler.go | 77 +---------- 6 files changed, 216 insertions(+), 123 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 025570b9c..101ef8d27 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -10,6 +10,18 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables" ) +const ( + AddonStrategyClusterResourceSet AddonStrategy = "ClusterResourceSet" + AddonStrategyHelmAddon AddonStrategy = "HelmAddon" + + VolumeBindingImmediate string = "Immmediate" + VolumeBindingWaitForFirstConsumer string = "WaitForFirstConsumer" + + VolumeReclaimRecycle string = "Recycle" + VolumeReclaimDelete string = "Delete" + VolumeReclaimRetain string = "Retain" +) + type Addons struct { // +optional CNI *CNI `json:"cni,omitempty"` @@ -45,11 +57,6 @@ func (Addons) VariableSchema() clusterv1.VariableSchema { type AddonStrategy string -const ( - AddonStrategyClusterResourceSet AddonStrategy = "ClusterResourceSet" - AddonStrategyHelmAddon AddonStrategy = "HelmAddon" -) - // CNI required for providing CNI configuration. type CNI struct { // +optional @@ -135,50 +142,76 @@ func (ClusterAutoscaler) VariableSchema() clusterv1.VariableSchema { } } +type DefaultStorage struct { + ProviderName string `json:"providerName"` + StorageClassConfigName string `json:"storageClassConfigName"` +} + type CSIProviders struct { // +optional Providers []CSIProvider `json:"providers,omitempty"` - // +optional - DefaultStorageClassName string `json:"defaultStorageClassName,omitempty"` + DefaultStorage *DefaultStorage `json:"defaultStorage,omitempty"` } type CSIProvider struct { - // +optional - Name string `json:"name,omitempty"` + Name string `json:"name"` // +optional StorageClassConfig []StorageClassConfig `json:"storageClassConfig,omitempty"` - // +optional - Strategy AddonStrategy `json:"strategy,omitempty"` + Strategy AddonStrategy `json:"strategy"` // +optional Credentials *corev1.SecretReference `json:"credentials,omitempty"` } type StorageClassConfig struct { - // +optional - Name string `json:"name,omitempty"` + Name string `json:"name"` // +optional Parameters map[string]string `json:"parameters,omitempty"` + + // +optional + ReclaimPolicy string `json:"reclaimPolicy,omitempty"` + + // +optional + VolumeBindingMode string `json:"volumeBindingMode,omitempty"` } func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { supportedCSIProviders := []string{CSIProviderAWSEBS, CSIProviderNutanix} + supportedReclaimPolicies := []string{ + VolumeReclaimRecycle, + VolumeReclaimDelete, + VolumeReclaimRetain, + } + supportedBindingModes := []string{ + VolumeBindingImmediate, + VolumeBindingWaitForFirstConsumer, + } return clusterv1.VariableSchema{ OpenAPIV3Schema: clusterv1.JSONSchemaProps{ Type: "object", Properties: map[string]clusterv1.JSONSchemaProps{ "name": { - Type: "string", - Enum: variables.MustMarshalValuesToEnumJSON(supportedCSIProviders...), + Type: "string", + Description: "Name of storage class config.", + Enum: variables.MustMarshalValuesToEnumJSON(supportedCSIProviders...), }, "parameters": { Type: "object", + Description: "Parameters passed into the storage class object.", XPreserveUnknownFields: true, }, + "reclaimPolicy": { + Type: "string", + Enum: variables.MustMarshalValuesToEnumJSON(supportedReclaimPolicies...), + }, + "volumeBindingMode": { + Type: "string", + Enum: variables.MustMarshalValuesToEnumJSON(supportedBindingModes...), + }, }, }, } @@ -216,14 +249,41 @@ func (CSIProvider) VariableSchema() clusterv1.VariableSchema { }, }, }, - "storageClassConfig": StorageClassConfig{}.VariableSchema().OpenAPIV3Schema, + "storageClassConfig": { + Type: "array", + Items: &clusterv1.JSONSchemaProps{ + Type: "object", + Properties: StorageClassConfig{}.VariableSchema().OpenAPIV3Schema.Properties, + }, + }, }, }, } } -func (CSIProviders) VariableSchema() clusterv1.VariableSchema { +func (DefaultStorage) VariableSchema() clusterv1.VariableSchema { supportedCSIProviders := []string{CSIProviderAWSEBS, CSIProviderNutanix} + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Type: "object", + Description: "A tuple of provider name and storage class ", + Properties: map[string]clusterv1.JSONSchemaProps{ + "providerName": { + Type: "string", + Description: "Name of the CSI Provider for the default storage class", + Enum: variables.MustMarshalValuesToEnumJSON( + supportedCSIProviders...), + }, + "storageClassConfigName": { + Type: "string", + Description: "Name of storage class config in any of the provider objects", + }, + }, + }, + } +} + +func (CSIProviders) VariableSchema() clusterv1.VariableSchema { return clusterv1.VariableSchema{ OpenAPIV3Schema: clusterv1.JSONSchemaProps{ Type: "object", @@ -235,12 +295,7 @@ func (CSIProviders) VariableSchema() clusterv1.VariableSchema { Properties: CSIProvider{}.VariableSchema().OpenAPIV3Schema.Properties, }, }, - "defaultStorageClassName": { - Type: "string", - Description: "Storage Class that will be made default for the cluster.", - Enum: variables.MustMarshalValuesToEnumJSON( - supportedCSIProviders...), - }, + "defaultStorage": DefaultStorage{}.VariableSchema().OpenAPIV3Schema, }, }, } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 29687e997..d55db46f9 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -288,6 +288,11 @@ func (in *CSIProviders) DeepCopyInto(out *CSIProviders) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.DefaultStorage != nil { + in, out := &in.DefaultStorage, &out.DefaultStorage + *out = new(DefaultStorage) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIProviders. @@ -372,6 +377,21 @@ func (in *ClusterConfigSpec) DeepCopy() *ClusterConfigSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DefaultStorage) DeepCopyInto(out *DefaultStorage) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefaultStorage. +func (in *DefaultStorage) DeepCopy() *DefaultStorage { + if in == nil { + return nil + } + out := new(DefaultStorage) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DockerNodeSpec) DeepCopyInto(out *DockerNodeSpec) { *out = *in diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/csi/aws-ebs/manifests/aws-ebs-csi-configmap.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/csi/aws-ebs/manifests/aws-ebs-csi-configmap.yaml index 09e7ce18e..5529a361f 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/csi/aws-ebs/manifests/aws-ebs-csi-configmap.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/csi/aws-ebs/manifests/aws-ebs-csi-configmap.yaml @@ -8,16 +8,6 @@ apiVersion: v1 data: aws-ebs-csi.yaml: | - apiVersion: storage.k8s.io/v1 - kind: StorageClass - metadata: - name: ebs-sc - parameters: - csi.storage.k8s.io/fstype: ext4 - type: gp3 - provisioner: ebs.csi.aws.com - volumeBindingMode: WaitForFirstConsumer - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: diff --git a/hack/addons/kustomize/aws-ebs-csi/helm-values.yaml b/hack/addons/kustomize/aws-ebs-csi/helm-values.yaml index d1cf5632d..33bb95823 100644 --- a/hack/addons/kustomize/aws-ebs-csi/helm-values.yaml +++ b/hack/addons/kustomize/aws-ebs-csi/helm-values.yaml @@ -27,10 +27,3 @@ node: sidecars: snapshotter: forceEnable: true -storageClasses: -- metadata: - name: ebs-sc - volumeBindingMode: WaitForFirstConsumer - parameters: - csi.storage.k8s.io/fstype: ext4 - type: gp3 diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 0d75a2212..25ea8f42e 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -7,16 +7,38 @@ import ( "context" "fmt" + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" + lifecycleutils "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/lifecycle/utils" "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) +const ( + variableRootName = "csi" + kindStorageClass = "StorageClass" + awsEBSProvisionerName = "ebs.csi.aws.com" +) + +var ( + defualtStorageClassKey = "storageclass.kubernetes.io/is-default-class" + defaultStorageClassMap = map[string]string{ + defualtStorageClassKey: "true", + } + defaultParams = map[string]string{ + "csi.storage.k8s.io/fstype": "ext4", + "type": "gp3", + } +) + type AWSEBSConfig struct { *options.GlobalOptions defaultAWSEBSConfigMapName string @@ -46,10 +68,83 @@ func New( } } -func (a *AWSEBS) EnsureCSIConfigMapForCluster( +func (a *AWSEBS) Apply( ctx context.Context, - cluster *clusterv1.Cluster, -) (*corev1.ConfigMap, error) { + provider v1alpha1.CSIProvider, + defaultStorageConfig *v1alpha1.DefaultStorage, + req *runtimehooksv1.AfterControlPlaneInitializedRequest, +) error { + strategy := provider.Strategy + switch strategy { + case v1alpha1.AddonStrategyClusterResourceSet: + err := a.handleCRSApply(ctx, defaultStorageConfig, req) + if err != nil { + return err + } + case v1alpha1.AddonStrategyHelmAddon: + fallthrough + default: + return fmt.Errorf("Stategy %s not implemented", strategy) + } + return a.createStorageClasses(ctx, provider.StorageClassConfig, defaultStorageConfig) +} + +func (a *AWSEBS) createStorageClasses(ctx context.Context, + configs []v1alpha1.StorageClassConfig, + defaultStorageConfig *v1alpha1.DefaultStorage, +) error { + for _, c := range configs { + var volumeBindingMode *storagev1.VolumeBindingMode + switch c.VolumeBindingMode { + case v1alpha1.VolumeBindingImmediate: + volumeBindingMode = ptr.To(storagev1.VolumeBindingImmediate) + case v1alpha1.VolumeBindingWaitForFirstConsumer: + fallthrough + default: + volumeBindingMode = ptr.To(storagev1.VolumeBindingWaitForFirstConsumer) + } + var reclaimPolicy *corev1.PersistentVolumeReclaimPolicy + switch c.ReclaimPolicy { + case v1alpha1.VolumeReclaimRecycle: + reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimRecycle) + case v1alpha1.VolumeReclaimDelete: + reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimDelete) + case v1alpha1.VolumeReclaimRetain: + reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimRetain) + } + params := defaultParams + if c.Parameters != nil { + params = c.DeepCopy().Parameters + } + setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && + v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName + sc := storagev1.StorageClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: c.Name, + Namespace: a.config.DefaultsNamespace(), + }, + Provisioner: awsEBSProvisionerName, + Parameters: params, + VolumeBindingMode: volumeBindingMode, + ReclaimPolicy: reclaimPolicy, + } + if setAsDefault { + sc.ObjectMeta.Annotations = defaultStorageClassMap + } + if err := client.ServerSideApply(ctx, a.client, &sc); err != nil { + return fmt.Errorf( + "failed to create storage class %w", + err, + ) + } + } + return nil +} + +func (a *AWSEBS) handleCRSApply(ctx context.Context, + defaultStorageConfig *v1alpha1.DefaultStorage, + req *runtimehooksv1.AfterControlPlaneInitializedRequest, +) error { awsEBSCSIConfigMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: a.config.DefaultsNamespace(), @@ -61,22 +156,31 @@ func (a *AWSEBS) EnsureCSIConfigMapForCluster( ) err := a.client.Get(ctx, defaultAWSEBSCSIConfigMapObjName, awsEBSCSIConfigMap) if err != nil { - return nil, fmt.Errorf( + return fmt.Errorf( "failed to retrieve default AWS EBS CSI manifests ConfigMap %q: %w", defaultAWSEBSCSIConfigMapObjName, err, ) } - - awsEBSConfigMap := generateAWSEBSCSIConfigMap(awsEBSCSIConfigMap, cluster) - if err := client.ServerSideApply(ctx, a.client, awsEBSConfigMap); err != nil { - return nil, fmt.Errorf( + cluster := req.Cluster + cm := generateAWSEBSCSIConfigMap(awsEBSCSIConfigMap, &cluster) + if err := client.ServerSideApply(ctx, a.client, cm); err != nil { + return fmt.Errorf( "failed to apply AWS EBS CSI manifests ConfigMap: %w", err, ) } - - return awsEBSConfigMap, nil + err = lifecycleutils.EnsureCRSForClusterFromConfigMaps( + ctx, + cm.Name, + a.client, + &req.Cluster, + cm, + ) + if err != nil { + return err + } + return nil } func generateAWSEBSCSIConfigMap( diff --git a/pkg/handlers/generic/lifecycle/csi/handler.go b/pkg/handlers/generic/lifecycle/csi/handler.go index c084c05f1..80f1c6372 100644 --- a/pkg/handlers/generic/lifecycle/csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/handler.go @@ -7,11 +7,7 @@ import ( "context" "fmt" - "github.com/go-logr/logr" - corev1 "k8s.io/api/core/v1" - clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" - utilyaml "sigs.k8s.io/cluster-api/util/yaml" ctrl "sigs.k8s.io/controller-runtime" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -20,23 +16,14 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" - lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" ) const ( variableRootName = "csi" - kindStorageClass = "StorageClass" -) - -var ( - defualtStorageClassKey = "storageclass.kubernetes.io/is-default-class" - defaultStorageClassMap = map[string]string{ - defualtStorageClassKey: "true", - } ) type CSIProvider interface { - EnsureCSIConfigMapForCluster(context.Context, *clusterv1.Cluster) (*corev1.ConfigMap, error) + Apply(context.Context, v1alpha1.CSIProvider, *v1alpha1.DefaultStorage, *runtimehooksv1.AfterControlPlaneInitializedRequest) error } type CSIHandler struct { @@ -117,73 +104,17 @@ func (c *CSIHandler) AfterControlPlaneInitialized( ) continue } - log.Info(fmt.Sprintf("Creating config map for csi provider %s", provider)) - cm, err := handler.EnsureCSIConfigMapForCluster(ctx, &req.Cluster) + log.Info(fmt.Sprintf("Creating csi provider %s", provider)) + err = handler.Apply(ctx, provider, csiProviders.DefaultStorage, req) if err != nil { log.Error( err, fmt.Sprintf( - "failed to ensure %s csi driver installation manifests ConfigMap", + "failed to create %s csi driver object.", provider.Name, ), ) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) } - if cm != nil { - if provider.Name == csiProviders.DefaultClassName { - log.Info("Setting default storage class ", provider, csiProviders.DefaultClassName) - err = setDefaultStorageClass(log, cm) - if err != nil { - log.Error(err, "failed to set default storage class") - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - } - if err := c.client.Update(ctx, cm); err != nil { - log.Error(err, "failed to apply default storage class annotation to configmap") - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - } - } - err = lifecycleutils.EnsureCRSForClusterFromConfigMaps( - ctx, - cm.Name, - c.client, - &req.Cluster, - cm, - ) - if err != nil { - log.Error( - err, - fmt.Sprintf( - "failed to ensure %s csi driver installation manifests ConfigMap", - provider.Name, - ), - ) - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - } - } - } -} - -func setDefaultStorageClass( - log logr.Logger, - cm *corev1.ConfigMap, -) error { - for k, contents := range cm.Data { - objs, err := utilyaml.ToUnstructured([]byte(contents)) - if err != nil { - log.Error(err, "failed to parse yaml") - continue - } - for i := range objs { - obj := objs[i] - if obj.GetKind() == kindStorageClass { - obj.SetAnnotations(defaultStorageClassMap) - } - } - rawObjs, err := utilyaml.FromUnstructured(objs) - if err != nil { - return fmt.Errorf("failed to convert unstructured objects back to string %w", err) - } - cm.Data[k] = string(rawObjs) } - return nil } From 39cf44f06077970c8ece4c51aee0e20eb49b8a67 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 21 Mar 2024 10:46:29 -0600 Subject: [PATCH 35/87] fix: adds proper permissions and api fixes --- api/v1alpha1/addon_types.go | 2 - .../templates/role.yaml | 10 ++ .../clusterautoscaler/strategy_helmaddon.go | 32 +---- .../generic/lifecycle/csi/aws-ebs/handler.go | 7 +- pkg/handlers/generic/lifecycle/csi/doc.go | 1 + .../lifecycle/csi/nutanix-csi/handler.go | 135 ++++++++++++++++++ pkg/handlers/generic/lifecycle/handlers.go | 13 +- pkg/handlers/generic/lifecycle/utils/utils.go | 26 ++++ 8 files changed, 193 insertions(+), 33 deletions(-) create mode 100644 pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 101ef8d27..df4ff06bb 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -180,7 +180,6 @@ type StorageClassConfig struct { } func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { - supportedCSIProviders := []string{CSIProviderAWSEBS, CSIProviderNutanix} supportedReclaimPolicies := []string{ VolumeReclaimRecycle, VolumeReclaimDelete, @@ -197,7 +196,6 @@ func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { "name": { Type: "string", Description: "Name of storage class config.", - Enum: variables.MustMarshalValuesToEnumJSON(supportedCSIProviders...), }, "parameters": { Type: "object", diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml index 9f909c5e3..9e47fb55a 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml @@ -69,3 +69,13 @@ rules: - get - list - watch +- apiGroups: + - storage.k8s.io + resources: + - storageclass + verbs: + - create + - get + - list + - patch + - update diff --git a/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go b/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go index 007d19ab4..7ee2ed2a3 100644 --- a/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go +++ b/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go @@ -9,7 +9,6 @@ import ( "github.com/go-logr/logr" "github.com/spf13/pflag" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capiv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -18,6 +17,7 @@ import ( caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" ) const ( @@ -53,7 +53,10 @@ func (s helmAddonStrategy) apply( log logr.Logger, ) error { log.Info("Retrieving cluster-autoscaler installation values template for cluster") - valuesTemplateConfigMap, err := s.retrieveValuesTemplateConfigMap(ctx, defaultsNamespace) + valuesTemplateConfigMap, err := utils.RetrieveValuesTemplateConfigMap(ctx, + s.client, + s.config.defaultValuesTemplateConfigMapName, + defaultsNamespace) if err != nil { return fmt.Errorf( "failed to retrieve cluster-autoscaler installation values template ConfigMap for cluster: %w", @@ -108,28 +111,3 @@ func (s helmAddonStrategy) apply( return nil } - -func (s helmAddonStrategy) retrieveValuesTemplateConfigMap( - ctx context.Context, - defaultsNamespace string, -) (*corev1.ConfigMap, error) { - configMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: defaultsNamespace, - Name: s.config.defaultValuesTemplateConfigMapName, - }, - } - configMapObjName := ctrlclient.ObjectKeyFromObject( - configMap, - ) - err := s.client.Get(ctx, configMapObjName, configMap) - if err != nil { - return nil, fmt.Errorf( - "failed to retrieve installation values template ConfigMap %q: %w", - configMapObjName, - err, - ) - } - - return configMap, nil -} diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 25ea8f42e..e37ee1e7b 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -77,7 +77,7 @@ func (a *AWSEBS) Apply( strategy := provider.Strategy switch strategy { case v1alpha1.AddonStrategyClusterResourceSet: - err := a.handleCRSApply(ctx, defaultStorageConfig, req) + err := a.handleCRSApply(ctx, req) if err != nil { return err } @@ -119,6 +119,10 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName sc := storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: "storageclass", + APIVersion: storagev1.SchemeGroupVersion.String(), + }, ObjectMeta: metav1.ObjectMeta{ Name: c.Name, Namespace: a.config.DefaultsNamespace(), @@ -142,7 +146,6 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, } func (a *AWSEBS) handleCRSApply(ctx context.Context, - defaultStorageConfig *v1alpha1.DefaultStorage, req *runtimehooksv1.AfterControlPlaneInitializedRequest, ) error { awsEBSCSIConfigMap := &corev1.ConfigMap{ diff --git a/pkg/handlers/generic/lifecycle/csi/doc.go b/pkg/handlers/generic/lifecycle/csi/doc.go index 9a2cc0ff4..238c82185 100644 --- a/pkg/handlers/generic/lifecycle/csi/doc.go +++ b/pkg/handlers/generic/lifecycle/csi/doc.go @@ -9,4 +9,5 @@ // // +kubebuilder:rbac:groups=addons.cluster.x-k8s.io,resources=clusterresourcesets,verbs=watch;list;get;create;patch;update;delete // +kubebuilder:rbac:groups="",resources=configmaps,verbs=watch;list;get;create;patch;update;delete +// +kubebuilder:rbac:groups="storage.k8s.io",resources=storageclass,verbs=list;get;create;patch;update package csi diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go new file mode 100644 index 000000000..ed5ed1cff --- /dev/null +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -0,0 +1,135 @@ +package nutanix + +import ( + "context" + "fmt" + + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/k8s/client" + "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/lifecycle/utils" + "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/options" + "github.com/spf13/pflag" + + caaphv1 "github.com/d2iq-labs/capi-runtime-extensions/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + capiv1 "sigs.k8s.io/cluster-api/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" +) + +const ( + defaultHelmRepositoryURL = "https://nutanix.github.io/helm/" + defaultHelmChartVersion = "v2.6.6" + defaultHelmChartName = "nutanix-csi-storage" + defaultHelmReleaseNameTemplate = "nutanix-csi-storage-%s" +) + +type NutanixCSIConfig struct { + *options.GlobalOptions + defaultValuesTemplateConfigMapName string +} + +func (n *NutanixCSIConfig) AddFlags(prefix string, flags *pflag.FlagSet) { + flags.StringVar( + &n.defaultValuesTemplateConfigMapName, + prefix+".default-values-template-configmap-name", + "default-nutanix-csi-helm-values-template", + "default values ConfigMap name", + ) +} + +type NutanixCSI struct { + client ctrlclient.Client + config *NutanixCSIConfig +} + +func New( + c ctrlclient.Client, + cfg *NutanixCSIConfig, +) *NutanixCSI { + return &NutanixCSI{ + client: c, + config: cfg, + } +} + +func (n *NutanixCSI) Apply( + ctx context.Context, + provider v1alpha1.CSIProvider, + defaultStorageConfig *v1alpha1.DefaultStorage, + req *runtimehooksv1.AfterControlPlaneInitializedRequest, +) error { + strategy := provider.Strategy + switch strategy { + case v1alpha1.AddonStrategyHelmAddon: + err := n.handleHelmAddonApply(ctx, req) + if err != nil { + return err + } + case v1alpha1.AddonStrategyClusterResourceSet: + fallthrough + default: + return fmt.Errorf("Stategy %s not implemented", strategy) + } + return n.createStorageClasses(ctx, provider.StorageClassConfig, defaultStorageConfig) +} + +func (n *NutanixCSI) handleHelmAddonApply( + ctx context.Context, + req *runtimehooksv1.AfterControlPlaneInitializedRequest, +) error { + valuesTemplateConfigMap, err := utils.RetrieveValuesTemplateConfigMap(ctx, + n.client, + n.config.defaultValuesTemplateConfigMapName, + n.config.DefaultsNamespace()) + if err != nil { + return fmt.Errorf( + "failed to retrieve nutanix csi installation values template ConfigMap for cluster: %w", + err, + ) + } + values := valuesTemplateConfigMap.Data["values.yaml"] + + hcp := &caaphv1.HelmChartProxy{ + TypeMeta: metav1.TypeMeta{ + APIVersion: caaphv1.GroupVersion.String(), + Kind: "HelmChartProxy", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: req.Cluster.Namespace, + Name: "nutanix-csi-" + req.Cluster.Name, + }, + Spec: caaphv1.HelmChartProxySpec{ + RepoURL: defaultHelmRepositoryURL, + ChartName: defaultHelmChartName, + ClusterSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{capiv1.ClusterNameLabel: req.Cluster.Name}, + }, + ReleaseNamespace: req.Cluster.Namespace, + ReleaseName: fmt.Sprintf(defaultHelmReleaseNameTemplate, req.Cluster.Name), + Version: defaultHelmChartVersion, + ValuesTemplate: values, + }, + } + + if err = controllerutil.SetOwnerReference(&req.Cluster, hcp, n.client.Scheme()); err != nil { + return fmt.Errorf( + "failed to set owner reference on nutanix-csi installation HelmChartProxy: %w", + err, + ) + } + + if err = client.ServerSideApply(ctx, n.client, hcp); err != nil { + return fmt.Errorf("failed to apply nutanix-csi installation HelmChartProxy: %w", err) + } + + return nil +} + +func (n *NutanixCSI) createStorageClasses(ctx context.Context, + configs []v1alpha1.StorageClassConfig, + defaultStorageConfig *v1alpha1.DefaultStorage, +) error { + return nil +} diff --git a/pkg/handlers/generic/lifecycle/handlers.go b/pkg/handlers/generic/lifecycle/handlers.go index 366e78196..33d08e130 100644 --- a/pkg/handlers/generic/lifecycle/handlers.go +++ b/pkg/handlers/generic/lifecycle/handlers.go @@ -16,6 +16,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/cilium" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi" awsebs "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/aws-ebs" + nutanixcsi "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/nutanix-csi" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/nfd" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/servicelbgc" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" @@ -27,7 +28,8 @@ type Handlers struct { nfdConfig *nfd.Config clusterAutoscalerConfig *clusterautoscaler.Config ebsConfig *awsebs.AWSEBSConfig - awsccmConfig *awsccm.AWSCCMConfig + nutnaixCSIConfig *nutanixcsi.NutanixCSIConfig + awsCPIConfig *awscpi.AWSCPIConfig } func New(globalOptions *options.GlobalOptions) *Handlers { @@ -38,12 +40,14 @@ func New(globalOptions *options.GlobalOptions) *Handlers { clusterAutoscalerConfig: &clusterautoscaler.Config{GlobalOptions: globalOptions}, ebsConfig: &awsebs.AWSEBSConfig{GlobalOptions: globalOptions}, awsccmConfig: &awsccm.AWSCCMConfig{GlobalOptions: globalOptions}, + nutnaixCSIConfig: &nutanixcsi.NutanixCSIConfig{GlobalOptions: globalOptions}, } } func (h *Handlers) AllHandlers(mgr manager.Manager) []handlers.Named { csiHandlers := map[string]csi.CSIProvider{ - v1alpha1.CSIProviderAWSEBS: awsebs.New(mgr.GetClient(), h.ebsConfig), + v1alpha1.CSIProviderAWSEBS: awsebs.New(mgr.GetClient(), h.ebsConfig), + v1alpha1.CSIProviderNutanix: nutanixcsi.New(mgr.GetClient(), h.nutnaixCSIConfig), } ccmHandlers := map[string]ccm.CCMProvider{ v1alpha1.CCMProviderAWS: awsccm.New(mgr.GetClient(), h.awsccmConfig), @@ -66,5 +70,10 @@ func (h *Handlers) AddFlags(flagSet *pflag.FlagSet) { h.calicoCNIConfig.AddFlags("cni.calico", flagSet) h.ciliumCNIConfig.AddFlags("cni.cilium", flagSet) h.ebsConfig.AddFlags("awsebs", pflag.CommandLine) +<<<<<<< HEAD h.awsccmConfig.AddFlags("awsccm", pflag.CommandLine) +======= + h.nutnaixCSIConfig.AddFlags("nutanixcsi", flagSet) + h.awsCPIConfig.AddFlags("awscpi", pflag.CommandLine) +>>>>>>> f7ff2e9 (fix: adds proper permissions and api fixes) } diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index 00915b7ab..33553499b 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -86,3 +86,29 @@ func EnsureNamespace(ctx context.Context, c ctrlclient.Client, name string) erro return nil } + +func RetrieveValuesTemplateConfigMap( + ctx context.Context, + c ctrlclient.Client, + configMapName, + defaultsNamespace string, +) (*corev1.ConfigMap, error) { + configMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: defaultsNamespace, + Name: configMapName, + }, + } + configMapObjName := ctrlclient.ObjectKeyFromObject( + configMap, + ) + err := c.Get(ctx, configMapObjName, configMap) + if err != nil { + return nil, fmt.Errorf( + "failed to retrieve installation values template ConfigMap %q: %w", + configMapObjName, + err, + ) + } + return configMap, nil +} From c6733ba3d0a38ccdffa7c2d870731c3d9f6dc0b8 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 21 Mar 2024 11:26:57 -0600 Subject: [PATCH 36/87] fix: adds configuration for new storage to examples/ --- examples/capi-quick-start/aws-cluster-calico-crs.yaml | 6 ++++++ .../capi-quick-start/aws-cluster-calico-helm-addon.yaml | 6 ++++++ examples/capi-quick-start/aws-cluster-cilium-crs.yaml | 6 ++++++ .../capi-quick-start/aws-cluster-cilium-helm-addon.yaml | 6 ++++++ hack/examples/patches/aws/csi.yaml | 6 ++++++ 5 files changed, 30 insertions(+) diff --git a/examples/capi-quick-start/aws-cluster-calico-crs.yaml b/examples/capi-quick-start/aws-cluster-calico-crs.yaml index 847222c10..09c3a5a39 100644 --- a/examples/capi-quick-start/aws-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/aws-cluster-calico-crs.yaml @@ -28,8 +28,14 @@ spec: provider: Calico strategy: ClusterResourceSet csi: + defaultStorageConfig: + providerName: aws-ebs + storageClassConfigName: aws-ebs-sc providers: - name: aws-ebs + storageClassConfig: + - name: aws-ebs-sc + strategy: ClusterResourceSet nfd: strategy: ClusterResourceSet aws: diff --git a/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml index ac26e8051..15c7dfd4a 100644 --- a/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml @@ -28,8 +28,14 @@ spec: provider: Calico strategy: HelmAddon csi: + defaultStorageConfig: + providerName: aws-ebs + storageClassConfigName: aws-ebs-sc providers: - name: aws-ebs + storageClassConfig: + - name: aws-ebs-sc + strategy: ClusterResourceSet nfd: strategy: HelmAddon aws: diff --git a/examples/capi-quick-start/aws-cluster-cilium-crs.yaml b/examples/capi-quick-start/aws-cluster-cilium-crs.yaml index 2fd77b867..bc832e0b5 100644 --- a/examples/capi-quick-start/aws-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/aws-cluster-cilium-crs.yaml @@ -28,8 +28,14 @@ spec: provider: Cilium strategy: ClusterResourceSet csi: + defaultStorageConfig: + providerName: aws-ebs + storageClassConfigName: aws-ebs-sc providers: - name: aws-ebs + storageClassConfig: + - name: aws-ebs-sc + strategy: ClusterResourceSet nfd: strategy: ClusterResourceSet aws: diff --git a/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml index 4bd929d2f..563dfa1d6 100644 --- a/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml @@ -28,8 +28,14 @@ spec: provider: Cilium strategy: HelmAddon csi: + defaultStorageConfig: + providerName: aws-ebs + storageClassConfigName: aws-ebs-sc providers: - name: aws-ebs + storageClassConfig: + - name: aws-ebs-sc + strategy: ClusterResourceSet nfd: strategy: HelmAddon aws: diff --git a/hack/examples/patches/aws/csi.yaml b/hack/examples/patches/aws/csi.yaml index 1d395d192..f92b2f939 100644 --- a/hack/examples/patches/aws/csi.yaml +++ b/hack/examples/patches/aws/csi.yaml @@ -4,5 +4,11 @@ - op: "add" path: "/spec/topology/variables/0/value/addons/csi" value: + defaultStorageConfig: + providerName: aws-ebs + storageClassConfigName: aws-ebs-sc providers: - name: aws-ebs + storageClassConfig: + - name: aws-ebs-sc + strategy: ClusterResourceSet From d5c5ec2868c881a91e400c4fe0839785b2efbd91 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 21 Mar 2024 11:32:55 -0600 Subject: [PATCH 37/87] fix: don't use deepcopy --- .../templates/role.yaml | 2 +- .../aws-cluster-calico-crs.yaml | 2 +- .../aws-cluster-calico-helm-addon.yaml | 2 +- .../aws-cluster-cilium-crs.yaml | 2 +- .../aws-cluster-cilium-helm-addon.yaml | 2 +- hack/examples/patches/aws/csi.yaml | 2 +- .../generic/lifecycle/csi/aws-ebs/handler.go | 24 ++++++++++++++----- pkg/handlers/generic/lifecycle/csi/doc.go | 2 +- .../lifecycle/csi/nutanix-csi/handler.go | 10 ++++---- 9 files changed, 30 insertions(+), 18 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml index 9e47fb55a..e3cd174f7 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml @@ -72,7 +72,7 @@ rules: - apiGroups: - storage.k8s.io resources: - - storageclass + - storageclasses verbs: - create - get diff --git a/examples/capi-quick-start/aws-cluster-calico-crs.yaml b/examples/capi-quick-start/aws-cluster-calico-crs.yaml index 09c3a5a39..68221eaff 100644 --- a/examples/capi-quick-start/aws-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/aws-cluster-calico-crs.yaml @@ -28,7 +28,7 @@ spec: provider: Calico strategy: ClusterResourceSet csi: - defaultStorageConfig: + defaultStorage: providerName: aws-ebs storageClassConfigName: aws-ebs-sc providers: diff --git a/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml index 15c7dfd4a..c7dde4e5f 100644 --- a/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml @@ -28,7 +28,7 @@ spec: provider: Calico strategy: HelmAddon csi: - defaultStorageConfig: + defaultStorage: providerName: aws-ebs storageClassConfigName: aws-ebs-sc providers: diff --git a/examples/capi-quick-start/aws-cluster-cilium-crs.yaml b/examples/capi-quick-start/aws-cluster-cilium-crs.yaml index bc832e0b5..88ee71752 100644 --- a/examples/capi-quick-start/aws-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/aws-cluster-cilium-crs.yaml @@ -28,7 +28,7 @@ spec: provider: Cilium strategy: ClusterResourceSet csi: - defaultStorageConfig: + defaultStorage: providerName: aws-ebs storageClassConfigName: aws-ebs-sc providers: diff --git a/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml index 563dfa1d6..91fd7923b 100644 --- a/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml @@ -28,7 +28,7 @@ spec: provider: Cilium strategy: HelmAddon csi: - defaultStorageConfig: + defaultStorage: providerName: aws-ebs storageClassConfigName: aws-ebs-sc providers: diff --git a/hack/examples/patches/aws/csi.yaml b/hack/examples/patches/aws/csi.yaml index f92b2f939..fccddd2ad 100644 --- a/hack/examples/patches/aws/csi.yaml +++ b/hack/examples/patches/aws/csi.yaml @@ -4,7 +4,7 @@ - op: "add" path: "/spec/topology/variables/0/value/addons/csi" value: - defaultStorageConfig: + defaultStorage: providerName: aws-ebs storageClassConfigName: aws-ebs-sc providers: diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index e37ee1e7b..fd8010b6d 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -7,15 +7,17 @@ import ( "context" "fmt" - "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" - lifecycleutils "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/lifecycle/utils" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + "sigs.k8s.io/cluster-api/controllers/remote" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + capiutil "sigs.k8s.io/cluster-api/util" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" @@ -86,11 +88,12 @@ func (a *AWSEBS) Apply( default: return fmt.Errorf("Stategy %s not implemented", strategy) } - return a.createStorageClasses(ctx, provider.StorageClassConfig, defaultStorageConfig) + return a.createStorageClasses(ctx, provider.StorageClassConfig, req.Cluster, defaultStorageConfig) } func (a *AWSEBS) createStorageClasses(ctx context.Context, configs []v1alpha1.StorageClassConfig, + cluster clusterv1.Cluster, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { for _, c := range configs { @@ -114,13 +117,17 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, } params := defaultParams if c.Parameters != nil { - params = c.DeepCopy().Parameters + m := make(map[string]string) + for k, v := range c.Parameters { + m[k] = v + } + params = m } setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName sc := storagev1.StorageClass{ TypeMeta: metav1.TypeMeta{ - Kind: "storageclass", + Kind: "StorageClass", APIVersion: storagev1.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ @@ -135,7 +142,12 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, if setAsDefault { sc.ObjectMeta.Annotations = defaultStorageClassMap } - if err := client.ServerSideApply(ctx, a.client, &sc); err != nil { + workloadClient, err := remote.NewClusterClient(ctx, "", a.client, capiutil.ObjectKey(&cluster)) + if err != nil { + return err + } + + if err := client.ServerSideApply(ctx, workloadClient, &sc); err != nil { return fmt.Errorf( "failed to create storage class %w", err, diff --git a/pkg/handlers/generic/lifecycle/csi/doc.go b/pkg/handlers/generic/lifecycle/csi/doc.go index 238c82185..41a048f24 100644 --- a/pkg/handlers/generic/lifecycle/csi/doc.go +++ b/pkg/handlers/generic/lifecycle/csi/doc.go @@ -9,5 +9,5 @@ // // +kubebuilder:rbac:groups=addons.cluster.x-k8s.io,resources=clusterresourcesets,verbs=watch;list;get;create;patch;update;delete // +kubebuilder:rbac:groups="",resources=configmaps,verbs=watch;list;get;create;patch;update;delete -// +kubebuilder:rbac:groups="storage.k8s.io",resources=storageclass,verbs=list;get;create;patch;update +// +kubebuilder:rbac:groups="storage.k8s.io",resources=storageclasses,verbs=list;get;create;patch;update package csi diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index ed5ed1cff..f5584ac8b 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -4,13 +4,13 @@ import ( "context" "fmt" - "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" - "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/k8s/client" - "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/lifecycle/utils" - "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/options" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" "github.com/spf13/pflag" - caaphv1 "github.com/d2iq-labs/capi-runtime-extensions/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" + caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capiv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" From 80a80dbe0976fb83d39cc90300133040e79d8817 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 21 Mar 2024 17:29:49 -0600 Subject: [PATCH 38/87] fix: rename files to put the configmaps in the right place --- .../templates/csi/nutanix/manifests/helm-addon-installation.yaml | 0 .../templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename charts/{capi-runtime-extensions => cluster-api-runtime-extensions-nutanix}/templates/csi/nutanix/manifests/helm-addon-installation.yaml (100%) rename charts/{capi-runtime-extensions => cluster-api-runtime-extensions-nutanix}/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml (100%) diff --git a/charts/capi-runtime-extensions/templates/csi/nutanix/manifests/helm-addon-installation.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/helm-addon-installation.yaml similarity index 100% rename from charts/capi-runtime-extensions/templates/csi/nutanix/manifests/helm-addon-installation.yaml rename to charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/helm-addon-installation.yaml diff --git a/charts/capi-runtime-extensions/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml similarity index 100% rename from charts/capi-runtime-extensions/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml rename to charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml From 2280da18829b979f471131fc94431927cb5bf4d1 Mon Sep 17 00:00:00 2001 From: faiq Date: Tue, 26 Mar 2024 12:55:28 -0600 Subject: [PATCH 39/87] refactor: apply suggestion from review --- pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index fd8010b6d..12ea241b3 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -6,6 +6,7 @@ package aws import ( "context" "fmt" + "maps" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" @@ -117,11 +118,7 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, } params := defaultParams if c.Parameters != nil { - m := make(map[string]string) - for k, v := range c.Parameters { - m[k] = v - } - params = m + params = maps.Clone(c.Parameters) } setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName From efdeab15fd12cb05283317d276ff92e4733b75e2 Mon Sep 17 00:00:00 2001 From: faiq Date: Tue, 26 Mar 2024 13:34:49 -0600 Subject: [PATCH 40/87] fix: linting errors --- api/v1alpha1/zz_generated.deepcopy.go | 2 +- .../generic/lifecycle/csi/aws-ebs/handler.go | 24 +++++++++----- pkg/handlers/generic/lifecycle/csi/handler.go | 7 +++- .../generic/lifecycle/csi/handler_test.go | 33 +------------------ .../lifecycle/csi/nutanix-csi/handler.go | 15 ++++----- 5 files changed, 31 insertions(+), 50 deletions(-) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index d55db46f9..467ea9763 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -9,7 +9,7 @@ package v1alpha1 import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 12ea241b3..7546a2164 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -8,8 +8,6 @@ import ( "fmt" "maps" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" - lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" storagev1 "k8s.io/api/storage/v1" @@ -21,7 +19,9 @@ import ( capiutil "sigs.k8s.io/cluster-api/util" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) @@ -85,16 +85,20 @@ func (a *AWSEBS) Apply( return err } case v1alpha1.AddonStrategyHelmAddon: - fallthrough default: - return fmt.Errorf("Stategy %s not implemented", strategy) + return fmt.Errorf("stategy %s not implemented", strategy) } - return a.createStorageClasses(ctx, provider.StorageClassConfig, req.Cluster, defaultStorageConfig) + return a.createStorageClasses( + ctx, + provider.StorageClassConfig, + &req.Cluster, + defaultStorageConfig, + ) } func (a *AWSEBS) createStorageClasses(ctx context.Context, configs []v1alpha1.StorageClassConfig, - cluster clusterv1.Cluster, + cluster *clusterv1.Cluster, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { for _, c := range configs { @@ -103,7 +107,6 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, case v1alpha1.VolumeBindingImmediate: volumeBindingMode = ptr.To(storagev1.VolumeBindingImmediate) case v1alpha1.VolumeBindingWaitForFirstConsumer: - fallthrough default: volumeBindingMode = ptr.To(storagev1.VolumeBindingWaitForFirstConsumer) } @@ -139,7 +142,12 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, if setAsDefault { sc.ObjectMeta.Annotations = defaultStorageClassMap } - workloadClient, err := remote.NewClusterClient(ctx, "", a.client, capiutil.ObjectKey(&cluster)) + workloadClient, err := remote.NewClusterClient( + ctx, + "", + a.client, + capiutil.ObjectKey(cluster), + ) if err != nil { return err } diff --git a/pkg/handlers/generic/lifecycle/csi/handler.go b/pkg/handlers/generic/lifecycle/csi/handler.go index 80f1c6372..14209bec3 100644 --- a/pkg/handlers/generic/lifecycle/csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/handler.go @@ -23,7 +23,12 @@ const ( ) type CSIProvider interface { - Apply(context.Context, v1alpha1.CSIProvider, *v1alpha1.DefaultStorage, *runtimehooksv1.AfterControlPlaneInitializedRequest) error + Apply( + context.Context, + v1alpha1.CSIProvider, + *v1alpha1.DefaultStorage, + *runtimehooksv1.AfterControlPlaneInitializedRequest, + ) error } type CSIHandler struct { diff --git a/pkg/handlers/generic/lifecycle/csi/handler_test.go b/pkg/handlers/generic/lifecycle/csi/handler_test.go index de5015895..b6a14183f 100644 --- a/pkg/handlers/generic/lifecycle/csi/handler_test.go +++ b/pkg/handlers/generic/lifecycle/csi/handler_test.go @@ -4,26 +4,12 @@ package csi import ( - "strings" "testing" - "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -var startAWSConfigMap = ` -apiVersion: storage.k8s.io/v1 -kind: StorageClass -metadata: - name: ebs-sc -parameters: - csi.storage.k8s.io/fstype: ext4 - type: gp3 -provisioner: ebs.csi.aws.com -volumeBindingMode: WaitForFirstConsumer -` - func Test_setDefaultStorageClass(t *testing.T) { tests := []struct { name string @@ -37,30 +23,13 @@ func Test_setDefaultStorageClass(t *testing.T) { Name: "test1", Namespace: "default", }, - Data: map[string]string{ - "aws-ebs-csi.yaml": startAWSConfigMap, - }, + Data: map[string]string{}, }, key: "aws-ebs-csi.yaml", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := setDefaultStorageClass( - logr.Discard(), - tt.startConfigMap, - ) - if err != nil { - t.Fatal("failed to set default storage class", err) - } - if !strings.Contains(tt.startConfigMap.Data[tt.key], defualtStorageClassKey) { - t.Logf( - "expected %s to containe %s", - tt.startConfigMap.Data[tt.key], - defualtStorageClassKey, - ) - t.Fail() - } }) } } diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index f5584ac8b..96a2e4c79 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -4,18 +4,18 @@ import ( "context" "fmt" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" "github.com/spf13/pflag" - - caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" capiv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) const ( @@ -68,9 +68,8 @@ func (n *NutanixCSI) Apply( return err } case v1alpha1.AddonStrategyClusterResourceSet: - fallthrough default: - return fmt.Errorf("Stategy %s not implemented", strategy) + return fmt.Errorf("stategy %s not implemented", strategy) } return n.createStorageClasses(ctx, provider.StorageClassConfig, defaultStorageConfig) } From e4c3aa56c2a68dfb6001ec1ff6f6ac2daa80d65e Mon Sep 17 00:00:00 2001 From: faiq Date: Tue, 26 Mar 2024 14:45:22 -0600 Subject: [PATCH 41/87] feat: adds nutanix driver create storage class --- .../generic/lifecycle/csi/aws-ebs/handler.go | 77 ++-------------- .../lifecycle/csi/nutanix-csi/handler.go | 27 +++++- pkg/handlers/generic/lifecycle/utils/utils.go | 87 +++++++++++++++++++ 3 files changed, 117 insertions(+), 74 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 7546a2164..70153104e 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -6,17 +6,12 @@ package aws import ( "context" "fmt" - "maps" "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" - storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" - "sigs.k8s.io/cluster-api/controllers/remote" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" - capiutil "sigs.k8s.io/cluster-api/util" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" @@ -25,23 +20,6 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) -const ( - variableRootName = "csi" - kindStorageClass = "StorageClass" - awsEBSProvisionerName = "ebs.csi.aws.com" -) - -var ( - defualtStorageClassKey = "storageclass.kubernetes.io/is-default-class" - defaultStorageClassMap = map[string]string{ - defualtStorageClassKey: "true", - } - defaultParams = map[string]string{ - "csi.storage.k8s.io/fstype": "ext4", - "type": "gp3", - } -) - type AWSEBSConfig struct { *options.GlobalOptions defaultAWSEBSConfigMapName string @@ -102,61 +80,18 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { for _, c := range configs { - var volumeBindingMode *storagev1.VolumeBindingMode - switch c.VolumeBindingMode { - case v1alpha1.VolumeBindingImmediate: - volumeBindingMode = ptr.To(storagev1.VolumeBindingImmediate) - case v1alpha1.VolumeBindingWaitForFirstConsumer: - default: - volumeBindingMode = ptr.To(storagev1.VolumeBindingWaitForFirstConsumer) - } - var reclaimPolicy *corev1.PersistentVolumeReclaimPolicy - switch c.ReclaimPolicy { - case v1alpha1.VolumeReclaimRecycle: - reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimRecycle) - case v1alpha1.VolumeReclaimDelete: - reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimDelete) - case v1alpha1.VolumeReclaimRetain: - reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimRetain) - } - params := defaultParams - if c.Parameters != nil { - params = maps.Clone(c.Parameters) - } setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName - sc := storagev1.StorageClass{ - TypeMeta: metav1.TypeMeta{ - Kind: "StorageClass", - APIVersion: storagev1.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: c.Name, - Namespace: a.config.DefaultsNamespace(), - }, - Provisioner: awsEBSProvisionerName, - Parameters: params, - VolumeBindingMode: volumeBindingMode, - ReclaimPolicy: reclaimPolicy, - } - if setAsDefault { - sc.ObjectMeta.Annotations = defaultStorageClassMap - } - workloadClient, err := remote.NewClusterClient( + err := lifecycleutils.CreateStorageClass( ctx, - "", a.client, - capiutil.ObjectKey(cluster), + c, + cluster, + a.config.GlobalOptions.DefaultsNamespace(), + setAsDefault, ) if err != nil { - return err - } - - if err := client.ServerSideApply(ctx, workloadClient, &sc); err != nil { - return fmt.Errorf( - "failed to create storage class %w", - err, - ) + return fmt.Errorf("failed to create storageclass %w", err) } } return nil diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 96a2e4c79..49f2fafbd 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -6,7 +6,7 @@ import ( "github.com/spf13/pflag" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - capiv1 "sigs.k8s.io/cluster-api/api/v1beta1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -71,7 +71,12 @@ func (n *NutanixCSI) Apply( default: return fmt.Errorf("stategy %s not implemented", strategy) } - return n.createStorageClasses(ctx, provider.StorageClassConfig, defaultStorageConfig) + return n.createStorageClasses( + ctx, + provider.StorageClassConfig, + &req.Cluster, + defaultStorageConfig, + ) } func (n *NutanixCSI) handleHelmAddonApply( @@ -103,7 +108,7 @@ func (n *NutanixCSI) handleHelmAddonApply( RepoURL: defaultHelmRepositoryURL, ChartName: defaultHelmChartName, ClusterSelector: metav1.LabelSelector{ - MatchLabels: map[string]string{capiv1.ClusterNameLabel: req.Cluster.Name}, + MatchLabels: map[string]string{clusterv1.ClusterNameLabel: req.Cluster.Name}, }, ReleaseNamespace: req.Cluster.Namespace, ReleaseName: fmt.Sprintf(defaultHelmReleaseNameTemplate, req.Cluster.Name), @@ -128,7 +133,23 @@ func (n *NutanixCSI) handleHelmAddonApply( func (n *NutanixCSI) createStorageClasses(ctx context.Context, configs []v1alpha1.StorageClassConfig, + cluster *clusterv1.Cluster, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { + for _, c := range configs { + setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && + v1alpha1.CSIProviderNutanix == defaultStorageConfig.ProviderName + err := utils.CreateStorageClass( + ctx, + n.client, + c, + cluster, + n.config.GlobalOptions.DefaultsNamespace(), + setAsDefault, + ) + if err != nil { + return fmt.Errorf("failed to create storageclass %w", err) + } + } return nil } diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index 33553499b..06887648c 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -6,17 +6,39 @@ package utils import ( "context" "fmt" + "maps" corev1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + "sigs.k8s.io/cluster-api/controllers/remote" crsv1 "sigs.k8s.io/cluster-api/exp/addons/api/v1beta1" + capiutil "sigs.k8s.io/cluster-api/util" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" ) +const ( + kindStorageClass = "StorageClass" + awsEBSProvisionerName = "ebs.csi.aws.com" +) + +var ( + defualtStorageClassKey = "storageclass.kubernetes.io/is-default-class" + defaultStorageClassMap = map[string]string{ + defualtStorageClassKey: "true", + } + defaultParams = map[string]string{ + "csi.storage.k8s.io/fstype": "ext4", + "type": "gp3", + } +) + func EnsureCRSForClusterFromConfigMaps( ctx context.Context, crsName string, @@ -112,3 +134,68 @@ func RetrieveValuesTemplateConfigMap( } return configMap, nil } + +func CreateStorageClass( + ctx context.Context, + cl ctrlclient.Client, + storageConfig v1alpha1.StorageClassConfig, + cluster *clusterv1.Cluster, + defaultsNamespace string, + isDefault bool, +) error { + var volumeBindingMode *storagev1.VolumeBindingMode + switch storageConfig.VolumeBindingMode { + case v1alpha1.VolumeBindingImmediate: + volumeBindingMode = ptr.To(storagev1.VolumeBindingImmediate) + case v1alpha1.VolumeBindingWaitForFirstConsumer: + default: + volumeBindingMode = ptr.To(storagev1.VolumeBindingWaitForFirstConsumer) + } + var reclaimPolicy *corev1.PersistentVolumeReclaimPolicy + switch storageConfig.ReclaimPolicy { + case v1alpha1.VolumeReclaimRecycle: + reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimRecycle) + case v1alpha1.VolumeReclaimDelete: + reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimDelete) + case v1alpha1.VolumeReclaimRetain: + reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimRetain) + } + params := defaultParams + if storageConfig.Parameters != nil { + params = maps.Clone(storageConfig.Parameters) + } + sc := storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: "StorageClass", + APIVersion: storagev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: storageConfig.Name, + Namespace: defaultsNamespace, + }, + Provisioner: awsEBSProvisionerName, + Parameters: params, + VolumeBindingMode: volumeBindingMode, + ReclaimPolicy: reclaimPolicy, + } + if isDefault { + sc.ObjectMeta.Annotations = defaultStorageClassMap + } + workloadClient, err := remote.NewClusterClient( + ctx, + "", + cl, + capiutil.ObjectKey(cluster), + ) + if err != nil { + return err + } + + if err := client.ServerSideApply(ctx, workloadClient, &sc); err != nil { + return fmt.Errorf( + "failed to create storage class %w", + err, + ) + } + return nil +} From e58e2f85d1e2dc1c335f450ab55e7b588158e1cf Mon Sep 17 00:00:00 2001 From: faiq Date: Tue, 26 Mar 2024 14:53:54 -0600 Subject: [PATCH 42/87] fix: pre-commit errors --- charts/cluster-api-runtime-extensions-nutanix/README.md | 2 ++ .../csi/nutanix/manifests/helm-addon-installation.yaml | 3 +++ hack/addons/kustomize/nutanix-csi/helm-values.yaml | 3 +++ hack/addons/update-nutanix-csi.sh | 2 +- pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go | 3 +++ 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/README.md b/charts/cluster-api-runtime-extensions-nutanix/README.md index a90733b90..3049ea2a1 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/README.md +++ b/charts/cluster-api-runtime-extensions-nutanix/README.md @@ -49,6 +49,8 @@ A Helm chart for cluster-api-runtime-extensions-nutanix | hooks.cni.cilium.crsStrategy.defaultCiliumConfigMap.name | string | `"cilium"` | | | hooks.cni.cilium.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.cni.cilium.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-cilium-cni-helm-values-template"` | | +| hooks.csi.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | +| hooks.csi.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-nutanix-csi-helm-values-template"` | | | hooks.nfd.crsStrategy.defaultInstallationConfigMap.name | string | `"node-feature-discovery"` | | | hooks.nfd.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.nfd.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-nfd-helm-values-template"` | | diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/helm-addon-installation.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/helm-addon-installation.yaml index a92e3ff95..b62635034 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/helm-addon-installation.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/helm-addon-installation.yaml @@ -1,3 +1,6 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + {{- if .Values.hooks.csi.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.create }} apiVersion: v1 kind: ConfigMap diff --git a/hack/addons/kustomize/nutanix-csi/helm-values.yaml b/hack/addons/kustomize/nutanix-csi/helm-values.yaml index a16eb51a5..eebd55d74 100644 --- a/hack/addons/kustomize/nutanix-csi/helm-values.yaml +++ b/hack/addons/kustomize/nutanix-csi/helm-values.yaml @@ -1 +1,4 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + createSecret: false diff --git a/hack/addons/update-nutanix-csi.sh b/hack/addons/update-nutanix-csi.sh index 5ce837e21..e18414a86 100755 --- a/hack/addons/update-nutanix-csi.sh +++ b/hack/addons/update-nutanix-csi.sh @@ -31,7 +31,7 @@ kubectl create configmap nutanix-csi --dry-run=client --output yaml \ >"${ASSETS_DIR}/nutanix-csi-configmap.yaml" # add warning not to edit file directly -cat <"${GIT_REPO_ROOT}/charts/capi-runtime-extensions/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml" +cat <"${GIT_REPO_ROOT}/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml" $(cat "${GIT_REPO_ROOT}/hack/license-header.yaml.txt") #================================================================= diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 49f2fafbd..5ea0085e8 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -1,3 +1,6 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + package nutanix import ( From 79defdec7e5557acba3fccef7e2a7880fb8cbecf Mon Sep 17 00:00:00 2001 From: faiq Date: Wed, 27 Mar 2024 10:35:38 -0600 Subject: [PATCH 43/87] fix: pass in provisioner name --- .../generic/lifecycle/csi/aws-ebs/handler.go | 5 +++ .../generic/lifecycle/csi/handler_test.go | 35 ------------------- .../lifecycle/csi/nutanix-csi/handler.go | 2 ++ pkg/handlers/generic/lifecycle/utils/utils.go | 10 +++--- 4 files changed, 12 insertions(+), 40 deletions(-) delete mode 100644 pkg/handlers/generic/lifecycle/csi/handler_test.go diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 70153104e..7c669d773 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -20,6 +20,10 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) +const ( + awsEBSProvisionerName = "ebs.csi.aws.com" +) + type AWSEBSConfig struct { *options.GlobalOptions defaultAWSEBSConfigMapName string @@ -88,6 +92,7 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, c, cluster, a.config.GlobalOptions.DefaultsNamespace(), + awsEBSProvisionerName, setAsDefault, ) if err != nil { diff --git a/pkg/handlers/generic/lifecycle/csi/handler_test.go b/pkg/handlers/generic/lifecycle/csi/handler_test.go deleted file mode 100644 index b6a14183f..000000000 --- a/pkg/handlers/generic/lifecycle/csi/handler_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2023 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package csi - -import ( - "testing" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -func Test_setDefaultStorageClass(t *testing.T) { - tests := []struct { - name string - startConfigMap *corev1.ConfigMap - key string - }{ - { - name: "aws config map", - startConfigMap: &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test1", - Namespace: "default", - }, - Data: map[string]string{}, - }, - key: "aws-ebs-csi.yaml", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - }) - } -} diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 5ea0085e8..4a1331ba3 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -26,6 +26,7 @@ const ( defaultHelmChartVersion = "v2.6.6" defaultHelmChartName = "nutanix-csi-storage" defaultHelmReleaseNameTemplate = "nutanix-csi-storage-%s" + nutanixCSIProvisionerName = "csi.nutanix.com" ) type NutanixCSIConfig struct { @@ -147,6 +148,7 @@ func (n *NutanixCSI) createStorageClasses(ctx context.Context, n.client, c, cluster, + nutanixCSIProvisionerName, n.config.GlobalOptions.DefaultsNamespace(), setAsDefault, ) diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index 06887648c..72dbf2f5a 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -24,8 +24,7 @@ import ( ) const ( - kindStorageClass = "StorageClass" - awsEBSProvisionerName = "ebs.csi.aws.com" + kindStorageClass = "StorageClass" ) var ( @@ -140,7 +139,8 @@ func CreateStorageClass( cl ctrlclient.Client, storageConfig v1alpha1.StorageClassConfig, cluster *clusterv1.Cluster, - defaultsNamespace string, + defaultsNamespace, + provisionerName string, isDefault bool, ) error { var volumeBindingMode *storagev1.VolumeBindingMode @@ -166,14 +166,14 @@ func CreateStorageClass( } sc := storagev1.StorageClass{ TypeMeta: metav1.TypeMeta{ - Kind: "StorageClass", + Kind: kindStorageClass, APIVersion: storagev1.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: storageConfig.Name, Namespace: defaultsNamespace, }, - Provisioner: awsEBSProvisionerName, + Provisioner: provisionerName, Parameters: params, VolumeBindingMode: volumeBindingMode, ReclaimPolicy: reclaimPolicy, From 7d0c094e138d2f23dd54eca92f03b7dbd782847a Mon Sep 17 00:00:00 2001 From: faiq Date: Wed, 27 Mar 2024 17:28:53 -0600 Subject: [PATCH 44/87] refactor: deploy storage class as a cluster resource set --- api/v1alpha1/clusterconfig_types.go | 8 +- .../generic/lifecycle/csi/aws-ebs/handler.go | 33 ++++--- .../lifecycle/csi/nutanix-csi/handler.go | 34 ++++--- pkg/handlers/generic/lifecycle/utils/utils.go | 67 ++++++++----- .../generic/lifecycle/utils/utils_test.go | 95 +++++++++++++++++++ 5 files changed, 185 insertions(+), 52 deletions(-) create mode 100644 pkg/handlers/generic/lifecycle/utils/utils_test.go diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index 75e02b61c..c664fc665 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -14,9 +14,13 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/openapi/patterns" ) +type StorageDriver string + const ( - CNIProviderCalico = "Calico" - CNIProviderCilium = "Cilium" + CNIProviderCalico = "Calico" + CNIProviderCilium = "Cilium" + AWSEBSDriver StorageDriver = "ebs.csi.aws.com" + NutanixDriver StorageDriver = "csi.nutanix.com" CSIProviderAWSEBS = "aws-ebs" CSIProviderNutanix = "nutanix" diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 7c669d773..15305348c 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/pflag" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -20,10 +21,6 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) -const ( - awsEBSProvisionerName = "ebs.csi.aws.com" -) - type AWSEBSConfig struct { *options.GlobalOptions defaultAWSEBSConfigMapName string @@ -83,23 +80,33 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, cluster *clusterv1.Cluster, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { + allStorageClasses := make([]runtime.Object, 0, len(configs)) for _, c := range configs { setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName - err := lifecycleutils.CreateStorageClass( - ctx, - a.client, + allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass( c, cluster, a.config.GlobalOptions.DefaultsNamespace(), - awsEBSProvisionerName, + v1alpha1.CSIProviderAWSEBS, setAsDefault, - ) - if err != nil { - return fmt.Errorf("failed to create storageclass %w", err) - } + )) } - return nil + cm, err := lifecycleutils.CreateConfigMapForCRS( + "aws-storageclass-cm", + a.config.DefaultsNamespace(), + allStorageClasses..., + ) + if err != nil { + return err + } + return lifecycleutils.EnsureCRSForClusterFromConfigMaps( + ctx, + "aws-storageclass-crs", + a.client, + cluster, + cm, + ) } func (a *AWSEBS) handleCRSApply(ctx context.Context, diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 4a1331ba3..4f2d67a8b 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/pflag" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" @@ -17,7 +18,7 @@ import ( caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" + lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) @@ -26,7 +27,6 @@ const ( defaultHelmChartVersion = "v2.6.6" defaultHelmChartName = "nutanix-csi-storage" defaultHelmReleaseNameTemplate = "nutanix-csi-storage-%s" - nutanixCSIProvisionerName = "csi.nutanix.com" ) type NutanixCSIConfig struct { @@ -87,7 +87,7 @@ func (n *NutanixCSI) handleHelmAddonApply( ctx context.Context, req *runtimehooksv1.AfterControlPlaneInitializedRequest, ) error { - valuesTemplateConfigMap, err := utils.RetrieveValuesTemplateConfigMap(ctx, + valuesTemplateConfigMap, err := lifecycleutils.RetrieveValuesTemplateConfigMap(ctx, n.client, n.config.defaultValuesTemplateConfigMapName, n.config.DefaultsNamespace()) @@ -140,21 +140,31 @@ func (n *NutanixCSI) createStorageClasses(ctx context.Context, cluster *clusterv1.Cluster, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { + allStorageClasses := make([]runtime.Object, 0, len(configs)) for _, c := range configs { setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && v1alpha1.CSIProviderNutanix == defaultStorageConfig.ProviderName - err := utils.CreateStorageClass( - ctx, - n.client, + allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass( c, cluster, - nutanixCSIProvisionerName, n.config.GlobalOptions.DefaultsNamespace(), + v1alpha1.NutanixDriver, setAsDefault, - ) - if err != nil { - return fmt.Errorf("failed to create storageclass %w", err) - } + )) } - return nil + cm, err := lifecycleutils.CreateConfigMapForCRS( + "nutanix-storageclass-cm", + n.config.DefaultsNamespace(), + allStorageClasses..., + ) + if err != nil { + return err + } + return lifecycleutils.EnsureCRSForClusterFromConfigMaps( + ctx, + "nutanix-storageclass-crs", + n.client, + cluster, + cm, + ) } diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index 72dbf2f5a..7c58c8017 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -11,11 +11,12 @@ import ( corev1 "k8s.io/api/core/v1" storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" - "sigs.k8s.io/cluster-api/controllers/remote" crsv1 "sigs.k8s.io/cluster-api/exp/addons/api/v1beta1" - capiutil "sigs.k8s.io/cluster-api/util" + utilyaml "sigs.k8s.io/cluster-api/util/yaml" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -24,7 +25,8 @@ import ( ) const ( - kindStorageClass = "StorageClass" + kindStorageClass = "StorageClass" + defaultCRSConfigMapKey = "custom-resources.yaml" ) var ( @@ -135,20 +137,17 @@ func RetrieveValuesTemplateConfigMap( } func CreateStorageClass( - ctx context.Context, - cl ctrlclient.Client, storageConfig v1alpha1.StorageClassConfig, cluster *clusterv1.Cluster, - defaultsNamespace, - provisionerName string, + defaultsNamespace string, + provisionerName v1alpha1.StorageDriver, isDefault bool, -) error { +) *storagev1.StorageClass { var volumeBindingMode *storagev1.VolumeBindingMode switch storageConfig.VolumeBindingMode { case v1alpha1.VolumeBindingImmediate: volumeBindingMode = ptr.To(storagev1.VolumeBindingImmediate) case v1alpha1.VolumeBindingWaitForFirstConsumer: - default: volumeBindingMode = ptr.To(storagev1.VolumeBindingWaitForFirstConsumer) } var reclaimPolicy *corev1.PersistentVolumeReclaimPolicy @@ -173,7 +172,7 @@ func CreateStorageClass( Name: storageConfig.Name, Namespace: defaultsNamespace, }, - Provisioner: provisionerName, + Provisioner: string(provisionerName), Parameters: params, VolumeBindingMode: volumeBindingMode, ReclaimPolicy: reclaimPolicy, @@ -181,21 +180,39 @@ func CreateStorageClass( if isDefault { sc.ObjectMeta.Annotations = defaultStorageClassMap } - workloadClient, err := remote.NewClusterClient( - ctx, - "", - cl, - capiutil.ObjectKey(cluster), - ) - if err != nil { - return err - } + return &sc +} - if err := client.ServerSideApply(ctx, workloadClient, &sc); err != nil { - return fmt.Errorf( - "failed to create storage class %w", - err, - ) +func CreateConfigMapForCRS(configMapName, configMapNamespace string, + objs ...runtime.Object, +) (*corev1.ConfigMap, error) { + cm := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapName, + Namespace: configMapNamespace, + }, + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ConfigMap", + }, + Data: make(map[string]string), + } + l := make([][]byte, 0, len(objs)) + for _, v := range objs { + obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(v) + if err != nil { + return nil, err + } + objYaml, err := utilyaml.FromUnstructured([]unstructured.Unstructured{ + { + Object: obj, + }, + }) + if err != nil { + return nil, err + } + l = append(l, objYaml) } - return nil + cm.Data[defaultCRSConfigMapKey] = fmt.Sprintf("|\n%s", string(utilyaml.JoinYaml(l...))) + return cm, nil } diff --git a/pkg/handlers/generic/lifecycle/utils/utils_test.go b/pkg/handlers/generic/lifecycle/utils/utils_test.go new file mode 100644 index 000000000..fccea15b8 --- /dev/null +++ b/pkg/handlers/generic/lifecycle/utils/utils_test.go @@ -0,0 +1,95 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +func TestCreateConfigMapForCRS(t *testing.T) { + tests := []struct { + name string + testCMName string + testNamespace string + objs []runtime.Object + expectedCM corev1.ConfigMap + }{ + { + name: "multiple storage class objects", + testCMName: "test", + testNamespace: "default", + objs: []runtime.Object{ + &storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: kindStorageClass, + APIVersion: storagev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + }, + &storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: kindStorageClass, + APIVersion: storagev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-2", + Namespace: "default", + }, + }, + }, + expectedCM: corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "default", + }, + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ConfigMap", + }, + Data: map[string]string{ + defaultCRSConfigMapKey: `| +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + creationTimestamp: null + name: test + namespace: default +provisioner: "" +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + creationTimestamp: null + name: test-2 + namespace: default +provisioner: ""`, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cm, err := CreateConfigMapForCRS(tt.testCMName, tt.testNamespace, tt.objs...) + if err != nil { + t.Errorf("failed to create cm with error %v", err) + } + data, ok := cm.Data[defaultCRSConfigMapKey] + if !ok { + t.Errorf("expected %s to exist in cm.Data. got %v", defaultCRSConfigMapKey, cm.Data) + } + expected := tt.expectedCM.Data[defaultCRSConfigMapKey] + if data != expected { + t.Errorf("expected %s \n got %s", expected, data) + } + }) + } +} From a54e97c5476e2ae99dddf65f0a6b667e6e804603 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 28 Mar 2024 09:11:10 -0600 Subject: [PATCH 45/87] refactor: change name of example sc --- examples/capi-quick-start/aws-cluster-calico-crs.yaml | 2 +- examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml | 2 +- examples/capi-quick-start/aws-cluster-cilium-crs.yaml | 2 +- examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml | 2 +- hack/examples/patches/aws/csi.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/capi-quick-start/aws-cluster-calico-crs.yaml b/examples/capi-quick-start/aws-cluster-calico-crs.yaml index 68221eaff..fe1ffdef1 100644 --- a/examples/capi-quick-start/aws-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/aws-cluster-calico-crs.yaml @@ -34,7 +34,7 @@ spec: providers: - name: aws-ebs storageClassConfig: - - name: aws-ebs-sc + - name: aws-ebs strategy: ClusterResourceSet nfd: strategy: ClusterResourceSet diff --git a/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml index c7dde4e5f..8041814b5 100644 --- a/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml @@ -34,7 +34,7 @@ spec: providers: - name: aws-ebs storageClassConfig: - - name: aws-ebs-sc + - name: aws-ebs strategy: ClusterResourceSet nfd: strategy: HelmAddon diff --git a/examples/capi-quick-start/aws-cluster-cilium-crs.yaml b/examples/capi-quick-start/aws-cluster-cilium-crs.yaml index 88ee71752..cf11f7edd 100644 --- a/examples/capi-quick-start/aws-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/aws-cluster-cilium-crs.yaml @@ -34,7 +34,7 @@ spec: providers: - name: aws-ebs storageClassConfig: - - name: aws-ebs-sc + - name: aws-ebs strategy: ClusterResourceSet nfd: strategy: ClusterResourceSet diff --git a/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml index 91fd7923b..bc7efdc8a 100644 --- a/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml @@ -34,7 +34,7 @@ spec: providers: - name: aws-ebs storageClassConfig: - - name: aws-ebs-sc + - name: aws-ebs strategy: ClusterResourceSet nfd: strategy: HelmAddon diff --git a/hack/examples/patches/aws/csi.yaml b/hack/examples/patches/aws/csi.yaml index fccddd2ad..f76374834 100644 --- a/hack/examples/patches/aws/csi.yaml +++ b/hack/examples/patches/aws/csi.yaml @@ -10,5 +10,5 @@ providers: - name: aws-ebs storageClassConfig: - - name: aws-ebs-sc + - name: aws-ebs strategy: ClusterResourceSet From dda31d8284dec3dc777b541cf0a882615a75e837 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 28 Mar 2024 09:16:16 -0600 Subject: [PATCH 46/87] fix: typo for default storage class key --- .../generic/lifecycle/clusterautoscaler/strategy_helmaddon.go | 3 ++- pkg/handlers/generic/lifecycle/utils/utils.go | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go b/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go index 7ee2ed2a3..a22e69d2f 100644 --- a/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go +++ b/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go @@ -53,7 +53,8 @@ func (s helmAddonStrategy) apply( log logr.Logger, ) error { log.Info("Retrieving cluster-autoscaler installation values template for cluster") - valuesTemplateConfigMap, err := utils.RetrieveValuesTemplateConfigMap(ctx, + valuesTemplateConfigMap, err := utils.RetrieveValuesTemplateConfigMap( + ctx, s.client, s.config.defaultValuesTemplateConfigMapName, defaultsNamespace) diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index 7c58c8017..10c38bee6 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -30,9 +30,9 @@ const ( ) var ( - defualtStorageClassKey = "storageclass.kubernetes.io/is-default-class" + defaultStorageClassKey = "storageclass.kubernetes.io/is-default-class" defaultStorageClassMap = map[string]string{ - defualtStorageClassKey: "true", + defaultStorageClassKey: "true", } defaultParams = map[string]string{ "csi.storage.k8s.io/fstype": "ext4", From 832cc64fc9c077cb7016e437f760c197477312a7 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 28 Mar 2024 11:03:33 -0600 Subject: [PATCH 47/87] fix: addon defaults for csi --- api/v1alpha1/addon_types.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index df4ff06bb..270ca65dc 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -5,6 +5,7 @@ package v1alpha1 import ( corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables" @@ -203,12 +204,14 @@ func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { XPreserveUnknownFields: true, }, "reclaimPolicy": { - Type: "string", - Enum: variables.MustMarshalValuesToEnumJSON(supportedReclaimPolicies...), + Type: "string", + Enum: variables.MustMarshalValuesToEnumJSON(supportedReclaimPolicies...), + Default: variables.MustMarshal(VolumeReclaimDelete), }, "volumeBindingMode": { - Type: "string", - Enum: variables.MustMarshalValuesToEnumJSON(supportedBindingModes...), + Type: "string", + Enum: variables.MustMarshalValuesToEnumJSON(supportedBindingModes...), + Default: variables.MustMarshal(VolumeBindingWaitForFirstConsumer), }, }, }, @@ -250,8 +253,8 @@ func (CSIProvider) VariableSchema() clusterv1.VariableSchema { "storageClassConfig": { Type: "array", Items: &clusterv1.JSONSchemaProps{ - Type: "object", - Properties: StorageClassConfig{}.VariableSchema().OpenAPIV3Schema.Properties, + Type: "object", + Items: ptr.To(StorageClassConfig{}.VariableSchema().OpenAPIV3Schema), }, }, }, @@ -289,8 +292,8 @@ func (CSIProviders) VariableSchema() clusterv1.VariableSchema { "providers": { Type: "array", Items: &clusterv1.JSONSchemaProps{ - Type: "object", - Properties: CSIProvider{}.VariableSchema().OpenAPIV3Schema.Properties, + Type: "object", + Items: ptr.To(CSIProvider{}.VariableSchema().OpenAPIV3Schema), }, }, "defaultStorage": DefaultStorage{}.VariableSchema().OpenAPIV3Schema, From 868022f7c6f24d8ba4622a03beaf78dc1f00c70b Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 28 Mar 2024 12:29:54 -0600 Subject: [PATCH 48/87] fix: sets the Items correctly --- api/v1alpha1/addon_types.go | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 270ca65dc..19bd443d6 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -15,12 +15,12 @@ const ( AddonStrategyClusterResourceSet AddonStrategy = "ClusterResourceSet" AddonStrategyHelmAddon AddonStrategy = "HelmAddon" - VolumeBindingImmediate string = "Immmediate" - VolumeBindingWaitForFirstConsumer string = "WaitForFirstConsumer" + VolumeBindingImmediate = "Immmediate" + VolumeBindingWaitForFirstConsumer = "WaitForFirstConsumer" - VolumeReclaimRecycle string = "Recycle" - VolumeReclaimDelete string = "Delete" - VolumeReclaimRetain string = "Retain" + VolumeReclaimRecycle = "Recycle" + VolumeReclaimDelete = "Delete" + VolumeReclaimRetain = "Retain" ) type Addons struct { @@ -199,9 +199,11 @@ func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { Description: "Name of storage class config.", }, "parameters": { - Type: "object", - Description: "Parameters passed into the storage class object.", - XPreserveUnknownFields: true, + Type: "object", + Description: "Parameters passed into the storage class object.", + AdditionalProperties: &clusterv1.JSONSchemaProps{ + Type: "string", + }, }, "reclaimPolicy": { Type: "string", @@ -251,11 +253,8 @@ func (CSIProvider) VariableSchema() clusterv1.VariableSchema { }, }, "storageClassConfig": { - Type: "array", - Items: &clusterv1.JSONSchemaProps{ - Type: "object", - Items: ptr.To(StorageClassConfig{}.VariableSchema().OpenAPIV3Schema), - }, + Type: "array", + Items: ptr.To(StorageClassConfig{}.VariableSchema().OpenAPIV3Schema), }, }, }, @@ -290,11 +289,8 @@ func (CSIProviders) VariableSchema() clusterv1.VariableSchema { Type: "object", Properties: map[string]clusterv1.JSONSchemaProps{ "providers": { - Type: "array", - Items: &clusterv1.JSONSchemaProps{ - Type: "object", - Items: ptr.To(CSIProvider{}.VariableSchema().OpenAPIV3Schema), - }, + Type: "array", + Items: ptr.To(CSIProvider{}.VariableSchema().OpenAPIV3Schema), }, "defaultStorage": DefaultStorage{}.VariableSchema().OpenAPIV3Schema, }, From 25b05fca89e890429bde8754faac48ca66828570 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 28 Mar 2024 12:37:47 -0600 Subject: [PATCH 49/87] fix: examples --- examples/capi-quick-start/aws-cluster-calico-crs.yaml | 2 +- examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml | 2 +- examples/capi-quick-start/aws-cluster-cilium-crs.yaml | 2 +- examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml | 2 +- hack/examples/patches/aws/csi.yaml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/capi-quick-start/aws-cluster-calico-crs.yaml b/examples/capi-quick-start/aws-cluster-calico-crs.yaml index fe1ffdef1..790b4a640 100644 --- a/examples/capi-quick-start/aws-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/aws-cluster-calico-crs.yaml @@ -30,7 +30,7 @@ spec: csi: defaultStorage: providerName: aws-ebs - storageClassConfigName: aws-ebs-sc + storageClassConfigName: aws-ebs providers: - name: aws-ebs storageClassConfig: diff --git a/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml index 8041814b5..52bf9648a 100644 --- a/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/aws-cluster-calico-helm-addon.yaml @@ -30,7 +30,7 @@ spec: csi: defaultStorage: providerName: aws-ebs - storageClassConfigName: aws-ebs-sc + storageClassConfigName: aws-ebs providers: - name: aws-ebs storageClassConfig: diff --git a/examples/capi-quick-start/aws-cluster-cilium-crs.yaml b/examples/capi-quick-start/aws-cluster-cilium-crs.yaml index cf11f7edd..e9541e789 100644 --- a/examples/capi-quick-start/aws-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/aws-cluster-cilium-crs.yaml @@ -30,7 +30,7 @@ spec: csi: defaultStorage: providerName: aws-ebs - storageClassConfigName: aws-ebs-sc + storageClassConfigName: aws-ebs providers: - name: aws-ebs storageClassConfig: diff --git a/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml index bc7efdc8a..e803994e8 100644 --- a/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/aws-cluster-cilium-helm-addon.yaml @@ -30,7 +30,7 @@ spec: csi: defaultStorage: providerName: aws-ebs - storageClassConfigName: aws-ebs-sc + storageClassConfigName: aws-ebs providers: - name: aws-ebs storageClassConfig: diff --git a/hack/examples/patches/aws/csi.yaml b/hack/examples/patches/aws/csi.yaml index f76374834..0bbe4c5bd 100644 --- a/hack/examples/patches/aws/csi.yaml +++ b/hack/examples/patches/aws/csi.yaml @@ -6,7 +6,7 @@ value: defaultStorage: providerName: aws-ebs - storageClassConfigName: aws-ebs-sc + storageClassConfigName: aws-ebs providers: - name: aws-ebs storageClassConfig: From 59bf818e983fbd945db78c35bde5bcc6680e33e9 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 28 Mar 2024 13:22:28 -0600 Subject: [PATCH 50/87] fix: actually apply cm --- pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go | 4 ++++ pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 15305348c..f3ab9c2ee 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -100,6 +100,10 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, if err != nil { return err } + err = client.ServerSideApply(ctx, a.client, cm) + if err != nil { + return err + } return lifecycleutils.EnsureCRSForClusterFromConfigMaps( ctx, "aws-storageclass-crs", diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 4f2d67a8b..0e6b1abf9 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -160,6 +160,10 @@ func (n *NutanixCSI) createStorageClasses(ctx context.Context, if err != nil { return err } + err = client.ServerSideApply(ctx, n.client, cm) + if err != nil { + return err + } return lifecycleutils.EnsureCRSForClusterFromConfigMaps( ctx, "nutanix-storageclass-crs", From 3eee6ce2b224aae64006b41117980e1c4a834828 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 28 Mar 2024 13:35:03 -0600 Subject: [PATCH 51/87] fix: storage class crs --- pkg/handlers/generic/lifecycle/utils/utils.go | 2 +- pkg/handlers/generic/lifecycle/utils/utils_test.go | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index 10c38bee6..d87e225c4 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -213,6 +213,6 @@ func CreateConfigMapForCRS(configMapName, configMapNamespace string, } l = append(l, objYaml) } - cm.Data[defaultCRSConfigMapKey] = fmt.Sprintf("|\n%s", string(utilyaml.JoinYaml(l...))) + cm.Data[defaultCRSConfigMapKey] = string(utilyaml.JoinYaml(l...)) return cm, nil } diff --git a/pkg/handlers/generic/lifecycle/utils/utils_test.go b/pkg/handlers/generic/lifecycle/utils/utils_test.go index fccea15b8..26ec622e6 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils_test.go +++ b/pkg/handlers/generic/lifecycle/utils/utils_test.go @@ -56,8 +56,7 @@ func TestCreateConfigMapForCRS(t *testing.T) { Kind: "ConfigMap", }, Data: map[string]string{ - defaultCRSConfigMapKey: `| -apiVersion: storage.k8s.io/v1 + defaultCRSConfigMapKey: `apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: creationTimestamp: null From f0397e5e2fed98e5e1334a9f83bf644dd64c9e58 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 28 Mar 2024 13:58:23 -0600 Subject: [PATCH 52/87] fix: use a unique storage class cm per cluster --- pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go | 2 +- pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index f3ab9c2ee..8aa171907 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -93,7 +93,7 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, )) } cm, err := lifecycleutils.CreateConfigMapForCRS( - "aws-storageclass-cm", + fmt.Sprintf("aws-storageclass-cm-%s", cluster.Name), a.config.DefaultsNamespace(), allStorageClasses..., ) diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 0e6b1abf9..8869fac3e 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -153,7 +153,7 @@ func (n *NutanixCSI) createStorageClasses(ctx context.Context, )) } cm, err := lifecycleutils.CreateConfigMapForCRS( - "nutanix-storageclass-cm", + fmt.Sprintf("nutanix-storageclass-cm-%s", cluster.Name), n.config.DefaultsNamespace(), allStorageClasses..., ) From c57e70924c41d76407b4f10f656d85fa973c3254 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 28 Mar 2024 14:07:51 -0600 Subject: [PATCH 53/87] refactor: rename CSIProviders to CSI --- api/v1alpha1/addon_types.go | 8 +-- api/v1alpha1/zz_generated.deepcopy.go | 60 ++++++++++++------- .../templates/role.yaml | 2 +- make/addons.mk | 13 +--- pkg/handlers/generic/lifecycle/csi/handler.go | 2 +- 5 files changed, 46 insertions(+), 39 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 19bd443d6..b550445a4 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -37,7 +37,7 @@ type Addons struct { CCM *CCM `json:"ccm,omitempty"` // +optional - CSIProviders *CSIProviders `json:"csi,omitempty"` + CSIProviders *CSI `json:"csi,omitempty"` } func (Addons) VariableSchema() clusterv1.VariableSchema { @@ -49,7 +49,7 @@ func (Addons) VariableSchema() clusterv1.VariableSchema { "cni": CNI{}.VariableSchema().OpenAPIV3Schema, "nfd": NFD{}.VariableSchema().OpenAPIV3Schema, "clusterAutoscaler": ClusterAutoscaler{}.VariableSchema().OpenAPIV3Schema, - "csi": CSIProviders{}.VariableSchema().OpenAPIV3Schema, + "csi": CSI{}.VariableSchema().OpenAPIV3Schema, "ccm": CCM{}.VariableSchema().OpenAPIV3Schema, }, }, @@ -148,7 +148,7 @@ type DefaultStorage struct { StorageClassConfigName string `json:"storageClassConfigName"` } -type CSIProviders struct { +type CSI struct { // +optional Providers []CSIProvider `json:"providers,omitempty"` // +optional @@ -283,7 +283,7 @@ func (DefaultStorage) VariableSchema() clusterv1.VariableSchema { } } -func (CSIProviders) VariableSchema() clusterv1.VariableSchema { +func (CSI) VariableSchema() clusterv1.VariableSchema { return clusterv1.VariableSchema{ OpenAPIV3Schema: clusterv1.JSONSchemaProps{ Type: "object", diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 467ea9763..ec26a8beb 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -206,7 +206,7 @@ func (in *Addons) DeepCopyInto(out *Addons) { } if in.CSIProviders != nil { in, out := &in.CSIProviders, &out.CSIProviders - *out = new(CSIProviders) + *out = new(CSI) (*in).DeepCopyInto(*out) } } @@ -252,34 +252,24 @@ func (in *CNI) DeepCopy() *CNI { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CSIProvider) DeepCopyInto(out *CSIProvider) { +<<<<<<< HEAD +======= +func (in *CPI) DeepCopyInto(out *CPI) { *out = *in - if in.StorageClassConfig != nil { - in, out := &in.StorageClassConfig, &out.StorageClassConfig - *out = make([]StorageClassConfig, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Credentials != nil { - in, out := &in.Credentials, &out.Credentials - *out = new(v1.SecretReference) - **out = **in - } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIProvider. -func (in *CSIProvider) DeepCopy() *CSIProvider { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CPI. +func (in *CPI) DeepCopy() *CPI { if in == nil { return nil } - out := new(CSIProvider) + out := new(CPI) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CSIProviders) DeepCopyInto(out *CSIProviders) { +func (in *CSI) DeepCopyInto(out *CSI) { *out = *in if in.Providers != nil { in, out := &in.Providers, &out.Providers @@ -295,12 +285,40 @@ func (in *CSIProviders) DeepCopyInto(out *CSIProviders) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIProviders. -func (in *CSIProviders) DeepCopy() *CSIProviders { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSI. +func (in *CSI) DeepCopy() *CSI { if in == nil { return nil } - out := new(CSIProviders) + out := new(CSI) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +>>>>>>> 1020f52 (refactor: rename CSIProviders to CSI) +func (in *CSIProvider) DeepCopyInto(out *CSIProvider) { + *out = *in + if in.StorageClassConfig != nil { + in, out := &in.StorageClassConfig, &out.StorageClassConfig + *out = make([]StorageClassConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Credentials != nil { + in, out := &in.Credentials, &out.Credentials + *out = new(v1.SecretReference) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CSIProvider. +func (in *CSIProvider) DeepCopy() *CSIProvider { + if in == nil { + return nil + } + out := new(CSIProvider) in.DeepCopyInto(out) return out } diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml index e3cd174f7..84702cdfb 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml @@ -4,7 +4,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: {{ include "chart.name" . }}-manager-role + name: cluster-api-runtime-extensions-nutanix-manager-role rules: - apiGroups: - "" diff --git a/make/addons.mk b/make/addons.mk index 4cc4d8f42..64c1b42db 100644 --- a/make/addons.mk +++ b/make/addons.mk @@ -7,7 +7,7 @@ export NODE_FEATURE_DISCOVERY_VERSION := $(shell goprintconst -file pkg/handlers export CLUSTER_AUTOSCALER_VERSION := 9.35.0 export AWS_CSI_SNAPSHOT_CONTROLLER_VERSION := v6.3.3 export AWS_EBS_CSI_CHART_VERSION := v2.28.1 -<<<<<<< HEAD +export NUTANIX_CSI_CHART_VERSION := v2.6.6 # a map of AWS CCM versions export AWS_CCM_VERSION_127 := v1.27.1 export AWS_CCM_CHART_VERSION_127 := 0.0.8 @@ -16,17 +16,6 @@ export AWS_CCM_CHART_VERSION_128 := 0.0.8 .PHONY: addons.sync addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler aws-ebs-csi aws-ccm.127 aws-ccm.128) -======= -export NUTANIX_CSI_CHART_VERSION := v2.6.6 -# a map of AWS CPI versions -export AWS_CPI_VERSION_127 := v1.27.1 -export AWS_CPI_CHART_VERSION_127 := 0.0.8 -export AWS_CPI_VERSION_128 := v1.28.1 -export AWS_CPI_CHART_VERSION_128 := 0.0.8 - -.PHONY: addons.sync -addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler aws-ebs-csi aws-cpi.127 aws-cpi.128 nutanix-csi) ->>>>>>> 625d067 (feat: minor API tweaks and adds tooling for chart) .PHONY: update-addon.calico update-addon.calico: ; $(info $(M) updating calico manifests) diff --git a/pkg/handlers/generic/lifecycle/csi/handler.go b/pkg/handlers/generic/lifecycle/csi/handler.go index 14209bec3..e7bccfb3b 100644 --- a/pkg/handlers/generic/lifecycle/csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/handler.go @@ -72,7 +72,7 @@ func (c *CSIHandler) AfterControlPlaneInitialized( ) varMap := variables.ClusterVariablesToVariablesMap(req.Cluster.Spec.Topology.Variables) resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) - csiProviders, found, err := variables.Get[v1alpha1.CSIProviders]( + csiProviders, found, err := variables.Get[v1alpha1.CSI]( varMap, c.variableName, c.variablePath...) From 8ceebeff2ebcb61c80a3c4ca2afadcd341fa42c7 Mon Sep 17 00:00:00 2001 From: faiq Date: Thu, 28 Mar 2024 16:02:34 -0600 Subject: [PATCH 54/87] fix: more unit tests --- api/v1alpha1/clusterconfig_types.go | 10 +- .../generic/lifecycle/csi/aws-ebs/handler.go | 3 +- .../lifecycle/csi/nutanix-csi/handler.go | 3 +- pkg/handlers/generic/lifecycle/utils/utils.go | 10 +- .../generic/lifecycle/utils/utils_test.go | 95 +++++++++++++++++++ 5 files changed, 108 insertions(+), 13 deletions(-) diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index c664fc665..83242d1b9 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -14,13 +14,13 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/openapi/patterns" ) -type StorageDriver string +type StorageProvisioner string const ( - CNIProviderCalico = "Calico" - CNIProviderCilium = "Cilium" - AWSEBSDriver StorageDriver = "ebs.csi.aws.com" - NutanixDriver StorageDriver = "csi.nutanix.com" + CNIProviderCalico = "Calico" + CNIProviderCilium = "Cilium" + AWSEBSProvisioner StorageProvisioner = "ebs.csi.aws.com" + NutanixProvisioner StorageProvisioner = "csi.nutanix.com" CSIProviderAWSEBS = "aws-ebs" CSIProviderNutanix = "nutanix" diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 8aa171907..528d50cef 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -86,9 +86,8 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass( c, - cluster, a.config.GlobalOptions.DefaultsNamespace(), - v1alpha1.CSIProviderAWSEBS, + v1alpha1.AWSEBSProvisioner, setAsDefault, )) } diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 8869fac3e..bb721f366 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -146,9 +146,8 @@ func (n *NutanixCSI) createStorageClasses(ctx context.Context, v1alpha1.CSIProviderNutanix == defaultStorageConfig.ProviderName allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass( c, - cluster, n.config.GlobalOptions.DefaultsNamespace(), - v1alpha1.NutanixDriver, + v1alpha1.NutanixProvisioner, setAsDefault, )) } diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index d87e225c4..6906be3b3 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -34,7 +34,7 @@ var ( defaultStorageClassMap = map[string]string{ defaultStorageClassKey: "true", } - defaultParams = map[string]string{ + defaultAWSStorageClassParams = map[string]string{ "csi.storage.k8s.io/fstype": "ext4", "type": "gp3", } @@ -138,9 +138,8 @@ func RetrieveValuesTemplateConfigMap( func CreateStorageClass( storageConfig v1alpha1.StorageClassConfig, - cluster *clusterv1.Cluster, defaultsNamespace string, - provisionerName v1alpha1.StorageDriver, + provisionerName v1alpha1.StorageProvisioner, isDefault bool, ) *storagev1.StorageClass { var volumeBindingMode *storagev1.VolumeBindingMode @@ -159,7 +158,10 @@ func CreateStorageClass( case v1alpha1.VolumeReclaimRetain: reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimRetain) } - params := defaultParams + var params map[string]string + if provisionerName == v1alpha1.AWSEBSProvisioner { + params = defaultAWSStorageClassParams + } if storageConfig.Parameters != nil { params = maps.Clone(storageConfig.Parameters) } diff --git a/pkg/handlers/generic/lifecycle/utils/utils_test.go b/pkg/handlers/generic/lifecycle/utils/utils_test.go index 26ec622e6..feae34c02 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils_test.go +++ b/pkg/handlers/generic/lifecycle/utils/utils_test.go @@ -6,12 +6,107 @@ package utils import ( "testing" + "github.com/google/go-cmp/cmp" corev1 "k8s.io/api/core/v1" storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/ptr" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" ) +func TestCreateStorageClass(t *testing.T) { + tests := []struct { + name string + defaultsNamespace string + storageConfig v1alpha1.StorageClassConfig + expectedStorageClass *storagev1.StorageClass + provisioner v1alpha1.StorageProvisioner + isDefault bool + }{ + { + name: "defaulting with AWS", + storageConfig: v1alpha1.StorageClassConfig{ + Name: "aws-ebs", + ReclaimPolicy: v1alpha1.VolumeReclaimDelete, + VolumeBindingMode: v1alpha1.VolumeBindingWaitForFirstConsumer, + Parameters: nil, + }, + expectedStorageClass: &storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: kindStorageClass, + APIVersion: storagev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "aws-ebs", + Namespace: "default", + }, + Parameters: defaultAWSStorageClassParams, + ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), + VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), + Provisioner: string(v1alpha1.AWSEBSProvisioner), + }, + provisioner: v1alpha1.AWSEBSProvisioner, + defaultsNamespace: "default", + }, + { + name: "nutanix for nutanix files", + storageConfig: v1alpha1.StorageClassConfig{ + Name: "nutanix-volumes", + ReclaimPolicy: v1alpha1.VolumeReclaimDelete, + VolumeBindingMode: v1alpha1.VolumeBindingWaitForFirstConsumer, + Parameters: map[string]string{ + "csi.storage.k8s.io/fstype": "ext4", + "flashMode": "ENABLED", + "storageContainer": "storage-container-name", + "chapAuth": "ENABLED", + "storageType": "NutanixVolumes", + "whitelistIPMode": "ENABLED", + "whitelistIPAddr": "1.1.1.1", + }, + }, + expectedStorageClass: &storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: kindStorageClass, + APIVersion: storagev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "nutanix-volumes", + Namespace: "default", + }, + Parameters: map[string]string{ + "csi.storage.k8s.io/fstype": "ext4", + "flashMode": "ENABLED", + "storageContainer": "storage-container-name", + "chapAuth": "ENABLED", + "storageType": "NutanixVolumes", + "whitelistIPMode": "ENABLED", + "whitelistIPAddr": "1.1.1.1", + }, + ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), + VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), + Provisioner: string(v1alpha1.NutanixProvisioner), + }, + provisioner: v1alpha1.NutanixProvisioner, + defaultsNamespace: "default", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sc := CreateStorageClass( + tt.storageConfig, + tt.defaultsNamespace, + tt.provisioner, + false, + ) + if diff := cmp.Diff(sc, tt.expectedStorageClass); diff != "" { + t.Errorf("CreateStorageClass() mismatch (-want +got):\n%s", diff) + } + }) + } +} + func TestCreateConfigMapForCRS(t *testing.T) { tests := []struct { name string From 3269c5b05db6b44109b91c32ee801bd530111a6e Mon Sep 17 00:00:00 2001 From: faiq Date: Fri, 29 Mar 2024 08:50:15 -0600 Subject: [PATCH 55/87] fix: gomod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index c1df13beb..c55396282 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api v0.0.0-00010101000000-000000000000 github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common v0.0.0-00010101000000-000000000000 github.com/go-logr/logr v1.4.1 + github.com/google/go-cmp v0.6.0 github.com/onsi/ginkgo/v2 v2.16.0 github.com/onsi/gomega v1.31.1 github.com/spf13/pflag v1.0.5 @@ -71,7 +72,6 @@ require ( github.com/golang/protobuf v1.5.4 // indirect github.com/google/cel-go v0.17.7 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-github/v53 v53.2.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect From f963e9790f513122c970a5e61d86bcc0159cfa09 Mon Sep 17 00:00:00 2001 From: faiq Date: Fri, 29 Mar 2024 09:29:25 -0600 Subject: [PATCH 56/87] test: adds a unit test for no params --- .../generic/lifecycle/utils/utils_test.go | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pkg/handlers/generic/lifecycle/utils/utils_test.go b/pkg/handlers/generic/lifecycle/utils/utils_test.go index feae34c02..af23ce985 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils_test.go +++ b/pkg/handlers/generic/lifecycle/utils/utils_test.go @@ -91,6 +91,29 @@ func TestCreateStorageClass(t *testing.T) { provisioner: v1alpha1.NutanixProvisioner, defaultsNamespace: "default", }, + { + name: "nutanix defaults", + storageConfig: v1alpha1.StorageClassConfig{ + Name: "nutanix-volumes", + ReclaimPolicy: v1alpha1.VolumeReclaimDelete, + VolumeBindingMode: v1alpha1.VolumeBindingWaitForFirstConsumer, + }, + expectedStorageClass: &storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: kindStorageClass, + APIVersion: storagev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "nutanix-volumes", + Namespace: "default", + }, + ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), + VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), + Provisioner: string(v1alpha1.NutanixProvisioner), + }, + provisioner: v1alpha1.NutanixProvisioner, + defaultsNamespace: "default", + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 9ec05d13ee12c20c339d989d62189fb8ee05daa3 Mon Sep 17 00:00:00 2001 From: faiq Date: Fri, 29 Mar 2024 12:05:44 -0600 Subject: [PATCH 57/87] feat: create crs from provider credentials --- pkg/handlers/generic/lifecycle/ccm/handler.go | 2 +- .../clusterautoscaler/strategy_crs.go | 2 +- .../lifecycle/cni/calico/strategy_crs.go | 2 +- .../lifecycle/cni/cilium/strategy_crs.go | 2 +- .../generic/lifecycle/csi/aws-ebs/handler.go | 4 +-- .../lifecycle/csi/nutanix-csi/handler.go | 33 ++++++++++++++++++- .../generic/lifecycle/nfd/strategy_crs.go | 2 +- pkg/handlers/generic/lifecycle/utils/utils.go | 29 ++++++++++++---- 8 files changed, 62 insertions(+), 14 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/ccm/handler.go b/pkg/handlers/generic/lifecycle/ccm/handler.go index 43360aa1b..04dd32f85 100644 --- a/pkg/handlers/generic/lifecycle/ccm/handler.go +++ b/pkg/handlers/generic/lifecycle/ccm/handler.go @@ -114,7 +114,7 @@ func (c *CCMHandler) AfterControlPlaneInitialized( ) return } - err = lifecycleutils.EnsureCRSForClusterFromConfigMaps(ctx, cm.Name, c.client, &req.Cluster, cm) + err = lifecycleutils.EnsureCRSForClusterFromObjects(ctx, cm.Name, c.client, &req.Cluster, cm) if err != nil { log.Error( err, diff --git a/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_crs.go b/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_crs.go index 981d4ec01..432efba62 100644 --- a/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_crs.go +++ b/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_crs.go @@ -121,7 +121,7 @@ func (s crsStrategy) apply( ) } - if err = utils.EnsureCRSForClusterFromConfigMaps(ctx, cm.Name, s.client, targetCluster, cm); err != nil { + if err = utils.EnsureCRSForClusterFromObjects(ctx, cm.Name, s.client, targetCluster, cm); err != nil { return fmt.Errorf( "failed to apply cluster-autoscaler installation ClusterResourceSet: %w", err, diff --git a/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go b/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go index a08a686e2..27a366137 100644 --- a/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go +++ b/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go @@ -150,7 +150,7 @@ func (s crsStrategy) ensureCNICRSForCluster( ) } - if err := utils.EnsureCRSForClusterFromConfigMaps(ctx, cm.Name, s.client, cluster, tigeraConfigMap, cm); err != nil { + if err := utils.EnsureCRSForClusterFromObjects(ctx, cm.Name, s.client, cluster, tigeraConfigMap, cm); err != nil { return fmt.Errorf( "failed to apply Calico CNI installation ClusterResourceSet: %w", err, diff --git a/pkg/handlers/generic/lifecycle/cni/cilium/strategy_crs.go b/pkg/handlers/generic/lifecycle/cni/cilium/strategy_crs.go index 28f07a77c..6a9b805ac 100644 --- a/pkg/handlers/generic/lifecycle/cni/cilium/strategy_crs.go +++ b/pkg/handlers/generic/lifecycle/cni/cilium/strategy_crs.go @@ -87,7 +87,7 @@ func (s crsStrategy) apply( ) } - if err := utils.EnsureCRSForClusterFromConfigMaps(ctx, cm.Name, s.client, cluster, cm); err != nil { + if err := utils.EnsureCRSForClusterFromObjects(ctx, cm.Name, s.client, cluster, cm); err != nil { return fmt.Errorf( "failed to apply Cilium CNI installation ClusterResourceSet: %w", err, diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 528d50cef..90072b3a2 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -103,7 +103,7 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, if err != nil { return err } - return lifecycleutils.EnsureCRSForClusterFromConfigMaps( + return lifecycleutils.EnsureCRSForClusterFromObjects( ctx, "aws-storageclass-crs", a.client, @@ -140,7 +140,7 @@ func (a *AWSEBS) handleCRSApply(ctx context.Context, err, ) } - err = lifecycleutils.EnsureCRSForClusterFromConfigMaps( + err = lifecycleutils.EnsureCRSForClusterFromObjects( ctx, cm.Name, a.client, diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index bb721f366..090a9e06d 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -8,6 +8,7 @@ import ( "fmt" "github.com/spf13/pflag" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -75,6 +76,36 @@ func (n *NutanixCSI) Apply( default: return fmt.Errorf("stategy %s not implemented", strategy) } + if provider.Credentials != nil { + sec := &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: provider.Credentials.Name, + Name: provider.Credentials.Namespace, + }, + } + err := n.client.Get( + ctx, + ctrlclient.ObjectKeyFromObject(sec), + sec, + ) + if err != nil { + return err + } + err = lifecycleutils.EnsureCRSForClusterFromObjects( + ctx, + fmt.Sprintf("nutanix-csi-credentials-crs-%s", req.Cluster.Name), + n.client, + &req.Cluster, + sec, + ) + if err != nil { + return err + } + } return n.createStorageClasses( ctx, provider.StorageClassConfig, @@ -163,7 +194,7 @@ func (n *NutanixCSI) createStorageClasses(ctx context.Context, if err != nil { return err } - return lifecycleutils.EnsureCRSForClusterFromConfigMaps( + return lifecycleutils.EnsureCRSForClusterFromObjects( ctx, "nutanix-storageclass-crs", n.client, diff --git a/pkg/handlers/generic/lifecycle/nfd/strategy_crs.go b/pkg/handlers/generic/lifecycle/nfd/strategy_crs.go index 461db5318..26498d482 100644 --- a/pkg/handlers/generic/lifecycle/nfd/strategy_crs.go +++ b/pkg/handlers/generic/lifecycle/nfd/strategy_crs.go @@ -87,7 +87,7 @@ func (s crsStrategy) apply( ) } - if err := utils.EnsureCRSForClusterFromConfigMaps(ctx, cm.Name, s.client, cluster, cm); err != nil { + if err := utils.EnsureCRSForClusterFromObjects(ctx, cm.Name, s.client, cluster, cm); err != nil { return fmt.Errorf( "failed to apply NFD installation ClusterResourceSet: %w", err, diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index 6906be3b3..885d45c65 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -40,18 +40,35 @@ var ( } ) -func EnsureCRSForClusterFromConfigMaps( +func EnsureCRSForClusterFromObjects( ctx context.Context, crsName string, c ctrlclient.Client, cluster *clusterv1.Cluster, - configMaps ...*corev1.ConfigMap, + objects ...runtime.Object, ) error { - resources := make([]crsv1.ResourceRef, 0, len(configMaps)) - for _, cm := range configMaps { + resources := make([]crsv1.ResourceRef, 0, len(objects)) + for _, obj := range objects { + var name string + var kind crsv1.ClusterResourceSetResourceKind + cm, ok := obj.(*corev1.ConfigMap) + if !ok { + sec, secOk := obj.(*corev1.Secret) + if !secOk { + return fmt.Errorf( + "cannot create ClusterResourceSet with obj %v only secrets and configmaps are supported", + obj, + ) + } + name = sec.Name + kind = crsv1.SecretClusterResourceSetResourceKind + } else { + name = cm.Name + kind = crsv1.ConfigMapClusterResourceSetResourceKind + } resources = append(resources, crsv1.ResourceRef{ - Kind: string(crsv1.ConfigMapClusterResourceSetResourceKind), - Name: cm.Name, + Name: name, + Kind: string(kind), }) } From 13aa430c05968f9108d194277c1d454b71ab1b8c Mon Sep 17 00:00:00 2001 From: faiq Date: Fri, 29 Mar 2024 12:34:08 -0600 Subject: [PATCH 58/87] feat: set a default storage class if 1 provider and 1 storage class config --- .../generic/lifecycle/csi/aws-ebs/handler.go | 5 ++++- pkg/handlers/generic/lifecycle/csi/handler.go | 13 ++++++++++++- .../generic/lifecycle/csi/nutanix-csi/handler.go | 6 +++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 90072b3a2..188e051b5 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -54,6 +54,7 @@ func (a *AWSEBS) Apply( ctx context.Context, provider v1alpha1.CSIProvider, defaultStorageConfig *v1alpha1.DefaultStorage, + hasOneProviderAndOneStorageClass bool, req *runtimehooksv1.AfterControlPlaneInitializedRequest, ) error { strategy := provider.Strategy @@ -71,6 +72,7 @@ func (a *AWSEBS) Apply( ctx, provider.StorageClassConfig, &req.Cluster, + hasOneProviderAndOneStorageClass, defaultStorageConfig, ) } @@ -78,12 +80,13 @@ func (a *AWSEBS) Apply( func (a *AWSEBS) createStorageClasses(ctx context.Context, configs []v1alpha1.StorageClassConfig, cluster *clusterv1.Cluster, + hasOneProviderAndOneStorageClass bool, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { allStorageClasses := make([]runtime.Object, 0, len(configs)) for _, c := range configs { setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && - v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName + v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName || hasOneProviderAndOneStorageClass allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass( c, a.config.GlobalOptions.DefaultsNamespace(), diff --git a/pkg/handlers/generic/lifecycle/csi/handler.go b/pkg/handlers/generic/lifecycle/csi/handler.go index e7bccfb3b..59774aa56 100644 --- a/pkg/handlers/generic/lifecycle/csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/handler.go @@ -27,6 +27,7 @@ type CSIProvider interface { context.Context, v1alpha1.CSIProvider, *v1alpha1.DefaultStorage, + bool, // this is a bool which keeps track of the case where a user has only one provider and one storageclass *runtimehooksv1.AfterControlPlaneInitializedRequest, ) error } @@ -98,6 +99,10 @@ func (c *CSIHandler) AfterControlPlaneInitialized( ) return } + hasOneProviderAndOneStorageClass := len(csiProviders.Providers) == 1 && + len(csiProviders.Providers[0].StorageClassConfig) == 1 && + csiProviders.DefaultStorage == nil + for _, provider := range csiProviders.Providers { handler, ok := c.ProviderHandler[provider.Name] if !ok { @@ -110,7 +115,13 @@ func (c *CSIHandler) AfterControlPlaneInitialized( continue } log.Info(fmt.Sprintf("Creating csi provider %s", provider)) - err = handler.Apply(ctx, provider, csiProviders.DefaultStorage, req) + err = handler.Apply( + ctx, + provider, + csiProviders.DefaultStorage, + hasOneProviderAndOneStorageClass, + req, + ) if err != nil { log.Error( err, diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 090a9e06d..756dabd45 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -63,6 +63,7 @@ func (n *NutanixCSI) Apply( ctx context.Context, provider v1alpha1.CSIProvider, defaultStorageConfig *v1alpha1.DefaultStorage, + hasOneProviderAndOneStorageClass bool, req *runtimehooksv1.AfterControlPlaneInitializedRequest, ) error { strategy := provider.Strategy @@ -110,6 +111,7 @@ func (n *NutanixCSI) Apply( ctx, provider.StorageClassConfig, &req.Cluster, + hasOneProviderAndOneStorageClass, defaultStorageConfig, ) } @@ -169,12 +171,14 @@ func (n *NutanixCSI) handleHelmAddonApply( func (n *NutanixCSI) createStorageClasses(ctx context.Context, configs []v1alpha1.StorageClassConfig, cluster *clusterv1.Cluster, + hasOneProviderAndOneStorageClass bool, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { allStorageClasses := make([]runtime.Object, 0, len(configs)) for _, c := range configs { setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && - v1alpha1.CSIProviderNutanix == defaultStorageConfig.ProviderName + v1alpha1.CSIProviderNutanix == defaultStorageConfig.ProviderName || + hasOneProviderAndOneStorageClass allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass( c, n.config.GlobalOptions.DefaultsNamespace(), From 6845f969f13271c77cc3e911dc6d27d93bd44d7b Mon Sep 17 00:00:00 2001 From: faiq Date: Fri, 29 Mar 2024 12:57:03 -0600 Subject: [PATCH 59/87] refactor: use default storage config obj --- .../generic/lifecycle/csi/aws-ebs/handler.go | 5 +---- pkg/handlers/generic/lifecycle/csi/handler.go | 12 ++++++++---- .../generic/lifecycle/csi/nutanix-csi/handler.go | 6 +----- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 188e051b5..90072b3a2 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -54,7 +54,6 @@ func (a *AWSEBS) Apply( ctx context.Context, provider v1alpha1.CSIProvider, defaultStorageConfig *v1alpha1.DefaultStorage, - hasOneProviderAndOneStorageClass bool, req *runtimehooksv1.AfterControlPlaneInitializedRequest, ) error { strategy := provider.Strategy @@ -72,7 +71,6 @@ func (a *AWSEBS) Apply( ctx, provider.StorageClassConfig, &req.Cluster, - hasOneProviderAndOneStorageClass, defaultStorageConfig, ) } @@ -80,13 +78,12 @@ func (a *AWSEBS) Apply( func (a *AWSEBS) createStorageClasses(ctx context.Context, configs []v1alpha1.StorageClassConfig, cluster *clusterv1.Cluster, - hasOneProviderAndOneStorageClass bool, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { allStorageClasses := make([]runtime.Object, 0, len(configs)) for _, c := range configs { setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && - v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName || hasOneProviderAndOneStorageClass + v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass( c, a.config.GlobalOptions.DefaultsNamespace(), diff --git a/pkg/handlers/generic/lifecycle/csi/handler.go b/pkg/handlers/generic/lifecycle/csi/handler.go index 59774aa56..01f3e2b66 100644 --- a/pkg/handlers/generic/lifecycle/csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/handler.go @@ -27,7 +27,6 @@ type CSIProvider interface { context.Context, v1alpha1.CSIProvider, *v1alpha1.DefaultStorage, - bool, // this is a bool which keeps track of the case where a user has only one provider and one storageclass *runtimehooksv1.AfterControlPlaneInitializedRequest, ) error } @@ -99,9 +98,15 @@ func (c *CSIHandler) AfterControlPlaneInitialized( ) return } - hasOneProviderAndOneStorageClass := len(csiProviders.Providers) == 1 && + if len(csiProviders.Providers) == 1 && + csiProviders.Providers[0].StorageClassConfig != nil && len(csiProviders.Providers[0].StorageClassConfig) == 1 && - csiProviders.DefaultStorage == nil + csiProviders.DefaultStorage == nil { + csiProviders.DefaultStorage = &v1alpha1.DefaultStorage{ + ProviderName: csiProviders.Providers[0].Name, + StorageClassConfigName: csiProviders.Providers[0].StorageClassConfig[0].Name, + } + } for _, provider := range csiProviders.Providers { handler, ok := c.ProviderHandler[provider.Name] @@ -119,7 +124,6 @@ func (c *CSIHandler) AfterControlPlaneInitialized( ctx, provider, csiProviders.DefaultStorage, - hasOneProviderAndOneStorageClass, req, ) if err != nil { diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 756dabd45..090a9e06d 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -63,7 +63,6 @@ func (n *NutanixCSI) Apply( ctx context.Context, provider v1alpha1.CSIProvider, defaultStorageConfig *v1alpha1.DefaultStorage, - hasOneProviderAndOneStorageClass bool, req *runtimehooksv1.AfterControlPlaneInitializedRequest, ) error { strategy := provider.Strategy @@ -111,7 +110,6 @@ func (n *NutanixCSI) Apply( ctx, provider.StorageClassConfig, &req.Cluster, - hasOneProviderAndOneStorageClass, defaultStorageConfig, ) } @@ -171,14 +169,12 @@ func (n *NutanixCSI) handleHelmAddonApply( func (n *NutanixCSI) createStorageClasses(ctx context.Context, configs []v1alpha1.StorageClassConfig, cluster *clusterv1.Cluster, - hasOneProviderAndOneStorageClass bool, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { allStorageClasses := make([]runtime.Object, 0, len(configs)) for _, c := range configs { setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && - v1alpha1.CSIProviderNutanix == defaultStorageConfig.ProviderName || - hasOneProviderAndOneStorageClass + v1alpha1.CSIProviderNutanix == defaultStorageConfig.ProviderName allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass( c, n.config.GlobalOptions.DefaultsNamespace(), From 5ab09f8ce4de67e4f94413c3277f19e94b0d0c3c Mon Sep 17 00:00:00 2001 From: faiq Date: Fri, 29 Mar 2024 13:39:43 -0600 Subject: [PATCH 60/87] feat: allow volume expansion --- api/v1alpha1/addon_types.go | 18 +++++++++++--- pkg/handlers/generic/lifecycle/utils/utils.go | 9 +++---- .../generic/lifecycle/utils/utils_test.go | 24 +++++++++++-------- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index b550445a4..a21f1353c 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -178,6 +178,9 @@ type StorageClassConfig struct { // +optional VolumeBindingMode string `json:"volumeBindingMode,omitempty"` + + // +optional + AllowExpansion bool `json:"allowExpansion,omitempty"` } func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { @@ -192,7 +195,8 @@ func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { } return clusterv1.VariableSchema{ OpenAPIV3Schema: clusterv1.JSONSchemaProps{ - Type: "object", + Type: "object", + Required: []string{"name"}, Properties: map[string]clusterv1.JSONSchemaProps{ "name": { Type: "string", @@ -215,6 +219,11 @@ func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { Enum: variables.MustMarshalValuesToEnumJSON(supportedBindingModes...), Default: variables.MustMarshal(VolumeBindingWaitForFirstConsumer), }, + "allowExpansion": { + Type: "boolean", + Default: variables.MustMarshal(false), + Description: "If the storage class should allow volume expanding", + }, }, }, } @@ -224,7 +233,8 @@ func (CSIProvider) VariableSchema() clusterv1.VariableSchema { supportedCSIProviders := []string{CSIProviderAWSEBS, CSIProviderNutanix} return clusterv1.VariableSchema{ OpenAPIV3Schema: clusterv1.JSONSchemaProps{ - Type: "object", + Type: "object", + Required: []string{"name", "strategy"}, Properties: map[string]clusterv1.JSONSchemaProps{ "name": { Description: "Name of the CSI Provider", @@ -267,12 +277,14 @@ func (DefaultStorage) VariableSchema() clusterv1.VariableSchema { OpenAPIV3Schema: clusterv1.JSONSchemaProps{ Type: "object", Description: "A tuple of provider name and storage class ", + Required: []string{"providerName", "storageClassConfigName"}, Properties: map[string]clusterv1.JSONSchemaProps{ "providerName": { Type: "string", Description: "Name of the CSI Provider for the default storage class", Enum: variables.MustMarshalValuesToEnumJSON( - supportedCSIProviders...), + supportedCSIProviders..., + ), }, "storageClassConfigName": { Type: "string", diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index 885d45c65..7da8bc5b2 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -191,10 +191,11 @@ func CreateStorageClass( Name: storageConfig.Name, Namespace: defaultsNamespace, }, - Provisioner: string(provisionerName), - Parameters: params, - VolumeBindingMode: volumeBindingMode, - ReclaimPolicy: reclaimPolicy, + Provisioner: string(provisionerName), + Parameters: params, + VolumeBindingMode: volumeBindingMode, + ReclaimPolicy: reclaimPolicy, + AllowVolumeExpansion: ptr.To(storageConfig.AllowExpansion), } if isDefault { sc.ObjectMeta.Annotations = defaultStorageClassMap diff --git a/pkg/handlers/generic/lifecycle/utils/utils_test.go b/pkg/handlers/generic/lifecycle/utils/utils_test.go index af23ce985..420ebe562 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils_test.go +++ b/pkg/handlers/generic/lifecycle/utils/utils_test.go @@ -32,6 +32,7 @@ func TestCreateStorageClass(t *testing.T) { ReclaimPolicy: v1alpha1.VolumeReclaimDelete, VolumeBindingMode: v1alpha1.VolumeBindingWaitForFirstConsumer, Parameters: nil, + AllowExpansion: true, }, expectedStorageClass: &storagev1.StorageClass{ TypeMeta: metav1.TypeMeta{ @@ -42,10 +43,11 @@ func TestCreateStorageClass(t *testing.T) { Name: "aws-ebs", Namespace: "default", }, - Parameters: defaultAWSStorageClassParams, - ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), - VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), - Provisioner: string(v1alpha1.AWSEBSProvisioner), + Parameters: defaultAWSStorageClassParams, + ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), + VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), + Provisioner: string(v1alpha1.AWSEBSProvisioner), + AllowVolumeExpansion: ptr.To(true), }, provisioner: v1alpha1.AWSEBSProvisioner, defaultsNamespace: "default", @@ -84,9 +86,10 @@ func TestCreateStorageClass(t *testing.T) { "whitelistIPMode": "ENABLED", "whitelistIPAddr": "1.1.1.1", }, - ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), - VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), - Provisioner: string(v1alpha1.NutanixProvisioner), + ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), + VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), + Provisioner: string(v1alpha1.NutanixProvisioner), + AllowVolumeExpansion: ptr.To(false), }, provisioner: v1alpha1.NutanixProvisioner, defaultsNamespace: "default", @@ -107,9 +110,10 @@ func TestCreateStorageClass(t *testing.T) { Name: "nutanix-volumes", Namespace: "default", }, - ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), - VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), - Provisioner: string(v1alpha1.NutanixProvisioner), + ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), + VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), + Provisioner: string(v1alpha1.NutanixProvisioner), + AllowVolumeExpansion: ptr.To(false), }, provisioner: v1alpha1.NutanixProvisioner, defaultsNamespace: "default", From 05faebb781346ffab925e4d0db72dbdf7021741a Mon Sep 17 00:00:00 2001 From: faiq Date: Fri, 29 Mar 2024 14:01:20 -0600 Subject: [PATCH 61/87] feat: deploy snapshot chart with nutanix --- api/v1alpha1/zz_generated.deepcopy.go | 18 ------- .../templates/role.yaml | 2 +- make/addons.mk | 1 - pkg/handlers/generic/lifecycle/csi/handler.go | 7 ++- .../lifecycle/csi/nutanix-csi/handler.go | 53 ++++++++++++++++--- pkg/handlers/generic/lifecycle/handlers.go | 6 +-- 6 files changed, 51 insertions(+), 36 deletions(-) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ec26a8beb..4f33138e6 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -251,23 +251,6 @@ func (in *CNI) DeepCopy() *CNI { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -<<<<<<< HEAD -======= -func (in *CPI) DeepCopyInto(out *CPI) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CPI. -func (in *CPI) DeepCopy() *CPI { - if in == nil { - return nil - } - out := new(CPI) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CSI) DeepCopyInto(out *CSI) { *out = *in @@ -296,7 +279,6 @@ func (in *CSI) DeepCopy() *CSI { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. ->>>>>>> 1020f52 (refactor: rename CSIProviders to CSI) func (in *CSIProvider) DeepCopyInto(out *CSIProvider) { *out = *in if in.StorageClassConfig != nil { diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml index 84702cdfb..e3cd174f7 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml @@ -4,7 +4,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: cluster-api-runtime-extensions-nutanix-manager-role + name: {{ include "chart.name" . }}-manager-role rules: - apiGroups: - "" diff --git a/make/addons.mk b/make/addons.mk index 64c1b42db..c09890922 100644 --- a/make/addons.mk +++ b/make/addons.mk @@ -44,4 +44,3 @@ update-addon.aws-ccm.%: ; $(info $(M) updating aws ccm $* manifests) .PHONY: update-addon.nutanix-csi update-addon.nutanix-csi: ; $(info $(M) updating nutanix csi manifests) ./hack/addons/update-nutanix-csi.sh - diff --git a/pkg/handlers/generic/lifecycle/csi/handler.go b/pkg/handlers/generic/lifecycle/csi/handler.go index 01f3e2b66..fd07767c6 100644 --- a/pkg/handlers/generic/lifecycle/csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/handler.go @@ -99,7 +99,6 @@ func (c *CSIHandler) AfterControlPlaneInitialized( return } if len(csiProviders.Providers) == 1 && - csiProviders.Providers[0].StorageClassConfig != nil && len(csiProviders.Providers[0].StorageClassConfig) == 1 && csiProviders.DefaultStorage == nil { csiProviders.DefaultStorage = &v1alpha1.DefaultStorage{ @@ -113,13 +112,13 @@ func (c *CSIHandler) AfterControlPlaneInitialized( if !ok { log.V(4).Info( fmt.Sprintf( - "Skipping CSI handler, for provider given in %q. Provider handler not given ", - provider, + "Skipping CSI handler, for provider given in %s. Provider handler not given.", + provider.Name, ), ) continue } - log.Info(fmt.Sprintf("Creating csi provider %s", provider)) + log.Info(fmt.Sprintf("Creating csi provider %s", provider.Name)) err = handler.Apply( ctx, provider, diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 090a9e06d..90190bef1 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -24,10 +24,14 @@ import ( ) const ( - defaultHelmRepositoryURL = "https://nutanix.github.io/helm/" - defaultHelmChartVersion = "v2.6.6" - defaultHelmChartName = "nutanix-csi-storage" - defaultHelmReleaseNameTemplate = "nutanix-csi-storage-%s" + defaultHelmRepositoryURL = "https://nutanix.github.io/helm/" + defaultStorageHelmChartVersion = "v2.6.6" + defaultStorageHelmChartName = "nutanix-csi-storage" + defaultStorageHelmReleaseNameTemplate = "nutanix-csi-storage-%s" + + defaultSnapshotHelmChartVersion = "v6.3.2" + defaultSnapshotHelmChartName = "nutanix-csi-snapshot" + defaultSnapshotHelmReleaseNameTemplate = "nutanix-csi-snapshot-%s" ) type NutanixCSIConfig struct { @@ -141,13 +145,13 @@ func (n *NutanixCSI) handleHelmAddonApply( }, Spec: caaphv1.HelmChartProxySpec{ RepoURL: defaultHelmRepositoryURL, - ChartName: defaultHelmChartName, + ChartName: defaultStorageHelmChartName, ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{clusterv1.ClusterNameLabel: req.Cluster.Name}, }, ReleaseNamespace: req.Cluster.Namespace, - ReleaseName: fmt.Sprintf(defaultHelmReleaseNameTemplate, req.Cluster.Name), - Version: defaultHelmChartVersion, + ReleaseName: fmt.Sprintf(defaultStorageHelmReleaseNameTemplate, req.Cluster.Name), + Version: defaultStorageHelmChartVersion, ValuesTemplate: values, }, } @@ -163,6 +167,41 @@ func (n *NutanixCSI) handleHelmAddonApply( return fmt.Errorf("failed to apply nutanix-csi installation HelmChartProxy: %w", err) } + snapshotChart := &caaphv1.HelmChartProxy{ + TypeMeta: metav1.TypeMeta{ + APIVersion: caaphv1.GroupVersion.String(), + Kind: "HelmChartProxy", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: req.Cluster.Namespace, + Name: "nutanix-csi-snapshot" + req.Cluster.Name, + }, + Spec: caaphv1.HelmChartProxySpec{ + RepoURL: defaultHelmRepositoryURL, + ChartName: defaultSnapshotHelmChartName, + ClusterSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{clusterv1.ClusterNameLabel: req.Cluster.Name}, + }, + ReleaseNamespace: req.Cluster.Namespace, + ReleaseName: fmt.Sprintf(defaultStorageHelmReleaseNameTemplate, req.Cluster.Name), + Version: defaultSnapshotHelmChartVersion, + }, + } + + if err = controllerutil.SetOwnerReference(&req.Cluster, snapshotChart, n.client.Scheme()); err != nil { + return fmt.Errorf( + "failed to set owner reference on nutanix-csi installation HelmChartProxy: %w", + err, + ) + } + + if err = client.ServerSideApply(ctx, n.client, snapshotChart); err != nil { + return fmt.Errorf( + "failed to apply nutanix-csi-snapshot installation HelmChartProxy: %w", + err, + ) + } + return nil } diff --git a/pkg/handlers/generic/lifecycle/handlers.go b/pkg/handlers/generic/lifecycle/handlers.go index 33d08e130..b3b0d22fb 100644 --- a/pkg/handlers/generic/lifecycle/handlers.go +++ b/pkg/handlers/generic/lifecycle/handlers.go @@ -29,7 +29,7 @@ type Handlers struct { clusterAutoscalerConfig *clusterautoscaler.Config ebsConfig *awsebs.AWSEBSConfig nutnaixCSIConfig *nutanixcsi.NutanixCSIConfig - awsCPIConfig *awscpi.AWSCPIConfig + awsccmConfig *awsccm.AWSCCMConfig } func New(globalOptions *options.GlobalOptions) *Handlers { @@ -70,10 +70,6 @@ func (h *Handlers) AddFlags(flagSet *pflag.FlagSet) { h.calicoCNIConfig.AddFlags("cni.calico", flagSet) h.ciliumCNIConfig.AddFlags("cni.cilium", flagSet) h.ebsConfig.AddFlags("awsebs", pflag.CommandLine) -<<<<<<< HEAD h.awsccmConfig.AddFlags("awsccm", pflag.CommandLine) -======= h.nutnaixCSIConfig.AddFlags("nutanixcsi", flagSet) - h.awsCPIConfig.AddFlags("awscpi", pflag.CommandLine) ->>>>>>> f7ff2e9 (fix: adds proper permissions and api fixes) } From 92b06d4e2b872987f47212219bce6e9fb3b81999 Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Mon, 1 Apr 2024 10:25:03 -0700 Subject: [PATCH 62/87] fix: Nutanix examples (#19) * fix: update latest template * build: pin commit for nutanix examples --- .../defaultclusterclasses/nutanix-cluster-class.yaml | 4 ++-- hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl | 2 +- .../bases/nutanix/clusterclass/kustomization.yaml.tmpl | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml index 58e511c35..9bb5e3ef8 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml @@ -154,9 +154,9 @@ spec: - name: vip_arp value: "true" - name: address - value: "${CONTROL_PLANE_ENDPOINT_IP}" + value: "control_plane_endpoint_ip" - name: port - value: "${CONTROL_PLANE_ENDPOINT_PORT=6443}" + value: "control_plane_endpoint_port" - name: vip_cidr value: "32" - name: cp_enable diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index b75eb33cf..b5d850b65 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -5,7 +5,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: -- https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/main/templates/cluster-template-topology.yaml +- https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/51aa55fe8b194a261bc3cc4e6d24f5d430ec055a/templates/cluster-template-topology.yaml sortOptions: order: fifo diff --git a/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl index 24e9683ff..40cb4305b 100644 --- a/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl @@ -5,7 +5,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: -- https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/main/templates/cluster-template-clusterclass.yaml +- https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/51aa55fe8b194a261bc3cc4e6d24f5d430ec055a/templates/cluster-template-clusterclass.yaml configurations: - kustomizeconfig.yaml From 7665a94b97d763b553123af2358b23e157688b19 Mon Sep 17 00:00:00 2001 From: faiq Date: Mon, 1 Apr 2024 10:43:59 -0600 Subject: [PATCH 63/87] fix: apply suggestions from reviews --- api/v1alpha1/addon_types.go | 32 +++++++++---------- .../nutanix-cluster-class.yaml | 4 +-- .../lifecycle/csi/nutanix-csi/handler.go | 2 +- pkg/handlers/generic/lifecycle/utils/utils.go | 20 ++---------- 4 files changed, 21 insertions(+), 37 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index a21f1353c..6f524159d 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -5,6 +5,7 @@ package v1alpha1 import ( corev1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -12,15 +13,14 @@ import ( ) const ( - AddonStrategyClusterResourceSet AddonStrategy = "ClusterResourceSet" - AddonStrategyHelmAddon AddonStrategy = "HelmAddon" - - VolumeBindingImmediate = "Immmediate" - VolumeBindingWaitForFirstConsumer = "WaitForFirstConsumer" - - VolumeReclaimRecycle = "Recycle" - VolumeReclaimDelete = "Delete" - VolumeReclaimRetain = "Retain" + AddonStrategyClusterResourceSet AddonStrategy = "ClusterResourceSet" + AddonStrategyHelmAddon AddonStrategy = "HelmAddon" + VolumeBindingImmediate = storagev1.VolumeBindingImmediate + VolumeBindingWaitForFirstConsumer = storagev1.VolumeBindingWaitForFirstConsumer + + VolumeReclaimRecycle = corev1.PersistentVolumeReclaimRecycle + VolumeReclaimDelete = corev1.PersistentVolumeReclaimDelete + VolumeReclaimRetain = corev1.PersistentVolumeReclaimRetain ) type Addons struct { @@ -174,10 +174,10 @@ type StorageClassConfig struct { Parameters map[string]string `json:"parameters,omitempty"` // +optional - ReclaimPolicy string `json:"reclaimPolicy,omitempty"` + ReclaimPolicy corev1.PersistentVolumeReclaimPolicy `json:"reclaimPolicy,omitempty"` // +optional - VolumeBindingMode string `json:"volumeBindingMode,omitempty"` + VolumeBindingMode storagev1.VolumeBindingMode `json:"volumeBindingMode,omitempty"` // +optional AllowExpansion bool `json:"allowExpansion,omitempty"` @@ -185,13 +185,13 @@ type StorageClassConfig struct { func (StorageClassConfig) VariableSchema() clusterv1.VariableSchema { supportedReclaimPolicies := []string{ - VolumeReclaimRecycle, - VolumeReclaimDelete, - VolumeReclaimRetain, + string(VolumeReclaimRecycle), + string(VolumeReclaimDelete), + string(VolumeReclaimRetain), } supportedBindingModes := []string{ - VolumeBindingImmediate, - VolumeBindingWaitForFirstConsumer, + string(VolumeBindingImmediate), + string(VolumeBindingWaitForFirstConsumer), } return clusterv1.VariableSchema{ OpenAPIV3Schema: clusterv1.JSONSchemaProps{ diff --git a/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml index 58e511c35..9bb5e3ef8 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml @@ -154,9 +154,9 @@ spec: - name: vip_arp value: "true" - name: address - value: "${CONTROL_PLANE_ENDPOINT_IP}" + value: "control_plane_endpoint_ip" - name: port - value: "${CONTROL_PLANE_ENDPOINT_PORT=6443}" + value: "control_plane_endpoint_port" - name: vip_cidr value: "32" - name: cp_enable diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 90190bef1..142189b47 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -183,7 +183,7 @@ func (n *NutanixCSI) handleHelmAddonApply( MatchLabels: map[string]string{clusterv1.ClusterNameLabel: req.Cluster.Name}, }, ReleaseNamespace: req.Cluster.Namespace, - ReleaseName: fmt.Sprintf(defaultStorageHelmReleaseNameTemplate, req.Cluster.Name), + ReleaseName: fmt.Sprintf(defaultSnapshotHelmReleaseNameTemplate, req.Cluster.Name), Version: defaultSnapshotHelmChartVersion, }, } diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index 7da8bc5b2..aa6d42b30 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -159,22 +159,6 @@ func CreateStorageClass( provisionerName v1alpha1.StorageProvisioner, isDefault bool, ) *storagev1.StorageClass { - var volumeBindingMode *storagev1.VolumeBindingMode - switch storageConfig.VolumeBindingMode { - case v1alpha1.VolumeBindingImmediate: - volumeBindingMode = ptr.To(storagev1.VolumeBindingImmediate) - case v1alpha1.VolumeBindingWaitForFirstConsumer: - volumeBindingMode = ptr.To(storagev1.VolumeBindingWaitForFirstConsumer) - } - var reclaimPolicy *corev1.PersistentVolumeReclaimPolicy - switch storageConfig.ReclaimPolicy { - case v1alpha1.VolumeReclaimRecycle: - reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimRecycle) - case v1alpha1.VolumeReclaimDelete: - reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimDelete) - case v1alpha1.VolumeReclaimRetain: - reclaimPolicy = ptr.To(corev1.PersistentVolumeReclaimRetain) - } var params map[string]string if provisionerName == v1alpha1.AWSEBSProvisioner { params = defaultAWSStorageClassParams @@ -193,8 +177,8 @@ func CreateStorageClass( }, Provisioner: string(provisionerName), Parameters: params, - VolumeBindingMode: volumeBindingMode, - ReclaimPolicy: reclaimPolicy, + VolumeBindingMode: ptr.To(storageConfig.VolumeBindingMode), + ReclaimPolicy: ptr.To(storageConfig.ReclaimPolicy), AllowVolumeExpansion: ptr.To(storageConfig.AllowExpansion), } if isDefault { From ced51e35f777138968cadedf9491ec1e36ad3e1b Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Tue, 2 Apr 2024 15:30:53 -0700 Subject: [PATCH 64/87] docs: use a KUBERNETES_VERSION env variable (#22) * docs: use an env for KUBERNETES_VERSION * docs: use a more widely available Kubernetes version Makes the command more copy-paste friendly. Kubernetes v1.28.7 is supported here by Docker, AWS and CAPX. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e391b3025..6d20ce2a3 100644 --- a/README.md +++ b/README.md @@ -44,12 +44,13 @@ For example, the following command will create a Docker cluster with Cilium CNI ```shell export CLUSTER_NAME=docker-cluster-cilium-helm-addon export CLUSTER_FILE=examples/capi-quick-start/docker-cluster-cilium-helm-addon.yaml +export KUBERNETES_VERSION=v1.28.7 ``` ```shell clusterctl generate cluster ${CLUSTER_NAME} \ --from ${CLUSTER_FILE} \ - --kubernetes-version v1.29.1 \ + --kubernetes-version ${KUBERNETES_VERSION} \ --worker-machine-count 1 | \ kubectl apply --server-side -f - ``` From aa6feca03910691e14123d338d6726ab8f8c39f5 Mon Sep 17 00:00:00 2001 From: Deepak Muley Date: Wed, 3 Apr 2024 08:40:03 -0700 Subject: [PATCH 65/87] feat: Add support for CAPX (#6) * fix: added support for capx * refactor: reuse existing CAPX types * fix: set allowed enums for Nutanix resource types * fix: set required for Nutanix node type * fix: reuse resource.Quantity types * fix: set defaults and validation * fix: rename field to subnets * refactor: fix handlers after API changes * test: add new unit tests * refactor: bring back host instead of address * fix: examples with updated APIs * fix: using latest capx private brach to test kube-vip fix * fix: set namespace for credentialRef The patch failed with the following error: got failure response with message failed to apply JSON patches to input: replace operation does not apply: doc is missing key: /spec/template/spec/prismCentral/credentialRef/namespace: missing value. * docs: fix users example * docs: deploying Calico for Nutanix * fix: added basic docs for nutanix mutations * fix: lint related fixes * docs: minor changes --------- Co-authored-by: Dimitri Koshkin --- api/v1alpha1/clusterconfig_types.go | 12 + api/v1alpha1/common_types.go | 37 + api/v1alpha1/constants.go | 2 + api/v1alpha1/node_types.go | 9 + api/v1alpha1/nutanix_clusterconfig_types.go | 115 +++ api/v1alpha1/nutanix_node_types.go | 163 +++++ api/v1alpha1/zz_generated.deepcopy.go | 153 +++- .../README.md | 5 + .../nutanix-cluster-class.yaml | 16 +- .../manifests/nutanix/crs-installation.yaml | 36 + .../nutanix/helm-addon-installation.yaml | 23 + .../values.yaml | 8 + cmd/main.go | 13 + common/go.mod | 1 + common/go.sum | 691 ++++++++++++++++++ .../pkg/testutils/capitest/request/items.go | 80 ++ .../customization/docker/custom-image.md | 4 +- docs/content/customization/generic/users.md | 6 +- docs/content/customization/nutanix/_index.md | 7 + .../nutanix/control-plane-endpoint.md | 38 + .../customization/nutanix/machine-details.md | 112 +++ .../nutanix/prism-central-endpoint.md | 45 ++ .../nutanix-cluster-calico-crs.yaml | 10 +- .../nutanix-cluster-calico-helm-addon.yaml | 10 +- .../nutanix-cluster-cilium-crs.yaml | 10 +- .../nutanix-cluster-cilium-helm-addon.yaml | 10 +- go.mod | 1 + go.sum | 301 ++++++++ .../nutanix/cluster/kustomization.yaml.tmpl | 2 +- .../clusterclass/kustomization.yaml.tmpl | 23 +- .../patches/nutanix/initialize-variables.yaml | 10 +- make/examples.mk | 1 + .../lifecycle/cni/calico/strategy_crs.go | 5 +- .../cni/calico/strategy_helmaddon.go | 5 +- .../nutanix/clusterconfig/variables.go | 52 ++ .../mutation/controlplaneendpoint/inject.go | 134 ++++ .../tests/generate_patches.go | 59 ++ .../controlplaneendpoint/variables_test.go | 86 +++ .../nutanix/mutation/machinedetails/inject.go | 113 +++ .../machinedetails/inject_control_plane.go | 25 + .../mutation/machinedetails/inject_worker.go | 24 + .../machinedetails/tests/generate_patches.go | 161 ++++ .../mutation/machinedetails/variables_test.go | 132 ++++ .../nutanix/mutation/metapatch_handler.go | 44 ++ .../mutation/metapatch_handler_test.go | 134 ++++ .../mutation/prismcentralendpoint/inject.go | 122 ++++ .../tests/generate_patches.go | 71 ++ .../prismcentralendpoint/variables_test.go | 85 +++ pkg/handlers/nutanix/mutation/suite_test.go | 48 ++ .../nutanix/workerconfig/variables.go | 52 ++ .../nutanix/workerconfig/variables_test.go | 24 + 51 files changed, 3290 insertions(+), 40 deletions(-) create mode 100644 api/v1alpha1/nutanix_clusterconfig_types.go create mode 100644 api/v1alpha1/nutanix_node_types.go create mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/cni/calico/manifests/nutanix/crs-installation.yaml create mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/cni/calico/manifests/nutanix/helm-addon-installation.yaml create mode 100644 docs/content/customization/nutanix/_index.md create mode 100644 docs/content/customization/nutanix/control-plane-endpoint.md create mode 100644 docs/content/customization/nutanix/machine-details.md create mode 100644 docs/content/customization/nutanix/prism-central-endpoint.md create mode 100644 pkg/handlers/nutanix/clusterconfig/variables.go create mode 100644 pkg/handlers/nutanix/mutation/controlplaneendpoint/inject.go create mode 100644 pkg/handlers/nutanix/mutation/controlplaneendpoint/tests/generate_patches.go create mode 100644 pkg/handlers/nutanix/mutation/controlplaneendpoint/variables_test.go create mode 100644 pkg/handlers/nutanix/mutation/machinedetails/inject.go create mode 100644 pkg/handlers/nutanix/mutation/machinedetails/inject_control_plane.go create mode 100644 pkg/handlers/nutanix/mutation/machinedetails/inject_worker.go create mode 100644 pkg/handlers/nutanix/mutation/machinedetails/tests/generate_patches.go create mode 100644 pkg/handlers/nutanix/mutation/machinedetails/variables_test.go create mode 100644 pkg/handlers/nutanix/mutation/metapatch_handler.go create mode 100644 pkg/handlers/nutanix/mutation/metapatch_handler_test.go create mode 100644 pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go create mode 100644 pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go create mode 100644 pkg/handlers/nutanix/mutation/prismcentralendpoint/variables_test.go create mode 100644 pkg/handlers/nutanix/mutation/suite_test.go create mode 100644 pkg/handlers/nutanix/workerconfig/variables.go create mode 100644 pkg/handlers/nutanix/workerconfig/variables_test.go diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index 944823b25..ba7e012b0 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -45,6 +45,8 @@ type ClusterConfigSpec struct { AWS *AWSSpec `json:"aws,omitempty"` // +optional Docker *DockerSpec `json:"docker,omitempty"` + // +optional + Nutanix *NutanixSpec `json:"nutanix,omitempty"` GenericClusterConfig `json:",inline"` @@ -76,6 +78,16 @@ func (s ClusterConfigSpec) VariableSchema() clusterv1.VariableSchema { //nolint: }.VariableSchema().OpenAPIV3Schema, }, ) + case s.Nutanix != nil: + maps.Copy( + clusterConfigProps.OpenAPIV3Schema.Properties, + map[string]clusterv1.JSONSchemaProps{ + NutanixVariableName: NutanixSpec{}.VariableSchema().OpenAPIV3Schema, + "controlPlane": NodeConfigSpec{ + Nutanix: &NutanixNodeSpec{}, + }.VariableSchema().OpenAPIV3Schema, + }, + ) } return clusterConfigProps diff --git a/api/v1alpha1/common_types.go b/api/v1alpha1/common_types.go index fab81e9f8..d2e3244a3 100644 --- a/api/v1alpha1/common_types.go +++ b/api/v1alpha1/common_types.go @@ -3,6 +3,17 @@ package v1alpha1 +import ( + "k8s.io/utils/ptr" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables" +) + +const ( + APIServerPort = 6443 +) + // ObjectMeta is metadata that all persisted resources must have, which includes all objects // users must create. This is a copy of customizable fields from metav1.ObjectMeta. // @@ -23,3 +34,29 @@ type ObjectMeta struct { // +optional Annotations map[string]string `json:"annotations,omitempty"` } + +type ControlPlaneEndpointSpec clusterv1.APIEndpoint + +func (ControlPlaneEndpointSpec) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Description: "Kubernetes control-plane endpoint configuration", + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "host": { + Description: "host ip/fqdn for control plane API Server", + Type: "string", + MinLength: ptr.To[int64](1), + }, + "port": { + Description: "port for control plane API Server", + Type: "integer", + Default: variables.MustMarshal(APIServerPort), + Minimum: ptr.To[int64](1), + Maximum: ptr.To[int64](65535), + }, + }, + Required: []string{"host", "port"}, + }, + } +} diff --git a/api/v1alpha1/constants.go b/api/v1alpha1/constants.go index 8dd88b4a8..de4b8b1f6 100644 --- a/api/v1alpha1/constants.go +++ b/api/v1alpha1/constants.go @@ -12,4 +12,6 @@ const ( ClusterAutoscalerVariableName = "clusterAutoscaler" // AWSVariableName is the AWS config patch variable name. AWSVariableName = "aws" + // NutanixVariableName is the Nutanix config patch variable name. + NutanixVariableName = "nutanix" ) diff --git a/api/v1alpha1/node_types.go b/api/v1alpha1/node_types.go index b9b678866..f2d3c6bf3 100644 --- a/api/v1alpha1/node_types.go +++ b/api/v1alpha1/node_types.go @@ -29,6 +29,8 @@ type NodeConfigSpec struct { AWS *AWSNodeSpec `json:"aws,omitempty"` // +optional Docker *DockerNodeSpec `json:"docker,omitempty"` + // +optional + Nutanix *NutanixNodeSpec `json:"nutanix,omitempty"` } func (s NodeConfigSpec) VariableSchema() clusterv1.VariableSchema { @@ -49,6 +51,13 @@ func (s NodeConfigSpec) VariableSchema() clusterv1.VariableSchema { "docker": DockerNodeSpec{}.VariableSchema().OpenAPIV3Schema, }, ) + case s.Nutanix != nil: + maps.Copy( + nodeConfigProps.OpenAPIV3Schema.Properties, + map[string]clusterv1.JSONSchemaProps{ + "nutanix": NutanixNodeSpec{}.VariableSchema().OpenAPIV3Schema, + }, + ) } return nodeConfigProps diff --git a/api/v1alpha1/nutanix_clusterconfig_types.go b/api/v1alpha1/nutanix_clusterconfig_types.go new file mode 100644 index 000000000..783416e8d --- /dev/null +++ b/api/v1alpha1/nutanix_clusterconfig_types.go @@ -0,0 +1,115 @@ +// Copyright 2024 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import ( + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables" +) + +const ( + PrismCentralPort = 9440 +) + +// NutanixSpec defines the desired state of NutanixCluster. +type NutanixSpec struct { + // ControlPlaneEndpoint represents the endpoint used to communicate with the control plane. + // host can be either DNS name or ip address + ControlPlaneEndpoint clusterv1.APIEndpoint `json:"controlPlaneEndpoint"` + + // Nutanix Prism Central endpoint configuration. + PrismCentralEndpoint NutanixPrismCentralEndpointSpec `json:"prismCentralEndpoint"` +} + +func (NutanixSpec) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Description: "Nutanix cluster configuration", + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "controlPlaneEndpoint": ControlPlaneEndpointSpec{}.VariableSchema().OpenAPIV3Schema, + "prismCentralEndpoint": NutanixPrismCentralEndpointSpec{}.VariableSchema().OpenAPIV3Schema, + }, + }, + } +} + +type NutanixPrismCentralEndpointSpec struct { + // host is the DNS name or IP address of the Nutanix Prism Central + Host string `json:"host"` + + // port is the port number to access the Nutanix Prism Central + Port int32 `json:"port"` + + // use insecure connection to Prism Central endpoint + // +optional + Insecure bool `json:"insecure"` + + // A reference to the ConfigMap containing a PEM encoded x509 cert for the RootCA that was used to create + // the certificate for a Prism Central that uses certificates that were issued by a non-publicly trusted RootCA. + // The trust bundle is added to the cert pool used to authenticate the TLS connection to the Prism Central. + // +optional + AdditionalTrustBundle *corev1.LocalObjectReference `json:"additionalTrustBundle,omitempty"` + + // A reference to the Secret for credential information for the target Prism Central instance + Credentials corev1.LocalObjectReference `json:"credentials"` +} + +func (NutanixPrismCentralEndpointSpec) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Description: "Nutanix Prism Central endpoint configuration", + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "host": { + Description: "the DNS name or IP address of the Nutanix Prism Central", + Type: "string", + MinLength: ptr.To[int64](1), + }, + "port": { + Description: "The port number to access the Nutanix Prism Central", + Type: "integer", + Default: variables.MustMarshal(PrismCentralPort), + Minimum: ptr.To[int64](1), + Maximum: ptr.To[int64](65535), + }, + "insecure": { + Description: "Use insecure connection to Prism Central endpoint", + Type: "boolean", + }, + "additionalTrustBundle": { + Description: "A reference to the ConfigMap containing a PEM encoded x509 cert for the RootCA " + + "that was used to create the certificate for a Prism Central that uses certificates " + + "that were issued by a non-publicly trusted RootCA." + + "The trust bundle is added to the cert pool used to authenticate the TLS connection " + + "to the Prism Central.", + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "name": { + Description: "The name of the ConfigMap", + Type: "string", + }, + }, + Required: []string{"name"}, + }, + "credentials": { + Description: "A reference to the Secret for credential information" + + "for the target Prism Central instance", + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "name": { + Description: "The name of the Secret", + Type: "string", + }, + }, + Required: []string{"name"}, + }, + }, + Required: []string{"host", "port", "credentials"}, + }, + } +} diff --git a/api/v1alpha1/nutanix_node_types.go b/api/v1alpha1/nutanix_node_types.go new file mode 100644 index 000000000..1637721fa --- /dev/null +++ b/api/v1alpha1/nutanix_node_types.go @@ -0,0 +1,163 @@ +// Copyright 2024 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/resource" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + capxv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables" +) + +type NutanixNodeSpec struct { + MachineDetails NutanixMachineDetails `json:"machineDetails"` +} + +func (NutanixNodeSpec) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Description: "Nutanix Node configuration", + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "machineDetails": NutanixMachineDetails{}.VariableSchema().OpenAPIV3Schema, + }, + Required: []string{"machineDetails"}, + }, + } +} + +type NutanixMachineDetails struct { + // vcpusPerSocket is the number of vCPUs per socket of the VM + VCPUsPerSocket int32 `json:"vcpusPerSocket"` + + // vcpuSockets is the number of vCPU sockets of the VM + VCPUSockets int32 `json:"vcpuSockets"` + + // memorySize is the memory size (in Quantity format) of the VM + MemorySize resource.Quantity `json:"memorySize"` + + // image is to identify the rhcos image uploaded to the Prism Central (PC) + // The image identifier (uuid or name) can be obtained from the Prism Central console + // or using the prism_central API. + Image NutanixResourceIdentifier `json:"image"` + + // cluster is to identify the cluster (the Prism Element under management + // of the Prism Central), in which the Machine's VM will be created. + // The cluster identifier (uuid or name) can be obtained from the Prism Central console + // or using the prism_central API. + Cluster NutanixResourceIdentifier `json:"cluster"` + + // subnet is to identify the cluster's network subnet to use for the Machine's VM + // The cluster identifier (uuid or name) can be obtained from the Prism Central console + // or using the prism_central API. + Subnets NutanixResourceIdentifiers `json:"subnets"` + + // Defines the boot type of the virtual machine. Only supports UEFI and Legacy + BootType NutanixBootType `json:"bootType,omitempty"` + + // systemDiskSize is size (in Quantity format) of the system disk of the VM + // The minimum systemDiskSize is 20Gi bytes + SystemDiskSize resource.Quantity `json:"systemDiskSize"` +} + +func (NutanixMachineDetails) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Description: "Nutanix Machine configuration", + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "vcpusPerSocket": { + Description: "vcpusPerSocket is the number of vCPUs per socket of the VM", + Type: "integer", + }, + "vcpuSockets": { + Description: "vcpuSockets is the number of vCPU sockets of the VM", + Type: "integer", + }, + "memorySize": { + Description: "memorySize is the memory size (in Quantity format) of the VM eg. 4Gi", + Type: "string", + }, + "image": NutanixResourceIdentifier{}.VariableSchema().OpenAPIV3Schema, + "cluster": NutanixResourceIdentifier{}.VariableSchema().OpenAPIV3Schema, + "subnets": NutanixResourceIdentifiers{}.VariableSchema().OpenAPIV3Schema, + "bootType": NutanixBootType(capxv1.NutanixBootTypeLegacy).VariableSchema().OpenAPIV3Schema, + "systemDiskSize": { + Description: "systemDiskSize is size (in Quantity format) of the system disk of the VM eg. 20Gi", + Type: "string", + }, + }, + Required: []string{"vcpusPerSocket", "vcpuSockets", "memorySize", "image", "cluster", "subnets", "systemDiskSize"}, + }, + } +} + +// NutanixIdentifierType is an enumeration of different resource identifier types. +type NutanixIdentifierType capxv1.NutanixIdentifierType + +func (NutanixIdentifierType) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Type: "string", + Description: "NutanixIdentifierType is an enumeration of different resource identifier types", + Enum: variables.MustMarshalValuesToEnumJSON( + capxv1.NutanixIdentifierUUID, + capxv1.NutanixIdentifierName, + ), + }, + } +} + +// NutanixBootType is an enumeration of different boot types. +type NutanixBootType capxv1.NutanixBootType + +func (NutanixBootType) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Type: "string", + Description: "NutanixBootType is an enumeration of different boot types.", + Enum: variables.MustMarshalValuesToEnumJSON( + capxv1.NutanixBootTypeLegacy, + capxv1.NutanixBootTypeUEFI, + ), + }, + } +} + +type NutanixResourceIdentifier capxv1.NutanixResourceIdentifier + +func (NutanixResourceIdentifier) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Description: "Nutanix Resource Identifier", + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "type": NutanixIdentifierType(capxv1.NutanixIdentifierName).VariableSchema().OpenAPIV3Schema, + "uuid": { + Type: "string", + Description: "uuid is the UUID of the resource in the PC.", + }, + "name": { + Type: "string", + Description: "name is the resource name in the PC.", + }, + }, + }, + } +} + +type NutanixResourceIdentifiers []NutanixResourceIdentifier + +func (NutanixResourceIdentifiers) VariableSchema() clusterv1.VariableSchema { + resourceSchema := NutanixResourceIdentifier{}.VariableSchema().OpenAPIV3Schema + + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Description: "Nutanix resource identifier", + Type: "array", + Items: &resourceSchema, + }, + } +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index a6f927730..3bb80cb1d 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -9,7 +9,7 @@ package v1alpha1 import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -359,6 +359,11 @@ func (in *ClusterConfigSpec) DeepCopyInto(out *ClusterConfigSpec) { *out = new(DockerSpec) **out = **in } + if in.Nutanix != nil { + in, out := &in.Nutanix, &out.Nutanix + *out = new(NutanixSpec) + (*in).DeepCopyInto(*out) + } in.GenericClusterConfig.DeepCopyInto(&out.GenericClusterConfig) if in.ControlPlane != nil { in, out := &in.ControlPlane, &out.ControlPlane @@ -377,6 +382,21 @@ func (in *ClusterConfigSpec) DeepCopy() *ClusterConfigSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ControlPlaneEndpointSpec) DeepCopyInto(out *ControlPlaneEndpointSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControlPlaneEndpointSpec. +func (in *ControlPlaneEndpointSpec) DeepCopy() *ControlPlaneEndpointSpec { + if in == nil { + return nil + } + out := new(ControlPlaneEndpointSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DefaultStorage) DeepCopyInto(out *DefaultStorage) { *out = *in @@ -690,6 +710,11 @@ func (in *NodeConfigSpec) DeepCopyInto(out *NodeConfigSpec) { *out = new(DockerNodeSpec) (*in).DeepCopyInto(*out) } + if in.Nutanix != nil { + in, out := &in.Nutanix, &out.Nutanix + *out = new(NutanixNodeSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NodeConfigSpec. @@ -702,6 +727,132 @@ func (in *NodeConfigSpec) DeepCopy() *NodeConfigSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NutanixMachineDetails) DeepCopyInto(out *NutanixMachineDetails) { + *out = *in + out.MemorySize = in.MemorySize.DeepCopy() + in.Image.DeepCopyInto(&out.Image) + in.Cluster.DeepCopyInto(&out.Cluster) + if in.Subnets != nil { + in, out := &in.Subnets, &out.Subnets + *out = make(NutanixResourceIdentifiers, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.SystemDiskSize = in.SystemDiskSize.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixMachineDetails. +func (in *NutanixMachineDetails) DeepCopy() *NutanixMachineDetails { + if in == nil { + return nil + } + out := new(NutanixMachineDetails) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NutanixNodeSpec) DeepCopyInto(out *NutanixNodeSpec) { + *out = *in + in.MachineDetails.DeepCopyInto(&out.MachineDetails) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixNodeSpec. +func (in *NutanixNodeSpec) DeepCopy() *NutanixNodeSpec { + if in == nil { + return nil + } + out := new(NutanixNodeSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NutanixPrismCentralEndpointSpec) DeepCopyInto(out *NutanixPrismCentralEndpointSpec) { + *out = *in + if in.AdditionalTrustBundle != nil { + in, out := &in.AdditionalTrustBundle, &out.AdditionalTrustBundle + *out = new(v1.LocalObjectReference) + **out = **in + } + out.Credentials = in.Credentials +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixPrismCentralEndpointSpec. +func (in *NutanixPrismCentralEndpointSpec) DeepCopy() *NutanixPrismCentralEndpointSpec { + if in == nil { + return nil + } + out := new(NutanixPrismCentralEndpointSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NutanixResourceIdentifier) DeepCopyInto(out *NutanixResourceIdentifier) { + *out = *in + if in.UUID != nil { + in, out := &in.UUID, &out.UUID + *out = new(string) + **out = **in + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixResourceIdentifier. +func (in *NutanixResourceIdentifier) DeepCopy() *NutanixResourceIdentifier { + if in == nil { + return nil + } + out := new(NutanixResourceIdentifier) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in NutanixResourceIdentifiers) DeepCopyInto(out *NutanixResourceIdentifiers) { + { + in := &in + *out = make(NutanixResourceIdentifiers, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixResourceIdentifiers. +func (in NutanixResourceIdentifiers) DeepCopy() NutanixResourceIdentifiers { + if in == nil { + return nil + } + out := new(NutanixResourceIdentifiers) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NutanixSpec) DeepCopyInto(out *NutanixSpec) { + *out = *in + out.ControlPlaneEndpoint = in.ControlPlaneEndpoint + in.PrismCentralEndpoint.DeepCopyInto(&out.PrismCentralEndpoint) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NutanixSpec. +func (in *NutanixSpec) DeepCopy() *NutanixSpec { + if in == nil { + return nil + } + out := new(NutanixSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ObjectMeta) DeepCopyInto(out *ObjectMeta) { *out = *in diff --git a/charts/cluster-api-runtime-extensions-nutanix/README.md b/charts/cluster-api-runtime-extensions-nutanix/README.md index 3049ea2a1..4baba852b 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/README.md +++ b/charts/cluster-api-runtime-extensions-nutanix/README.md @@ -40,12 +40,17 @@ A Helm chart for cluster-api-runtime-extensions-nutanix | hooks.cni.calico.crsStrategy.defaultInstallationConfigMaps.DockerCluster.configMap.content | string | `""` | | | hooks.cni.calico.crsStrategy.defaultInstallationConfigMaps.DockerCluster.configMap.name | string | `"calico-cni-crs-installation-dockercluster"` | | | hooks.cni.calico.crsStrategy.defaultInstallationConfigMaps.DockerCluster.create | bool | `true` | | +| hooks.cni.calico.crsStrategy.defaultInstallationConfigMaps.NutanixCluster.configMap.content | string | `""` | | +| hooks.cni.calico.crsStrategy.defaultInstallationConfigMaps.NutanixCluster.configMap.name | string | `"calico-cni-crs-installation-nutanixcluster"` | | +| hooks.cni.calico.crsStrategy.defaultInstallationConfigMaps.NutanixCluster.create | bool | `true` | | | hooks.cni.calico.crsStrategy.defaultTigeraOperatorConfigMap.name | string | `"tigera-operator"` | | | hooks.cni.calico.defaultPodSubnet | string | `"192.168.0.0/16"` | | | hooks.cni.calico.helmAddonStrategy.defaultValueTemplatesConfigMaps.AWSCluster.create | bool | `true` | | | hooks.cni.calico.helmAddonStrategy.defaultValueTemplatesConfigMaps.AWSCluster.name | string | `"calico-cni-helm-values-template-awscluster"` | | | hooks.cni.calico.helmAddonStrategy.defaultValueTemplatesConfigMaps.DockerCluster.create | bool | `true` | | | hooks.cni.calico.helmAddonStrategy.defaultValueTemplatesConfigMaps.DockerCluster.name | string | `"calico-cni-helm-values-template-dockercluster"` | | +| hooks.cni.calico.helmAddonStrategy.defaultValueTemplatesConfigMaps.NutanixCluster.create | bool | `true` | | +| hooks.cni.calico.helmAddonStrategy.defaultValueTemplatesConfigMaps.NutanixCluster.name | string | `"calico-cni-helm-values-template-nutanixcluster"` | | | hooks.cni.cilium.crsStrategy.defaultCiliumConfigMap.name | string | `"cilium"` | | | hooks.cni.cilium.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.cni.cilium.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-cilium-cni-helm-values-template"` | | diff --git a/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml index 9bb5e3ef8..61c04f53d 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses/nutanix-cluster-class.yaml @@ -174,11 +174,11 @@ spec: - name: vip_retryperiod value: "2" - name: svc_enable - value: "${KUBEVIP_SVC_ENABLE=false}" + value: "false" - name: lb_enable - value: "${KUBEVIP_LB_ENABLE=false}" + value: "false" - name: enableServicesElection - value: "${KUBEVIP_SVC_ELECTION=false}" + value: "false" securityContext: capabilities: add: @@ -252,7 +252,17 @@ metadata: spec: template: spec: + controlPlaneEndpoint: + host: PLACEHOLDER + port: 6443 failureDomains: [] + prismCentral: + address: PLACEHOLDER + credentialRef: + kind: Secret + name: PLACEHOLDER + namespace: default + port: 9440 --- apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 kind: NutanixMachineTemplate diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/cni/calico/manifests/nutanix/crs-installation.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/cni/calico/manifests/nutanix/crs-installation.yaml new file mode 100644 index 000000000..69798aed9 --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/cni/calico/manifests/nutanix/crs-installation.yaml @@ -0,0 +1,36 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +{{- if .Values.hooks.cni.calico.crsStrategy.defaultInstallationConfigMaps.NutanixCluster.create }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: '{{ .Values.hooks.cni.calico.crsStrategy.defaultInstallationConfigMaps.NutanixCluster.configMap.name }}' +data: + calico-installation: | +{{- if .Values.hooks.cni.calico.crsStrategy.defaultInstallationConfigMaps.NutanixCluster.configMap.content -}} + {{ .Values.hooks.cni.calico.crsStrategy.defaultInstallationConfigMaps.NutanixCluster.configMap.content | nindent 4 }} +{{- else -}} + # This section includes base Calico installation configuration. + # For more information, see: https://docs.projectcalico.org/reference/installation/api + apiVersion: operator.tigera.io/v1 + kind: Installation + metadata: + name: default + spec: + cni: + type: Calico + # Configures Calico networking. + calicoNetwork: + # Note: The ipPools section cannot be modified post-install. + ipPools: + - blockSize: 26 + cidr: {{ .Values.hooks.cni.calico.defaultPodSubnet }} + encapsulation: IPIP + natOutgoing: Enabled + nodeSelector: all() + bgp: Enabled + nodeMetricsPort: 9091 + typhaMetricsPort: 9093 +{{- end -}} +{{- end -}} diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/cni/calico/manifests/nutanix/helm-addon-installation.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/cni/calico/manifests/nutanix/helm-addon-installation.yaml new file mode 100644 index 000000000..796dce4db --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/cni/calico/manifests/nutanix/helm-addon-installation.yaml @@ -0,0 +1,23 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +{{- if .Values.hooks.cni.calico.helmAddonStrategy.defaultValueTemplatesConfigMaps.NutanixCluster.create }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: '{{ .Values.hooks.cni.calico.helmAddonStrategy.defaultValueTemplatesConfigMaps.NutanixCluster.name }}' +data: + values.yaml: |- + installation: + cni: + type: Calico + calicoNetwork: + bgp: Enabled + ipPools:{{ printf "{{ range $cidr := .Cluster.spec.clusterNetwork.pods.cidrBlocks }}" }} + - cidr: {{ printf "{{ $cidr }}" }} + encapsulation: None + natOutgoing: Enabled + nodeSelector: all(){{ printf "{{ end }}" }} + nodeMetricsPort: 9091 + typhaMetricsPort: 9093 +{{- end -}} diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.yaml b/charts/cluster-api-runtime-extensions-nutanix/values.yaml index 9a2a4d7ba..93b1df268 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/values.yaml @@ -19,6 +19,11 @@ hooks: configMap: name: calico-cni-crs-installation-awscluster content: "" + NutanixCluster: + create: true + configMap: + name: calico-cni-crs-installation-nutanixcluster + content: "" helmAddonStrategy: defaultValueTemplatesConfigMaps: DockerCluster: @@ -27,6 +32,9 @@ hooks: AWSCluster: create: true name: calico-cni-helm-values-template-awscluster + NutanixCluster: + create: true + name: calico-cni-helm-values-template-nutanixcluster cilium: crsStrategy: defaultCiliumConfigMap: diff --git a/cmd/main.go b/cmd/main.go index fe4d25f5c..f43f3ff7e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -34,6 +34,9 @@ import ( dockermutation "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/docker/mutation" dockerworkerconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/docker/workerconfig" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle" + nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" + nutanixmutation "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation" + nutanixworkerconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/workerconfig" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) @@ -129,10 +132,20 @@ func main() { dockermutation.MetaWorkerPatchHandler(), } + // nutanixMetaHandlers combines all Nutanix patch and variable handlers under a single handler. + // It allows to specify configuration under a single variable. + nutanixMetaHandlers := []handlers.Named{ + nutanixclusterconfig.NewVariable(), + nutanixworkerconfig.NewVariable(), + nutanixmutation.MetaPatchHandler(mgr), + nutanixmutation.MetaWorkerPatchHandler(), + } + var allHandlers []handlers.Named allHandlers = append(allHandlers, genericLifecycleHandlers.AllHandlers(mgr)...) allHandlers = append(allHandlers, awsMetaHandlers...) allHandlers = append(allHandlers, dockerMetaHandlers...) + allHandlers = append(allHandlers, nutanixMetaHandlers...) runtimeWebhookServer := server.NewServer(runtimeWebhookServerOpts, allHandlers...) diff --git a/common/go.mod b/common/go.mod index d65da65ec..8c488f21a 100644 --- a/common/go.mod +++ b/common/go.mod @@ -52,6 +52,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nutanix-cloud-native/prism-go-client v0.3.4 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.18.0 // indirect diff --git a/common/go.sum b/common/go.sum index c18f9d540..a705598aa 100644 --- a/common/go.sum +++ b/common/go.sum @@ -1,121 +1,410 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/99designs/gqlgen v0.15.1/go.mod h1:nbeSjFkqphIqpZsYe1ULVz0yfH8hjpJdJIQoX/e0G2I= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= +github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= +github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/aws/aws-sdk-go v1.42.23/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bnkamalesh/webgo/v4 v4.1.11/go.mod h1:taIAonQTzao8G5rnB22WgKmQuIOWHpQ0n/YLAidBXlM= +github.com/bnkamalesh/webgo/v6 v6.2.2/go.mod h1:2Y+dEdTp1xC/ra+3PAVZV6hh4sCI+iPK7mcHt+t9bfM= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creasty/defaults v1.5.2/go.mod h1:FPZ+Y0WNrbqOVw+c6av63eyHUAl6pMHZwqLPvXUZGfY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= +github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg= +github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= +github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= +github.com/goccy/go-json v0.9.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/keploy/go-sdk v0.4.3/go.mod h1:tn62gQ8a/AD7mY51DvQfhudiBPTlD+w3XtXemDcbON4= +github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/labstack/echo/v4 v4.6.1/go.mod h1:RnjgMWNDB9g/HucVWhQYNQP9PvbYf6adqftqryo7s9k= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= +github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE= +github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= +github.com/lestrrat-go/jwx v1.2.20/go.mod h1:tLE1XszaFgd7zaS5wHe4NxA+XVhu7xgdRvDpNyi3kNM= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matryer/moq v0.2.3/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nutanix-cloud-native/prism-go-client v0.3.4 h1:bHY3VPrHHYnbRtkpGaKK+2ZmvUjNVRC55CYZbXIfnOk= +github.com/nutanix-cloud-native/prism-go-client v0.3.4/go.mod h1:tTIH02E6o6AWSShr98QChoxuZl+jBhkXFixom9+fd1Y= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo= github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= @@ -124,22 +413,54 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.35.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/vektah/gqlparser/v2 v2.2.0/go.mod h1:i3mQIGIrbK2PD1RrCeMTlVbkF2FJ6WkU1KJlJlC+3F4= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= +go.keploy.io/server v0.1.8/go.mod h1:ZqhwTZOBb+dzx5t30Wt6eUGI6kO5QizvPg6coNPtbow= +go.mongodb.org/mongo-driver v1.8.0/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.mongodb.org/mongo-driver v1.8.1/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0 h1:1eHu3/pUSWaOgltNK3WJFaywKsTIr/PwvHyDmi0lQA0= @@ -156,53 +477,284 @@ go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlA go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ= go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -211,51 +763,186 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA= google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI= google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM= google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= k8s.io/apiextensions-apiserver v0.29.3 h1:9HF+EtZaVpFjStakF4yVufnXGPRppWFEQ87qnO91YeI= k8s.io/apiextensions-apiserver v0.29.3/go.mod h1:po0XiY5scnpJfFizNGo6puNU6Fq6D70UJY2Cb2KwAVc= +k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= +k8s.io/apimachinery v0.24.3/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= k8s.io/apiserver v0.29.3 h1:xR7ELlJ/BZSr2n4CnD3lfA4gzFivh0wwfNfz9L0WZcE= k8s.io/apiserver v0.29.3/go.mod h1:hrvXlwfRulbMbBgmWRQlFru2b/JySDpmzvQwwk4GUOs= +k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= k8s.io/cluster-bootstrap v0.29.3 h1:DIMDZSN8gbFMy9CS2mAS2Iqq/fIUG783WN/1lqi5TF8= k8s.io/cluster-bootstrap v0.29.3/go.mod h1:aPAg1VtXx3uRrx5qU2jTzR7p1rf18zLXWS+pGhiqPto= k8s.io/component-base v0.29.3 h1:Oq9/nddUxlnrCuuR2K/jp6aflVvc0uDvxMzAWxnGzAo= k8s.io/component-base v0.29.3/go.mod h1:Yuj33XXjuOk2BAaHsIGHhCKZQAgYKhqIxIjIr2UXYio= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 h1:TgtAeesdhpm2SGwkQasmbeqDo8th5wOBA5h/AjTKA4I= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= sigs.k8s.io/cluster-api v1.6.3 h1:VOlPNg92PQLlhBVLc5pg+cbAuPvGOOBujeFLk9zgnoo= @@ -264,9 +951,13 @@ sigs.k8s.io/cluster-api/test v1.6.3 h1:ZCboLCTpKWzSbf+f7MpQT7EN8aeH9DNhJC1T9/vAu sigs.k8s.io/cluster-api/test v1.6.3/go.mod h1:AKs25dgW6AnyGaQBoWuXfWnBs+FT7vJmAI/aox64DEI= sigs.k8s.io/controller-runtime v0.17.2 h1:FwHwD1CTUemg0pW2otk7/U5/i5m2ymzvOXdbeGOUvw0= sigs.k8s.io/controller-runtime v0.17.2/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= +sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/common/pkg/testutils/capitest/request/items.go b/common/pkg/testutils/capitest/request/items.go index b3cd91664..dcc7b7144 100644 --- a/common/pkg/testutils/capitest/request/items.go +++ b/common/pkg/testutils/capitest/request/items.go @@ -15,6 +15,7 @@ import ( runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" capdv1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1" + capxv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" capav1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/serializer" ) @@ -163,6 +164,39 @@ func NewAWSClusterTemplateRequestItem( ) } +func NewNutanixClusterTemplateRequestItem( + uid types.UID, + existingSpec ...capxv1.NutanixClusterTemplateSpec, +) runtimehooksv1.GeneratePatchesRequestItem { + nutanixClusterTemplate := &capxv1.NutanixClusterTemplate{ + TypeMeta: metav1.TypeMeta{ + APIVersion: capxv1.GroupVersion.String(), + Kind: "NutanixClusterTemplate", + }, + } + + switch len(existingSpec) { + case 0: + // Do nothing. + case 1: + nutanixClusterTemplate.Spec = existingSpec[0] + default: + panic("can only take at most one existing spec") + } + + return NewRequestItem( + nutanixClusterTemplate, + &runtimehooksv1.HolderReference{ + APIVersion: clusterv1.GroupVersion.String(), + Kind: "Cluster", + FieldPath: "spec.infrastructureRef", + Name: ClusterName, + Namespace: Namespace, + }, + uid, + ) +} + func NewCPDockerMachineTemplateRequestItem( uid types.UID, ) runtimehooksv1.GeneratePatchesRequestItem { @@ -254,3 +288,49 @@ func NewWorkerAWSMachineTemplateRequestItem( uid, ) } + +func NewCPNutanixMachineTemplateRequestItem( + uid types.UID, +) runtimehooksv1.GeneratePatchesRequestItem { + return NewRequestItem( + &capxv1.NutanixMachineTemplate{ + TypeMeta: metav1.TypeMeta{ + APIVersion: capxv1.GroupVersion.String(), + Kind: "NutanixMachineTemplate", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "nutanix-machine-template", + Namespace: "nutanix-cluster", + }, + }, + &runtimehooksv1.HolderReference{ + APIVersion: controlplanev1.GroupVersion.String(), + Kind: "KubeadmControlPlane", + FieldPath: "spec.machineTemplate.infrastructureRef", + }, + uid, + ) +} + +func NewWorkerNutanixMachineTemplateRequestItem( + uid types.UID, +) runtimehooksv1.GeneratePatchesRequestItem { + return NewRequestItem( + &capxv1.NutanixMachineTemplate{ + TypeMeta: metav1.TypeMeta{ + APIVersion: capxv1.GroupVersion.String(), + Kind: "NutanixMachineTemplate", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "nutanix-machine-template", + Namespace: "nutanix-cluster", + }, + }, + &runtimehooksv1.HolderReference{ + APIVersion: clusterv1.GroupVersion.String(), + Kind: "MachineDeployment", + FieldPath: "spec.template.spec.infrastructureRef", + }, + uid, + ) +} diff --git a/docs/content/customization/docker/custom-image.md b/docs/content/customization/docker/custom-image.md index 773ea92ae..ed6dc1dd0 100644 --- a/docs/content/customization/docker/custom-image.md +++ b/docs/content/customization/docker/custom-image.md @@ -51,7 +51,7 @@ spec: Applying this configuration will result in the following value being set: -- control-plane `DockerMachineTemplte`: +- control-plane `DockerMachineTemplate`: - ```yaml spec: @@ -60,7 +60,7 @@ Applying this configuration will result in the following value being set: customImage: ghcr.io/mesosphere/kind-node:v1.2.3-cp ``` -- worker `DockerMachineTemplte`: +- worker `DockerMachineTemplate`: - ```yaml spec: diff --git a/docs/content/customization/generic/users.md b/docs/content/customization/generic/users.md index b7f7c304c..d0e1766ff 100644 --- a/docs/content/customization/generic/users.md +++ b/docs/content/customization/generic/users.md @@ -32,9 +32,9 @@ spec: - name: clusterConfig value: users: - - name: admin - - sshAuthorizedKeys: - - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAua0lo8BiGWgvIiDCKnQDKL5uERHfnehm0ns5CEJpJw optionalcomment" + - name: username + sshAuthorizedKeys: + - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAua0lo8BiGWgvIiDCKnQDKL5uERHfnehm0ns5CEJpJw optionalcomment" sudo: "ALL=(ALL) NOPASSWD:ALL" ``` diff --git a/docs/content/customization/nutanix/_index.md b/docs/content/customization/nutanix/_index.md new file mode 100644 index 000000000..30a6fc676 --- /dev/null +++ b/docs/content/customization/nutanix/_index.md @@ -0,0 +1,7 @@ ++++ +title = "Nutanix" +icon = "fa-brands fa-nutanix" ++++ + +The customizations in this section are applicable only to Nutanix clusters. They will only be applied to clusters that +use the `Nutanix` infrastructure provider, i.e. a CAPI `Cluster` that references an `NutanixCluster`. diff --git a/docs/content/customization/nutanix/control-plane-endpoint.md b/docs/content/customization/nutanix/control-plane-endpoint.md new file mode 100644 index 000000000..5c3bdbb75 --- /dev/null +++ b/docs/content/customization/nutanix/control-plane-endpoint.md @@ -0,0 +1,38 @@ ++++ +title = "Control Plane Endpoint" ++++ + +Configure Control Plane Endpoint. Defines the host IP and port of the CAPX Kubernetes cluster. + +## Examples + +### Set Control Plane Endpoint + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: +spec: + topology: + variables: + - name: clusterConfig + value: + nutanix: + controlPlaneEndpoint: + host: x.x.x.x + port: 6443 +``` + +Applying this configuration will result in the following value being set: + +- `NutanixCluster`: + +```yaml +spec: + template: + spec: + controlPlaneEndpoint: + host: x.x.x.x + port: 6443 +``` diff --git a/docs/content/customization/nutanix/machine-details.md b/docs/content/customization/nutanix/machine-details.md new file mode 100644 index 000000000..03b218228 --- /dev/null +++ b/docs/content/customization/nutanix/machine-details.md @@ -0,0 +1,112 @@ ++++ +title = "Machine Details" ++++ + +Configure Machine Details of Control plane and Worker nodes + +## Examples + +### Set Machine details of Control Plane and Worker nodes + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: +spec: + topology: + variables: + - name: clusterConfig + value: + controlPlane: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: pe-cluster-name + type: name + image: + name: os-image-name + type: name + memorySize: 4Gi + subnets: + - name: subnet-name + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 + - name: workerConfig + value: + nutanix: + machineDetails: + bootType: legacy + cluster: + name: pe-cluster-name + type: name + image: + name: os-image-name + type: name + memorySize: 4Gi + subnets: + - name: subnet-name + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 +``` + +Applying this configuration will result in the following value being set: + +- control-plane `NutanixMachineTemplate`: + +```yaml +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: NutanixMachineTemplate +metadata: + name: nutanix-quick-start-cp-nmt +spec: + template: + spec: + bootType: legacy + cluster: + name: pe-cluster-name + type: name + image: + name: os-image-name + type: name + memorySize: 4Gi + providerID: nutanix://vm-uuid + subnet: + - name: subnet-name + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 +``` + +- worker `NutanixMachineTemplate`: + +```yaml +apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 +kind: NutanixMachineTemplate +metadata: + name: nutanix-quick-start-md-nmt +spec: + template: + spec: + bootType: legacy + cluster: + name: pe-cluster-name + type: name + image: + name: os-image-name + type: name + memorySize: 4Gi + providerID: nutanix://vm-uuid + subnet: + - name: subnet-name + type: name + systemDiskSize: 40Gi + vcpuSockets: 2 + vcpusPerSocket: 1 +``` diff --git a/docs/content/customization/nutanix/prism-central-endpoint.md b/docs/content/customization/nutanix/prism-central-endpoint.md new file mode 100644 index 000000000..80d866eec --- /dev/null +++ b/docs/content/customization/nutanix/prism-central-endpoint.md @@ -0,0 +1,45 @@ ++++ +title = "Prism Central Endpoint" ++++ + +Configure Prism Central Endpoint to create machines on. + +## Examples + +### Set Prism Central Endpoint + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: +spec: + topology: + variables: + - name: clusterConfig + value: + nutanix: + prismCentralEndpoint: + credentials: + name: secret-name + host: x.x.x.x + insecure: false + port: 9440 +``` + +Applying this configuration will result in the following value being set: + +- control-plane NutanixClusterTemplate: + +```yaml +spec: + template: + spec: + prismCentral: + address: x.x.x.x + insecure: false + port: 9440 + credentialRef: + kind: Secret + name: secret-name +``` diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 36688ac95..7fa2f4766 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -339,7 +339,7 @@ spec: name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi - subnet: + subnets: - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi @@ -348,10 +348,10 @@ spec: nutanix: controlPlaneEndpoint: host: ${CONTROL_PLANE_ENDPOINT_IP} - port: ${CONTROL_PLANE_ENDPOINT_PORT} + port: 6443 prismCentralEndpoint: - additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle - credentialSecret: ${CLUSTER_NAME}-pc-creds + credentials: + name: ${CLUSTER_NAME}-pc-creds host: ${NUTANIX_ENDPOINT} insecure: ${NUTANIX_INSECURE} port: 9440 @@ -367,7 +367,7 @@ spec: name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi - subnet: + subnets: - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index 19cb1961a..31011b79d 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -339,7 +339,7 @@ spec: name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi - subnet: + subnets: - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi @@ -348,10 +348,10 @@ spec: nutanix: controlPlaneEndpoint: host: ${CONTROL_PLANE_ENDPOINT_IP} - port: ${CONTROL_PLANE_ENDPOINT_PORT} + port: 6443 prismCentralEndpoint: - additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle - credentialSecret: ${CLUSTER_NAME}-pc-creds + credentials: + name: ${CLUSTER_NAME}-pc-creds host: ${NUTANIX_ENDPOINT} insecure: ${NUTANIX_INSECURE} port: 9440 @@ -367,7 +367,7 @@ spec: name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi - subnet: + subnets: - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index 888cb9e78..3e86dc874 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -339,7 +339,7 @@ spec: name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi - subnet: + subnets: - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi @@ -348,10 +348,10 @@ spec: nutanix: controlPlaneEndpoint: host: ${CONTROL_PLANE_ENDPOINT_IP} - port: ${CONTROL_PLANE_ENDPOINT_PORT} + port: 6443 prismCentralEndpoint: - additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle - credentialSecret: ${CLUSTER_NAME}-pc-creds + credentials: + name: ${CLUSTER_NAME}-pc-creds host: ${NUTANIX_ENDPOINT} insecure: ${NUTANIX_INSECURE} port: 9440 @@ -367,7 +367,7 @@ spec: name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi - subnet: + subnets: - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 42ab33cb0..4cff901c0 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -339,7 +339,7 @@ spec: name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi - subnet: + subnets: - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi @@ -348,10 +348,10 @@ spec: nutanix: controlPlaneEndpoint: host: ${CONTROL_PLANE_ENDPOINT_IP} - port: ${CONTROL_PLANE_ENDPOINT_PORT} + port: 6443 prismCentralEndpoint: - additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle - credentialSecret: ${CLUSTER_NAME}-pc-creds + credentials: + name: ${CLUSTER_NAME}-pc-creds host: ${NUTANIX_ENDPOINT} insecure: ${NUTANIX_INSECURE} port: 9440 @@ -367,7 +367,7 @@ spec: name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi - subnet: + subnets: - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi diff --git a/go.mod b/go.mod index c55396282..6f4844444 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common v0.0.0-00010101000000-000000000000 github.com/go-logr/logr v1.4.1 github.com/google/go-cmp v0.6.0 + github.com/nutanix-cloud-native/prism-go-client v0.3.4 github.com/onsi/ginkgo/v2 v2.16.0 github.com/onsi/gomega v1.31.1 github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index ca45f459f..bbd861b14 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,9 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -36,8 +39,16 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/99designs/gqlgen v0.15.1/go.mod h1:nbeSjFkqphIqpZsYe1ULVz0yfH8hjpJdJIQoX/e0G2I= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= @@ -54,24 +65,43 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v24IBN1I= +github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= +github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/aws/aws-sdk-go v1.42.23/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bnkamalesh/webgo/v4 v4.1.11/go.mod h1:taIAonQTzao8G5rnB22WgKmQuIOWHpQ0n/YLAidBXlM= +github.com/bnkamalesh/webgo/v6 v6.2.2/go.mod h1:2Y+dEdTp1xC/ra+3PAVZV6hh4sCI+iPK7mcHt+t9bfM= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -84,6 +114,10 @@ github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBS github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coredns/caddy v1.1.0 h1:ezvsPrT/tA/7pYDBZxu0cT0VmWk75AfIaf6GSYCNMf0= github.com/coredns/caddy v1.1.0/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= github.com/coredns/corefile-migration v1.0.21 h1:W/DCETrHDiFo0Wj03EyMkaQ9fwsmSgqTCQDHpceaSsE= @@ -93,13 +127,18 @@ github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03V github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creasty/defaults v1.5.2/go.mod h1:FPZ+Y0WNrbqOVw+c6av63eyHUAl6pMHZwqLPvXUZGfY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= @@ -110,8 +149,12 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46 h1:7QPwrLT79GlD5sizHf27aoY2RTvw62mO6x7mxkScNk0= github.com/drone/envsubst/v2 v2.0.0-20210730161058-179042472c46/go.mod h1:esf2rsHFNlZlxsqsZDojNBcnNs5REqIvRrWRHqX0vEU= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -119,7 +162,9 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= @@ -127,31 +172,66 @@ github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= +github.com/go-chi/chi v1.5.4/go.mod h1:uaf8YgoFazUOkPBG7fxPftUylNumIev9awIWOENIuEg= +github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= +github.com/go-chi/render v1.0.1/go.mod h1:pq4Rr7HbnsdaeHagklXub+p6Wd16Af5l9koip1OvJns= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= +github.com/goccy/go-json v0.9.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -165,6 +245,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -179,12 +260,18 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -195,7 +282,10 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -204,6 +294,7 @@ github.com/google/go-github/v53 v53.2.0/go.mod h1:XhFRObz+m/l+UCm9b7KSIC3lT3NWSX github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -219,6 +310,9 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -226,25 +320,33 @@ github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+ github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= @@ -252,27 +354,60 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= +github.com/keploy/go-sdk v0.4.3/go.mod h1:tn62gQ8a/AD7mY51DvQfhudiBPTlD+w3XtXemDcbON4= +github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/labstack/echo/v4 v4.6.1/go.mod h1:RnjgMWNDB9g/HucVWhQYNQP9PvbYf6adqftqryo7s9k= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= +github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE= +github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= +github.com/lestrrat-go/jwx v1.2.20/go.mod h1:tLE1XszaFgd7zaS5wHe4NxA+XVhu7xgdRvDpNyi3kNM= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/matryer/moq v0.2.3/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -281,25 +416,50 @@ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQth github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nutanix-cloud-native/prism-go-client v0.3.4 h1:bHY3VPrHHYnbRtkpGaKK+2ZmvUjNVRC55CYZbXIfnOk= +github.com/nutanix-cloud-native/prism-go-client v0.3.4/go.mod h1:tTIH02E6o6AWSShr98QChoxuZl+jBhkXFixom9+fd1Y= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/ginkgo/v2 v2.16.0 h1:7q1w9frJDzninhXxjZd+Y/x54XNjG/UlRLIYPZafsPM= github.com/onsi/ginkgo/v2 v2.16.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo= github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -311,6 +471,8 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -327,19 +489,26 @@ github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lne github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ= github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY= github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -364,6 +533,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= @@ -371,12 +541,28 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.35.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/vektah/gqlparser/v2 v2.2.0/go.mod h1:i3mQIGIrbK2PD1RrCeMTlVbkF2FJ6WkU1KJlJlC+3F4= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= +github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= @@ -384,12 +570,16 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JB go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= +go.keploy.io/server v0.1.8/go.mod h1:ZqhwTZOBb+dzx5t30Wt6eUGI6kO5QizvPg6coNPtbow= +go.mongodb.org/mongo-driver v1.8.0/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= +go.mongodb.org/mongo-driver v1.8.1/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0 h1:PzIubN4/sjByhDRHLviCjJuweBXWFZWhghjg7cS28+M= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.0/go.mod h1:Ct6zzQEuGK3WpJs2n4dn+wfJYzd/+hNnxMRTWjGn30M= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.0 h1:1eHu3/pUSWaOgltNK3WJFaywKsTIr/PwvHyDmi0lQA0= @@ -406,12 +596,21 @@ go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlA go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ= go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -419,8 +618,15 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= @@ -460,11 +666,14 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -475,6 +684,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -485,16 +695,27 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= @@ -508,6 +729,9 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -520,11 +744,14 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -532,10 +759,16 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -546,6 +779,7 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -553,20 +787,35 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -578,6 +827,7 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -586,10 +836,13 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -597,12 +850,14 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -622,21 +877,26 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= @@ -665,6 +925,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -696,6 +958,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -703,12 +966,18 @@ google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA= google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI= @@ -728,9 +997,13 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -743,24 +1016,37 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -773,26 +1059,37 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= k8s.io/apiextensions-apiserver v0.29.3 h1:9HF+EtZaVpFjStakF4yVufnXGPRppWFEQ87qnO91YeI= k8s.io/apiextensions-apiserver v0.29.3/go.mod h1:po0XiY5scnpJfFizNGo6puNU6Fq6D70UJY2Cb2KwAVc= +k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= +k8s.io/apimachinery v0.24.3/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= k8s.io/apiserver v0.29.3 h1:xR7ELlJ/BZSr2n4CnD3lfA4gzFivh0wwfNfz9L0WZcE= k8s.io/apiserver v0.29.3/go.mod h1:hrvXlwfRulbMbBgmWRQlFru2b/JySDpmzvQwwk4GUOs= +k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= k8s.io/cluster-bootstrap v0.29.3 h1:DIMDZSN8gbFMy9CS2mAS2Iqq/fIUG783WN/1lqi5TF8= k8s.io/cluster-bootstrap v0.29.3/go.mod h1:aPAg1VtXx3uRrx5qU2jTzR7p1rf18zLXWS+pGhiqPto= k8s.io/component-base v0.29.3 h1:Oq9/nddUxlnrCuuR2K/jp6aflVvc0uDvxMzAWxnGzAo= k8s.io/component-base v0.29.3/go.mod h1:Yuj33XXjuOk2BAaHsIGHhCKZQAgYKhqIxIjIr2UXYio= +k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= k8s.io/kubelet v0.29.3 h1:X9h0ZHzc+eUeNTaksbN0ItHyvGhQ7Z0HPjnQD2oHdwU= k8s.io/kubelet v0.29.3/go.mod h1:jDiGuTkFOUynyBKzOoC1xRSWlgAZ9UPcTYeFyjr6vas= +k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= @@ -808,12 +1105,16 @@ sigs.k8s.io/cluster-api/test v1.6.3 h1:ZCboLCTpKWzSbf+f7MpQT7EN8aeH9DNhJC1T9/vAu sigs.k8s.io/cluster-api/test v1.6.3/go.mod h1:AKs25dgW6AnyGaQBoWuXfWnBs+FT7vJmAI/aox64DEI= sigs.k8s.io/controller-runtime v0.17.2 h1:FwHwD1CTUemg0pW2otk7/U5/i5m2ymzvOXdbeGOUvw0= sigs.k8s.io/controller-runtime v0.17.2/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= +sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/kind v0.20.0 h1:f0sc3v9mQbGnjBUaqSFST1dwIuiikKVGgoTwpoP33a8= sigs.k8s.io/kind v0.20.0/go.mod h1:aBlbxg08cauDgZ612shr017/rZwqd7AS563FvpWKPVs= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index b5d850b65..57d2a6d1a 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -5,7 +5,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: -- https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/51aa55fe8b194a261bc3cc4e6d24f5d430ec055a/templates/cluster-template-topology.yaml +- https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/1a7cd69ba35de01e56dcf2dda7f31973111d2317/templates/cluster-template-topology.yaml sortOptions: order: fifo diff --git a/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl index 40cb4305b..d79935f3b 100644 --- a/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/clusterclass/kustomization.yaml.tmpl @@ -5,7 +5,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: -- https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/51aa55fe8b194a261bc3cc4e6d24f5d430ec055a/templates/cluster-template-clusterclass.yaml +- https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/1a7cd69ba35de01e56dcf2dda7f31973111d2317/templates/cluster-template-clusterclass.yaml configurations: - kustomizeconfig.yaml @@ -29,3 +29,24 @@ patches: path: "/spec/patches" - op: "remove" path: "/spec/variables" + +# FIXME: Debug why some of the patches are needed. +# When the handler runs, it sends back multiple patches for individual fields. +# But CAPI fails applying them because of missing value. +- target: + kind: NutanixClusterTemplate + patch: |- + - op: "add" + path: "/spec/template/spec/controlPlaneEndpoint" + value: + host: PLACEHOLDER + port: 6443 + - op: "add" + path: "/spec/template/spec/prismCentral" + value: + address: PLACEHOLDER + port: 9440 + credentialRef: + name: PLACEHOLDER + kind: Secret + namespace: default diff --git a/hack/examples/patches/nutanix/initialize-variables.yaml b/hack/examples/patches/nutanix/initialize-variables.yaml index 9429272bd..46a17d7d2 100644 --- a/hack/examples/patches/nutanix/initialize-variables.yaml +++ b/hack/examples/patches/nutanix/initialize-variables.yaml @@ -9,13 +9,13 @@ value: controlPlaneEndpoint: host: ${CONTROL_PLANE_ENDPOINT_IP} - port: ${CONTROL_PLANE_ENDPOINT_PORT} + port: 6443 prismCentralEndpoint: - additionalTrustBundle: ${CLUSTER_NAME}-pc-trusted-ca-bundle host: ${NUTANIX_ENDPOINT} insecure: ${NUTANIX_INSECURE} port: 9440 - credentialSecret: ${CLUSTER_NAME}-pc-creds + credentials: + name: ${CLUSTER_NAME}-pc-creds - op: "add" path: "/spec/topology/variables/0/value/controlPlane" value: @@ -28,7 +28,7 @@ image: name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name - subnet: + subnets: - name: ${NUTANIX_SUBNET_NAME} type: name memorySize: 4Gi @@ -47,7 +47,7 @@ name: ${NUTANIX_MACHINE_TEMPLATE_IMAGE_NAME} type: name memorySize: 4Gi - subnet: + subnets: - name: ${NUTANIX_SUBNET_NAME} type: name systemDiskSize: 40Gi diff --git a/make/examples.mk b/make/examples.mk index b23f8f28e..3b7b9310a 100644 --- a/make/examples.mk +++ b/make/examples.mk @@ -5,6 +5,7 @@ export KUBERNETES_VERSION := v1.27.5 export CLUSTERCTL_VERSION := $(shell clusterctl version -o short 2>/dev/null) export CAPA_VERSION := $(shell cd hack/third-party/capa && go list -m -f '{{ .Version }}' sigs.k8s.io/cluster-api-provider-aws/v2) +export CAPX_VERSION := $(shell cd hack/third-party/capx && go list -m -f '{{ .Version }}' github.com/nutanix-cloud-native/cluster-api-provider-nutanix) .PHONY: examples.sync examples.sync: ## Syncs the examples by fetching upstream examples and applying kustomize patches diff --git a/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go b/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go index 27a366137..4a5ddf7cf 100644 --- a/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go +++ b/pkg/handlers/generic/lifecycle/cni/calico/strategy_crs.go @@ -42,8 +42,9 @@ func (c *crsConfig) AddFlags(prefix string, flags *pflag.FlagSet) { &c.defaultProviderInstallationConfigMapNames, prefix+".default-provider-installation-configmap-names", map[string]string{ - "DockerCluster": "calico-cni-crs-installation-dockercluster", - "AWSCluster": "calico-cni-crs-installation-awscluster", + "DockerCluster": "calico-cni-crs-installation-dockercluster", + "AWSCluster": "calico-cni-crs-installation-awscluster", + "NutanixCluster": "calico-cni-crs-installation-nutanixcluster", }, "map of provider cluster implementation type to default installation ConfigMap name", ) diff --git a/pkg/handlers/generic/lifecycle/cni/calico/strategy_helmaddon.go b/pkg/handlers/generic/lifecycle/cni/calico/strategy_helmaddon.go index 9f328082f..0495afee1 100644 --- a/pkg/handlers/generic/lifecycle/cni/calico/strategy_helmaddon.go +++ b/pkg/handlers/generic/lifecycle/cni/calico/strategy_helmaddon.go @@ -37,8 +37,9 @@ func (c *helmAddonConfig) AddFlags(prefix string, flags *pflag.FlagSet) { &c.defaultProviderInstallationValuesTemplatesConfigMapNames, prefix+".default-provider-installation-values-templates-configmap-names", map[string]string{ - "DockerCluster": "calico-cni-helm-values-template-dockercluster", - "AWSCluster": "calico-cni-helm-values-template-awscluster", + "DockerCluster": "calico-cni-helm-values-template-dockercluster", + "AWSCluster": "calico-cni-helm-values-template-awscluster", + "NutanixCluster": "calico-cni-helm-values-template-nutanixcluster", }, "map of provider cluster implementation type to default installation values ConfigMap name", ) diff --git a/pkg/handlers/nutanix/clusterconfig/variables.go b/pkg/handlers/nutanix/clusterconfig/variables.go new file mode 100644 index 000000000..cebff93c6 --- /dev/null +++ b/pkg/handlers/nutanix/clusterconfig/variables.go @@ -0,0 +1,52 @@ +// Copyright 2024 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package clusterconfig + +import ( + "context" + + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + commonhandlers "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +var ( + _ commonhandlers.Named = &nutanixClusterConfigVariableHandler{} + _ mutation.DiscoverVariables = &nutanixClusterConfigVariableHandler{} +) + +const ( + // HandlerNameVariable is the name of the variable handler. + HandlerNameVariable = "NutanixClusterConfigVars" + + // NutanixVariableName is the Nutanix config patch variable name. + NutanixVariableName = "nutanix" +) + +func NewVariable() *nutanixClusterConfigVariableHandler { + return &nutanixClusterConfigVariableHandler{} +} + +type nutanixClusterConfigVariableHandler struct{} + +func (h *nutanixClusterConfigVariableHandler) Name() string { + return HandlerNameVariable +} + +func (h *nutanixClusterConfigVariableHandler) DiscoverVariables( + ctx context.Context, + _ *runtimehooksv1.DiscoverVariablesRequest, + resp *runtimehooksv1.DiscoverVariablesResponse, +) { + resp.Variables = append(resp.Variables, clusterv1.ClusterClassVariable{ + Name: clusterconfig.MetaVariableName, + Required: true, + Schema: v1alpha1.ClusterConfigSpec{Nutanix: &v1alpha1.NutanixSpec{}}.VariableSchema(), + }) + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) +} diff --git a/pkg/handlers/nutanix/mutation/controlplaneendpoint/inject.go b/pkg/handlers/nutanix/mutation/controlplaneendpoint/inject.go new file mode 100644 index 000000000..1043689ba --- /dev/null +++ b/pkg/handlers/nutanix/mutation/controlplaneendpoint/inject.go @@ -0,0 +1,134 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package controlplaneendpoint + +import ( + "context" + "fmt" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + capiv1 "sigs.k8s.io/cluster-api/api/v1beta1" + controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + capxv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches/selectors" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +const ( + // VariableName is the external patch variable name. + VariableName = "controlPlaneEndpoint" +) + +type nutanixControlPlaneEndpoint struct { + variableName string + variableFieldPath []string +} + +func NewPatch() *nutanixControlPlaneEndpoint { + return newNutanixControlPlaneEndpoint( + clusterconfig.MetaVariableName, + v1alpha1.NutanixVariableName, + VariableName, + ) +} + +func newNutanixControlPlaneEndpoint( + variableName string, + variableFieldPath ...string, +) *nutanixControlPlaneEndpoint { + return &nutanixControlPlaneEndpoint{ + variableName: variableName, + variableFieldPath: variableFieldPath, + } +} + +func (h *nutanixControlPlaneEndpoint) Mutate( + ctx context.Context, + obj *unstructured.Unstructured, + vars map[string]apiextensionsv1.JSON, + holderRef runtimehooksv1.HolderReference, + _ client.ObjectKey, +) error { + log := ctrl.LoggerFrom(ctx).WithValues( + "holderRef", holderRef, + ) + + controlPlaneEndpointVar, found, err := variables.Get[v1alpha1.ControlPlaneEndpointSpec]( + vars, + h.variableName, + h.variableFieldPath..., + ) + if err != nil { + return err + } + if !found { + log.V(5).Info("Nutanix ControlPlaneEndpoint variable not defined") + return nil + } + + log = log.WithValues( + "variableName", + h.variableName, + "variableFieldPath", + h.variableFieldPath, + "variableValue", + controlPlaneEndpointVar, + ) + + if err := patches.MutateIfApplicable( + obj, + vars, + &holderRef, + selectors.ControlPlane(), + log, + func(obj *controlplanev1.KubeadmControlPlaneTemplate) error { + commands := []string{ + fmt.Sprintf("sed -i 's/control_plane_endpoint_ip/%s/g' /etc/kubernetes/manifests/kube-vip.yaml", + controlPlaneEndpointVar.Host), + fmt.Sprintf("sed -i 's/control_plane_endpoint_port/%d/g' /etc/kubernetes/manifests/kube-vip.yaml", + controlPlaneEndpointVar.Port), + } + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", client.ObjectKeyFromObject(obj), + ).Info("adding PreKubeadmCommands to control plane kubeadm config spec") + obj.Spec.Template.Spec.KubeadmConfigSpec.PreKubeadmCommands = append( + obj.Spec.Template.Spec.KubeadmConfigSpec.PreKubeadmCommands, + commands..., + ) + return nil + }, + ); err != nil { + return err + } + + return patches.MutateIfApplicable( + obj, + vars, + &holderRef, + selectors.InfrastructureCluster(capxv1.GroupVersion.Version, "NutanixClusterTemplate"), + log, + func(obj *capxv1.NutanixClusterTemplate) error { + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", client.ObjectKeyFromObject(obj), + ).Info("setting controlPlaneEndpoint in NutanixCluster spec") + + obj.Spec.Template.Spec.ControlPlaneEndpoint = capiv1.APIEndpoint{ + Host: controlPlaneEndpointVar.Host, + Port: controlPlaneEndpointVar.Port, + } + + return nil + }, + ) +} diff --git a/pkg/handlers/nutanix/mutation/controlplaneendpoint/tests/generate_patches.go b/pkg/handlers/nutanix/mutation/controlplaneendpoint/tests/generate_patches.go new file mode 100644 index 000000000..8a93eb8f5 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/controlplaneendpoint/tests/generate_patches.go @@ -0,0 +1,59 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package tests + +import ( + "testing" + + "github.com/onsi/gomega" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" +) + +func TestGeneratePatches( + t *testing.T, + generatorFunc func() mutation.GeneratePatches, + variableName string, + variablePath ...string, +) { + t.Helper() + + capitest.ValidateGeneratePatches( + t, + generatorFunc, + capitest.PatchTestDef{ + Name: "unset variable", + }, + capitest.PatchTestDef{ + Name: "ControlPlaneEndpoint set to valid host and port", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + clusterv1.APIEndpoint{ + Host: "10.20.100.10", + Port: 6443, + }, + variablePath..., + ), + }, + RequestItem: request.NewNutanixClusterTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "replace", + Path: "/spec/template/spec/controlPlaneEndpoint/host", + ValueMatcher: gomega.Equal("10.20.100.10"), + }, + { + Operation: "replace", + Path: "/spec/template/spec/controlPlaneEndpoint/port", + ValueMatcher: gomega.BeEquivalentTo(6443), + }, + }, + }, + ) +} diff --git a/pkg/handlers/nutanix/mutation/controlplaneendpoint/variables_test.go b/pkg/handlers/nutanix/mutation/controlplaneendpoint/variables_test.go new file mode 100644 index 000000000..372e39564 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/controlplaneendpoint/variables_test.go @@ -0,0 +1,86 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package controlplaneendpoint + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" +) + +func TestVariableValidation(t *testing.T) { + capitest.ValidateDiscoverVariables( + t, + clusterconfig.MetaVariableName, + ptr.To(v1alpha1.ClusterConfigSpec{Nutanix: &v1alpha1.NutanixSpec{}}.VariableSchema()), + true, + nutanixclusterconfig.NewVariable, + capitest.VariableTestDef{ + Name: "valid host and port", + Vals: v1alpha1.ClusterConfigSpec{ + Nutanix: &v1alpha1.NutanixSpec{ + ControlPlaneEndpoint: clusterv1.APIEndpoint{ + Host: "10.20.100.10", + Port: 6443, + }, + // PrismCentralEndpoint is a required field and must always be set + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + Host: "prism-central.nutanix.com", + Port: v1alpha1.PrismCentralPort, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + }, + }, + }, + capitest.VariableTestDef{ + Name: "empty host", + Vals: v1alpha1.ClusterConfigSpec{ + Nutanix: &v1alpha1.NutanixSpec{ + ControlPlaneEndpoint: clusterv1.APIEndpoint{ + Host: "", + Port: 6443, + }, + // PrismCentralEndpoint is a required field and must always be set + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + Host: "prism-central.nutanix.com", + Port: v1alpha1.PrismCentralPort, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + }, + }, + ExpectError: true, + }, + capitest.VariableTestDef{ + Name: "port set to 0", + Vals: v1alpha1.ClusterConfigSpec{ + Nutanix: &v1alpha1.NutanixSpec{ + ControlPlaneEndpoint: clusterv1.APIEndpoint{ + Host: "10.20.100.10", + Port: 0, + }, + // PrismCentralEndpoint is a required field and must always be set + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + Host: "prism-central.nutanix.com", + Port: v1alpha1.PrismCentralPort, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + }, + }, + ExpectError: true, + }, + ) +} diff --git a/pkg/handlers/nutanix/mutation/machinedetails/inject.go b/pkg/handlers/nutanix/mutation/machinedetails/inject.go new file mode 100644 index 000000000..9f17a07e9 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/machinedetails/inject.go @@ -0,0 +1,113 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package machinedetails + +import ( + "context" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + capxv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" +) + +const ( + // VariableName is the external patch variable name. + VariableName = "machineDetails" +) + +type nutanixMachineDetailsPatchHandler struct { + metaVariableName string + variableFieldPath []string + patchSelector clusterv1.PatchSelector +} + +func newNutanixMachineDetailsPatchHandler( + metaVariableName string, + variableFieldPath []string, + patchSelector clusterv1.PatchSelector, +) *nutanixMachineDetailsPatchHandler { + return &nutanixMachineDetailsPatchHandler{ + metaVariableName: metaVariableName, + variableFieldPath: variableFieldPath, + patchSelector: patchSelector, + } +} + +func (h *nutanixMachineDetailsPatchHandler) Mutate( + ctx context.Context, + obj *unstructured.Unstructured, + vars map[string]apiextensionsv1.JSON, + holderRef runtimehooksv1.HolderReference, + _ client.ObjectKey, +) error { + log := ctrl.LoggerFrom(ctx).WithValues( + "holderRef", holderRef, + ) + + nutanixMachineDetailsVar, found, err := variables.Get[v1alpha1.NutanixMachineDetails]( + vars, + h.metaVariableName, + h.variableFieldPath..., + ) + if err != nil { + return err + } + if !found { + log.V(5).Info("Nutanix machine details variable for workers not defined") + return nil + } + + log = log.WithValues( + "variableName", + h.metaVariableName, + "variableFieldPath", + h.variableFieldPath, + "variableValue", + nutanixMachineDetailsVar, + ) + + return patches.MutateIfApplicable( + obj, + vars, + &holderRef, + h.patchSelector, + log, + func(obj *capxv1.NutanixMachineTemplate) error { + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", client.ObjectKeyFromObject(obj), + ).Info("setting Nutanix machine details in worker NutanixMachineTemplate spec") + + spec := obj.Spec.Template.Spec + + spec.BootType = capxv1.NutanixBootType(nutanixMachineDetailsVar.BootType) + spec.Cluster = capxv1.NutanixResourceIdentifier(nutanixMachineDetailsVar.Cluster) + spec.Image = capxv1.NutanixResourceIdentifier(nutanixMachineDetailsVar.Image) + + spec.VCPUSockets = nutanixMachineDetailsVar.VCPUSockets + spec.VCPUsPerSocket = nutanixMachineDetailsVar.VCPUsPerSocket + spec.MemorySize = nutanixMachineDetailsVar.MemorySize + spec.SystemDiskSize = nutanixMachineDetailsVar.SystemDiskSize + + spec.Subnets = make( + []capxv1.NutanixResourceIdentifier, + len(nutanixMachineDetailsVar.Subnets), + ) + for i, subnet := range nutanixMachineDetailsVar.Subnets { + spec.Subnets[i] = capxv1.NutanixResourceIdentifier(subnet) + } + + obj.Spec.Template.Spec = spec + return nil + }, + ) +} diff --git a/pkg/handlers/nutanix/mutation/machinedetails/inject_control_plane.go b/pkg/handlers/nutanix/mutation/machinedetails/inject_control_plane.go new file mode 100644 index 000000000..04a51361f --- /dev/null +++ b/pkg/handlers/nutanix/mutation/machinedetails/inject_control_plane.go @@ -0,0 +1,25 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package machinedetails + +import ( + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches/selectors" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +func NewControlPlanePatch() *nutanixMachineDetailsPatchHandler { + return newNutanixMachineDetailsPatchHandler( + clusterconfig.MetaVariableName, + []string{ + clusterconfig.MetaControlPlaneConfigName, + v1alpha1.NutanixVariableName, + VariableName, + }, + selectors.InfrastructureControlPlaneMachines( + "v1beta1", + "NutanixMachineTemplate", + ), + ) +} diff --git a/pkg/handlers/nutanix/mutation/machinedetails/inject_worker.go b/pkg/handlers/nutanix/mutation/machinedetails/inject_worker.go new file mode 100644 index 000000000..200141060 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/machinedetails/inject_worker.go @@ -0,0 +1,24 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package machinedetails + +import ( + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches/selectors" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" +) + +func NewWorkerPatch() *nutanixMachineDetailsPatchHandler { + return newNutanixMachineDetailsPatchHandler( + workerconfig.MetaVariableName, + []string{ + v1alpha1.NutanixVariableName, + VariableName, + }, + selectors.InfrastructureWorkerMachineTemplates( + "v1beta1", + "NutanixMachineTemplate", + ), + ) +} diff --git a/pkg/handlers/nutanix/mutation/machinedetails/tests/generate_patches.go b/pkg/handlers/nutanix/mutation/machinedetails/tests/generate_patches.go new file mode 100644 index 000000000..9e38b6214 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/machinedetails/tests/generate_patches.go @@ -0,0 +1,161 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package tests + +import ( + "testing" + + "github.com/onsi/gomega" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/utils/ptr" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + capxv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" +) + +var ( + variableWithAllFieldsSet = v1alpha1.NutanixMachineDetails{ + BootType: v1alpha1.NutanixBootType(capxv1.NutanixBootTypeLegacy), + VCPUSockets: 2, + VCPUsPerSocket: 1, + Image: v1alpha1.NutanixResourceIdentifier{ + Type: capxv1.NutanixIdentifierName, + Name: ptr.To("fake-image"), + }, + Cluster: v1alpha1.NutanixResourceIdentifier{ + Type: capxv1.NutanixIdentifierName, + Name: ptr.To("fake-pe-cluster"), + }, + MemorySize: resource.MustParse("8Gi"), + SystemDiskSize: resource.MustParse("40Gi"), + Subnets: []v1alpha1.NutanixResourceIdentifier{ + { + Type: capxv1.NutanixIdentifierName, + Name: ptr.To("fake-subnet"), + }, + }, + } + + matchersForAllFieldsSet = []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/bootType", + ValueMatcher: gomega.BeEquivalentTo(capxv1.NutanixBootTypeLegacy), + }, + { + Operation: "add", + Path: "/spec/template/spec/image/name", + ValueMatcher: gomega.BeEquivalentTo("fake-image"), + }, + { + Operation: "replace", + Path: "/spec/template/spec/image/type", + ValueMatcher: gomega.BeEquivalentTo(capxv1.NutanixIdentifierName), + }, + { + Operation: "add", + Path: "/spec/template/spec/cluster/name", + ValueMatcher: gomega.BeEquivalentTo("fake-pe-cluster"), + }, + { + Operation: "replace", + Path: "/spec/template/spec/cluster/type", + ValueMatcher: gomega.BeEquivalentTo(capxv1.NutanixIdentifierName), + }, + { + Operation: "replace", + Path: "/spec/template/spec/vcpuSockets", + ValueMatcher: gomega.BeEquivalentTo(2), + }, + { + Operation: "replace", + Path: "/spec/template/spec/vcpusPerSocket", + ValueMatcher: gomega.BeEquivalentTo(1), + }, + { + Operation: "replace", + Path: "/spec/template/spec/memorySize", + ValueMatcher: gomega.BeEquivalentTo("8Gi"), + }, + { + Operation: "replace", + Path: "/spec/template/spec/systemDiskSize", + ValueMatcher: gomega.BeEquivalentTo("40Gi"), + }, + { + Operation: "replace", + Path: "/spec/template/spec/subnet", + ValueMatcher: gomega.HaveLen(1), + }, + } +) + +func TestControlPlaneGeneratePatches( + t *testing.T, + generatorFunc func() mutation.GeneratePatches, + variableName string, + variablePath ...string, +) { + t.Helper() + + capitest.ValidateGeneratePatches( + t, + generatorFunc, + capitest.PatchTestDef{ + Name: "unset variable", + }, + capitest.PatchTestDef{ + Name: "all fields set for control-plane", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + variableWithAllFieldsSet, + variablePath..., + ), + }, + RequestItem: request.NewCPNutanixMachineTemplateRequestItem(""), + ExpectedPatchMatchers: matchersForAllFieldsSet, + }, + ) +} + +func TestWorkerGeneratePatches( + t *testing.T, + generatorFunc func() mutation.GeneratePatches, + variableName string, + variablePath ...string, +) { + t.Helper() + + capitest.ValidateGeneratePatches( + t, + generatorFunc, + capitest.PatchTestDef{ + Name: "unset variable", + }, + capitest.PatchTestDef{ + Name: "all fields set for workers", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + variableWithAllFieldsSet, + variablePath..., + ), + capitest.VariableWithValue( + "builtin", + apiextensionsv1.JSON{ + Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), + }, + ), + }, + RequestItem: request.NewWorkerNutanixMachineTemplateRequestItem(""), + ExpectedPatchMatchers: matchersForAllFieldsSet, + }, + ) +} diff --git a/pkg/handlers/nutanix/mutation/machinedetails/variables_test.go b/pkg/handlers/nutanix/mutation/machinedetails/variables_test.go new file mode 100644 index 000000000..23d432d92 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/machinedetails/variables_test.go @@ -0,0 +1,132 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package machinedetails + +import ( + "testing" + + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/utils/ptr" + + capxv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" +) + +func TestVariableValidation(t *testing.T) { + testImageName := "fake-image" + testPEClusterName := "fake-pe-cluster" + capitest.ValidateDiscoverVariables( + t, + clusterconfig.MetaVariableName, + ptr.To(v1alpha1.ClusterConfigSpec{Nutanix: &v1alpha1.NutanixSpec{}}.VariableSchema()), + true, + nutanixclusterconfig.NewVariable, + capitest.VariableTestDef{ + Name: "all fields set", + Vals: v1alpha1.ClusterConfigSpec{ + ControlPlane: &v1alpha1.NodeConfigSpec{ + Nutanix: &v1alpha1.NutanixNodeSpec{ + MachineDetails: v1alpha1.NutanixMachineDetails{ + BootType: v1alpha1.NutanixBootType(capxv1.NutanixBootTypeLegacy), + VCPUSockets: 2, + VCPUsPerSocket: 1, + Image: v1alpha1.NutanixResourceIdentifier{ + Type: capxv1.NutanixIdentifierName, + Name: &testImageName, + }, + Cluster: v1alpha1.NutanixResourceIdentifier{ + Type: capxv1.NutanixIdentifierName, + Name: &testPEClusterName, + }, + MemorySize: resource.MustParse("8Gi"), + SystemDiskSize: resource.MustParse("40Gi"), + Subnets: []v1alpha1.NutanixResourceIdentifier{}, + }, + }, + }, + }, + }, + capitest.VariableTestDef{ + Name: "invalid boot type", + Vals: v1alpha1.ClusterConfigSpec{ + ControlPlane: &v1alpha1.NodeConfigSpec{ + Nutanix: &v1alpha1.NutanixNodeSpec{ + MachineDetails: v1alpha1.NutanixMachineDetails{ + BootType: "invalid", + VCPUSockets: 2, + VCPUsPerSocket: 1, + Image: v1alpha1.NutanixResourceIdentifier{ + Type: capxv1.NutanixIdentifierName, + Name: &testImageName, + }, + Cluster: v1alpha1.NutanixResourceIdentifier{ + Type: capxv1.NutanixIdentifierName, + Name: &testPEClusterName, + }, + MemorySize: resource.MustParse("8Gi"), + SystemDiskSize: resource.MustParse("40Gi"), + Subnets: []v1alpha1.NutanixResourceIdentifier{}, + }, + }, + }, + }, + ExpectError: true, + }, + capitest.VariableTestDef{ + Name: "invalid image type", + Vals: v1alpha1.ClusterConfigSpec{ + ControlPlane: &v1alpha1.NodeConfigSpec{ + Nutanix: &v1alpha1.NutanixNodeSpec{ + MachineDetails: v1alpha1.NutanixMachineDetails{ + BootType: v1alpha1.NutanixBootType(capxv1.NutanixBootTypeLegacy), + VCPUSockets: 2, + VCPUsPerSocket: 1, + Image: v1alpha1.NutanixResourceIdentifier{ + Type: "invalid", + Name: &testImageName, + }, + Cluster: v1alpha1.NutanixResourceIdentifier{ + Type: capxv1.NutanixIdentifierName, + Name: &testPEClusterName, + }, + MemorySize: resource.MustParse("8Gi"), + SystemDiskSize: resource.MustParse("40Gi"), + Subnets: []v1alpha1.NutanixResourceIdentifier{}, + }, + }, + }, + }, + ExpectError: true, + }, + capitest.VariableTestDef{ + Name: "invalid cluster type", + Vals: v1alpha1.ClusterConfigSpec{ + ControlPlane: &v1alpha1.NodeConfigSpec{ + Nutanix: &v1alpha1.NutanixNodeSpec{ + MachineDetails: v1alpha1.NutanixMachineDetails{ + BootType: v1alpha1.NutanixBootType(capxv1.NutanixBootTypeLegacy), + VCPUSockets: 2, + VCPUsPerSocket: 1, + Image: v1alpha1.NutanixResourceIdentifier{ + Type: capxv1.NutanixIdentifierName, + Name: &testImageName, + }, + Cluster: v1alpha1.NutanixResourceIdentifier{ + Type: "invalid", + Name: &testPEClusterName, + }, + MemorySize: resource.MustParse("8Gi"), + SystemDiskSize: resource.MustParse("40Gi"), + Subnets: []v1alpha1.NutanixResourceIdentifier{}, + }, + }, + }, + }, + ExpectError: true, + }, + ) +} diff --git a/pkg/handlers/nutanix/mutation/metapatch_handler.go b/pkg/handlers/nutanix/mutation/metapatch_handler.go new file mode 100644 index 000000000..c3bd1be77 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/metapatch_handler.go @@ -0,0 +1,44 @@ +// Copyright 2024 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package mutation + +import ( + "sigs.k8s.io/controller-runtime/pkg/manager" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + genericmutation "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/controlplaneendpoint" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/machinedetails" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/prismcentralendpoint" +) + +// MetaPatchHandler returns a meta patch handler for mutating CAPX clusters. +func MetaPatchHandler(mgr manager.Manager) handlers.Named { + patchHandlers := append( + []mutation.MetaMutator{ + controlplaneendpoint.NewPatch(), + prismcentralendpoint.NewPatch(), + machinedetails.NewControlPlanePatch(), + }, + genericmutation.MetaMutators(mgr)..., + ) + + return mutation.NewMetaGeneratePatchesHandler( + "nutanixClusterConfigPatch", + patchHandlers..., + ) +} + +// MetaWorkerPatchHandler returns a meta patch handler for mutating CAPA workers. +func MetaWorkerPatchHandler() handlers.Named { + patchHandlers := []mutation.MetaMutator{ + machinedetails.NewWorkerPatch(), + } + + return mutation.NewMetaGeneratePatchesHandler( + "nutanixWorkerConfigPatch", + patchHandlers..., + ) +} diff --git a/pkg/handlers/nutanix/mutation/metapatch_handler_test.go b/pkg/handlers/nutanix/mutation/metapatch_handler_test.go new file mode 100644 index 000000000..4216bc2cb --- /dev/null +++ b/pkg/handlers/nutanix/mutation/metapatch_handler_test.go @@ -0,0 +1,134 @@ +// Copyright 2024 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package mutation + +import ( + "testing" + + "sigs.k8s.io/controller-runtime/pkg/manager" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + auditpolicytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/auditpolicy/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/etcd" + etcdtests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/etcd/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/extraapiservercertsans" + extraapiservercertsanstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/extraapiservercertsans/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy" + httpproxytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/imageregistries" + imageregistrycredentialstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/imageregistries/credentials/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository" + kubernetesimagerepositorytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors" + globalimageregistrymirrortests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" + nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/controlplaneendpoint" + controlplaneendpointtests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/controlplaneendpoint/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/machinedetails" + machinedetailstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/machinedetails/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/prismcentralendpoint" + prismcentralendpointtests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests" +) + +func metaPatchGeneratorFunc(mgr manager.Manager) func() mutation.GeneratePatches { + return func() mutation.GeneratePatches { + return MetaPatchHandler(mgr).(mutation.GeneratePatches) + } +} + +func workerPatchGeneratorFunc() func() mutation.GeneratePatches { + return func() mutation.GeneratePatches { + return MetaWorkerPatchHandler().(mutation.GeneratePatches) + } +} + +func TestGeneratePatches(t *testing.T) { + t.Parallel() + + mgr := testEnv.Manager + + controlplaneendpointtests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + clusterconfig.MetaVariableName, + nutanixclusterconfig.NutanixVariableName, + controlplaneendpoint.VariableName, + ) + + prismcentralendpointtests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + clusterconfig.MetaVariableName, + nutanixclusterconfig.NutanixVariableName, + prismcentralendpoint.VariableName, + ) + + machinedetailstests.TestControlPlaneGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + clusterconfig.MetaVariableName, + clusterconfig.MetaControlPlaneConfigName, + nutanixclusterconfig.NutanixVariableName, + machinedetails.VariableName, + ) + + machinedetailstests.TestWorkerGeneratePatches( + t, + workerPatchGeneratorFunc(), + workerconfig.MetaVariableName, + nutanixclusterconfig.NutanixVariableName, + machinedetails.VariableName, + ) + + auditpolicytests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + ) + + httpproxytests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + clusterconfig.MetaVariableName, + httpproxy.VariableName, + ) + + etcdtests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + clusterconfig.MetaVariableName, + etcd.VariableName, + ) + + extraapiservercertsanstests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + clusterconfig.MetaVariableName, + extraapiservercertsans.VariableName, + ) + + kubernetesimagerepositorytests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + clusterconfig.MetaVariableName, + kubernetesimagerepository.VariableName, + ) + + imageregistrycredentialstests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + mgr.GetClient(), + clusterconfig.MetaVariableName, + imageregistries.VariableName, + ) + + globalimageregistrymirrortests.TestGeneratePatches( + t, + metaPatchGeneratorFunc(mgr), + mgr.GetClient(), + clusterconfig.MetaVariableName, + mirrors.GlobalMirrorVariableName, + ) +} diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go new file mode 100644 index 000000000..52cd75776 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go @@ -0,0 +1,122 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package prismcentralendpoint + +import ( + "context" + + "github.com/nutanix-cloud-native/prism-go-client/environment/credentials" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + capxv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/github.com/nutanix-cloud-native/cluster-api-provider-nutanix/api/v1beta1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches/selectors" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +const ( + // VariableName is the external patch variable name. + VariableName = "prismCentralEndpoint" +) + +type nutanixPrismCentralEndpoint struct { + variableName string + variableFieldPath []string +} + +func NewPatch() *nutanixPrismCentralEndpoint { + return newNutanixPrismCentralEndpoint( + clusterconfig.MetaVariableName, + v1alpha1.NutanixVariableName, + VariableName, + ) +} + +func newNutanixPrismCentralEndpoint( + variableName string, + variableFieldPath ...string, +) *nutanixPrismCentralEndpoint { + return &nutanixPrismCentralEndpoint{ + variableName: variableName, + variableFieldPath: variableFieldPath, + } +} + +func (h *nutanixPrismCentralEndpoint) Mutate( + ctx context.Context, + obj *unstructured.Unstructured, + vars map[string]apiextensionsv1.JSON, + holderRef runtimehooksv1.HolderReference, + clusterKey client.ObjectKey, +) error { + log := ctrl.LoggerFrom(ctx).WithValues( + "holderRef", holderRef, + ) + + prismCentralEndpointVar, found, err := variables.Get[v1alpha1.NutanixPrismCentralEndpointSpec]( + vars, + h.variableName, + h.variableFieldPath..., + ) + if err != nil { + return err + } + if !found { + log.V(5).Info("Nutanix PrismCentralEndpoint variable not defined") + return nil + } + + log = log.WithValues( + "variableName", + h.variableName, + "variableFieldPath", + h.variableFieldPath, + "variableValue", + prismCentralEndpointVar, + ) + + return patches.MutateIfApplicable( + obj, + vars, + &holderRef, + selectors.InfrastructureCluster(capxv1.GroupVersion.Version, "NutanixClusterTemplate"), + log, + func(obj *capxv1.NutanixClusterTemplate) error { + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", client.ObjectKeyFromObject(obj), + ).Info("setting prismCentralEndpoint in NutanixCluster spec") + + prismCentral := &credentials.NutanixPrismEndpoint{ + Address: prismCentralEndpointVar.Host, + Port: prismCentralEndpointVar.Port, + Insecure: prismCentralEndpointVar.Insecure, + CredentialRef: &credentials.NutanixCredentialReference{ + Kind: credentials.SecretKind, + Name: prismCentralEndpointVar.Credentials.Name, + // Assume the secret is in the same namespace as Cluster + Namespace: clusterKey.Namespace, + }, + } + if prismCentralEndpointVar.AdditionalTrustBundle != nil { + prismCentral.AdditionalTrustBundle = &credentials.NutanixTrustBundleReference{ + Kind: credentials.NutanixTrustBundleKindConfigMap, + Name: prismCentralEndpointVar.AdditionalTrustBundle.Name, + // Assume the ConfigMap is in the same namespace as Cluster + Namespace: clusterKey.Namespace, + } + } + + obj.Spec.Template.Spec.PrismCentral = prismCentral + + return nil + }, + ) +} diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go new file mode 100644 index 000000000..03aa9ab2d --- /dev/null +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go @@ -0,0 +1,71 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package tests + +import ( + "testing" + + "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" +) + +func TestGeneratePatches( + t *testing.T, + generatorFunc func() mutation.GeneratePatches, + variableName string, + variablePath ...string, +) { + t.Helper() + capitest.ValidateGeneratePatches( + t, + generatorFunc, + capitest.PatchTestDef{ + Name: "unset variable", + }, + capitest.PatchTestDef{ + Name: "all fields set", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + v1alpha1.NutanixPrismCentralEndpointSpec{ + Host: "prism-central.nutanix.com", + Port: 9441, + Insecure: false, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + AdditionalTrustBundle: ptr.To(corev1.LocalObjectReference{ + Name: "bundle", + }), + }, + variablePath..., + ), + }, + RequestItem: request.NewNutanixClusterTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "replace", + Path: "/spec/template/spec/prismCentral", + ValueMatcher: gomega.SatisfyAll( + gomega.HaveKeyWithValue( + "address", + gomega.BeEquivalentTo("prism-central.nutanix.com"), + ), + gomega.HaveKeyWithValue("port", gomega.BeEquivalentTo(9441)), + gomega.HaveKeyWithValue("insecure", false), + gomega.HaveKey("credentialRef"), + gomega.HaveKey("additionalTrustBundle"), + ), + }, + }, + }, + ) +} diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/variables_test.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/variables_test.go new file mode 100644 index 000000000..318189001 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/variables_test.go @@ -0,0 +1,85 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package prismcentralendpoint + +import ( + "testing" + + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" +) + +func TestVariableValidation(t *testing.T) { + capitest.ValidateDiscoverVariables( + t, + clusterconfig.MetaVariableName, + ptr.To(v1alpha1.ClusterConfigSpec{Nutanix: &v1alpha1.NutanixSpec{}}.VariableSchema()), + true, + nutanixclusterconfig.NewVariable, + capitest.VariableTestDef{ + Name: "valid PC address and port", + Vals: v1alpha1.ClusterConfigSpec{ + Nutanix: &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + Host: "prism-central.nutanix.com", + Port: v1alpha1.PrismCentralPort, + Insecure: false, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + // ControlPlaneEndpoint is a required field and must always be set + ControlPlaneEndpoint: clusterv1.APIEndpoint{ + Host: "10.20.100.10", + Port: 6443, + }, + }, + }, + }, + capitest.VariableTestDef{ + Name: "empty PC address", + Vals: v1alpha1.ClusterConfigSpec{ + Nutanix: &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + Port: v1alpha1.PrismCentralPort, + Insecure: false, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + // ControlPlaneEndpoint is a required field and must always be set + ControlPlaneEndpoint: clusterv1.APIEndpoint{ + Host: "10.20.100.10", + Port: 6443, + }, + }, + }, + ExpectError: true, + }, + capitest.VariableTestDef{ + Name: "nil PC credentials", + Vals: v1alpha1.ClusterConfigSpec{ + Nutanix: &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + Host: "prism-central.nutanix.com", + Port: v1alpha1.PrismCentralPort, + Insecure: false, + }, + // ControlPlaneEndpoint is a required field and must always be set + ControlPlaneEndpoint: clusterv1.APIEndpoint{ + Host: "10.20.100.10", + Port: 6443, + }, + }, + }, + ExpectError: true, + }, + ) +} diff --git a/pkg/handlers/nutanix/mutation/suite_test.go b/pkg/handlers/nutanix/mutation/suite_test.go new file mode 100644 index 000000000..5188c91c7 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/suite_test.go @@ -0,0 +1,48 @@ +// Copyright 2024 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package mutation + +import ( + "context" + "fmt" + "testing" + + ctrl "sigs.k8s.io/controller-runtime" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/test/helpers" +) + +var ( + testEnv *helpers.TestEnvironment + ctx = ctrl.SetupSignalHandler() +) + +func TestMain(m *testing.M) { + setupCtx, cancel := context.WithCancel(ctx) + setup(setupCtx) + defer teardown(cancel) + m.Run() +} + +func setup(ctx context.Context) { + testEnvConfig := helpers.NewTestEnvironmentConfiguration() + var err error + testEnv, err = testEnvConfig.Build() + if err != nil { + panic(err) + } + go func() { + fmt.Println("Starting the manager") + if err := testEnv.StartManager(ctx); err != nil { + panic(fmt.Sprintf("Failed to start the envtest manager: %v", err)) + } + }() +} + +func teardown(cancel context.CancelFunc) { + cancel() + if err := testEnv.Stop(); err != nil { + panic(fmt.Sprintf("Failed to stop envtest: %v", err)) + } +} diff --git a/pkg/handlers/nutanix/workerconfig/variables.go b/pkg/handlers/nutanix/workerconfig/variables.go new file mode 100644 index 000000000..719be0404 --- /dev/null +++ b/pkg/handlers/nutanix/workerconfig/variables.go @@ -0,0 +1,52 @@ +// Copyright 2024 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package workerconfig + +import ( + "context" + + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + commonhandlers "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" +) + +var ( + _ commonhandlers.Named = &nutanixWorkerConfigVariableHandler{} + _ mutation.DiscoverVariables = &nutanixWorkerConfigVariableHandler{} +) + +const ( + // HandlerNameVariable is the name of the variable handler. + HandlerNameVariable = "NutanixWorkerConfigVars" + + // NutanixVariableName is the Nutanix config patch variable name. + NutanixVariableName = "nutanix" +) + +func NewVariable() *nutanixWorkerConfigVariableHandler { + return &nutanixWorkerConfigVariableHandler{} +} + +type nutanixWorkerConfigVariableHandler struct{} + +func (h *nutanixWorkerConfigVariableHandler) Name() string { + return HandlerNameVariable +} + +func (h *nutanixWorkerConfigVariableHandler) DiscoverVariables( + ctx context.Context, + _ *runtimehooksv1.DiscoverVariablesRequest, + resp *runtimehooksv1.DiscoverVariablesResponse, +) { + resp.Variables = append(resp.Variables, clusterv1.ClusterClassVariable{ + Name: workerconfig.MetaVariableName, + Required: false, + Schema: v1alpha1.NodeConfigSpec{Nutanix: &v1alpha1.NutanixNodeSpec{}}.VariableSchema(), + }) + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) +} diff --git a/pkg/handlers/nutanix/workerconfig/variables_test.go b/pkg/handlers/nutanix/workerconfig/variables_test.go new file mode 100644 index 000000000..aad787ce8 --- /dev/null +++ b/pkg/handlers/nutanix/workerconfig/variables_test.go @@ -0,0 +1,24 @@ +// Copyright 2024 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package workerconfig + +import ( + "testing" + + "k8s.io/utils/ptr" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" +) + +func TestVariableValidation(t *testing.T) { + capitest.ValidateDiscoverVariables( + t, + workerconfig.MetaVariableName, + ptr.To(v1alpha1.NodeConfigSpec{Nutanix: &v1alpha1.NutanixNodeSpec{}}.VariableSchema()), + false, + NewVariable, + ) +} From d4768a4655aed0e536d33d847c2bb6cf1465af1e Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Thu, 4 Apr 2024 11:36:23 -0700 Subject: [PATCH 66/87] refactor: CCM code to support both CRS and CAAPH provider (#25) --- .../generic/lifecycle/ccm/aws/handler.go | 21 +++++++++++------ pkg/handlers/generic/lifecycle/ccm/handler.go | 23 ++++--------------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/ccm/aws/handler.go b/pkg/handlers/generic/lifecycle/ccm/aws/handler.go index 2e0e9225e..c9f34ebfc 100644 --- a/pkg/handlers/generic/lifecycle/ccm/aws/handler.go +++ b/pkg/handlers/generic/lifecycle/ccm/aws/handler.go @@ -16,6 +16,7 @@ import ( ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) @@ -52,10 +53,10 @@ func New( } } -func (a *AWSCCM) EnsureCCMConfigMapForCluster( +func (a *AWSCCM) Apply( ctx context.Context, cluster *clusterv1.Cluster, -) (*corev1.ConfigMap, error) { +) error { log := ctrl.LoggerFrom(ctx).WithValues( "cluster", cluster.Name, @@ -63,7 +64,7 @@ func (a *AWSCCM) EnsureCCMConfigMapForCluster( log.Info("Creating AWS CCM ConfigMap for Cluster") version, err := semver.ParseTolerant(cluster.Spec.Topology.Version) if err != nil { - return nil, fmt.Errorf("failed to parse version from cluster %w", err) + return fmt.Errorf("failed to parse version from cluster %w", err) } minorVersion := fmt.Sprintf("%d.%d", version.Major, version.Minor) configMapForMinorVersion := a.config.kubernetesMinorVersionToCCMConfigMapNames[minorVersion] @@ -79,7 +80,7 @@ func (a *AWSCCM) EnsureCCMConfigMapForCluster( err = a.client.Get(ctx, objName, ccmConfigMapForMinorVersion) if err != nil { log.Error(err, "failed to fetch CCM template for cluster") - return nil, fmt.Errorf( + return fmt.Errorf( "failed to retrieve default AWS CCM manifests ConfigMap %q: %w", objName, err, @@ -87,14 +88,20 @@ func (a *AWSCCM) EnsureCCMConfigMapForCluster( } ccmConfigMap := generateCCMConfigMapForCluster(ccmConfigMapForMinorVersion, cluster) - if err := client.ServerSideApply(ctx, a.client, ccmConfigMap); err != nil { + if err = client.ServerSideApply(ctx, a.client, ccmConfigMap); err != nil { log.Error(err, "failed to apply CCM configmap for cluster") - return nil, fmt.Errorf( + return fmt.Errorf( "failed to apply AWS CCM manifests ConfigMap: %w", err, ) } - return ccmConfigMap, nil + + err = lifecycleutils.EnsureCRSForClusterFromObjects(ctx, ccmConfigMap.Name, a.client, cluster, ccmConfigMap) + if err != nil { + return fmt.Errorf("failed to generate CCM CRS for cluster: %w", err) + } + + return nil } func generateCCMConfigMapForCluster( diff --git a/pkg/handlers/generic/lifecycle/ccm/handler.go b/pkg/handlers/generic/lifecycle/ccm/handler.go index 04dd32f85..08d8372f0 100644 --- a/pkg/handlers/generic/lifecycle/ccm/handler.go +++ b/pkg/handlers/generic/lifecycle/ccm/handler.go @@ -8,7 +8,6 @@ import ( "fmt" "strings" - corev1 "k8s.io/api/core/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" ctrl "sigs.k8s.io/controller-runtime" @@ -19,7 +18,6 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" - lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" ) const ( @@ -27,7 +25,7 @@ const ( ) type CCMProvider interface { - EnsureCCMConfigMapForCluster(context.Context, *clusterv1.Cluster) (*corev1.ConfigMap, error) + Apply(context.Context, *clusterv1.Cluster) error } type CCMHandler struct { @@ -100,31 +98,18 @@ func (c *CCMHandler) AfterControlPlaneInitialized( log.Info(fmt.Sprintf("No CCM handler provided for infra kind %s", infraKind)) return } - cm, err := handler.EnsureCCMConfigMapForCluster(ctx, &req.Cluster) + err = handler.Apply(ctx, &req.Cluster) if err != nil { log.Error( err, - "failed to generate CCM configmap", + "failed to deploy CCM for cluster", ) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage( - fmt.Sprintf("failed to generate CCM configmap: %v", + fmt.Sprintf("failed to deploy CCM for cluster: %v", err, ), ) return } - err = lifecycleutils.EnsureCRSForClusterFromObjects(ctx, cm.Name, c.client, &req.Cluster, cm) - if err != nil { - log.Error( - err, - "failed to generate CCM CRS for cluster", - ) - resp.SetStatus(runtimehooksv1.ResponseStatusFailure) - resp.SetMessage( - fmt.Sprintf("failed to generate CCM CRS: %v", - err, - ), - ) - } } From 583014ff7cec960fac4af05b9a2cfa3db6beda02 Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Thu, 4 Apr 2024 12:49:23 -0700 Subject: [PATCH 67/87] refactor: use a string type for Nutanix's AdditionalTrustBundle (#28) * refactor: use a string type for Nutanix's AdditionalTrustBundle Use a string instead of a ConfigMap reference to make it easier for both the handlers to use, and the clients to set in the API. * fix: force insecure: false with additionalTrustBundle --- api/v1alpha1/nutanix_clusterconfig_types.go | 16 ++----- api/v1alpha1/zz_generated.deepcopy.go | 2 +- .../nutanix/prism-central-endpoint.md | 46 ++++++++++++++++++- .../nutanix-cluster-calico-crs.yaml | 9 ---- .../nutanix-cluster-calico-helm-addon.yaml | 9 ---- .../nutanix-cluster-cilium-crs.yaml | 9 ---- .../nutanix-cluster-cilium-helm-addon.yaml | 9 ---- .../nutanix/cluster/kustomization.yaml.tmpl | 6 +++ .../remove-additional-trust-bundle/cm.yaml | 8 ++++ .../mutation/prismcentralendpoint/inject.go | 25 ++++++++-- .../tests/generate_patches.go | 46 +++++++++++++++++-- 11 files changed, 126 insertions(+), 59 deletions(-) create mode 100644 hack/examples/patches/nutanix/remove-additional-trust-bundle/cm.yaml diff --git a/api/v1alpha1/nutanix_clusterconfig_types.go b/api/v1alpha1/nutanix_clusterconfig_types.go index 783416e8d..6e39a6f88 100644 --- a/api/v1alpha1/nutanix_clusterconfig_types.go +++ b/api/v1alpha1/nutanix_clusterconfig_types.go @@ -49,11 +49,11 @@ type NutanixPrismCentralEndpointSpec struct { // +optional Insecure bool `json:"insecure"` - // A reference to the ConfigMap containing a PEM encoded x509 cert for the RootCA that was used to create + // A base64 PEM encoded x509 cert for the RootCA that was used to create // the certificate for a Prism Central that uses certificates that were issued by a non-publicly trusted RootCA. // The trust bundle is added to the cert pool used to authenticate the TLS connection to the Prism Central. // +optional - AdditionalTrustBundle *corev1.LocalObjectReference `json:"additionalTrustBundle,omitempty"` + AdditionalTrustBundle *string `json:"additionalTrustBundle,omitempty"` // A reference to the Secret for credential information for the target Prism Central instance Credentials corev1.LocalObjectReference `json:"credentials"` @@ -82,19 +82,13 @@ func (NutanixPrismCentralEndpointSpec) VariableSchema() clusterv1.VariableSchema Type: "boolean", }, "additionalTrustBundle": { - Description: "A reference to the ConfigMap containing a PEM encoded x509 cert for the RootCA " + + Description: "A base64 PEM encoded x509 cert for the RootCA " + "that was used to create the certificate for a Prism Central that uses certificates " + "that were issued by a non-publicly trusted RootCA." + "The trust bundle is added to the cert pool used to authenticate the TLS connection " + "to the Prism Central.", - Type: "object", - Properties: map[string]clusterv1.JSONSchemaProps{ - "name": { - Description: "The name of the ConfigMap", - Type: "string", - }, - }, - Required: []string{"name"}, + Type: "string", + Format: "byte", }, "credentials": { Description: "A reference to the Secret for credential information" + diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 3bb80cb1d..a98f87d08 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -774,7 +774,7 @@ func (in *NutanixPrismCentralEndpointSpec) DeepCopyInto(out *NutanixPrismCentral *out = *in if in.AdditionalTrustBundle != nil { in, out := &in.AdditionalTrustBundle, &out.AdditionalTrustBundle - *out = new(v1.LocalObjectReference) + *out = new(string) **out = **in } out.Credentials = in.Credentials diff --git a/docs/content/customization/nutanix/prism-central-endpoint.md b/docs/content/customization/nutanix/prism-central-endpoint.md index 80d866eec..33d8af8fe 100644 --- a/docs/content/customization/nutanix/prism-central-endpoint.md +++ b/docs/content/customization/nutanix/prism-central-endpoint.md @@ -29,7 +29,7 @@ spec: Applying this configuration will result in the following value being set: -- control-plane NutanixClusterTemplate: +- `NutanixClusterTemplate`: ```yaml spec: @@ -43,3 +43,47 @@ spec: kind: Secret name: secret-name ``` + +### Provide an Optional Trusted CA Bundle + +If the Prism Central endpoint uses a self-signed certificate, you can provide an additional trust bundle +to be used by the Nutanix provider. +This is a base64 PEM encoded x509 cert for the RootCA that was used to create the certificate for a Prism Central + +See [Nutanix Security Guide] for more information. + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: +spec: + topology: + variables: + - name: clusterConfig + value: + nutanix: + prismCentralEndpoint: + # ... + additionalTrustBundle: "LS0...=" +``` + +Applying this configuration will result in the following value being set: + +- `NutanixClusterTemplate`: + +```yaml +spec: + template: + spec: + prismCentral: + # ... + additionalTrustBundle: + kind: String + data: |- + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- +``` + +[Nutanix Security Guide]: https://portal.nutanix.com/page/documents/details?targetId=Nutanix-Security-Guide-v6_5:mul-security-ssl-certificate-pc-t.html diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 7fa2f4766..710f1a31c 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -1,13 +1,4 @@ apiVersion: v1 -binaryData: - ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} -kind: ConfigMap -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: ${CLUSTER_NAME}-pc-trusted-ca-bundle ---- -apiVersion: v1 data: nutanix-ccm.yaml: | --- diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index 31011b79d..e49994c81 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -1,13 +1,4 @@ apiVersion: v1 -binaryData: - ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} -kind: ConfigMap -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: ${CLUSTER_NAME}-pc-trusted-ca-bundle ---- -apiVersion: v1 data: nutanix-ccm.yaml: | --- diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index 3e86dc874..f089aa951 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -1,13 +1,4 @@ apiVersion: v1 -binaryData: - ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} -kind: ConfigMap -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: ${CLUSTER_NAME}-pc-trusted-ca-bundle ---- -apiVersion: v1 data: nutanix-ccm.yaml: | --- diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 4cff901c0..209c73674 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -1,13 +1,4 @@ apiVersion: v1 -binaryData: - ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} -kind: ConfigMap -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: ${CLUSTER_NAME}-pc-trusted-ca-bundle ---- -apiVersion: v1 data: nutanix-ccm.yaml: | --- diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index 57d2a6d1a..c957ef734 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -28,3 +28,9 @@ patches: - target: kind: Cluster path: ../../../patches/nutanix/initialize-variables.yaml + +# Remove Additional Trust Bundle ConfigMap +- target: + kind: ConfigMap + name: ".*-pc-trusted-ca-bundle" + path: ../../../patches/nutanix/remove-additional-trust-bundle/cm.yaml diff --git a/hack/examples/patches/nutanix/remove-additional-trust-bundle/cm.yaml b/hack/examples/patches/nutanix/remove-additional-trust-bundle/cm.yaml new file mode 100644 index 000000000..51ad983ba --- /dev/null +++ b/hack/examples/patches/nutanix/remove-additional-trust-bundle/cm.yaml @@ -0,0 +1,8 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +$patch: delete +apiVersion: v1 +kind: ConfigMap +metadata: + name: ${CLUSTER_NAME}-pc-trusted-ca-bundle diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go index 52cd75776..808cb6fda 100644 --- a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go @@ -5,10 +5,13 @@ package prismcentralendpoint import ( "context" + "encoding/base64" + "fmt" "github.com/nutanix-cloud-native/prism-go-client/environment/credentials" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/utils/ptr" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -105,15 +108,27 @@ func (h *nutanixPrismCentralEndpoint) Mutate( Namespace: clusterKey.Namespace, }, } - if prismCentralEndpointVar.AdditionalTrustBundle != nil { + additionalTrustBundle := ptr.Deref(prismCentralEndpointVar.AdditionalTrustBundle, "") + if additionalTrustBundle != "" { + var decoded []byte + decoded, err = base64.StdEncoding.DecodeString(additionalTrustBundle) + if err != nil { + log.Error(err, "error decoding additional trust bundle") + return fmt.Errorf("error decoding additional trust bundle: %w", err) + } prismCentral.AdditionalTrustBundle = &credentials.NutanixTrustBundleReference{ - Kind: credentials.NutanixTrustBundleKindConfigMap, - Name: prismCentralEndpointVar.AdditionalTrustBundle.Name, - // Assume the ConfigMap is in the same namespace as Cluster - Namespace: clusterKey.Namespace, + Kind: credentials.NutanixTrustBundleKindString, + Data: string(decoded), } } + // Always force insecure to false if additional trust bundle is provided. + // This ensures that the trust bundle is actually used to validate the connection. + if additionalTrustBundle != "" && prismCentral.Insecure { + log.Info("AdditionalTrustBundle is provided, setting insecure to false") + prismCentral.Insecure = false + } + obj.Spec.Template.Spec.PrismCentral = prismCentral return nil diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go index 03aa9ab2d..4ae6c6243 100644 --- a/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go @@ -17,6 +17,9 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" ) +//nolint:lll // just a long string +const testCertBundle = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVjekNDQTF1Z0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRUUZBRC4uQWtHQTFVRUJoTUNSMEl4CkV6QVJCZ05WQkFnVENsTnZiV1V0VTNSaGRHVXhGREFTQmdOVkJBb1RDMC4uMEVnVEhSa01UY3dOUVlEClZRUUxFeTVEYkdGemN5QXhJRkIxWW14cFl5QlFjbWx0WVhKNUlFTmxjbi4uWFJwYjI0Z1FYVjBhRzl5CmFYUjVNUlF3RWdZRFZRUURFd3RDWlhOMElFTkJJRXgwWkRBZUZ3MHdNRC4uVFV3TVRaYUZ3MHdNVEF5Ck1EUXhPVFV3TVRaYU1JR0hNUXN3Q1FZRFZRUUdFd0pIUWpFVE1CRUdBMS4uMjl0WlMxVGRHRjBaVEVVCk1CSUdBMVVFQ2hNTFFtVnpkQ0JEUVNCTWRHUXhOekExQmdOVkJBc1RMay4uREVnVUhWaWJHbGpJRkJ5CmFXMWhjbmtnUTJWeWRHbG1hV05oZEdsdmJpQkJkWFJvYjNKcGRIa3hGRC4uQU1UQzBKbGMzUWdRMEVnClRIUmtNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZy4uVHoybXI3U1ppQU1mUXl1CnZCak05T2lKalJhelhCWjFCalA1Q0UvV20vUnI1MDBQUksrTGg5eDVlSi4uL0FOQkUwc1RLMFpzREdNCmFrMm0xZzdvcnVJM2RZM1ZIcUl4RlR6MFRhMWQrTkFqd25MZTRuT2I3Ly4uazA1U2hoQnJKR0JLS3hiCjhuMTA0by81cDhIQXNaUGR6YkZNSXlOakp6Qk0ybzV5NUExM3dpTGl0RS4uZnlZa1F6YXhDdzBBd3psCmtWSGlJeUN1YUY0d2o1NzFwU3prdjZzdis0SURNYlQvWHBDbzhMNndUYS4uc2grZXRMRDZGdFRqWWJiCnJ2WjhSUU0xdGxLZG9NSGcycXhyYUFWKytITkJZbU5XczBkdUVkalViSi4uWEk5VHRuUzRvMUNrajdQCk9mbGppUUlEQVFBQm80SG5NSUhrTUIwR0ExVWREZ1FXQkJROHVyTUNSTC4uNUFrSXA5TkpISnc1VENCCnRBWURWUjBqQklHc01JR3BnQlE4dXJNQ1JMWVlNSFVLVTVBa0lwOU5KSC4uYVNCaWpDQmh6RUxNQWtHCkExVUVCaE1DUjBJeEV6QVJCZ05WQkFnVENsTnZiV1V0VTNSaGRHVXhGRC4uQW9UQzBKbGMzUWdRMEVnClRIUmtNVGN3TlFZRFZRUUxFeTVEYkdGemN5QXhJRkIxWW14cFl5QlFjbS4uRU5sY25ScFptbGpZWFJwCmIyNGdRWFYwYUc5eWFYUjVNUlF3RWdZRFZRUURFd3RDWlhOMElFTkJJRS4uREFNQmdOVkhSTUVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQkFVQUE0SUJBUUMxdVlCY3NTbmN3QS4uRENzUWVyNzcyQzJ1Y3BYCnhRVUUvQzBwV1dtNmdEa3dkNUQwRFNNREpScVYvd2VvWjR3QzZCNzNmNS4uYkxoR1lIYVhKZVNENktyClhjb093TGRTYUdtSllzbExLWkIzWklERXAwd1lUR2hndGViNkpGaVR0bi4uc2YyeGRyWWZQQ2lJQjdnCkJNQVY3R3pkYzRWc3BTNmxqckFoYmlpYXdkQmlRbFFtc0JlRno5SmtGNC4uYjNsOEJvR04rcU1hNTZZCkl0OHVuYTJnWTRsMk8vL29uODhyNUlXSmxtMUwwb0E4ZTRmUjJ5ckJIWC4uYWRzR2VGS2t5TnJ3R2kvCjd2UU1mWGRHc1JyWE5HUkduWCt2V0RaMy96V0kwam9EdENrTm5xRXBWbi4uSG9YCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=" + func TestGeneratePatches( t *testing.T, generatorFunc func() mutation.GeneratePatches, @@ -31,20 +34,52 @@ func TestGeneratePatches( Name: "unset variable", }, capitest.PatchTestDef{ - Name: "all fields set", + Name: "all required fields set", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + variableName, + v1alpha1.NutanixPrismCentralEndpointSpec{ + Host: "prism-central.nutanix.com", + Port: 9441, + Insecure: true, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + variablePath..., + ), + }, + RequestItem: request.NewNutanixClusterTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "replace", + Path: "/spec/template/spec/prismCentral", + ValueMatcher: gomega.SatisfyAll( + gomega.HaveKeyWithValue( + "address", + gomega.BeEquivalentTo("prism-central.nutanix.com"), + ), + gomega.HaveKeyWithValue("port", gomega.BeEquivalentTo(9441)), + gomega.HaveKeyWithValue("insecure", true), + gomega.HaveKey("credentialRef"), + gomega.Not(gomega.HaveKey("additionalTrustBundle")), + ), + }, + }, + }, + capitest.PatchTestDef{ + Name: "additional trust bundle is set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( variableName, v1alpha1.NutanixPrismCentralEndpointSpec{ Host: "prism-central.nutanix.com", Port: 9441, - Insecure: false, + Insecure: true, Credentials: corev1.LocalObjectReference{ Name: "credentials", }, - AdditionalTrustBundle: ptr.To(corev1.LocalObjectReference{ - Name: "bundle", - }), + AdditionalTrustBundle: ptr.To(testCertBundle), }, variablePath..., ), @@ -60,6 +95,7 @@ func TestGeneratePatches( gomega.BeEquivalentTo("prism-central.nutanix.com"), ), gomega.HaveKeyWithValue("port", gomega.BeEquivalentTo(9441)), + // Assert the insecure field was set to false as the additional trust bundle is set gomega.HaveKeyWithValue("insecure", false), gomega.HaveKey("credentialRef"), gomega.HaveKey("additionalTrustBundle"), From c4bed7af1dec53b7e9cb84edfd7cad60e1444cef Mon Sep 17 00:00:00 2001 From: Faiq Date: Thu, 4 Apr 2024 17:19:04 -0400 Subject: [PATCH 68/87] build: update devbox.lock (#29) --- devbox.lock | 1092 --------------------------------------------------- 1 file changed, 1092 deletions(-) diff --git a/devbox.lock b/devbox.lock index 73b569425..59ee0c2bb 100644 --- a/devbox.lock +++ b/devbox.lock @@ -8,43 +8,15 @@ "version": "1.6.27", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nnhjp60w14pdy1hjgxn9dfsg4nbfs93v-actionlint-1.6.27", - "default": true - } - ], "store_path": "/nix/store/nnhjp60w14pdy1hjgxn9dfsg4nbfs93v-actionlint-1.6.27" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/p8rc44x83sld3wk1m4y27za9n1mjyk48-actionlint-1.6.27", - "default": true - } - ], "store_path": "/nix/store/p8rc44x83sld3wk1m4y27za9n1mjyk48-actionlint-1.6.27" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7v1lh7c3pwlax5fy7pw233czn4hs89hl-actionlint-1.6.27", - "default": true - } - ], "store_path": "/nix/store/7v1lh7c3pwlax5fy7pw233czn4hs89hl-actionlint-1.6.27" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/56xxvs3yijdmhhxbfvps38nz95xdxgyl-actionlint-1.6.27", - "default": true - } - ], "store_path": "/nix/store/56xxvs3yijdmhhxbfvps38nz95xdxgyl-actionlint-1.6.27" } } @@ -56,43 +28,15 @@ "version": "3.10.1", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/5lygcps2ly736k0dvk2w4mx6yy8dzz6s-chart-testing-3.10.1", - "default": true - } - ], "store_path": "/nix/store/5lygcps2ly736k0dvk2w4mx6yy8dzz6s-chart-testing-3.10.1" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/103km469ldwrzs525m57bj409vxjlniw-chart-testing-3.10.1", - "default": true - } - ], "store_path": "/nix/store/103km469ldwrzs525m57bj409vxjlniw-chart-testing-3.10.1" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/c4qgh783pvhzqpv7skimzfs75pklbz4f-chart-testing-3.10.1", - "default": true - } - ], "store_path": "/nix/store/c4qgh783pvhzqpv7skimzfs75pklbz4f-chart-testing-3.10.1" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/wzscgl31rzxws05y7vxkl0f65fsiydmm-chart-testing-3.10.1", - "default": true - } - ], "store_path": "/nix/store/wzscgl31rzxws05y7vxkl0f65fsiydmm-chart-testing-3.10.1" } } @@ -104,43 +48,15 @@ "version": "1.6.3", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/6hsi8bj8ddbrv29jff467q1rqcfgs964-clusterctl-1.6.3", - "default": true - } - ], "store_path": "/nix/store/6hsi8bj8ddbrv29jff467q1rqcfgs964-clusterctl-1.6.3" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/jysji089cqrygcwl2ryvbb0sa3cjj8vv-clusterctl-1.6.3", - "default": true - } - ], "store_path": "/nix/store/jysji089cqrygcwl2ryvbb0sa3cjj8vv-clusterctl-1.6.3" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/gbch3dp061am97j79b56pp07121j781k-clusterctl-1.6.3", - "default": true - } - ], "store_path": "/nix/store/gbch3dp061am97j79b56pp07121j781k-clusterctl-1.6.3" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1xy66gcyxaqjhb5h15slyxzw64d920c6-clusterctl-1.6.3", - "default": true - } - ], "store_path": "/nix/store/1xy66gcyxaqjhb5h15slyxzw64d920c6-clusterctl-1.6.3" } } @@ -152,67 +68,15 @@ "version": "9.4", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/vinxz6lkrilb72dkzr3ny02nnvql6z50-coreutils-9.4", - "default": true - }, - { - "name": "info", - "path": "/nix/store/mgvngj0x370glcix9wfaripy3bx5j3s0-coreutils-9.4-info" - } - ], "store_path": "/nix/store/vinxz6lkrilb72dkzr3ny02nnvql6z50-coreutils-9.4" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/77fyfwmz29cz9j5x6yw2wrlm4rvasldv-coreutils-9.4", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/fkfnrbg62vbsdagml1c9vld3wpk3079n-coreutils-9.4-debug" - }, - { - "name": "info", - "path": "/nix/store/x14ppijm82bac50bgf2varjvdm0mr28f-coreutils-9.4-info" - } - ], "store_path": "/nix/store/77fyfwmz29cz9j5x6yw2wrlm4rvasldv-coreutils-9.4" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/spm5vvna0wwkknavwfgxdsbq48r5374a-coreutils-9.4", - "default": true - }, - { - "name": "info", - "path": "/nix/store/mpgbpc0iyn2wy1668b1f2lzw2b967zsh-coreutils-9.4-info" - } - ], "store_path": "/nix/store/spm5vvna0wwkknavwfgxdsbq48r5374a-coreutils-9.4" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/mb488rr560vq1xnl10hinnyfflcrd51n-coreutils-9.4", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/cgw6a9mc6v28dfbxjgprwv9dam57djsd-coreutils-9.4-debug" - }, - { - "name": "info", - "path": "/nix/store/m2zz2awv8a8118axl7qliq6dwpwb7q0v-coreutils-9.4-info" - } - ], "store_path": "/nix/store/mb488rr560vq1xnl10hinnyfflcrd51n-coreutils-9.4" } } @@ -224,43 +88,15 @@ "version": "1.4.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7lwyjdf9bhyihfdr9gm7ajhjbliphv34-envsubst-1.4.2", - "default": true - } - ], "store_path": "/nix/store/7lwyjdf9bhyihfdr9gm7ajhjbliphv34-envsubst-1.4.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/qsly6czilaakclr57zlaxl0y574f6lj3-envsubst-1.4.2", - "default": true - } - ], "store_path": "/nix/store/qsly6czilaakclr57zlaxl0y574f6lj3-envsubst-1.4.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/i5kjf63ns7b1scw1k3jvwlj6m5lpz3mi-envsubst-1.4.2", - "default": true - } - ], "store_path": "/nix/store/i5kjf63ns7b1scw1k3jvwlj6m5lpz3mi-envsubst-1.4.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/vgglbbxi4wa85g3fzb71jxbddkklhpvg-envsubst-1.4.2", - "default": true - } - ], "store_path": "/nix/store/vgglbbxi4wa85g3fzb71jxbddkklhpvg-envsubst-1.4.2" } } @@ -272,75 +108,15 @@ "version": "4.9.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/46ilsgv2hj073d3ghqv209bl95djki8q-findutils-4.9.0", - "default": true - }, - { - "name": "info", - "path": "/nix/store/a5bp80lnmw0cbmfqjxhkz1p5h825ii3p-findutils-4.9.0-info" - }, - { - "name": "locate", - "path": "/nix/store/af9i1zykrns1ha3rhzkpdvyxa1kkhg1z-findutils-4.9.0-locate" - } - ], "store_path": "/nix/store/46ilsgv2hj073d3ghqv209bl95djki8q-findutils-4.9.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ry6g1kym7g3i8813msq7b0gzqbdj1rfk-findutils-4.9.0", - "default": true - }, - { - "name": "info", - "path": "/nix/store/fi8k5nm1279ag30y5ghgzhadcqp00mrn-findutils-4.9.0-info" - }, - { - "name": "locate", - "path": "/nix/store/m17gn49zqfg4z43816p77fzpxlqrlk8d-findutils-4.9.0-locate" - } - ], "store_path": "/nix/store/ry6g1kym7g3i8813msq7b0gzqbdj1rfk-findutils-4.9.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/iqka9ifkjwwz0cf5dz8w7fl9p41p142p-findutils-4.9.0", - "default": true - }, - { - "name": "info", - "path": "/nix/store/r2p9iavm6ypdijwdm96c2jfhl8krs0xx-findutils-4.9.0-info" - }, - { - "name": "locate", - "path": "/nix/store/qwsfnln108rys79d8fnfa3qrajz03h39-findutils-4.9.0-locate" - } - ], "store_path": "/nix/store/iqka9ifkjwwz0cf5dz8w7fl9p41p142p-findutils-4.9.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/rr5pqqck5f6fjkv7agwjyhaljvh27ncn-findutils-4.9.0", - "default": true - }, - { - "name": "info", - "path": "/nix/store/9c6pyndcn1lr2wm210zylp3wv37b04g0-findutils-4.9.0-info" - }, - { - "name": "locate", - "path": "/nix/store/jsyyg8i8rbxj1gaki1szcl66cj93z8xk-findutils-4.9.0-locate" - } - ], "store_path": "/nix/store/rr5pqqck5f6fjkv7agwjyhaljvh27ncn-findutils-4.9.0" } } @@ -352,43 +128,15 @@ "version": "2.45.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ijbvh0hln26a39q5m7iavyvyj83adja9-gh-2.45.0", - "default": true - } - ], "store_path": "/nix/store/ijbvh0hln26a39q5m7iavyvyj83adja9-gh-2.45.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/33v7d9a7x91lzvyr8d76mzb5022glay4-gh-2.45.0", - "default": true - } - ], "store_path": "/nix/store/33v7d9a7x91lzvyr8d76mzb5022glay4-gh-2.45.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/snd8ridf0apgbk7ngyf4waqdk72mr9pm-gh-2.45.0", - "default": true - } - ], "store_path": "/nix/store/snd8ridf0apgbk7ngyf4waqdk72mr9pm-gh-2.45.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1krwa1i8qyxapbp6n02r4niwiqhhnaln-gh-2.45.0", - "default": true - } - ], "store_path": "/nix/store/1krwa1i8qyxapbp6n02r4niwiqhhnaln-gh-2.45.0" } } @@ -400,43 +148,15 @@ "version": "2.17.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/lxq0cx9km60yjwf63pmf1j3rbfr82q7x-ginkgo-2.17.0", - "default": true - } - ], "store_path": "/nix/store/lxq0cx9km60yjwf63pmf1j3rbfr82q7x-ginkgo-2.17.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1bf8v0b9k0pmmrs06h6zw13cxl0pmd9q-ginkgo-2.17.0", - "default": true - } - ], "store_path": "/nix/store/1bf8v0b9k0pmmrs06h6zw13cxl0pmd9q-ginkgo-2.17.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/7qyd3jfipsx9gj0wbkms245hkidlfb0f-ginkgo-2.17.0", - "default": true - } - ], "store_path": "/nix/store/7qyd3jfipsx9gj0wbkms245hkidlfb0f-ginkgo-2.17.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/bavqnxdhcvlpmkjvd0hcnhj3dlrrysmc-ginkgo-2.17.0", - "default": true - } - ], "store_path": "/nix/store/bavqnxdhcvlpmkjvd0hcnhj3dlrrysmc-ginkgo-2.17.0" } } @@ -448,67 +168,15 @@ "version": "2.43.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/4zyn11089z9i567c84d3628bq2k56q8r-git-2.43.2", - "default": true - }, - { - "name": "doc", - "path": "/nix/store/0vaafk5p4hh797n28w4nx1c5ykjq1kxc-git-2.43.2-doc" - } - ], "store_path": "/nix/store/4zyn11089z9i567c84d3628bq2k56q8r-git-2.43.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/6dmwwsmj6bp9ss0bsw5j042zjzx5p2kw-git-2.43.2", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/yx6wsnivlrbwajqbf933pj733ypj4bbd-git-2.43.2-debug" - }, - { - "name": "doc", - "path": "/nix/store/bxyy779y05dkvbzvpic3knycd3iyx8m4-git-2.43.2-doc" - } - ], "store_path": "/nix/store/6dmwwsmj6bp9ss0bsw5j042zjzx5p2kw-git-2.43.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ffnl9nk43qffalwvmb0bnhz3j2glkk1h-git-2.43.2", - "default": true - }, - { - "name": "doc", - "path": "/nix/store/8vpr8jl73k5m2cqbz4d16a6i3nw7x82s-git-2.43.2-doc" - } - ], "store_path": "/nix/store/ffnl9nk43qffalwvmb0bnhz3j2glkk1h-git-2.43.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/fmx804pc0bs1966xq5bb67kark2mww9r-git-2.43.2", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/sga5blm5fi6ad5hj4kg5m9m4gxgqmciv-git-2.43.2-debug" - }, - { - "name": "doc", - "path": "/nix/store/z9784jl4061n5bnbwjz2qd93c50r98m9-git-2.43.2-doc" - } - ], "store_path": "/nix/store/fmx804pc0bs1966xq5bb67kark2mww9r-git-2.43.2" } } @@ -520,87 +188,15 @@ "version": "4.4.1", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/b4jbbx01f3n4r97g49jnxw3clf4p1szv-gnumake-4.4.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/maj11ssnlx9lqd3vfmpfh45l6p5bxvv4-gnumake-4.4.1-man", - "default": true - }, - { - "name": "info", - "path": "/nix/store/rp5gi5y0dd2hzww57x7gkya7g2qg6rrq-gnumake-4.4.1-info" - } - ], "store_path": "/nix/store/b4jbbx01f3n4r97g49jnxw3clf4p1szv-gnumake-4.4.1" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/hfyyfn6h7cw2fvdc0jmpfigwi3rp7d2x-gnumake-4.4.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/z20ifgpnah4nnls4ylkij1gmrhg6bv10-gnumake-4.4.1-man", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/m8zg8w7m00hxjwxwcj1apcra1lh58j50-gnumake-4.4.1-debug" - }, - { - "name": "info", - "path": "/nix/store/sk9zc9r371pcpj5hhjck79h8a2i726qv-gnumake-4.4.1-info" - } - ], "store_path": "/nix/store/hfyyfn6h7cw2fvdc0jmpfigwi3rp7d2x-gnumake-4.4.1" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ry772inn49ra4vmns2vg67bjpqv29j0k-gnumake-4.4.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/dbd3dygcpky1s2yls12wzy8rsh0dzjbr-gnumake-4.4.1-man", - "default": true - }, - { - "name": "info", - "path": "/nix/store/4yi8y2v3h62jz3jia5zi60nrxgfbn05w-gnumake-4.4.1-info" - } - ], "store_path": "/nix/store/ry772inn49ra4vmns2vg67bjpqv29j0k-gnumake-4.4.1" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/0pkbh7939p7npr02ayama32pa389m5p7-gnumake-4.4.1", - "default": true - }, - { - "name": "man", - "path": "/nix/store/h420v4pzqavirmna1fz0r5cz3nbq65xq-gnumake-4.4.1-man", - "default": true - }, - { - "name": "debug", - "path": "/nix/store/l8523cnr1cn189yzchcq30iml87dr5a4-gnumake-4.4.1-debug" - }, - { - "name": "info", - "path": "/nix/store/bnjzmbm99sgviynsqxhz831cc9gvidnl-gnumake-4.4.1-info" - } - ], "store_path": "/nix/store/0pkbh7939p7npr02ayama32pa389m5p7-gnumake-4.4.1" } } @@ -612,59 +208,15 @@ "version": "4.9", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/zmmrhy50wsyg5k9wrmbpcnjz6swdsk58-gnused-4.9", - "default": true - }, - { - "name": "info", - "path": "/nix/store/bbq8l0cn5rsbf3nmfl4sxkynwzjwzxk4-gnused-4.9-info" - } - ], "store_path": "/nix/store/zmmrhy50wsyg5k9wrmbpcnjz6swdsk58-gnused-4.9" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/jcpl9xd17v9c8aqkdwakhw3mymmagshp-gnused-4.9", - "default": true - }, - { - "name": "info", - "path": "/nix/store/8jz40706yyf04dwbm1nl0mc4z905iq17-gnused-4.9-info" - } - ], "store_path": "/nix/store/jcpl9xd17v9c8aqkdwakhw3mymmagshp-gnused-4.9" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/wjlj4v79x8zxnx5ylfgmiqp36vm28ii6-gnused-4.9", - "default": true - }, - { - "name": "info", - "path": "/nix/store/75dy9xdcnfj9j0z7wd8jrlrgb0n96mb1-gnused-4.9-info" - } - ], "store_path": "/nix/store/wjlj4v79x8zxnx5ylfgmiqp36vm28ii6-gnused-4.9" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/q7kq0naays5251ihghw0ccsz39id7kk5-gnused-4.9", - "default": true - }, - { - "name": "info", - "path": "/nix/store/a81qmwij2v1pjwsq739l482fxkkn4s07-gnused-4.9-info" - } - ], "store_path": "/nix/store/q7kq0naays5251ihghw0ccsz39id7kk5-gnused-4.9" } } @@ -676,43 +228,15 @@ "version": "1.22.1", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/k9srp8ngvblscg68fdpcyqkydh86429k-go-1.22.1", - "default": true - } - ], "store_path": "/nix/store/k9srp8ngvblscg68fdpcyqkydh86429k-go-1.22.1" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/i604lwmgw1s8w3bdvsiz4332rx7fsb87-go-1.22.1", - "default": true - } - ], "store_path": "/nix/store/i604lwmgw1s8w3bdvsiz4332rx7fsb87-go-1.22.1" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/5dyp491ka5hx1g788dvnvadzk9kn92bp-go-1.22.1", - "default": true - } - ], "store_path": "/nix/store/5dyp491ka5hx1g788dvnvadzk9kn92bp-go-1.22.1" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/wkbckbd30nlhq4dxzg64q6y4vm1xx4fk-go-1.22.1", - "default": true - } - ], "store_path": "/nix/store/wkbckbd30nlhq4dxzg64q6y4vm1xx4fk-go-1.22.1" } } @@ -724,43 +248,15 @@ "version": "0.12.14", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/yzkh6mg18q5c2dxlrsdi750imm41div4-gojq-0.12.14", - "default": true - } - ], "store_path": "/nix/store/yzkh6mg18q5c2dxlrsdi750imm41div4-gojq-0.12.14" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/xb0b2ng2m3xdm5iah0cjbqsaqiz87qza-gojq-0.12.14", - "default": true - } - ], "store_path": "/nix/store/xb0b2ng2m3xdm5iah0cjbqsaqiz87qza-gojq-0.12.14" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1y68nsm5nx450lnvc6gr8as7231sfbhz-gojq-0.12.14", - "default": true - } - ], "store_path": "/nix/store/1y68nsm5nx450lnvc6gr8as7231sfbhz-gojq-0.12.14" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1ivsp6qjrkr3d2gzax6w8iai55qagliv-gojq-0.12.14", - "default": true - } - ], "store_path": "/nix/store/1ivsp6qjrkr3d2gzax6w8iai55qagliv-gojq-0.12.14" } } @@ -772,43 +268,15 @@ "version": "0.12.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/225jl3pgxsgivmvggjbijywn0vfc0nd1-golines-0.12.2", - "default": true - } - ], "store_path": "/nix/store/225jl3pgxsgivmvggjbijywn0vfc0nd1-golines-0.12.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nvfxf1ss0f2kq6cj1apa86yn7sxgxyb2-golines-0.12.2", - "default": true - } - ], "store_path": "/nix/store/nvfxf1ss0f2kq6cj1apa86yn7sxgxyb2-golines-0.12.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/jyyd2n5vbwl95a6jkb3xficbj54p8fj4-golines-0.12.2", - "default": true - } - ], "store_path": "/nix/store/jyyd2n5vbwl95a6jkb3xficbj54p8fj4-golines-0.12.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nach7a7wc17kb36pvfvjcbms2p99kfr5-golines-0.12.2", - "default": true - } - ], "store_path": "/nix/store/nach7a7wc17kb36pvfvjcbms2p99kfr5-golines-0.12.2" } } @@ -820,43 +288,15 @@ "version": "1.24.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/8dd7j0fgivrb62jq43pyvmmwz5q9qgas-goreleaser-1.24.0", - "default": true - } - ], "store_path": "/nix/store/8dd7j0fgivrb62jq43pyvmmwz5q9qgas-goreleaser-1.24.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/d0z2c8vwijna7cfdp28r5kj6p5f1abzs-goreleaser-1.24.0", - "default": true - } - ], "store_path": "/nix/store/d0z2c8vwijna7cfdp28r5kj6p5f1abzs-goreleaser-1.24.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/4rnps0ylkz2jaw1qdp29m0pyx62mkv93-goreleaser-1.24.0", - "default": true - } - ], "store_path": "/nix/store/4rnps0ylkz2jaw1qdp29m0pyx62mkv93-goreleaser-1.24.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ys8s2aigrqa8ylsj58wh3qvj61i0lirb-goreleaser-1.24.0", - "default": true - } - ], "store_path": "/nix/store/ys8s2aigrqa8ylsj58wh3qvj61i0lirb-goreleaser-1.24.0" } } @@ -868,43 +308,15 @@ "version": "1.10.1", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/0z0jj1xpcnbgmfymdll7qjggffv6x09f-gotestsum-1.10.1", - "default": true - } - ], "store_path": "/nix/store/0z0jj1xpcnbgmfymdll7qjggffv6x09f-gotestsum-1.10.1" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ii73x40gwzwgm7wp5svkay6k65w722ab-gotestsum-1.10.1", - "default": true - } - ], "store_path": "/nix/store/ii73x40gwzwgm7wp5svkay6k65w722ab-gotestsum-1.10.1" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/glqkgvz7ll2vg7mfm1nlrd49a1dwfpb2-gotestsum-1.10.1", - "default": true - } - ], "store_path": "/nix/store/glqkgvz7ll2vg7mfm1nlrd49a1dwfpb2-gotestsum-1.10.1" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/bydqdbg757r6g5r24bf6s7yb9zdc1q4d-gotestsum-1.10.1", - "default": true - } - ], "store_path": "/nix/store/bydqdbg757r6g5r24bf6s7yb9zdc1q4d-gotestsum-1.10.1" } } @@ -916,43 +328,15 @@ "version": "1.0.4", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/kcqx91mgrw03wgqzzx96xprfjzkkss96-govulncheck-1.0.4", - "default": true - } - ], "store_path": "/nix/store/kcqx91mgrw03wgqzzx96xprfjzkkss96-govulncheck-1.0.4" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/4m6afbm7qm1rq5ql9a0x4xcyzlj5i627-govulncheck-1.0.4", - "default": true - } - ], "store_path": "/nix/store/4m6afbm7qm1rq5ql9a0x4xcyzlj5i627-govulncheck-1.0.4" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nx4dsdypvbvizasrgjhpv82kw0fjlgm4-govulncheck-1.0.4", - "default": true - } - ], "store_path": "/nix/store/nx4dsdypvbvizasrgjhpv82kw0fjlgm4-govulncheck-1.0.4" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/kp3rjfdaxjx0m021nxp0kng5xx26p2j5-govulncheck-1.0.4", - "default": true - } - ], "store_path": "/nix/store/kp3rjfdaxjx0m021nxp0kng5xx26p2j5-govulncheck-1.0.4" } } @@ -964,43 +348,15 @@ "version": "1.11.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/dkky99zsrdkwz9hxprsq5zzha94jsrbj-helm-docs-1.11.2", - "default": true - } - ], "store_path": "/nix/store/dkky99zsrdkwz9hxprsq5zzha94jsrbj-helm-docs-1.11.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/3wamvq5mnmayksx0yy5ch9zb8mq42hd2-helm-docs-1.11.2", - "default": true - } - ], "store_path": "/nix/store/3wamvq5mnmayksx0yy5ch9zb8mq42hd2-helm-docs-1.11.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1pfj5vzrss4xd34hi0b119hpm5ymd9hv-helm-docs-1.11.2", - "default": true - } - ], "store_path": "/nix/store/1pfj5vzrss4xd34hi0b119hpm5ymd9hv-helm-docs-1.11.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/zdzdnhdbqfrm2lczw4h38ziipr4ixs1d-helm-docs-1.11.2", - "default": true - } - ], "store_path": "/nix/store/zdzdnhdbqfrm2lczw4h38ziipr4ixs1d-helm-docs-1.11.2" } } @@ -1012,43 +368,15 @@ "version": "0.124.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/rfkfvwigv0282mw24n3cdym7cyi542jy-hugo-0.124.0", - "default": true - } - ], "store_path": "/nix/store/rfkfvwigv0282mw24n3cdym7cyi542jy-hugo-0.124.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/0rnv4sichypqbprm4nqd0jjc27z5286c-hugo-0.124.0", - "default": true - } - ], "store_path": "/nix/store/0rnv4sichypqbprm4nqd0jjc27z5286c-hugo-0.124.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ip5zhc1rf2li8cmjwffjrj42r7nkkj4a-hugo-0.124.0", - "default": true - } - ], "store_path": "/nix/store/ip5zhc1rf2li8cmjwffjrj42r7nkkj4a-hugo-0.124.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/8syg9xrkp3nbpb1r4b469068kvk8gq2a-hugo-0.124.0", - "default": true - } - ], "store_path": "/nix/store/8syg9xrkp3nbpb1r4b469068kvk8gq2a-hugo-0.124.0" } } @@ -1060,43 +388,15 @@ "version": "0.22.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/87yk9f9zqzl4q6cawsw78l9c872xk3zb-kind-0.22.0", - "default": true - } - ], "store_path": "/nix/store/87yk9f9zqzl4q6cawsw78l9c872xk3zb-kind-0.22.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/hd04jgix5j5dj1grcgh9wwlz636243h6-kind-0.22.0", - "default": true - } - ], "store_path": "/nix/store/hd04jgix5j5dj1grcgh9wwlz636243h6-kind-0.22.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/114mq99ncln9x8h4mxpcjsflbh9qawxs-kind-0.22.0", - "default": true - } - ], "store_path": "/nix/store/114mq99ncln9x8h4mxpcjsflbh9qawxs-kind-0.22.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/d0wmw2i217vak50q2h94wic5ipi11jir-kind-0.22.0", - "default": true - } - ], "store_path": "/nix/store/d0wmw2i217vak50q2h94wic5ipi11jir-kind-0.22.0" } } @@ -1108,43 +408,15 @@ "version": "0.15.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/5d6ri1axxv9cwsac5lg1vz288zk5vf3s-ko-0.15.2", - "default": true - } - ], "store_path": "/nix/store/5d6ri1axxv9cwsac5lg1vz288zk5vf3s-ko-0.15.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/8d62nfbvadkbrqlp20451cm0pgp6zjxg-ko-0.15.2", - "default": true - } - ], "store_path": "/nix/store/8d62nfbvadkbrqlp20451cm0pgp6zjxg-ko-0.15.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/mbikn788gr04c9kkzkdic4w05l8nq7z9-ko-0.15.2", - "default": true - } - ], "store_path": "/nix/store/mbikn788gr04c9kkzkdic4w05l8nq7z9-ko-0.15.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/11h314lbbbj0989drrwc4bi2xrwvxywv-ko-0.15.2", - "default": true - } - ], "store_path": "/nix/store/11h314lbbbj0989drrwc4bi2xrwvxywv-ko-0.15.2" } } @@ -1156,43 +428,15 @@ "version": "3.14.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/yqlqfiab0nglynw6r74inrinbls15620-kubebuilder-3.14.0", - "default": true - } - ], "store_path": "/nix/store/yqlqfiab0nglynw6r74inrinbls15620-kubebuilder-3.14.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/g4nbjgznx6rcrlpg3xn4ynyyr5wvczjp-kubebuilder-3.14.0", - "default": true - } - ], "store_path": "/nix/store/g4nbjgznx6rcrlpg3xn4ynyyr5wvczjp-kubebuilder-3.14.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/xc309p246h3q5xn9gzkh49qcglhfj6ra-kubebuilder-3.14.0", - "default": true - } - ], "store_path": "/nix/store/xc309p246h3q5xn9gzkh49qcglhfj6ra-kubebuilder-3.14.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/3rzgxlj6msggxpy8zdf6ffk197wnmywr-kubebuilder-3.14.0", - "default": true - } - ], "store_path": "/nix/store/3rzgxlj6msggxpy8zdf6ffk197wnmywr-kubebuilder-3.14.0" } } @@ -1204,79 +448,15 @@ "version": "1.29.3", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/qrfxb19jr53r2kcsvga8wvg25v5dwyjh-kubectl-1.29.3", - "default": true - }, - { - "name": "man", - "path": "/nix/store/2m9dv8cvh6f90di79cmld40hmniw3h0i-kubectl-1.29.3-man", - "default": true - }, - { - "name": "convert", - "path": "/nix/store/j9rqnfgamf15lp5ijnp916hp3hl42xz8-kubectl-1.29.3-convert" - } - ], "store_path": "/nix/store/qrfxb19jr53r2kcsvga8wvg25v5dwyjh-kubectl-1.29.3" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/hmdnw2aivd5ywvg8h2d9sjghpp91jqmm-kubectl-1.29.3", - "default": true - }, - { - "name": "man", - "path": "/nix/store/av4rh67mx52js37csgyhl296bnp0z07s-kubectl-1.29.3-man", - "default": true - }, - { - "name": "convert", - "path": "/nix/store/w3pma5nyyxizibg6pbc6m1lqr0rfamn5-kubectl-1.29.3-convert" - } - ], "store_path": "/nix/store/hmdnw2aivd5ywvg8h2d9sjghpp91jqmm-kubectl-1.29.3" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1xvm25fyz9afncqgjxixjsjxfihvqf9k-kubectl-1.29.3", - "default": true - }, - { - "name": "man", - "path": "/nix/store/351mgjyq1jllp6347v71zpk54j7bws0w-kubectl-1.29.3-man", - "default": true - }, - { - "name": "convert", - "path": "/nix/store/4mf6d3vzql08zkg8rwac6y5nsjkcv6d1-kubectl-1.29.3-convert" - } - ], "store_path": "/nix/store/1xvm25fyz9afncqgjxixjsjxfihvqf9k-kubectl-1.29.3" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/xha7i9pddiz31bm9cr33njwnmzdpd3rf-kubectl-1.29.3", - "default": true - }, - { - "name": "man", - "path": "/nix/store/7alsjj9dc5j2xj28v6c0369wa7v1qgg0-kubectl-1.29.3-man", - "default": true - }, - { - "name": "convert", - "path": "/nix/store/gn5sj2jjwy2fvikgjkc76h8lagyszys0-kubectl-1.29.3-convert" - } - ], "store_path": "/nix/store/xha7i9pddiz31bm9cr33njwnmzdpd3rf-kubectl-1.29.3" } } @@ -1288,43 +468,15 @@ "version": "0.14.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/jblk86f5bi2dwg2w8g42xl9mpw1yrbi4-controller-tools-0.14.0", - "default": true - } - ], "store_path": "/nix/store/jblk86f5bi2dwg2w8g42xl9mpw1yrbi4-controller-tools-0.14.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/sq48wn8yyqkya8as690h61d1dlxwlkbi-controller-tools-0.14.0", - "default": true - } - ], "store_path": "/nix/store/sq48wn8yyqkya8as690h61d1dlxwlkbi-controller-tools-0.14.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nm2vx0f6ajmqpbi2c6z8wani5f1fdqb4-controller-tools-0.14.0", - "default": true - } - ], "store_path": "/nix/store/nm2vx0f6ajmqpbi2c6z8wani5f1fdqb4-controller-tools-0.14.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/f8h9pj08ksm49v980yb0slzrbpqqc98r-controller-tools-0.14.0", - "default": true - } - ], "store_path": "/nix/store/f8h9pj08ksm49v980yb0slzrbpqqc98r-controller-tools-0.14.0" } } @@ -1336,43 +488,15 @@ "version": "3.14.3", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/zy9621qww3klbwkffz2pp9kh3p0hdfs3-kubernetes-helm-3.14.3", - "default": true - } - ], "store_path": "/nix/store/zy9621qww3klbwkffz2pp9kh3p0hdfs3-kubernetes-helm-3.14.3" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/ki8zl3ccm68ma3kyjcnzdgfh4wslr2l6-kubernetes-helm-3.14.3", - "default": true - } - ], "store_path": "/nix/store/ki8zl3ccm68ma3kyjcnzdgfh4wslr2l6-kubernetes-helm-3.14.3" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/l6d6j4q4af0dhmjha0c7d010f3hj16b6-kubernetes-helm-3.14.3", - "default": true - } - ], "store_path": "/nix/store/l6d6j4q4af0dhmjha0c7d010f3hj16b6-kubernetes-helm-3.14.3" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/dnnm27a9s71pkgb7wjrdiw8gf9f7a003-kubernetes-helm-3.14.3", - "default": true - } - ], "store_path": "/nix/store/dnnm27a9s71pkgb7wjrdiw8gf9f7a003-kubernetes-helm-3.14.3" } } @@ -1384,43 +508,15 @@ "version": "5.3.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/452i1p4zhmbp0lij399pmlagvvhbz8qa-kustomize-5.3.0", - "default": true - } - ], "store_path": "/nix/store/452i1p4zhmbp0lij399pmlagvvhbz8qa-kustomize-5.3.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/db73m9xy7q4al1ypx3i4nbqw9wi25fpc-kustomize-5.3.0", - "default": true - } - ], "store_path": "/nix/store/db73m9xy7q4al1ypx3i4nbqw9wi25fpc-kustomize-5.3.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/r4kcp37cwrfskcdlk8r0hmwb5y6gh8lc-kustomize-5.3.0", - "default": true - } - ], "store_path": "/nix/store/r4kcp37cwrfskcdlk8r0hmwb5y6gh8lc-kustomize-5.3.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/y6q6p3fv79gahrkp6gz8q9lks4h0zgh8-kustomize-5.3.0", - "default": true - } - ], "store_path": "/nix/store/y6q6p3fv79gahrkp6gz8q9lks4h0zgh8-kustomize-5.3.0" } } @@ -1432,59 +528,15 @@ "version": "3.6.2", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/nwrn3g5v9bsrnd88v84q4q9japllx0jb-pre-commit-3.6.2", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/y3r47sj7njflny4l0x0a96bk24hfh7s4-pre-commit-3.6.2-dist" - } - ], "store_path": "/nix/store/nwrn3g5v9bsrnd88v84q4q9japllx0jb-pre-commit-3.6.2" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/61bnh53x2c6laq7vd7ssr23wm85zifs6-pre-commit-3.6.2", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/0rdbgni8iyzz32d24adg3rykkp4pc85m-pre-commit-3.6.2-dist" - } - ], "store_path": "/nix/store/61bnh53x2c6laq7vd7ssr23wm85zifs6-pre-commit-3.6.2" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/dpimv11qs1l3yyzb5nj94p2inpn35yj7-pre-commit-3.6.2", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/y1sav86i99mz03dp988lf1yxgcsdbff1-pre-commit-3.6.2-dist" - } - ], "store_path": "/nix/store/dpimv11qs1l3yyzb5nj94p2inpn35yj7-pre-commit-3.6.2" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/1n78gswil3nq9fdrff4rb2li4y45y5w4-pre-commit-3.6.2", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/ljfxnyrk6l9wpq2n5x79asgcw4pj7ay7-pre-commit-3.6.2-dist" - } - ], "store_path": "/nix/store/1n78gswil3nq9fdrff4rb2li4y45y5w4-pre-commit-3.6.2" } } @@ -1496,43 +548,15 @@ "version": "3.2.7", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/0kmy2vr9hznx2g22bvpavlcyrgjilx4z-rsync-3.2.7", - "default": true - } - ], "store_path": "/nix/store/0kmy2vr9hznx2g22bvpavlcyrgjilx4z-rsync-3.2.7" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/554m9gj7cd3qc7d9yyhvrw6l5gxwsf84-rsync-3.2.7", - "default": true - } - ], "store_path": "/nix/store/554m9gj7cd3qc7d9yyhvrw6l5gxwsf84-rsync-3.2.7" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/3f6wicmglmb803anbavd1gagbq16gqpb-rsync-3.2.7", - "default": true - } - ], "store_path": "/nix/store/3f6wicmglmb803anbavd1gagbq16gqpb-rsync-3.2.7" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/dc65w7qlnzqa9wfbyvyq5d8zv42v8zds-rsync-3.2.7", - "default": true - } - ], "store_path": "/nix/store/dc65w7qlnzqa9wfbyvyq5d8zv42v8zds-rsync-3.2.7" } } @@ -1544,43 +568,15 @@ "version": "3.8.0", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/6sicjz0jhnsazn34g9hlsjb7a80zm9i5-shfmt-3.8.0", - "default": true - } - ], "store_path": "/nix/store/6sicjz0jhnsazn34g9hlsjb7a80zm9i5-shfmt-3.8.0" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/l2l4hxcqypaqbp7ia8ig05345yx0sq5m-shfmt-3.8.0", - "default": true - } - ], "store_path": "/nix/store/l2l4hxcqypaqbp7ia8ig05345yx0sq5m-shfmt-3.8.0" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/6vh95c1bvnxr08ccy3p3gi02gxam5bns-shfmt-3.8.0", - "default": true - } - ], "store_path": "/nix/store/6vh95c1bvnxr08ccy3p3gi02gxam5bns-shfmt-3.8.0" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/sfdz20anszw4qfgwk71mmmfm0dzp94fv-shfmt-3.8.0", - "default": true - } - ], "store_path": "/nix/store/sfdz20anszw4qfgwk71mmmfm0dzp94fv-shfmt-3.8.0" } } @@ -1592,59 +588,15 @@ "version": "4.0.4", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/78j6khza1gr5zmbcldssr8zm8xxnzwps-python3.11-yamale-4.0.4", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/jfglw0libz2z4a97vnb8lsy1lqyrckvq-python3.11-yamale-4.0.4-dist" - } - ], "store_path": "/nix/store/78j6khza1gr5zmbcldssr8zm8xxnzwps-python3.11-yamale-4.0.4" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/9wdk342n50063l5y9idh4pl9gxvwdfyb-python3.11-yamale-4.0.4", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/4l5axk5c1878qmdpsgyc6kaf26gvvgms-python3.11-yamale-4.0.4-dist" - } - ], "store_path": "/nix/store/9wdk342n50063l5y9idh4pl9gxvwdfyb-python3.11-yamale-4.0.4" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/zy5pwvyhdyrkvgwwagf950pj0rvcdx68-python3.11-yamale-4.0.4", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/77a332bqd0j6xydhsny3xlm6sd5n5g7n-python3.11-yamale-4.0.4-dist" - } - ], "store_path": "/nix/store/zy5pwvyhdyrkvgwwagf950pj0rvcdx68-python3.11-yamale-4.0.4" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/9pzsm66srma437qmn3inib0r40jjawkm-python3.11-yamale-4.0.4", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/yf79fdb3nkb3ihklp9na61c74pnyh9h0-python3.11-yamale-4.0.4-dist" - } - ], "store_path": "/nix/store/9pzsm66srma437qmn3inib0r40jjawkm-python3.11-yamale-4.0.4" } } @@ -1656,59 +608,15 @@ "version": "1.35.1", "systems": { "aarch64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/shw3d5hqv1kjsxgs6favbb6icdf5zspz-python3.11-yamllint-1.35.1", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/i9fmwxqhi001mjn1vmmvn2a33fsddlz7-python3.11-yamllint-1.35.1-dist" - } - ], "store_path": "/nix/store/shw3d5hqv1kjsxgs6favbb6icdf5zspz-python3.11-yamllint-1.35.1" }, "aarch64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/qhciblsdwcx382ybhv4qy3pv321rprpn-python3.11-yamllint-1.35.1", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/3zx9gj6mma9g28vg9l6778h1la50s5zk-python3.11-yamllint-1.35.1-dist" - } - ], "store_path": "/nix/store/qhciblsdwcx382ybhv4qy3pv321rprpn-python3.11-yamllint-1.35.1" }, "x86_64-darwin": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/0qjkix7ixdmh056zg2w98yqfx31ip722-python3.11-yamllint-1.35.1", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/sbgn6iav52fp759y47h4j9kaxzmbqgkh-python3.11-yamllint-1.35.1-dist" - } - ], "store_path": "/nix/store/0qjkix7ixdmh056zg2w98yqfx31ip722-python3.11-yamllint-1.35.1" }, "x86_64-linux": { - "outputs": [ - { - "name": "out", - "path": "/nix/store/04jdxm8pyzbsg9vjgs0y1piglnn6bzny-python3.11-yamllint-1.35.1", - "default": true - }, - { - "name": "dist", - "path": "/nix/store/1grzppn23d79mkj9vyf9rs1f4w0xvyd6-python3.11-yamllint-1.35.1-dist" - } - ], "store_path": "/nix/store/04jdxm8pyzbsg9vjgs0y1piglnn6bzny-python3.11-yamllint-1.35.1" } } From f8c47e2456ebed65fc0ee43ef7d6563d806aacdc Mon Sep 17 00:00:00 2001 From: Shalin Patel Date: Fri, 5 Apr 2024 13:37:06 -0700 Subject: [PATCH 69/87] test: unit test for individual patch generator (#21) * test: unit test for individual patch generator * test: package level unit test for HTTPProxy * test: fix data race between multiple unit test that use envtest * test: make patchgenerator generic function * fix: linting errors after rebase from main --- api/v1alpha1/nutanix_node_types.go | 26 ++++-- common/go.mod | 4 + common/go.sum | 1 - common/pkg/testutils/capitest/patches.go | 86 ++++++++++--------- .../aws/mutation/region/inject_test.go | 35 ++++++++ .../mutation/region/tests/generate_patches.go | 5 +- .../generic/lifecycle/ccm/aws/handler.go | 8 +- .../generic/mutation/httpproxy/inject_test.go | 29 +++++++ .../httpproxy/tests/generate_patches.go | 5 +- .../tests/generate_patches.go | 1 + test/helpers/environment.go | 49 +++++++++++ test/helpers/envtest.go | 3 + 12 files changed, 196 insertions(+), 56 deletions(-) create mode 100644 pkg/handlers/aws/mutation/region/inject_test.go create mode 100644 test/helpers/environment.go diff --git a/api/v1alpha1/nutanix_node_types.go b/api/v1alpha1/nutanix_node_types.go index 1637721fa..8190c395a 100644 --- a/api/v1alpha1/nutanix_node_types.go +++ b/api/v1alpha1/nutanix_node_types.go @@ -80,16 +80,27 @@ func (NutanixMachineDetails) VariableSchema() clusterv1.VariableSchema { Description: "memorySize is the memory size (in Quantity format) of the VM eg. 4Gi", Type: "string", }, - "image": NutanixResourceIdentifier{}.VariableSchema().OpenAPIV3Schema, - "cluster": NutanixResourceIdentifier{}.VariableSchema().OpenAPIV3Schema, - "subnets": NutanixResourceIdentifiers{}.VariableSchema().OpenAPIV3Schema, - "bootType": NutanixBootType(capxv1.NutanixBootTypeLegacy).VariableSchema().OpenAPIV3Schema, + "image": NutanixResourceIdentifier{}.VariableSchema().OpenAPIV3Schema, + "cluster": NutanixResourceIdentifier{}.VariableSchema().OpenAPIV3Schema, + "subnets": NutanixResourceIdentifiers{}.VariableSchema().OpenAPIV3Schema, + "bootType": NutanixBootType( + capxv1.NutanixBootTypeLegacy, + ).VariableSchema(). + OpenAPIV3Schema, "systemDiskSize": { Description: "systemDiskSize is size (in Quantity format) of the system disk of the VM eg. 20Gi", Type: "string", }, }, - Required: []string{"vcpusPerSocket", "vcpuSockets", "memorySize", "image", "cluster", "subnets", "systemDiskSize"}, + Required: []string{ + "vcpusPerSocket", + "vcpuSockets", + "memorySize", + "image", + "cluster", + "subnets", + "systemDiskSize", + }, }, } } @@ -134,7 +145,10 @@ func (NutanixResourceIdentifier) VariableSchema() clusterv1.VariableSchema { Description: "Nutanix Resource Identifier", Type: "object", Properties: map[string]clusterv1.JSONSchemaProps{ - "type": NutanixIdentifierType(capxv1.NutanixIdentifierName).VariableSchema().OpenAPIV3Schema, + "type": NutanixIdentifierType( + capxv1.NutanixIdentifierName, + ).VariableSchema(). + OpenAPIV3Schema, "uuid": { Type: "string", Description: "uuid is the UUID of the resource in the PC.", diff --git a/common/go.mod b/common/go.mod index 8c488f21a..9fd75ed65 100644 --- a/common/go.mod +++ b/common/go.mod @@ -11,6 +11,7 @@ require ( github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api v0.0.0-00010101000000-000000000000 github.com/evanphx/json-patch/v5 v5.9.0 github.com/go-logr/logr v1.4.1 + github.com/onsi/ginkgo/v2 v2.15.0 github.com/onsi/gomega v1.31.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 @@ -36,6 +37,7 @@ require ( github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -43,6 +45,7 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/google/uuid v1.3.1 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -69,6 +72,7 @@ require ( golang.org/x/term v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.16.1 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect diff --git a/common/go.sum b/common/go.sum index a705598aa..d6c26d887 100644 --- a/common/go.sum +++ b/common/go.sum @@ -365,7 +365,6 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= diff --git a/common/pkg/testutils/capitest/patches.go b/common/pkg/testutils/capitest/patches.go index 43ce653ca..fa817d25f 100644 --- a/common/pkg/testutils/capitest/patches.go +++ b/common/pkg/testutils/capitest/patches.go @@ -7,8 +7,8 @@ import ( "context" "encoding/json" "fmt" - "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" "github.com/onsi/gomega/gstruct" gomegatypes "github.com/onsi/gomega/types" @@ -39,55 +39,57 @@ type JSONPatchMatcher struct { } func ValidateGeneratePatches[T mutation.GeneratePatches]( - t *testing.T, + t GinkgoTInterface, handlerCreator func() T, testDefs ...PatchTestDef, ) { t.Helper() + testFunc := func(tt *PatchTestDef) { + g := gomega.NewWithT(t) + h := handlerCreator() + req := &runtimehooksv1.GeneratePatchesRequest{ + Variables: tt.Vars, + Items: []runtimehooksv1.GeneratePatchesRequestItem{ + tt.RequestItem, + { + HolderReference: runtimehooksv1.HolderReference{ + APIVersion: capiv1.GroupVersion.String(), + Kind: "Cluster", + Namespace: request.Namespace, + Name: request.ClusterName, + }, + }, + }, + } + resp := &runtimehooksv1.GeneratePatchesResponse{} + h.GeneratePatches(context.Background(), req, resp) + expectedStatus := runtimehooksv1.ResponseStatusSuccess + if tt.ExpectedFailure { + expectedStatus = runtimehooksv1.ResponseStatusFailure + } + g.Expect(resp.Status). + To(gomega.Equal(expectedStatus), fmt.Sprintf("Message: %s", resp.Message)) + + if len(tt.ExpectedPatchMatchers) == 0 { + g.Expect(resp.Items).To(gomega.BeEmpty()) + return + } + g.Expect(resp.Items).To(containPatches(&tt.RequestItem, tt.ExpectedPatchMatchers...)) + if len(tt.UnexpectedPatchMatchers) > 0 { + g.Expect(resp.Items). + ToNot(containPatches(&tt.RequestItem, tt.UnexpectedPatchMatchers...)) + } + } + + // compose Ginkgo table arguments + // https://onsi.github.io/ginkgo/#table-specs for more details + testArgs := make([]TableEntry, 0, len(testDefs)) for testIdx := range testDefs { tt := testDefs[testIdx] - - t.Run(tt.Name, func(t *testing.T) { - t.Parallel() - - g := gomega.NewWithT(t) - h := handlerCreator() - req := &runtimehooksv1.GeneratePatchesRequest{ - Variables: tt.Vars, - Items: []runtimehooksv1.GeneratePatchesRequestItem{ - tt.RequestItem, - { - HolderReference: runtimehooksv1.HolderReference{ - APIVersion: capiv1.GroupVersion.String(), - Kind: "Cluster", - Namespace: request.Namespace, - Name: request.ClusterName, - }, - }, - }, - } - resp := &runtimehooksv1.GeneratePatchesResponse{} - h.GeneratePatches(context.Background(), req, resp) - expectedStatus := runtimehooksv1.ResponseStatusSuccess - if tt.ExpectedFailure { - expectedStatus = runtimehooksv1.ResponseStatusFailure - } - g.Expect(resp.Status). - To(gomega.Equal(expectedStatus), fmt.Sprintf("Message: %s", resp.Message)) - - if len(tt.ExpectedPatchMatchers) == 0 { - g.Expect(resp.Items).To(gomega.BeEmpty()) - return - } - g.Expect(resp.Items).To(containPatches(&tt.RequestItem, tt.ExpectedPatchMatchers...)) - - if len(tt.UnexpectedPatchMatchers) > 0 { - g.Expect(resp.Items). - ToNot(containPatches(&tt.RequestItem, tt.UnexpectedPatchMatchers...)) - } - }) + testArgs = append(testArgs, Entry(tt.Name, &tt)) } + DescribeTable("Patches", testFunc, testArgs) } // VariableWithValue returns a runtimehooksv1.Variable with the passed name and value. diff --git a/pkg/handlers/aws/mutation/region/inject_test.go b/pkg/handlers/aws/mutation/region/inject_test.go new file mode 100644 index 000000000..4f76e95ea --- /dev/null +++ b/pkg/handlers/aws/mutation/region/inject_test.go @@ -0,0 +1,35 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package region + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + regiontests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/region/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +func TestRegionPatch(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "AWS Region mutator suite") +} + +var _ = Describe("Generate AWS Region patches", func() { + // only add aws region patch + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } + regiontests.TestGeneratePatches( + GinkgoT(), + patchGenerator, + clusterconfig.MetaVariableName, + v1alpha1.AWSVariableName, + VariableName, + ) +}) diff --git a/pkg/handlers/aws/mutation/region/tests/generate_patches.go b/pkg/handlers/aws/mutation/region/tests/generate_patches.go index 909d2f5c3..883d603c5 100644 --- a/pkg/handlers/aws/mutation/region/tests/generate_patches.go +++ b/pkg/handlers/aws/mutation/region/tests/generate_patches.go @@ -4,8 +4,7 @@ package tests import ( - "testing" - + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -15,7 +14,7 @@ import ( ) func TestGeneratePatches( - t *testing.T, + t GinkgoTInterface, generatorFunc func() mutation.GeneratePatches, variableName string, variablePath ...string, diff --git a/pkg/handlers/generic/lifecycle/ccm/aws/handler.go b/pkg/handlers/generic/lifecycle/ccm/aws/handler.go index c9f34ebfc..fa37fd1db 100644 --- a/pkg/handlers/generic/lifecycle/ccm/aws/handler.go +++ b/pkg/handlers/generic/lifecycle/ccm/aws/handler.go @@ -96,7 +96,13 @@ func (a *AWSCCM) Apply( ) } - err = lifecycleutils.EnsureCRSForClusterFromObjects(ctx, ccmConfigMap.Name, a.client, cluster, ccmConfigMap) + err = lifecycleutils.EnsureCRSForClusterFromObjects( + ctx, + ccmConfigMap.Name, + a.client, + cluster, + ccmConfigMap, + ) if err != nil { return fmt.Errorf("failed to generate CCM CRS for cluster: %w", err) } diff --git a/pkg/handlers/generic/mutation/httpproxy/inject_test.go b/pkg/handlers/generic/mutation/httpproxy/inject_test.go index caae06f15..13f183394 100644 --- a/pkg/handlers/generic/mutation/httpproxy/inject_test.go +++ b/pkg/handlers/generic/mutation/httpproxy/inject_test.go @@ -6,9 +6,15 @@ package httpproxy import ( "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" v1 "k8s.io/api/core/v1" capiv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + httpproxy "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/test/helpers" ) func TestGenerateNoProxy(t *testing.T) { @@ -179,3 +185,26 @@ func TestGenerateNoProxy(t *testing.T) { }) } } + +func TestHTTPProxyPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "HTTP Proxy mutator suite") +} + +var _ = Describe("Generate HTTPProxy Patches", func() { + // only add HTTPProxy patch + patchGenerator := func() mutation.GeneratePatches { + // Always initialize the testEnv variable in the closure. + // This will allow ginkgo to initialize testEnv variable during test execution time. + testEnv := helpers.TestEnv + return mutation.NewMetaGeneratePatchesHandler( + "", + NewPatch(testEnv.Client)).(mutation.GeneratePatches) + } + httpproxy.TestGeneratePatches( + GinkgoT(), + patchGenerator, + clusterconfig.MetaVariableName, + VariableName, + ) +}) diff --git a/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go b/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go index f3b437ed5..302cc96d3 100644 --- a/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go @@ -4,8 +4,7 @@ package tests import ( - "testing" - + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" "k8s.io/apiserver/pkg/storage/names" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -17,7 +16,7 @@ import ( ) func TestGeneratePatches( - t *testing.T, + t GinkgoTInterface, generatorFunc func() mutation.GeneratePatches, variableName string, variablePath ...string, diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go index 4ae6c6243..0b9003fc1 100644 --- a/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go @@ -17,6 +17,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" ) +// //nolint:lll // just a long string const testCertBundle = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVjekNDQTF1Z0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRUUZBRC4uQWtHQTFVRUJoTUNSMEl4CkV6QVJCZ05WQkFnVENsTnZiV1V0VTNSaGRHVXhGREFTQmdOVkJBb1RDMC4uMEVnVEhSa01UY3dOUVlEClZRUUxFeTVEYkdGemN5QXhJRkIxWW14cFl5QlFjbWx0WVhKNUlFTmxjbi4uWFJwYjI0Z1FYVjBhRzl5CmFYUjVNUlF3RWdZRFZRUURFd3RDWlhOMElFTkJJRXgwWkRBZUZ3MHdNRC4uVFV3TVRaYUZ3MHdNVEF5Ck1EUXhPVFV3TVRaYU1JR0hNUXN3Q1FZRFZRUUdFd0pIUWpFVE1CRUdBMS4uMjl0WlMxVGRHRjBaVEVVCk1CSUdBMVVFQ2hNTFFtVnpkQ0JEUVNCTWRHUXhOekExQmdOVkJBc1RMay4uREVnVUhWaWJHbGpJRkJ5CmFXMWhjbmtnUTJWeWRHbG1hV05oZEdsdmJpQkJkWFJvYjNKcGRIa3hGRC4uQU1UQzBKbGMzUWdRMEVnClRIUmtNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZy4uVHoybXI3U1ppQU1mUXl1CnZCak05T2lKalJhelhCWjFCalA1Q0UvV20vUnI1MDBQUksrTGg5eDVlSi4uL0FOQkUwc1RLMFpzREdNCmFrMm0xZzdvcnVJM2RZM1ZIcUl4RlR6MFRhMWQrTkFqd25MZTRuT2I3Ly4uazA1U2hoQnJKR0JLS3hiCjhuMTA0by81cDhIQXNaUGR6YkZNSXlOakp6Qk0ybzV5NUExM3dpTGl0RS4uZnlZa1F6YXhDdzBBd3psCmtWSGlJeUN1YUY0d2o1NzFwU3prdjZzdis0SURNYlQvWHBDbzhMNndUYS4uc2grZXRMRDZGdFRqWWJiCnJ2WjhSUU0xdGxLZG9NSGcycXhyYUFWKytITkJZbU5XczBkdUVkalViSi4uWEk5VHRuUzRvMUNrajdQCk9mbGppUUlEQVFBQm80SG5NSUhrTUIwR0ExVWREZ1FXQkJROHVyTUNSTC4uNUFrSXA5TkpISnc1VENCCnRBWURWUjBqQklHc01JR3BnQlE4dXJNQ1JMWVlNSFVLVTVBa0lwOU5KSC4uYVNCaWpDQmh6RUxNQWtHCkExVUVCaE1DUjBJeEV6QVJCZ05WQkFnVENsTnZiV1V0VTNSaGRHVXhGRC4uQW9UQzBKbGMzUWdRMEVnClRIUmtNVGN3TlFZRFZRUUxFeTVEYkdGemN5QXhJRkIxWW14cFl5QlFjbS4uRU5sY25ScFptbGpZWFJwCmIyNGdRWFYwYUc5eWFYUjVNUlF3RWdZRFZRUURFd3RDWlhOMElFTkJJRS4uREFNQmdOVkhSTUVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQkFVQUE0SUJBUUMxdVlCY3NTbmN3QS4uRENzUWVyNzcyQzJ1Y3BYCnhRVUUvQzBwV1dtNmdEa3dkNUQwRFNNREpScVYvd2VvWjR3QzZCNzNmNS4uYkxoR1lIYVhKZVNENktyClhjb093TGRTYUdtSllzbExLWkIzWklERXAwd1lUR2hndGViNkpGaVR0bi4uc2YyeGRyWWZQQ2lJQjdnCkJNQVY3R3pkYzRWc3BTNmxqckFoYmlpYXdkQmlRbFFtc0JlRno5SmtGNC4uYjNsOEJvR04rcU1hNTZZCkl0OHVuYTJnWTRsMk8vL29uODhyNUlXSmxtMUwwb0E4ZTRmUjJ5ckJIWC4uYWRzR2VGS2t5TnJ3R2kvCjd2UU1mWGRHc1JyWE5HUkduWCt2V0RaMy96V0kwam9EdENrTm5xRXBWbi4uSG9YCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=" diff --git a/test/helpers/environment.go b/test/helpers/environment.go new file mode 100644 index 000000000..9d0e48263 --- /dev/null +++ b/test/helpers/environment.go @@ -0,0 +1,49 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package helpers + +import ( + "context" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/klog/v2" + "k8s.io/klog/v2/textlogger" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +var TestEnv *TestEnvironment + +// Initialize the test environment. BeforeSuite will be only executed if this package is loaded by the test. +var _ = BeforeSuite(func(ctx SpecContext) { + By("Initialize loggers for testing") + // Uninitialized logger spits stacktrace as warning during test execution + logger := textlogger.NewLogger(textlogger.NewConfig()) + // use klog as the internal logger for this envtest environment. + log.SetLogger(logger) + // additionally force all of the controllers to use the Ginkgo logger. + ctrl.SetLogger(logger) + klog.InitFlags(nil) + // add logger for ginkgo + klog.SetOutput(GinkgoWriter) + + By("Starting test environment") + testEnvConfig := NewTestEnvironmentConfiguration() + var err error + TestEnv, err = testEnvConfig.Build() + if err != nil { + panic(err) + } + By("Starting the manager") + go func() { + defer GinkgoRecover() + Expect(TestEnv.StartManager(ctx)).To(Succeed()) + }() +}, NodeTimeout(60*time.Second)) + +var _ = AfterSuite(func(ctx context.Context) { + Expect(TestEnv.Stop()).To(Succeed()) +}) diff --git a/test/helpers/envtest.go b/test/helpers/envtest.go index 26257229d..190b8f009 100644 --- a/test/helpers/envtest.go +++ b/test/helpers/envtest.go @@ -137,6 +137,9 @@ func (t *TestEnvironment) StartManager(ctx context.Context) error { // Stop stops the test environment. func (t *TestEnvironment) Stop() error { + if t.cancel != nil { + t.cancel() + } return t.env.Stop() } From 184e7d6eceb226874cbca6883759336870d3a4e3 Mon Sep 17 00:00:00 2001 From: Shalin Patel Date: Fri, 5 Apr 2024 14:34:03 -0700 Subject: [PATCH 70/87] test: move all patch generator unit tests to their own packages (#23) * test: unit test for individual patch generator * test: package level unit test for HTTPProxy * test: move region and httpproxy patch generator unit test invocation * fix: linting errors * test: move all AWS patch unit tests to their own packages (#24) * test: move instanceprofile tests to its own package * test: move instancetype unit tests to its own package * test: move ami unit tests to its own package * test: move aws network tests to its own package * test: move controlplaneloadbalancer unit tests to its own package * test: move aws cni unit tests to its own package * test: fix linting errors * test: unit tests for AWS security groups * test: move customimage unit tests to their own package (#30) * test: move all Nutanix patch handler unit tests (#32) * test: move controlplane endpoint unit tests * test: move PC endpoint unit tests * test: nove machinedetails unit tests * test: move generic patch unit tests to own packages (#31) * test: move audit policy tests to their own package * test: move etcd unit tests to their own package * test: move extra api server cert sans to its own package * test: move image registry unit tests to its own package * test: move kubernetes image repository unit tests * test: move mirror unit tests * test: move users unit tests * test: remove gereric unit tests from nutanix meta patch handler * test: cleaned up meta level unit test suites --- common/pkg/testutils/capitest/patches.go | 46 +++ .../mutation/ami/inject_control_plane_test.go | 100 +++++ .../aws/mutation/ami/inject_suite_test.go | 16 + ...erate_patches.go => inject_worker_test.go} | 125 ++----- .../generate_patches.go => inject_test.go} | 65 ++-- .../generate_patches.go => inject_test.go} | 56 ++- .../inject_control_plane_test.go | 58 +++ .../iaminstanceprofile/inject_suite_test.go | 16 + ...erate_patches.go => inject_worker_test.go} | 82 ++--- .../instancetype/inject_control_plane_test.go | 58 +++ .../instancetype/inject_suite_test.go | 16 + ...erate_patches.go => inject_worker_test.go} | 82 ++--- .../aws/mutation/metapatch_handler_test.go | 200 ---------- .../generate_patches.go => inject_test.go} | 63 ++-- .../aws/mutation/region/inject_test.go | 50 ++- .../mutation/region/tests/generate_patches.go | 47 --- .../inject_control_plane_test.go | 75 ++++ .../securitygroups/inject_suite_test.go | 16 + .../securitygroups/inject_worker_test.go | 81 ++++ pkg/handlers/aws/mutation/suite_test.go | 48 --- .../customimage/inject_control_plane_test.go | 77 ++++ .../mutation/customimage/inject_suite_test.go | 16 + .../customimage/inject_worker_test.go | 80 ++++ .../customimage/tests/generate_patches.go | 122 ------ .../docker/mutation/metapatch_handler_test.go | 124 ------- pkg/handlers/docker/mutation/suite_test.go | 48 --- .../generate_patches.go => inject_test.go} | 36 +- .../generate_patches.go => inject_test.go} | 56 +-- .../generate_patches.go => inject_test.go} | 46 ++- .../generic/mutation/httpproxy/inject_test.go | 91 ++++- .../httpproxy/tests/generate_patches.go | 95 ----- .../credentials/inject_test.go | 346 ++++++++++++++++++ .../credentials/tests/generate_patches.go | 327 ----------------- .../generate_patches.go => inject_test.go} | 46 ++- .../generate_patches.go => inject_test.go} | 100 +++-- .../generic/mutation/users/inject_test.go | 88 +++++ .../mutation/users/tests/generate_patches.go | 97 ----- .../generate_patches.go => inject_test.go} | 52 ++- ...atches.go => inject_control_plane_test.go} | 82 ++--- .../machinedetails/inject_suite_test.go | 16 + .../machinedetails/inject_worker_test.go | 59 +++ .../mutation/metapatch_handler_test.go | 134 ------- .../generate_patches.go => inject_test.go} | 58 ++- pkg/handlers/nutanix/mutation/suite_test.go | 48 --- test/helpers/environment.go | 15 - test/helpers/envtest.go | 7 + 46 files changed, 1775 insertions(+), 1791 deletions(-) create mode 100644 pkg/handlers/aws/mutation/ami/inject_control_plane_test.go create mode 100644 pkg/handlers/aws/mutation/ami/inject_suite_test.go rename pkg/handlers/aws/mutation/ami/{tests/generate_patches.go => inject_worker_test.go} (52%) rename pkg/handlers/aws/mutation/cni/calico/{tests/generate_patches.go => inject_test.go} (89%) rename pkg/handlers/aws/mutation/controlplaneloadbalancer/{tests/generate_patches.go => inject_test.go} (65%) create mode 100644 pkg/handlers/aws/mutation/iaminstanceprofile/inject_control_plane_test.go create mode 100644 pkg/handlers/aws/mutation/iaminstanceprofile/inject_suite_test.go rename pkg/handlers/aws/mutation/iaminstanceprofile/{tests/generate_patches.go => inject_worker_test.go} (50%) create mode 100644 pkg/handlers/aws/mutation/instancetype/inject_control_plane_test.go create mode 100644 pkg/handlers/aws/mutation/instancetype/inject_suite_test.go rename pkg/handlers/aws/mutation/instancetype/{tests/generate_patches.go => inject_worker_test.go} (50%) delete mode 100644 pkg/handlers/aws/mutation/metapatch_handler_test.go rename pkg/handlers/aws/mutation/network/{tests/generate_patches.go => inject_test.go} (69%) delete mode 100644 pkg/handlers/aws/mutation/region/tests/generate_patches.go create mode 100644 pkg/handlers/aws/mutation/securitygroups/inject_control_plane_test.go create mode 100644 pkg/handlers/aws/mutation/securitygroups/inject_suite_test.go create mode 100644 pkg/handlers/aws/mutation/securitygroups/inject_worker_test.go delete mode 100644 pkg/handlers/aws/mutation/suite_test.go create mode 100644 pkg/handlers/docker/mutation/customimage/inject_control_plane_test.go create mode 100644 pkg/handlers/docker/mutation/customimage/inject_suite_test.go create mode 100644 pkg/handlers/docker/mutation/customimage/inject_worker_test.go delete mode 100644 pkg/handlers/docker/mutation/customimage/tests/generate_patches.go delete mode 100644 pkg/handlers/docker/mutation/metapatch_handler_test.go delete mode 100644 pkg/handlers/docker/mutation/suite_test.go rename pkg/handlers/generic/mutation/auditpolicy/{tests/generate_patches.go => inject_test.go} (76%) rename pkg/handlers/generic/mutation/etcd/{tests/generate_patches.go => inject_test.go} (76%) rename pkg/handlers/generic/mutation/extraapiservercertsans/{tests/generate_patches.go => inject_test.go} (60%) delete mode 100644 pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go delete mode 100644 pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_patches.go rename pkg/handlers/generic/mutation/kubernetesimagerepository/{tests/generate_patches.go => inject_test.go} (58%) rename pkg/handlers/generic/mutation/mirrors/{tests/generate_patches.go => inject_test.go} (76%) delete mode 100644 pkg/handlers/generic/mutation/users/tests/generate_patches.go rename pkg/handlers/nutanix/mutation/controlplaneendpoint/{tests/generate_patches.go => inject_test.go} (56%) rename pkg/handlers/nutanix/mutation/machinedetails/{tests/generate_patches.go => inject_control_plane_test.go} (72%) create mode 100644 pkg/handlers/nutanix/mutation/machinedetails/inject_suite_test.go create mode 100644 pkg/handlers/nutanix/mutation/machinedetails/inject_worker_test.go delete mode 100644 pkg/handlers/nutanix/mutation/metapatch_handler_test.go rename pkg/handlers/nutanix/mutation/prismcentralendpoint/{tests/generate_patches.go => inject_test.go} (80%) delete mode 100644 pkg/handlers/nutanix/mutation/suite_test.go diff --git a/common/pkg/testutils/capitest/patches.go b/common/pkg/testutils/capitest/patches.go index fa817d25f..cffaaabf5 100644 --- a/common/pkg/testutils/capitest/patches.go +++ b/common/pkg/testutils/capitest/patches.go @@ -92,6 +92,52 @@ func ValidateGeneratePatches[T mutation.GeneratePatches]( DescribeTable("Patches", testFunc, testArgs) } +// TODO(shalinpatel): AssertGeneratePatches is a replacement of ValidateGeneratePatches function. +// remove ValidateGeneratePatches once all the shared test cases are moved to their own patch package. +func AssertGeneratePatches[T mutation.GeneratePatches]( + t GinkgoTInterface, + handlerCreator func() T, + tt *PatchTestDef, +) { + t.Helper() + + g := gomega.NewWithT(t) + h := handlerCreator() + req := &runtimehooksv1.GeneratePatchesRequest{ + Variables: tt.Vars, + Items: []runtimehooksv1.GeneratePatchesRequestItem{ + tt.RequestItem, + { + HolderReference: runtimehooksv1.HolderReference{ + APIVersion: capiv1.GroupVersion.String(), + Kind: "Cluster", + Namespace: request.Namespace, + Name: request.ClusterName, + }, + }, + }, + } + resp := &runtimehooksv1.GeneratePatchesResponse{} + h.GeneratePatches(context.Background(), req, resp) + expectedStatus := runtimehooksv1.ResponseStatusSuccess + if tt.ExpectedFailure { + expectedStatus = runtimehooksv1.ResponseStatusFailure + } + g.Expect(resp.Status). + To(gomega.Equal(expectedStatus), fmt.Sprintf("Message: %s", resp.Message)) + + if len(tt.ExpectedPatchMatchers) == 0 { + g.Expect(resp.Items).To(gomega.BeEmpty()) + return + } + g.Expect(resp.Items).To(containPatches(&tt.RequestItem, tt.ExpectedPatchMatchers...)) + + if len(tt.UnexpectedPatchMatchers) > 0 { + g.Expect(resp.Items). + ToNot(containPatches(&tt.RequestItem, tt.UnexpectedPatchMatchers...)) + } +} + // VariableWithValue returns a runtimehooksv1.Variable with the passed name and value. func VariableWithValue( variableName string, diff --git a/pkg/handlers/aws/mutation/ami/inject_control_plane_test.go b/pkg/handlers/aws/mutation/ami/inject_control_plane_test.go new file mode 100644 index 000000000..638446022 --- /dev/null +++ b/pkg/handlers/aws/mutation/ami/inject_control_plane_test.go @@ -0,0 +1,100 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package ami + +import ( + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +var _ = Describe("Generate AMI patches for ControlPlane", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewControlPlanePatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "AMI set for control plane", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.AMISpec{ID: "ami-controlplane"}, + clusterconfig.MetaControlPlaneConfigName, + v1alpha1.AWSVariableName, + VariableName, + ), + }, + RequestItem: request.NewCPAWSMachineTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/ami/id", + ValueMatcher: gomega.Equal("ami-controlplane"), + }, + }, + }, + { + Name: "AMI lookup format set for control plane", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.AMISpec{ + Lookup: &v1alpha1.AMILookup{ + Format: "test-{{.kubernetesVersion}}-format", + Org: "1234", + BaseOS: "testOS", + }, + }, + clusterconfig.MetaControlPlaneConfigName, + v1alpha1.AWSVariableName, + VariableName, + ), + }, + RequestItem: request.NewCPAWSMachineTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/imageLookupFormat", + ValueMatcher: gomega.Equal("test-{{.kubernetesVersion}}-format"), + }, + { + Operation: "add", + Path: "/spec/template/spec/imageLookupOrg", + ValueMatcher: gomega.Equal("1234"), + }, + { + Operation: "add", + Path: "/spec/template/spec/imageLookupBaseOS", + ValueMatcher: gomega.Equal("testOS"), + }, + }, + UnexpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/ami/id", + ValueMatcher: gomega.Equal(""), + }, + }, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/ami/inject_suite_test.go b/pkg/handlers/aws/mutation/ami/inject_suite_test.go new file mode 100644 index 000000000..bb77ba57e --- /dev/null +++ b/pkg/handlers/aws/mutation/ami/inject_suite_test.go @@ -0,0 +1,16 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package ami + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestAMIPatch(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "AMI patches for ControlPlane and Workers suite") +} diff --git a/pkg/handlers/aws/mutation/ami/tests/generate_patches.go b/pkg/handlers/aws/mutation/ami/inject_worker_test.go similarity index 52% rename from pkg/handlers/aws/mutation/ami/tests/generate_patches.go rename to pkg/handlers/aws/mutation/ami/inject_worker_test.go index 36f86066b..237f0963a 100644 --- a/pkg/handlers/aws/mutation/ami/tests/generate_patches.go +++ b/pkg/handlers/aws/mutation/ami/inject_worker_test.go @@ -1,11 +1,10 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package ami import ( - "testing" - + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -14,99 +13,23 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" ) -func TestControlPlaneGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "AMI set for control plane", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.AMISpec{ID: "ami-controlplane"}, - variablePath..., - ), - }, - RequestItem: request.NewCPAWSMachineTemplateRequestItem("1234"), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/ami/id", - ValueMatcher: gomega.Equal("ami-controlplane"), - }, - }, - }, - capitest.PatchTestDef{ - Name: "AMI lookup format set for control plane", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.AMISpec{ - Lookup: &v1alpha1.AMILookup{ - Format: "test-{{.kubernetesVersion}}-format", - Org: "12345", - BaseOS: "testOS", - }, - }, - variablePath..., - ), - }, - RequestItem: request.NewCPAWSMachineTemplateRequestItem("1234"), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/imageLookupFormat", - ValueMatcher: gomega.Equal("test-{{.kubernetesVersion}}-format"), - }, - { - Operation: "add", - Path: "/spec/template/spec/imageLookupOrg", - ValueMatcher: gomega.Equal("12345"), - }, - { - Operation: "add", - Path: "/spec/template/spec/imageLookupBaseOS", - ValueMatcher: gomega.Equal("testOS"), - }, - }, - UnexpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/ami/id", - ValueMatcher: gomega.Equal(""), - }, - }, - }, - ) -} - -func TestWorkerGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() +var _ = Describe("Generate AMI patches for Worker", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewWorkerPatch()).(mutation.GeneratePatches) + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ + testDefs := []capitest.PatchTestDef{ + { Name: "AMI set for workers", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + workerconfig.MetaVariableName, v1alpha1.AMISpec{ID: "ami-controlplane"}, - variablePath..., + v1alpha1.AWSVariableName, + VariableName, ), capitest.VariableWithValue( "builtin", @@ -124,11 +47,11 @@ func TestWorkerGeneratePatches( }, }, }, - capitest.PatchTestDef{ + { Name: "AMI lookup format set for worker", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + workerconfig.MetaVariableName, v1alpha1.AMISpec{ Lookup: &v1alpha1.AMILookup{ Format: "test-{{.kubernetesVersion}}-format", @@ -136,8 +59,8 @@ func TestWorkerGeneratePatches( BaseOS: "testOS", }, }, - - variablePath..., + v1alpha1.AWSVariableName, + VariableName, ), capitest.VariableWithValue( "builtin", @@ -172,5 +95,17 @@ func TestWorkerGeneratePatches( }, }, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/cni/calico/tests/generate_patches.go b/pkg/handlers/aws/mutation/cni/calico/inject_test.go similarity index 89% rename from pkg/handlers/aws/mutation/cni/calico/tests/generate_patches.go rename to pkg/handlers/aws/mutation/cni/calico/inject_test.go index d9bf7be65..2bba0f09f 100644 --- a/pkg/handlers/aws/mutation/cni/calico/tests/generate_patches.go +++ b/pkg/handlers/aws/mutation/cni/calico/inject_test.go @@ -1,13 +1,13 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package calico import ( "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" - "github.com/onsi/gomega/format" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" capav1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2" @@ -15,34 +15,33 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" ) -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() +func TestCalicoPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "AWS Calico CNI ingress mutator suite") +} - format.MaxLength = 0 - format.TruncatedDiff = false +var _ = Describe("Generate AWS Calico CNI ingress patches", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ + { Name: "provider set with AWSClusterTemplate", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.CNI{ Provider: v1alpha1.CNIProviderCalico, }, - variablePath..., + "addons", + v1alpha1.CNIVariableName, ), }, RequestItem: request.NewAWSClusterTemplateRequestItem("1234"), @@ -101,15 +100,16 @@ func TestGeneratePatches( ), }}, }, - capitest.PatchTestDef{ + { Name: "provider set with AWSClusterTemplate pre-existing rules", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.CNI{ Provider: v1alpha1.CNIProviderCalico, }, - variablePath..., + "addons", + v1alpha1.CNIVariableName, ), }, RequestItem: request.NewAWSClusterTemplateRequestItem( @@ -193,15 +193,16 @@ func TestGeneratePatches( ), }}, }, - capitest.PatchTestDef{ + { Name: "provider set with AWSClusterTemplate conflicting pre-existing rules", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.CNI{ Provider: v1alpha1.CNIProviderCalico, }, - variablePath..., + "addons", + v1alpha1.CNIVariableName, ), }, RequestItem: request.NewAWSClusterTemplateRequestItem( @@ -273,5 +274,17 @@ func TestGeneratePatches( ), }}, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/controlplaneloadbalancer/tests/generate_patches.go b/pkg/handlers/aws/mutation/controlplaneloadbalancer/inject_test.go similarity index 65% rename from pkg/handlers/aws/mutation/controlplaneloadbalancer/tests/generate_patches.go rename to pkg/handlers/aws/mutation/controlplaneloadbalancer/inject_test.go index f799d0624..60a5c4ec5 100644 --- a/pkg/handlers/aws/mutation/controlplaneloadbalancer/tests/generate_patches.go +++ b/pkg/handlers/aws/mutation/controlplaneloadbalancer/inject_test.go @@ -1,11 +1,12 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package controlplaneloadbalancer import ( "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -14,31 +15,33 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" ) -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() +func TestControlPlaneLoadBalancerPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "AWS ControlPlane LoadBalancer mutator suite") +} + +var _ = Describe("Generate AWS ControlPlane LoadBalancer patches", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ + { Name: "ControlPlaneLoadbalancer scheme set to internet-facing", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.AWSLoadBalancerSpec{ Scheme: &capav1.ELBSchemeInternetFacing, }, - variablePath..., + v1alpha1.AWSVariableName, + VariableName, ), }, RequestItem: request.NewAWSClusterTemplateRequestItem("1234"), @@ -50,15 +53,16 @@ func TestGeneratePatches( ), }}, }, - capitest.PatchTestDef{ + { Name: "ControlPlaneLoadbalancer scheme set to internal", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.AWSLoadBalancerSpec{ Scheme: &capav1.ELBSchemeInternal, }, - variablePath..., + v1alpha1.AWSVariableName, + VariableName, ), }, RequestItem: request.NewAWSClusterTemplateRequestItem("1234"), @@ -70,5 +74,17 @@ func TestGeneratePatches( ), }}, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/iaminstanceprofile/inject_control_plane_test.go b/pkg/handlers/aws/mutation/iaminstanceprofile/inject_control_plane_test.go new file mode 100644 index 000000000..11d7b0ed9 --- /dev/null +++ b/pkg/handlers/aws/mutation/iaminstanceprofile/inject_control_plane_test.go @@ -0,0 +1,58 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package iaminstanceprofile + +import ( + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +var _ = Describe("Generate IAMInstanceProfile patches for ControlPlane", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewControlPlanePatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "unset variable", + }, + { + Name: "iamInstanceProfile for control plane set", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + "control-plane.cluster-api-provider-aws.sigs.k8s.io", + clusterconfig.MetaControlPlaneConfigName, + v1alpha1.AWSVariableName, + VariableName, + ), + }, + RequestItem: request.NewCPAWSMachineTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/iamInstanceProfile", + ValueMatcher: gomega.Equal("control-plane.cluster-api-provider-aws.sigs.k8s.io"), + }}, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/iaminstanceprofile/inject_suite_test.go b/pkg/handlers/aws/mutation/iaminstanceprofile/inject_suite_test.go new file mode 100644 index 000000000..6cf5402dc --- /dev/null +++ b/pkg/handlers/aws/mutation/iaminstanceprofile/inject_suite_test.go @@ -0,0 +1,16 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package iaminstanceprofile + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestIAMInstnaceProfilePatch(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "IAMInstanceProfile patches for ControlPlane and Workers suite") +} diff --git a/pkg/handlers/aws/mutation/iaminstanceprofile/tests/generate_patches.go b/pkg/handlers/aws/mutation/iaminstanceprofile/inject_worker_test.go similarity index 50% rename from pkg/handlers/aws/mutation/iaminstanceprofile/tests/generate_patches.go rename to pkg/handlers/aws/mutation/iaminstanceprofile/inject_worker_test.go index 6f36d196f..a3044de6d 100644 --- a/pkg/handlers/aws/mutation/iaminstanceprofile/tests/generate_patches.go +++ b/pkg/handlers/aws/mutation/iaminstanceprofile/inject_worker_test.go @@ -1,74 +1,38 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package iaminstanceprofile import ( - "testing" - + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" ) -func TestControlPlaneGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() +var _ = Describe("Generate IAMInstanceProfile patches for Worker", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewWorkerPatch()).(mutation.GeneratePatches) + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ - Name: "iamInstanceProfile set", + { + Name: "iamInstanceProfile for worker set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, - "control-plane.cluster-api-provider-aws.sigs.k8s.io", - variablePath..., - ), - }, - RequestItem: request.NewCPAWSMachineTemplateRequestItem("1234"), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/iamInstanceProfile", - ValueMatcher: gomega.Equal("control-plane.cluster-api-provider-aws.sigs.k8s.io"), - }}, - }, - ) -} - -func TestWorkerGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "unset variable", - }, - capitest.PatchTestDef{ - Name: "iamInstanceProfile set", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, + workerconfig.MetaVariableName, "nodes.cluster-api-provider-aws.sigs.k8s.io", - variablePath..., + v1alpha1.AWSVariableName, + VariableName, ), capitest.VariableWithValue( "builtin", @@ -84,5 +48,17 @@ func TestWorkerGeneratePatches( ValueMatcher: gomega.Equal("nodes.cluster-api-provider-aws.sigs.k8s.io"), }}, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/instancetype/inject_control_plane_test.go b/pkg/handlers/aws/mutation/instancetype/inject_control_plane_test.go new file mode 100644 index 000000000..e13189a47 --- /dev/null +++ b/pkg/handlers/aws/mutation/instancetype/inject_control_plane_test.go @@ -0,0 +1,58 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package instancetype + +import ( + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +var _ = Describe("Generate InstanceType patches for ControlPlane", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewControlPlanePatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "unset variable", + }, + { + Name: "instanceType for controlplane set", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + "m5.xlarge", + clusterconfig.MetaControlPlaneConfigName, + v1alpha1.AWSVariableName, + VariableName, + ), + }, + RequestItem: request.NewCPAWSMachineTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "replace", + Path: "/spec/template/spec/instanceType", + ValueMatcher: gomega.Equal("m5.xlarge"), + }}, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/instancetype/inject_suite_test.go b/pkg/handlers/aws/mutation/instancetype/inject_suite_test.go new file mode 100644 index 000000000..393d232d7 --- /dev/null +++ b/pkg/handlers/aws/mutation/instancetype/inject_suite_test.go @@ -0,0 +1,16 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package instancetype + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestInstanceTypePatch(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "InstanceType patches for ControlPlane and Workers suite") +} diff --git a/pkg/handlers/aws/mutation/instancetype/tests/generate_patches.go b/pkg/handlers/aws/mutation/instancetype/inject_worker_test.go similarity index 50% rename from pkg/handlers/aws/mutation/instancetype/tests/generate_patches.go rename to pkg/handlers/aws/mutation/instancetype/inject_worker_test.go index ef9959535..03cbec647 100644 --- a/pkg/handlers/aws/mutation/instancetype/tests/generate_patches.go +++ b/pkg/handlers/aws/mutation/instancetype/inject_worker_test.go @@ -1,74 +1,38 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package instancetype import ( - "testing" - + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" ) -func TestControlPlaneGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() +var _ = Describe("Generate InstanceType patches for Worker", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewWorkerPatch()).(mutation.GeneratePatches) + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ - Name: "instanceType set", + { + Name: "instanceType for workers set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, - "m5.xlarge", - variablePath..., - ), - }, - RequestItem: request.NewCPAWSMachineTemplateRequestItem("1234"), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "replace", - Path: "/spec/template/spec/instanceType", - ValueMatcher: gomega.Equal("m5.xlarge"), - }}, - }, - ) -} - -func TestWorkerGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "unset variable", - }, - capitest.PatchTestDef{ - Name: "instanceType set", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, + workerconfig.MetaVariableName, "m5.2xlarge", - variablePath..., + v1alpha1.AWSVariableName, + VariableName, ), capitest.VariableWithValue( "builtin", @@ -84,5 +48,17 @@ func TestWorkerGeneratePatches( ValueMatcher: gomega.Equal("m5.2xlarge"), }}, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/metapatch_handler_test.go b/pkg/handlers/aws/mutation/metapatch_handler_test.go deleted file mode 100644 index f8c7f1c0f..000000000 --- a/pkg/handlers/aws/mutation/metapatch_handler_test.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2023 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package mutation - -import ( - "testing" - - "sigs.k8s.io/controller-runtime/pkg/manager" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/ami" - amitests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/ami/tests" - calicotests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/cni/calico/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/controlplaneloadbalancer" - controlplaneloadbalancertests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/controlplaneloadbalancer/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/iaminstanceprofile" - iaminstanceprofiletests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/iaminstanceprofile/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/instancetype" - instancetypetests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/instancetype/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/network" - networktests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/network/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/region" - regiontests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/region/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" - auditpolicytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/auditpolicy/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/etcd" - etcdtests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/etcd/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/extraapiservercertsans" - extraapiservercertsanstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/extraapiservercertsans/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy" - httpproxytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/imageregistries" - imageregistrycredentialstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/imageregistries/credentials/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository" - kubernetesimagerepositorytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors" - globalimageregistrymirrortests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/users" - userstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/users/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" -) - -func metaPatchGeneratorFunc(mgr manager.Manager) func() mutation.GeneratePatches { - return func() mutation.GeneratePatches { - return MetaPatchHandler(mgr).(mutation.GeneratePatches) - } -} - -func workerPatchGeneratorFunc() func() mutation.GeneratePatches { - return func() mutation.GeneratePatches { - return MetaWorkerPatchHandler().(mutation.GeneratePatches) - } -} - -func TestGeneratePatches(t *testing.T) { - t.Parallel() - - mgr := testEnv.Manager - - regiontests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - v1alpha1.AWSVariableName, - region.VariableName, - ) - - iaminstanceprofiletests.TestControlPlaneGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - clusterconfig.MetaControlPlaneConfigName, - v1alpha1.AWSVariableName, - iaminstanceprofile.VariableName, - ) - - iaminstanceprofiletests.TestWorkerGeneratePatches( - t, - workerPatchGeneratorFunc(), - workerconfig.MetaVariableName, - v1alpha1.AWSVariableName, - iaminstanceprofile.VariableName, - ) - - instancetypetests.TestControlPlaneGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - clusterconfig.MetaControlPlaneConfigName, - v1alpha1.AWSVariableName, - instancetype.VariableName, - ) - - instancetypetests.TestWorkerGeneratePatches( - t, - workerPatchGeneratorFunc(), - workerconfig.MetaVariableName, - v1alpha1.AWSVariableName, - instancetype.VariableName, - ) - - calicotests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - "addons", - v1alpha1.CNIVariableName, - ) - - auditpolicytests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - ) - - httpproxytests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - httpproxy.VariableName, - ) - - etcdtests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - etcd.VariableName, - ) - - extraapiservercertsanstests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - extraapiservercertsans.VariableName, - ) - - kubernetesimagerepositorytests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - kubernetesimagerepository.VariableName, - ) - - imageregistrycredentialstests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - mgr.GetClient(), - clusterconfig.MetaVariableName, - imageregistries.VariableName, - ) - - globalimageregistrymirrortests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - mgr.GetClient(), - clusterconfig.MetaVariableName, - mirrors.GlobalMirrorVariableName, - ) - - amitests.TestControlPlaneGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - clusterconfig.MetaControlPlaneConfigName, - v1alpha1.AWSVariableName, - ami.VariableName, - ) - - amitests.TestWorkerGeneratePatches( - t, - workerPatchGeneratorFunc(), - workerconfig.MetaVariableName, - v1alpha1.AWSVariableName, - ami.VariableName, - ) - - networktests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - v1alpha1.AWSVariableName, - network.VariableName, - ) - - controlplaneloadbalancertests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - v1alpha1.AWSVariableName, - controlplaneloadbalancer.VariableName, - ) - - userstests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - users.VariableName, - ) -} diff --git a/pkg/handlers/aws/mutation/network/tests/generate_patches.go b/pkg/handlers/aws/mutation/network/inject_test.go similarity index 69% rename from pkg/handlers/aws/mutation/network/tests/generate_patches.go rename to pkg/handlers/aws/mutation/network/inject_test.go index 09dcdfd78..f91185cf3 100644 --- a/pkg/handlers/aws/mutation/network/tests/generate_patches.go +++ b/pkg/handlers/aws/mutation/network/inject_test.go @@ -1,11 +1,12 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package network import ( "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -13,33 +14,35 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" ) -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() +func TestNetworkPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "AWS Network mutator suite") +} + +var _ = Describe("Generate AWS Network patches", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ + { Name: "VPC ID set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.AWSNetwork{ VPC: &v1alpha1.VPC{ ID: "vpc-1234", }, }, - variablePath..., + v1alpha1.AWSVariableName, + VariableName, ), }, RequestItem: request.NewAWSClusterTemplateRequestItem("1234"), @@ -49,11 +52,11 @@ func TestGeneratePatches( ValueMatcher: gomega.Equal("vpc-1234"), }}, }, - capitest.PatchTestDef{ + { Name: "Subnet IDs set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.AWSNetwork{ Subnets: v1alpha1.Subnets{ {ID: "subnet-1"}, @@ -61,7 +64,8 @@ func TestGeneratePatches( {ID: "subnet-3"}, }, }, - variablePath..., + v1alpha1.AWSVariableName, + VariableName, ), }, RequestItem: request.NewAWSClusterTemplateRequestItem("1234"), @@ -71,11 +75,11 @@ func TestGeneratePatches( ValueMatcher: gomega.HaveLen(3), }}, }, - capitest.PatchTestDef{ + { Name: "both VPC ID and Subnet IDs set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.AWSNetwork{ VPC: &v1alpha1.VPC{ ID: "vpc-1234", @@ -86,7 +90,8 @@ func TestGeneratePatches( {ID: "subnet-3"}, }, }, - variablePath..., + v1alpha1.AWSVariableName, + VariableName, ), }, RequestItem: request.NewAWSClusterTemplateRequestItem("1234"), @@ -100,5 +105,17 @@ func TestGeneratePatches( ValueMatcher: gomega.HaveLen(3), }}, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/region/inject_test.go b/pkg/handlers/aws/mutation/region/inject_test.go index 4f76e95ea..d38da4eda 100644 --- a/pkg/handlers/aws/mutation/region/inject_test.go +++ b/pkg/handlers/aws/mutation/region/inject_test.go @@ -7,16 +7,18 @@ import ( "testing" . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" + "github.com/onsi/gomega" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" - regiontests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/region/tests" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" ) func TestRegionPatch(t *testing.T) { - RegisterFailHandler(Fail) + gomega.RegisterFailHandler(Fail) RunSpecs(t, "AWS Region mutator suite") } @@ -25,11 +27,39 @@ var _ = Describe("Generate AWS Region patches", func() { patchGenerator := func() mutation.GeneratePatches { return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) } - regiontests.TestGeneratePatches( - GinkgoT(), - patchGenerator, - clusterconfig.MetaVariableName, - v1alpha1.AWSVariableName, - VariableName, - ) + + testDefs := []capitest.PatchTestDef{ + { + Name: "unset variable", + }, + { + Name: "region set", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + "a-specific-region", + v1alpha1.AWSVariableName, + VariableName, + ), + }, + RequestItem: request.NewAWSClusterTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/region", + ValueMatcher: gomega.Equal("a-specific-region"), + }}, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } }) diff --git a/pkg/handlers/aws/mutation/region/tests/generate_patches.go b/pkg/handlers/aws/mutation/region/tests/generate_patches.go deleted file mode 100644 index 883d603c5..000000000 --- a/pkg/handlers/aws/mutation/region/tests/generate_patches.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2023 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package tests - -import ( - . "github.com/onsi/ginkgo/v2" - "github.com/onsi/gomega" - runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" -) - -func TestGeneratePatches( - t GinkgoTInterface, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "unset variable", - }, - capitest.PatchTestDef{ - Name: "region set", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - "a-specific-region", - variablePath..., - ), - }, - RequestItem: request.NewAWSClusterTemplateRequestItem("1234"), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/region", - ValueMatcher: gomega.Equal("a-specific-region"), - }}, - }, - ) -} diff --git a/pkg/handlers/aws/mutation/securitygroups/inject_control_plane_test.go b/pkg/handlers/aws/mutation/securitygroups/inject_control_plane_test.go new file mode 100644 index 000000000..8c67e96f2 --- /dev/null +++ b/pkg/handlers/aws/mutation/securitygroups/inject_control_plane_test.go @@ -0,0 +1,75 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package securitygroups + +import ( + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + "k8s.io/utils/ptr" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +var _ = Describe("Generate SecurityGroup patches for ControlPlane", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewControlPlanePatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "unset variable", + }, + { + Name: "SecurityGroups for controlplane set", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.AdditionalSecurityGroup{ + {ID: ptr.To("sg-1")}, + {ID: ptr.To("sg-2")}, + {ID: ptr.To("sg-3")}, + }, + clusterconfig.MetaControlPlaneConfigName, + v1alpha1.AWSVariableName, + VariableName, + ), + }, + RequestItem: request.NewCPAWSMachineTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/additionalSecurityGroups", + ValueMatcher: gomega.HaveLen(3), + }, + // TODO(shalinpatel): add matcher to check if all SG are set + // { + // Operation: "add", + // Path: "/spec/template/spec/additionalSecurityGroups", + // ValueMatcher: gomega.ContainElements( + // gomega.HaveKeyWithValue("id", "sg-1"), + // gomega.HaveKeyWithValue("id", "sg-2"), + // gomega.HaveKeyWithValue("id", "sg-3"), + // ), + // }, + }, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/securitygroups/inject_suite_test.go b/pkg/handlers/aws/mutation/securitygroups/inject_suite_test.go new file mode 100644 index 000000000..09ae3ad05 --- /dev/null +++ b/pkg/handlers/aws/mutation/securitygroups/inject_suite_test.go @@ -0,0 +1,16 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package securitygroups + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestSecurityGroupsPatch(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "AWS security groups patches for ControlPlane and Workers suite") +} diff --git a/pkg/handlers/aws/mutation/securitygroups/inject_worker_test.go b/pkg/handlers/aws/mutation/securitygroups/inject_worker_test.go new file mode 100644 index 000000000..2e4d90844 --- /dev/null +++ b/pkg/handlers/aws/mutation/securitygroups/inject_worker_test.go @@ -0,0 +1,81 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package securitygroups + +import ( + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/utils/ptr" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" +) + +var _ = Describe("Generate AWS SecurityGroups patches for Worker", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewWorkerPatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "unset variable", + }, + { + Name: "SecurityGroups for workers set", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + workerconfig.MetaVariableName, + v1alpha1.AdditionalSecurityGroup{ + {ID: ptr.To("sg-1")}, + {ID: ptr.To("sg-2")}, + {ID: ptr.To("sg-3")}, + }, + v1alpha1.AWSVariableName, + VariableName, + ), + capitest.VariableWithValue( + "builtin", + apiextensionsv1.JSON{ + Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), + }, + ), + }, + RequestItem: request.NewWorkerAWSMachineTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/additionalSecurityGroups", + ValueMatcher: gomega.HaveLen(3), + }, + // TODO(shalinpatel): add matcher to check if all SG are set + // { + // Operation: "add", + // Path: "/spec/template/spec/additionalSecurityGroups", + // ValueMatcher: gomega.ContainElements( + // gomega.HaveKeyWithValue("id", "sg-1"), + // gomega.HaveKeyWithValue("id", "sg-2"), + // gomega.HaveKeyWithValue("id", "sg-3"), + // ), + // }, + }, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/aws/mutation/suite_test.go b/pkg/handlers/aws/mutation/suite_test.go deleted file mode 100644 index 5188c91c7..000000000 --- a/pkg/handlers/aws/mutation/suite_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2024 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package mutation - -import ( - "context" - "fmt" - "testing" - - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/test/helpers" -) - -var ( - testEnv *helpers.TestEnvironment - ctx = ctrl.SetupSignalHandler() -) - -func TestMain(m *testing.M) { - setupCtx, cancel := context.WithCancel(ctx) - setup(setupCtx) - defer teardown(cancel) - m.Run() -} - -func setup(ctx context.Context) { - testEnvConfig := helpers.NewTestEnvironmentConfiguration() - var err error - testEnv, err = testEnvConfig.Build() - if err != nil { - panic(err) - } - go func() { - fmt.Println("Starting the manager") - if err := testEnv.StartManager(ctx); err != nil { - panic(fmt.Sprintf("Failed to start the envtest manager: %v", err)) - } - }() -} - -func teardown(cancel context.CancelFunc) { - cancel() - if err := testEnv.Stop(); err != nil { - panic(fmt.Sprintf("Failed to stop envtest: %v", err)) - } -} diff --git a/pkg/handlers/docker/mutation/customimage/inject_control_plane_test.go b/pkg/handlers/docker/mutation/customimage/inject_control_plane_test.go new file mode 100644 index 000000000..fa40cbd5d --- /dev/null +++ b/pkg/handlers/docker/mutation/customimage/inject_control_plane_test.go @@ -0,0 +1,77 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package customimage + +import ( + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + dockerclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/docker/clusterconfig" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" +) + +var _ = Describe("Docker CustomImage patches for ControlPlane", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewControlPlanePatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "image unset for control plane", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + "builtin", + apiextensionsv1.JSON{Raw: []byte(`{"controlPlane": {"version": "v1.2.3"}}`)}, + ), + }, + RequestItem: request.NewCPDockerMachineTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/customImage", + ValueMatcher: gomega.Equal("ghcr.io/mesosphere/kind-node:v1.2.3"), + }}, + }, + { + Name: "image set for control plane", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + "a-specific-image", + clusterconfig.MetaControlPlaneConfigName, + dockerclusterconfig.DockerVariableName, + VariableName, + ), + capitest.VariableWithValue( + "builtin", + apiextensionsv1.JSON{ + Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), + }, + ), + }, + RequestItem: request.NewCPDockerMachineTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/customImage", + ValueMatcher: gomega.Equal("a-specific-image"), + }}, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/docker/mutation/customimage/inject_suite_test.go b/pkg/handlers/docker/mutation/customimage/inject_suite_test.go new file mode 100644 index 000000000..9f17edd7c --- /dev/null +++ b/pkg/handlers/docker/mutation/customimage/inject_suite_test.go @@ -0,0 +1,16 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package customimage + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestCustomImagePatch(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Docker CustomImage patches for ControlPlane and Workers suite") +} diff --git a/pkg/handlers/docker/mutation/customimage/inject_worker_test.go b/pkg/handlers/docker/mutation/customimage/inject_worker_test.go new file mode 100644 index 000000000..b13f582d7 --- /dev/null +++ b/pkg/handlers/docker/mutation/customimage/inject_worker_test.go @@ -0,0 +1,80 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package customimage + +import ( + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + dockerworkerconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/docker/workerconfig" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" +) + +var _ = Describe("Docker CustomImage patches for workers", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewWorkerPatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "image unset for workers", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + "builtin", + apiextensionsv1.JSON{ + Raw: []byte( + `{"machineDeployment": {"class": "a-worker", "version": "v1.2.3"}}`, + ), + }, + ), + }, + RequestItem: request.NewWorkerDockerMachineTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/customImage", + ValueMatcher: gomega.Equal("ghcr.io/mesosphere/kind-node:v1.2.3"), + }}, + }, + { + Name: "image set for workers", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + workerconfig.MetaVariableName, + "a-specific-image", + dockerworkerconfig.DockerVariableName, + VariableName, + ), + capitest.VariableWithValue( + "builtin", + apiextensionsv1.JSON{ + Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), + }, + ), + }, + RequestItem: request.NewWorkerDockerMachineTemplateRequestItem("1234"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/customImage", + ValueMatcher: gomega.Equal("a-specific-image"), + }}, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/docker/mutation/customimage/tests/generate_patches.go b/pkg/handlers/docker/mutation/customimage/tests/generate_patches.go deleted file mode 100644 index 7b1b9b6e4..000000000 --- a/pkg/handlers/docker/mutation/customimage/tests/generate_patches.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2023 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package tests - -import ( - "testing" - - "github.com/onsi/gomega" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" -) - -func TestControlPlaneGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "image unset for control plane", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - "builtin", - apiextensionsv1.JSON{Raw: []byte(`{"controlPlane": {"version": "v1.2.3"}}`)}, - ), - }, - RequestItem: request.NewCPDockerMachineTemplateRequestItem("1234"), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/customImage", - ValueMatcher: gomega.Equal("ghcr.io/mesosphere/kind-node:v1.2.3"), - }}, - }, - capitest.PatchTestDef{ - Name: "image set for control plane", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - "a-specific-image", - variablePath..., - ), - capitest.VariableWithValue( - "builtin", - apiextensionsv1.JSON{ - Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), - }, - ), - }, - RequestItem: request.NewCPDockerMachineTemplateRequestItem("1234"), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/customImage", - ValueMatcher: gomega.Equal("a-specific-image"), - }}, - }, - ) -} - -func TestWorkerGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "image unset for workers", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - "builtin", - apiextensionsv1.JSON{ - Raw: []byte( - `{"machineDeployment": {"class": "a-worker", "version": "v1.2.3"}}`, - ), - }, - ), - }, - RequestItem: request.NewWorkerDockerMachineTemplateRequestItem("1234"), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/customImage", - ValueMatcher: gomega.Equal("ghcr.io/mesosphere/kind-node:v1.2.3"), - }}, - }, - capitest.PatchTestDef{ - Name: "image set for workers", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - "a-specific-image", - variablePath..., - ), - capitest.VariableWithValue( - "builtin", - apiextensionsv1.JSON{ - Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), - }, - ), - }, - RequestItem: request.NewWorkerDockerMachineTemplateRequestItem("1234"), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/customImage", - ValueMatcher: gomega.Equal("a-specific-image"), - }}, - }, - ) -} diff --git a/pkg/handlers/docker/mutation/metapatch_handler_test.go b/pkg/handlers/docker/mutation/metapatch_handler_test.go deleted file mode 100644 index cdcd81994..000000000 --- a/pkg/handlers/docker/mutation/metapatch_handler_test.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2023 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package mutation - -import ( - "testing" - - "sigs.k8s.io/controller-runtime/pkg/manager" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" - dockerclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/docker/clusterconfig" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/docker/mutation/customimage" - customimagetests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/docker/mutation/customimage/tests" - dockerworkerconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/docker/workerconfig" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" - auditpolicytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/auditpolicy/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/etcd" - etcdtests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/etcd/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/extraapiservercertsans" - extraapiservercertsanstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/extraapiservercertsans/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy" - httpproxytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/imageregistries" - imageregistrycredentialstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/imageregistries/credentials/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository" - kubernetesimagerepositorytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors" - globalimageregistrymirrortests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/users" - userstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/users/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" -) - -func metaPatchGeneratorFunc(mgr manager.Manager) func() mutation.GeneratePatches { - return func() mutation.GeneratePatches { - return MetaPatchHandler(mgr).(mutation.GeneratePatches) - } -} - -func workerPatchGeneratorFunc() func() mutation.GeneratePatches { - return func() mutation.GeneratePatches { - return MetaWorkerPatchHandler().(mutation.GeneratePatches) - } -} - -func TestGeneratePatches(t *testing.T) { - t.Parallel() - - mgr := testEnv.Manager - - customimagetests.TestControlPlaneGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - clusterconfig.MetaControlPlaneConfigName, - dockerclusterconfig.DockerVariableName, - customimage.VariableName, - ) - - customimagetests.TestWorkerGeneratePatches( - t, - workerPatchGeneratorFunc(), - workerconfig.MetaVariableName, - dockerworkerconfig.DockerVariableName, - customimage.VariableName, - ) - - auditpolicytests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - ) - - httpproxytests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - httpproxy.VariableName, - ) - - etcdtests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - etcd.VariableName, - ) - - extraapiservercertsanstests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - extraapiservercertsans.VariableName, - ) - - kubernetesimagerepositorytests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - kubernetesimagerepository.VariableName, - ) - - imageregistrycredentialstests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - mgr.GetClient(), - clusterconfig.MetaVariableName, - imageregistries.VariableName, - ) - - globalimageregistrymirrortests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - mgr.GetClient(), - clusterconfig.MetaVariableName, - mirrors.GlobalMirrorVariableName, - ) - - userstests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - users.VariableName, - ) -} diff --git a/pkg/handlers/docker/mutation/suite_test.go b/pkg/handlers/docker/mutation/suite_test.go deleted file mode 100644 index 5188c91c7..000000000 --- a/pkg/handlers/docker/mutation/suite_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2024 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package mutation - -import ( - "context" - "fmt" - "testing" - - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/test/helpers" -) - -var ( - testEnv *helpers.TestEnvironment - ctx = ctrl.SetupSignalHandler() -) - -func TestMain(m *testing.M) { - setupCtx, cancel := context.WithCancel(ctx) - setup(setupCtx) - defer teardown(cancel) - m.Run() -} - -func setup(ctx context.Context) { - testEnvConfig := helpers.NewTestEnvironmentConfiguration() - var err error - testEnv, err = testEnvConfig.Build() - if err != nil { - panic(err) - } - go func() { - fmt.Println("Starting the manager") - if err := testEnv.StartManager(ctx); err != nil { - panic(fmt.Sprintf("Failed to start the envtest manager: %v", err)) - } - }() -} - -func teardown(cancel context.CancelFunc) { - cancel() - if err := testEnv.Stop(); err != nil { - panic(fmt.Sprintf("Failed to stop envtest: %v", err)) - } -} diff --git a/pkg/handlers/generic/mutation/auditpolicy/tests/generate_patches.go b/pkg/handlers/generic/mutation/auditpolicy/inject_test.go similarity index 76% rename from pkg/handlers/generic/mutation/auditpolicy/tests/generate_patches.go rename to pkg/handlers/generic/mutation/auditpolicy/inject_test.go index 3380817f2..685707528 100644 --- a/pkg/handlers/generic/mutation/auditpolicy/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/auditpolicy/inject_test.go @@ -1,11 +1,12 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package auditpolicy import ( "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" @@ -13,18 +14,21 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" ) -func TestGeneratePatches( - t *testing.T, generatorFunc func() mutation.GeneratePatches, -) { - t.Helper() +func TestAuditPolicyPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "Audit Policy mutator suite") +} + +var _ = Describe("Generate Audit Policy patches", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ + { Name: "auditpolicy set for KubeadmControlPlaneTemplate", RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ @@ -71,5 +75,13 @@ func TestGeneratePatches( ), }}, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches(GinkgoT(), patchGenerator, &tt) + }) + } +}) diff --git a/pkg/handlers/generic/mutation/etcd/tests/generate_patches.go b/pkg/handlers/generic/mutation/etcd/inject_test.go similarity index 76% rename from pkg/handlers/generic/mutation/etcd/tests/generate_patches.go rename to pkg/handlers/generic/mutation/etcd/inject_test.go index 833a86ede..f71925b33 100644 --- a/pkg/handlers/generic/mutation/etcd/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/etcd/inject_test.go @@ -1,11 +1,12 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package etcd import ( "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -13,34 +14,35 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" ) -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() +func TestEtcdPolicyPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "etcd mutator suite") +} + +var _ = Describe("Generate etcd patches", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ + { Name: "etcd imageRepository and imageTag set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.Etcd{ Image: &v1alpha1.Image{ Repository: "my-registry.io/my-org/my-repo", Tag: "v3.5.99_custom.0", }, }, - variablePath..., + VariableName, ), }, RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), @@ -60,17 +62,17 @@ func TestGeneratePatches( }, }, }, - capitest.PatchTestDef{ + { Name: "etcd imageRepository set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.Etcd{ Image: &v1alpha1.Image{ Repository: "my-registry.io/my-org/my-repo", }, }, - variablePath..., + VariableName, ), }, RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), @@ -89,17 +91,17 @@ func TestGeneratePatches( }, }, }, - capitest.PatchTestDef{ + { Name: "etcd imageTag set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.Etcd{ Image: &v1alpha1.Image{ Tag: "v3.5.99_custom.0", }, }, - variablePath..., + VariableName, ), }, RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), @@ -118,5 +120,13 @@ func TestGeneratePatches( }, }, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches(GinkgoT(), patchGenerator, &tt) + }) + } +}) diff --git a/pkg/handlers/generic/mutation/extraapiservercertsans/tests/generate_patches.go b/pkg/handlers/generic/mutation/extraapiservercertsans/inject_test.go similarity index 60% rename from pkg/handlers/generic/mutation/extraapiservercertsans/tests/generate_patches.go rename to pkg/handlers/generic/mutation/extraapiservercertsans/inject_test.go index d70beb7ad..3c4cb3745 100644 --- a/pkg/handlers/generic/mutation/extraapiservercertsans/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/extraapiservercertsans/inject_test.go @@ -1,11 +1,12 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package extraapiservercertsans import ( "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -13,29 +14,30 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" ) -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ +func TestExtraAPIServerCertSANsPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "Extra API server certificate mutator suite") +} + +var _ = Describe("Generate Extra API server certificate patches", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ + { Name: "extra API server cert SANs set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.ExtraAPIServerCertSANs{"a.b.c.example.com", "d.e.f.example.com"}, - variablePath..., + VariableName, ), }, RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), @@ -51,5 +53,13 @@ func TestGeneratePatches( ), }}, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches(GinkgoT(), patchGenerator, &tt) + }) + } +}) diff --git a/pkg/handlers/generic/mutation/httpproxy/inject_test.go b/pkg/handlers/generic/mutation/httpproxy/inject_test.go index 13f183394..0b697397c 100644 --- a/pkg/handlers/generic/mutation/httpproxy/inject_test.go +++ b/pkg/handlers/generic/mutation/httpproxy/inject_test.go @@ -9,11 +9,15 @@ import ( . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" v1 "k8s.io/api/core/v1" + "k8s.io/apiserver/pkg/storage/names" capiv1 "sigs.k8s.io/cluster-api/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" - httpproxy "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy/tests" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/test/helpers" ) @@ -201,10 +205,83 @@ var _ = Describe("Generate HTTPProxy Patches", func() { "", NewPatch(testEnv.Client)).(mutation.GeneratePatches) } - httpproxy.TestGeneratePatches( - GinkgoT(), - patchGenerator, - clusterconfig.MetaVariableName, - VariableName, - ) + + testDefs := []capitest.PatchTestDef{ + { + Name: "unset variable", + }, + { + Name: "http proxy set for KubeadmConfigTemplate generic worker", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.HTTPProxy{ + HTTP: "http://example.com", + HTTPS: "https://example.com", + AdditionalNo: []string{"no-proxy.example.com"}, + }, + VariableName, + ), + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": names.SimpleNameGenerator.GenerateName("worker-"), + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/systemd/system/containerd.service.d/http-proxy.conf", + ), + gomega.HaveKeyWithValue( + "path", "/etc/systemd/system/kubelet.service.d/http-proxy.conf", + ), + ), + }}, + }, + { + Name: "http proxy set for KubeadmControlPlaneTemplate", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.HTTPProxy{ + HTTP: "http://example.com", + HTTPS: "https://example.com", + AdditionalNo: []string{"no-proxy.example.com"}, + }, + VariableName, + ), + }, + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/systemd/system/containerd.service.d/http-proxy.conf", + ), + gomega.HaveKeyWithValue( + "path", "/etc/systemd/system/kubelet.service.d/http-proxy.conf", + ), + ), + }}, + }, + } + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } }) diff --git a/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go b/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go deleted file mode 100644 index 302cc96d3..000000000 --- a/pkg/handlers/generic/mutation/httpproxy/tests/generate_patches.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2023 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package tests - -import ( - . "github.com/onsi/ginkgo/v2" - "github.com/onsi/gomega" - "k8s.io/apiserver/pkg/storage/names" - runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" -) - -func TestGeneratePatches( - t GinkgoTInterface, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "unset variable", - }, - capitest.PatchTestDef{ - Name: "http proxy set for KubeadmConfigTemplate generic worker", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.HTTPProxy{ - HTTP: "http://example.com", - HTTPS: "https://example.com", - AdditionalNo: []string{"no-proxy.example.com"}, - }, - variablePath..., - ), - capitest.VariableWithValue( - "builtin", - map[string]any{ - "machineDeployment": map[string]any{ - "class": names.SimpleNameGenerator.GenerateName("worker-"), - }, - }, - ), - }, - RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/files", - ValueMatcher: gomega.ContainElements( - gomega.HaveKeyWithValue( - "path", "/etc/systemd/system/containerd.service.d/http-proxy.conf", - ), - gomega.HaveKeyWithValue( - "path", "/etc/systemd/system/kubelet.service.d/http-proxy.conf", - ), - ), - }}, - }, - capitest.PatchTestDef{ - Name: "http proxy set for KubeadmControlPlaneTemplate", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.HTTPProxy{ - HTTP: "http://example.com", - HTTPS: "https://example.com", - AdditionalNo: []string{"no-proxy.example.com"}, - }, - variablePath..., - ), - }, - RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/files", - ValueMatcher: gomega.ContainElements( - gomega.HaveKeyWithValue( - "path", "/etc/systemd/system/containerd.service.d/http-proxy.conf", - ), - gomega.HaveKeyWithValue( - "path", "/etc/systemd/system/kubelet.service.d/http-proxy.conf", - ), - ), - }}, - }, - ) -} diff --git a/pkg/handlers/generic/mutation/imageregistries/credentials/inject_test.go b/pkg/handlers/generic/mutation/imageregistries/credentials/inject_test.go index e51af2b70..76498969e 100644 --- a/pkg/handlers/generic/mutation/imageregistries/credentials/inject_test.go +++ b/pkg/handlers/generic/mutation/imageregistries/credentials/inject_test.go @@ -6,7 +6,26 @@ package credentials import ( "testing" + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apiserver/pkg/storage/names" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/imageregistries" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/test/helpers" +) + +const ( + validSecretName = "myregistry-credentials" + registryStaticCredentialsSecretSuffix = "registry-creds" ) func Test_needImageRegistryCredentialsConfiguration(t *testing.T) { @@ -100,3 +119,330 @@ func Test_needImageRegistryCredentialsConfiguration(t *testing.T) { }) } } + +func TestImageRegistriesPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "Image registry mutator suite") +} + +var _ = Describe("Generate Image registry patches", func() { + patchGenerator := func() mutation.GeneratePatches { + // Always initialize the testEnv variable in the closure. + // This will allow ginkgo to initialize testEnv variable during test execution time. + testEnv := helpers.TestEnv + // use direct client instead of controller client. This will allow the patch handler to read k8s object + // that are written by the tests. + // Test cases writes credentials secret that the mutator handler reads. + // Using direct client will enable reading it immediately. + client, err := testEnv.GetK8sClient() + gomega.Expect(err).To(gomega.BeNil()) + return mutation.NewMetaGeneratePatchesHandler("", NewPatch(client)).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "unset variable", + }, + { + Name: "files added in KubeadmControlPlaneTemplate for ECR without a Secret", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.ImageRegistries{ + v1alpha1.ImageRegistry{ + URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com", + }, + }, + imageregistries.VariableName, + ), + }, + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/cre/install-kubelet-credential-providers.sh", + ), + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/image-credential-provider-config.yaml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/dynamic-credential-provider-config.yaml", + ), + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/preKubeadmCommands", + ValueMatcher: gomega.ContainElement( + "/bin/bash /etc/cre/install-kubelet-credential-providers.sh", + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/initConfiguration/nodeRegistration/kubeletExtraArgs", + ValueMatcher: gomega.HaveKeyWithValue( + "image-credential-provider-bin-dir", + "/etc/kubernetes/image-credential-provider/", + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/joinConfiguration/nodeRegistration/kubeletExtraArgs", + ValueMatcher: gomega.HaveKeyWithValue( + "image-credential-provider-config", + "/etc/kubernetes/image-credential-provider-config.yaml", + ), + }, + }, + }, + { + Name: "files added in KubeadmControlPlaneTemplate for registry with a Secret", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.ImageRegistries{ + v1alpha1.ImageRegistry{ + URL: "https://registry.example.com", + Credentials: &v1alpha1.RegistryCredentials{ + SecretRef: &corev1.LocalObjectReference{ + Name: validSecretName, + }, + }, + }, + }, + imageregistries.VariableName, + ), + }, + RequestItem: request.NewKubeadmControlPlaneTemplateRequest( + "", + "test-kubeadmconfigtemplate", + ), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/cre/install-kubelet-credential-providers.sh", + ), + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/image-credential-provider-config.yaml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/dynamic-credential-provider-config.yaml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/static-image-credentials.json", + ), + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/preKubeadmCommands", + ValueMatcher: gomega.ContainElement( + "/bin/bash /etc/cre/install-kubelet-credential-providers.sh", + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/initConfiguration/nodeRegistration/kubeletExtraArgs", + ValueMatcher: gomega.HaveKeyWithValue( + "image-credential-provider-bin-dir", + "/etc/kubernetes/image-credential-provider/", + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/joinConfiguration/nodeRegistration/kubeletExtraArgs", + ValueMatcher: gomega.HaveKeyWithValue( + "image-credential-provider-config", + "/etc/kubernetes/image-credential-provider-config.yaml", + ), + }, + }, + }, + { + Name: "files added in KubeadmConfigTemplate for ECR without a Secret", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.ImageRegistries{ + v1alpha1.ImageRegistry{ + URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com", + }, + }, + imageregistries.VariableName, + ), + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": names.SimpleNameGenerator.GenerateName("worker-"), + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/cre/install-kubelet-credential-providers.sh", + ), + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/image-credential-provider-config.yaml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/dynamic-credential-provider-config.yaml", + ), + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/preKubeadmCommands", + ValueMatcher: gomega.ContainElement( + "/bin/bash /etc/cre/install-kubelet-credential-providers.sh", + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/joinConfiguration/nodeRegistration/kubeletExtraArgs", + ValueMatcher: gomega.HaveKeyWithValue( + "image-credential-provider-bin-dir", + "/etc/kubernetes/image-credential-provider/", + ), + }, + }, + }, + { + Name: "files added in KubeadmConfigTemplate for registry with a Secret", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.ImageRegistries{ + v1alpha1.ImageRegistry{ + URL: "https://registry.example.com", + Credentials: &v1alpha1.RegistryCredentials{ + SecretRef: &corev1.LocalObjectReference{ + Name: validSecretName, + }, + }, + }, + }, + imageregistries.VariableName, + ), + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": names.SimpleNameGenerator.GenerateName("worker-"), + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequest("", "test-kubeadmconfigtemplate"), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", "/etc/cre/install-kubelet-credential-providers.sh", + ), + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/image-credential-provider-config.yaml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/dynamic-credential-provider-config.yaml", + ), + gomega.HaveKeyWithValue( + "path", "/etc/kubernetes/static-image-credentials.json", + ), + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/preKubeadmCommands", + ValueMatcher: gomega.ContainElement( + "/bin/bash /etc/cre/install-kubelet-credential-providers.sh", + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/joinConfiguration/nodeRegistration/kubeletExtraArgs", + ValueMatcher: gomega.HaveKeyWithValue( + "image-credential-provider-bin-dir", + "/etc/kubernetes/image-credential-provider/", + ), + }, + }, + }, + { + Name: "error for a registry with no credentials", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.ImageRegistries{ + v1alpha1.ImageRegistry{ + URL: "https://registry.example.com", + }, + }, + imageregistries.VariableName, + ), + }, + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + ExpectedFailure: true, + }, + } + + // Create credentials secret before each test + BeforeEach(func(ctx SpecContext) { + client, err := helpers.TestEnv.GetK8sClient() + gomega.Expect(err).To(gomega.BeNil()) + gomega.Expect(client.Create( + ctx, + newRegistryCredentialsSecret(validSecretName, request.Namespace), + )).To(gomega.BeNil()) + }) + + // Delete credentials secret after each test + AfterEach(func(ctx SpecContext) { + client, err := helpers.TestEnv.GetK8sClient() + gomega.Expect(err).To(gomega.BeNil()) + gomega.Expect(client.Delete( + ctx, + newRegistryCredentialsSecret(validSecretName, request.Namespace), + )).To(gomega.BeNil()) + }) + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches(GinkgoT(), patchGenerator, &tt) + }) + } +}) + +func newRegistryCredentialsSecret(name, namespace string) *corev1.Secret { + secretData := map[string][]byte{ + "username": []byte("myuser"), + "password": []byte("mypassword"), + } + return &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: namespace, + }, + Data: secretData, + Type: corev1.SecretTypeOpaque, + } +} diff --git a/pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_patches.go b/pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_patches.go deleted file mode 100644 index 05b797312..000000000 --- a/pkg/handlers/generic/mutation/imageregistries/credentials/tests/generate_patches.go +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright 2023 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package tests - -import ( - "context" - "testing" - - "github.com/onsi/gomega" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apiserver/pkg/storage/names" - runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" -) - -const ( - validSecretName = "myregistry-credentials" - registryStaticCredentialsSecretSuffix = "registry-creds" -) - -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - fakeClient client.Client, - variableName string, - variablePath ...string, -) { - t.Helper() - - require.NoError( - t, - fakeClient.Create( - context.Background(), - newRegistryCredentialsSecret(validSecretName, request.Namespace), - ), - ) - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "unset variable", - }, - capitest.PatchTestDef{ - Name: "files added in KubeadmControlPlaneTemplate for ECR without a Secret", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.ImageRegistries{ - v1alpha1.ImageRegistry{ - URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com", - }, - }, - variablePath..., - ), - }, - RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/files", - ValueMatcher: gomega.ContainElements( - gomega.HaveKeyWithValue( - "path", "/etc/cre/install-kubelet-credential-providers.sh", - ), - gomega.HaveKeyWithValue( - "path", "/etc/kubernetes/image-credential-provider-config.yaml", - ), - gomega.HaveKeyWithValue( - "path", "/etc/kubernetes/dynamic-credential-provider-config.yaml", - ), - ), - }, - { - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/preKubeadmCommands", - ValueMatcher: gomega.ContainElement( - "/bin/bash /etc/cre/install-kubelet-credential-providers.sh", - ), - }, - { - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/initConfiguration/nodeRegistration/kubeletExtraArgs", - ValueMatcher: gomega.HaveKeyWithValue( - "image-credential-provider-bin-dir", - "/etc/kubernetes/image-credential-provider/", - ), - }, - { - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/joinConfiguration/nodeRegistration/kubeletExtraArgs", - ValueMatcher: gomega.HaveKeyWithValue( - "image-credential-provider-config", - "/etc/kubernetes/image-credential-provider-config.yaml", - ), - }, - }, - }, - capitest.PatchTestDef{ - Name: "files added in KubeadmControlPlaneTemplate for registry with a Secret", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.ImageRegistries{ - v1alpha1.ImageRegistry{ - URL: "https://registry.example.com", - Credentials: &v1alpha1.RegistryCredentials{ - SecretRef: &corev1.LocalObjectReference{ - Name: validSecretName, - }, - }, - }, - }, - variablePath..., - ), - }, - RequestItem: request.NewKubeadmControlPlaneTemplateRequest( - "", - "test-kubeadmconfigtemplate", - ), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/files", - ValueMatcher: gomega.ContainElements( - gomega.HaveKeyWithValue( - "path", "/etc/cre/install-kubelet-credential-providers.sh", - ), - gomega.HaveKeyWithValue( - "path", "/etc/kubernetes/image-credential-provider-config.yaml", - ), - gomega.HaveKeyWithValue( - "path", "/etc/kubernetes/dynamic-credential-provider-config.yaml", - ), - gomega.HaveKeyWithValue( - "path", "/etc/kubernetes/static-image-credentials.json", - ), - ), - }, - { - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/preKubeadmCommands", - ValueMatcher: gomega.ContainElement( - "/bin/bash /etc/cre/install-kubelet-credential-providers.sh", - ), - }, - { - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/initConfiguration/nodeRegistration/kubeletExtraArgs", - ValueMatcher: gomega.HaveKeyWithValue( - "image-credential-provider-bin-dir", - "/etc/kubernetes/image-credential-provider/", - ), - }, - { - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/joinConfiguration/nodeRegistration/kubeletExtraArgs", - ValueMatcher: gomega.HaveKeyWithValue( - "image-credential-provider-config", - "/etc/kubernetes/image-credential-provider-config.yaml", - ), - }, - }, - }, - capitest.PatchTestDef{ - Name: "files added in KubeadmConfigTemplate for ECR without a Secret", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.ImageRegistries{ - v1alpha1.ImageRegistry{ - URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com", - }, - }, - variablePath..., - ), - capitest.VariableWithValue( - "builtin", - map[string]any{ - "machineDeployment": map[string]any{ - "class": names.SimpleNameGenerator.GenerateName("worker-"), - }, - }, - ), - }, - RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/files", - ValueMatcher: gomega.ContainElements( - gomega.HaveKeyWithValue( - "path", "/etc/cre/install-kubelet-credential-providers.sh", - ), - gomega.HaveKeyWithValue( - "path", "/etc/kubernetes/image-credential-provider-config.yaml", - ), - gomega.HaveKeyWithValue( - "path", "/etc/kubernetes/dynamic-credential-provider-config.yaml", - ), - ), - }, - { - Operation: "add", - Path: "/spec/template/spec/preKubeadmCommands", - ValueMatcher: gomega.ContainElement( - "/bin/bash /etc/cre/install-kubelet-credential-providers.sh", - ), - }, - { - Operation: "add", - Path: "/spec/template/spec/joinConfiguration/nodeRegistration/kubeletExtraArgs", - ValueMatcher: gomega.HaveKeyWithValue( - "image-credential-provider-bin-dir", - "/etc/kubernetes/image-credential-provider/", - ), - }, - }, - }, - capitest.PatchTestDef{ - Name: "files added in KubeadmConfigTemplate for registry with a Secret", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.ImageRegistries{ - v1alpha1.ImageRegistry{ - URL: "https://registry.example.com", - Credentials: &v1alpha1.RegistryCredentials{ - SecretRef: &corev1.LocalObjectReference{ - Name: validSecretName, - }, - }, - }, - }, - variablePath..., - ), - capitest.VariableWithValue( - "builtin", - map[string]any{ - "machineDeployment": map[string]any{ - "class": names.SimpleNameGenerator.GenerateName("worker-"), - }, - }, - ), - }, - RequestItem: request.NewKubeadmConfigTemplateRequest("", "test-kubeadmconfigtemplate"), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ - { - Operation: "add", - Path: "/spec/template/spec/files", - ValueMatcher: gomega.ContainElements( - gomega.HaveKeyWithValue( - "path", "/etc/cre/install-kubelet-credential-providers.sh", - ), - gomega.HaveKeyWithValue( - "path", "/etc/kubernetes/image-credential-provider-config.yaml", - ), - gomega.HaveKeyWithValue( - "path", "/etc/kubernetes/dynamic-credential-provider-config.yaml", - ), - gomega.HaveKeyWithValue( - "path", "/etc/kubernetes/static-image-credentials.json", - ), - ), - }, - { - Operation: "add", - Path: "/spec/template/spec/preKubeadmCommands", - ValueMatcher: gomega.ContainElement( - "/bin/bash /etc/cre/install-kubelet-credential-providers.sh", - ), - }, - { - Operation: "add", - Path: "/spec/template/spec/joinConfiguration/nodeRegistration/kubeletExtraArgs", - ValueMatcher: gomega.HaveKeyWithValue( - "image-credential-provider-bin-dir", - "/etc/kubernetes/image-credential-provider/", - ), - }, - }, - }, - capitest.PatchTestDef{ - Name: "error for a registry with no credentials", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - v1alpha1.ImageRegistries{ - v1alpha1.ImageRegistry{ - URL: "https://registry.example.com", - }, - }, - variablePath..., - ), - }, - RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), - ExpectedFailure: true, - }, - ) -} - -func newRegistryCredentialsSecret(name, namespace string) *corev1.Secret { - secretData := map[string][]byte{ - "username": []byte("myuser"), - "password": []byte("mypassword"), - } - return &corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - Data: secretData, - Type: corev1.SecretTypeOpaque, - } -} diff --git a/pkg/handlers/generic/mutation/kubernetesimagerepository/tests/generate_patches.go b/pkg/handlers/generic/mutation/kubernetesimagerepository/inject_test.go similarity index 58% rename from pkg/handlers/generic/mutation/kubernetesimagerepository/tests/generate_patches.go rename to pkg/handlers/generic/mutation/kubernetesimagerepository/inject_test.go index eefe534c2..e29d47aa7 100644 --- a/pkg/handlers/generic/mutation/kubernetesimagerepository/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/kubernetesimagerepository/inject_test.go @@ -1,11 +1,12 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package kubernetesimagerepository import ( "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -13,29 +14,30 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" ) -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ +func TestKubernetesImageRepositoryPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "Kubernetes Image Repository mutator suite") +} + +var _ = Describe("Generate Kubernetes Image Repository patches", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ + { Name: "kubernetesImageRepository set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.KubernetesImageRepository("my-registry.io/my-org/my-repo"), - variablePath..., + VariableName, ), }, RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), @@ -48,5 +50,13 @@ func TestGeneratePatches( ), }}, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches(GinkgoT(), patchGenerator, &tt) + }) + } +}) diff --git a/pkg/handlers/generic/mutation/mirrors/tests/generate_patches.go b/pkg/handlers/generic/mutation/mirrors/inject_test.go similarity index 76% rename from pkg/handlers/generic/mutation/mirrors/tests/generate_patches.go rename to pkg/handlers/generic/mutation/mirrors/inject_test.go index dd3a040a2..3e7c9106d 100644 --- a/pkg/handlers/generic/mutation/mirrors/tests/generate_patches.go +++ b/pkg/handlers/generic/mutation/mirrors/inject_test.go @@ -1,24 +1,24 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package mirrors import ( - "context" "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" - "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apiserver/pkg/storage/names" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" - "sigs.k8s.io/controller-runtime/pkg/client" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/test/helpers" ) const ( @@ -29,35 +29,35 @@ const ( workerRegistryAsMirrorCreds = "kubeadmConfigTemplateRegistryAsMirrorCreds" ) -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - fakeClient client.Client, - variableName string, - variablePath ...string, -) { - t.Helper() +func TestMirrorsPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "Global mirror mutator suite") +} - require.NoError( - t, - fakeClient.Create( - context.Background(), - newMirrorSecret(validMirrorCASecretName, request.Namespace), - ), - ) +var _ = Describe("Generate Global mirror patches", func() { + patchGenerator := func() mutation.GeneratePatches { + // Always initialize the testEnv variable in the closure. + // This will allow ginkgo to initialize testEnv variable during test execution time. + testEnv := helpers.TestEnv + // use direct client instead of controller client. This will allow the patch handler to read k8s object + // that are written by the tests. + // Test cases writes credentials secret that the mutator handler reads. + // Using direct client will enable reading it immediately. + client, err := testEnv.GetK8sClient() + gomega.Expect(err).To(gomega.BeNil()) + return mutation.NewMetaGeneratePatchesHandler("", NewPatch(client)).(mutation.GeneratePatches) + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ + testDefs := []capitest.PatchTestDef{ + { Name: "files added in KubeadmControlPlaneTemplate for registry with mirror without CA Certificate", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.GlobalImageRegistryMirror{ URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com", }, - variablePath..., + GlobalMirrorVariableName, ), }, RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), @@ -90,11 +90,11 @@ func TestGeneratePatches( }, }, }, - capitest.PatchTestDef{ + { Name: "files added in KubeadmControlPlaneTemplate for registry with mirror with CA Certificate", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.GlobalImageRegistryMirror{ URL: "https://registry.example.com", Credentials: &v1alpha1.RegistryCredentials{ @@ -103,7 +103,7 @@ func TestGeneratePatches( }, }, }, - variablePath..., + GlobalMirrorVariableName, ), }, RequestItem: request.NewKubeadmControlPlaneTemplateRequest("", cpRegistryAsMirrorCreds), @@ -139,15 +139,15 @@ func TestGeneratePatches( }, }, }, - capitest.PatchTestDef{ + { Name: "files added in KubeadmConfigTemplate for registry mirror wihthout CA certificate", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.GlobalImageRegistryMirror{ URL: "https://123456789.dkr.ecr.us-east-1.amazonaws.com", }, - variablePath..., + GlobalMirrorVariableName, ), capitest.VariableWithValue( "builtin", @@ -188,11 +188,11 @@ func TestGeneratePatches( }, }, }, - capitest.PatchTestDef{ + { Name: "files added in KubeadmConfigTemplate for registry mirror with secret for CA certificate", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.GlobalImageRegistryMirror{ URL: "https://registry.example.com", Credentials: &v1alpha1.RegistryCredentials{ @@ -201,7 +201,7 @@ func TestGeneratePatches( }, }, }, - variablePath..., + GlobalMirrorVariableName, ), capitest.VariableWithValue( "builtin", @@ -245,8 +245,36 @@ func TestGeneratePatches( }, }, }, - ) -} + } + + // Create credentials secret before each test + BeforeEach(func(ctx SpecContext) { + client, err := helpers.TestEnv.GetK8sClient() + gomega.Expect(err).To(gomega.BeNil()) + gomega.Expect(client.Create( + ctx, + newMirrorSecret(validMirrorCASecretName, request.Namespace), + )).To(gomega.BeNil()) + }) + + // Delete credentials secret after each test + AfterEach(func(ctx SpecContext) { + client, err := helpers.TestEnv.GetK8sClient() + gomega.Expect(err).To(gomega.BeNil()) + gomega.Expect(client.Delete( + ctx, + newMirrorSecret(validMirrorCASecretName, request.Namespace), + )).To(gomega.BeNil()) + }) + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches(GinkgoT(), patchGenerator, &tt) + }) + } +}) func newMirrorSecret(name, namespace string) *corev1.Secret { secretData := map[string][]byte{ diff --git a/pkg/handlers/generic/mutation/users/inject_test.go b/pkg/handlers/generic/mutation/users/inject_test.go index 22eb1c812..924321800 100644 --- a/pkg/handlers/generic/mutation/users/inject_test.go +++ b/pkg/handlers/generic/mutation/users/inject_test.go @@ -7,10 +7,18 @@ import ( "testing" "github.com/google/go-cmp/cmp" + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + "k8s.io/apiserver/pkg/storage/names" "k8s.io/utils/ptr" bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" ) func Test_generateBootstrapUser(t *testing.T) { @@ -114,3 +122,83 @@ func Test_generateBootstrapUser(t *testing.T) { }) } } + +var ( + testUser1 = v1alpha1.User{ + Name: "complete", + HashedPassword: "password", + SSHAuthorizedKeys: []string{ + "key1", + "key2", + }, + Sudo: "ALL=(ALL) NOPASSWD:ALL", + } + testUser2 = v1alpha1.User{ + Name: "onlyname", + } +) + +func TestUsersPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "Users mutator suite") +} + +var _ = Describe("Generate Users patches", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "unset variable", + }, + { + Name: "users set for KubeadmControlPlaneTemplate", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + []v1alpha1.User{testUser1, testUser2}, + VariableName, + ), + }, + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/users", + ValueMatcher: gomega.HaveLen(2), + }}, + }, + { + Name: "users set for KubeadmConfigTemplate generic worker", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + []v1alpha1.User{testUser1, testUser2}, + VariableName, + ), + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": names.SimpleNameGenerator.GenerateName("worker-"), + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ + Operation: "add", + Path: "/spec/template/spec/users", + ValueMatcher: gomega.HaveLen(2), + }}, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches(GinkgoT(), patchGenerator, &tt) + }) + } +}) diff --git a/pkg/handlers/generic/mutation/users/tests/generate_patches.go b/pkg/handlers/generic/mutation/users/tests/generate_patches.go deleted file mode 100644 index 2eff072f5..000000000 --- a/pkg/handlers/generic/mutation/users/tests/generate_patches.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2023 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package tests - -import ( - "testing" - - "github.com/onsi/gomega" - "k8s.io/apiserver/pkg/storage/names" - runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" -) - -var ( - testUser1 = v1alpha1.User{ - Name: "complete", - HashedPassword: "password", - SSHAuthorizedKeys: []string{ - "key1", - "key2", - }, - Sudo: "ALL=(ALL) NOPASSWD:ALL", - } - testUser2 = v1alpha1.User{ - Name: "onlyname", - } -) - -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "unset variable", - }, - capitest.PatchTestDef{ - Name: "users set for KubeadmControlPlaneTemplate", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - []v1alpha1.User{testUser1, testUser2}, - variablePath..., - ), - }, - RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/kubeadmConfigSpec/users", - ValueMatcher: gomega.HaveLen(2), - }}, - }, - ) - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "unset variable", - }, - capitest.PatchTestDef{ - Name: "users set for KubeadmConfigTemplate generic worker", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - []v1alpha1.User{testUser1, testUser2}, - variablePath..., - ), - capitest.VariableWithValue( - "builtin", - map[string]any{ - "machineDeployment": map[string]any{ - "class": names.SimpleNameGenerator.GenerateName("worker-"), - }, - }, - ), - }, - RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), - ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{ - Operation: "add", - Path: "/spec/template/spec/users", - ValueMatcher: gomega.HaveLen(2), - }}, - }, - ) -} diff --git a/pkg/handlers/nutanix/mutation/controlplaneendpoint/tests/generate_patches.go b/pkg/handlers/nutanix/mutation/controlplaneendpoint/inject_test.go similarity index 56% rename from pkg/handlers/nutanix/mutation/controlplaneendpoint/tests/generate_patches.go rename to pkg/handlers/nutanix/mutation/controlplaneendpoint/inject_test.go index 8a93eb8f5..6ae946e79 100644 --- a/pkg/handlers/nutanix/mutation/controlplaneendpoint/tests/generate_patches.go +++ b/pkg/handlers/nutanix/mutation/controlplaneendpoint/inject_test.go @@ -1,11 +1,12 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package controlplaneendpoint import ( "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -13,32 +14,35 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" ) -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ +func TestControlPlaneEndpointPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "Nutanix ControlPlane endpoint suite") +} + +var _ = Describe("Generate Nutanix ControlPlane endpoint patches", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ + { Name: "ControlPlaneEndpoint set to valid host and port", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, clusterv1.APIEndpoint{ Host: "10.20.100.10", Port: 6443, }, - variablePath..., + nutanixclusterconfig.NutanixVariableName, + VariableName, ), }, RequestItem: request.NewNutanixClusterTemplateRequestItem(""), @@ -55,5 +59,17 @@ func TestGeneratePatches( }, }, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/nutanix/mutation/machinedetails/tests/generate_patches.go b/pkg/handlers/nutanix/mutation/machinedetails/inject_control_plane_test.go similarity index 72% rename from pkg/handlers/nutanix/mutation/machinedetails/tests/generate_patches.go rename to pkg/handlers/nutanix/mutation/machinedetails/inject_control_plane_test.go index 9e38b6214..3d05ef071 100644 --- a/pkg/handlers/nutanix/mutation/machinedetails/tests/generate_patches.go +++ b/pkg/handlers/nutanix/mutation/machinedetails/inject_control_plane_test.go @@ -1,13 +1,11 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package machinedetails import ( - "testing" - + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/resource" "k8s.io/utils/ptr" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" @@ -17,6 +15,8 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" ) var ( @@ -96,66 +96,40 @@ var ( } ) -func TestControlPlaneGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() +var _ = Describe("Generate Nutanix Machine Details patches for ControlPlane", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewControlPlanePatch()).(mutation.GeneratePatches) + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ + { Name: "all fields set for control-plane", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, variableWithAllFieldsSet, - variablePath..., + clusterconfig.MetaControlPlaneConfigName, + nutanixclusterconfig.NutanixVariableName, + VariableName, ), }, RequestItem: request.NewCPNutanixMachineTemplateRequestItem(""), ExpectedPatchMatchers: matchersForAllFieldsSet, }, - ) -} - -func TestWorkerGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() + } - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ - Name: "unset variable", - }, - capitest.PatchTestDef{ - Name: "all fields set for workers", - Vars: []runtimehooksv1.Variable{ - capitest.VariableWithValue( - variableName, - variableWithAllFieldsSet, - variablePath..., - ), - capitest.VariableWithValue( - "builtin", - apiextensionsv1.JSON{ - Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), - }, - ), - }, - RequestItem: request.NewWorkerNutanixMachineTemplateRequestItem(""), - ExpectedPatchMatchers: matchersForAllFieldsSet, - }, - ) -} + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/nutanix/mutation/machinedetails/inject_suite_test.go b/pkg/handlers/nutanix/mutation/machinedetails/inject_suite_test.go new file mode 100644 index 000000000..0bc40008e --- /dev/null +++ b/pkg/handlers/nutanix/mutation/machinedetails/inject_suite_test.go @@ -0,0 +1,16 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package machinedetails + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestMachineDetailsPatch(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Nutanix Machine Details patches for ControlPlane and Workers suite") +} diff --git a/pkg/handlers/nutanix/mutation/machinedetails/inject_worker_test.go b/pkg/handlers/nutanix/mutation/machinedetails/inject_worker_test.go new file mode 100644 index 000000000..9481bf960 --- /dev/null +++ b/pkg/handlers/nutanix/mutation/machinedetails/inject_worker_test.go @@ -0,0 +1,59 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package machinedetails + +import ( + . "github.com/onsi/ginkgo/v2" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" + nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" +) + +var _ = Describe("Generate Nutanix Machine Details patches for Worker", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewWorkerPatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "unset variable", + }, + { + Name: "all fields set for workers", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + workerconfig.MetaVariableName, + variableWithAllFieldsSet, + nutanixclusterconfig.NutanixVariableName, + VariableName, + ), + capitest.VariableWithValue( + "builtin", + apiextensionsv1.JSON{ + Raw: []byte(`{"machineDeployment": {"class": "a-worker"}}`), + }, + ), + }, + RequestItem: request.NewWorkerNutanixMachineTemplateRequestItem(""), + ExpectedPatchMatchers: matchersForAllFieldsSet, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/nutanix/mutation/metapatch_handler_test.go b/pkg/handlers/nutanix/mutation/metapatch_handler_test.go deleted file mode 100644 index 4216bc2cb..000000000 --- a/pkg/handlers/nutanix/mutation/metapatch_handler_test.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2024 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package mutation - -import ( - "testing" - - "sigs.k8s.io/controller-runtime/pkg/manager" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" - auditpolicytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/auditpolicy/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/etcd" - etcdtests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/etcd/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/extraapiservercertsans" - extraapiservercertsanstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/extraapiservercertsans/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy" - httpproxytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/imageregistries" - imageregistrycredentialstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/imageregistries/credentials/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository" - kubernetesimagerepositorytests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/kubernetesimagerepository/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors" - globalimageregistrymirrortests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/mirrors/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" - nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/controlplaneendpoint" - controlplaneendpointtests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/controlplaneendpoint/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/machinedetails" - machinedetailstests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/machinedetails/tests" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/prismcentralendpoint" - prismcentralendpointtests "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests" -) - -func metaPatchGeneratorFunc(mgr manager.Manager) func() mutation.GeneratePatches { - return func() mutation.GeneratePatches { - return MetaPatchHandler(mgr).(mutation.GeneratePatches) - } -} - -func workerPatchGeneratorFunc() func() mutation.GeneratePatches { - return func() mutation.GeneratePatches { - return MetaWorkerPatchHandler().(mutation.GeneratePatches) - } -} - -func TestGeneratePatches(t *testing.T) { - t.Parallel() - - mgr := testEnv.Manager - - controlplaneendpointtests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - nutanixclusterconfig.NutanixVariableName, - controlplaneendpoint.VariableName, - ) - - prismcentralendpointtests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - nutanixclusterconfig.NutanixVariableName, - prismcentralendpoint.VariableName, - ) - - machinedetailstests.TestControlPlaneGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - clusterconfig.MetaControlPlaneConfigName, - nutanixclusterconfig.NutanixVariableName, - machinedetails.VariableName, - ) - - machinedetailstests.TestWorkerGeneratePatches( - t, - workerPatchGeneratorFunc(), - workerconfig.MetaVariableName, - nutanixclusterconfig.NutanixVariableName, - machinedetails.VariableName, - ) - - auditpolicytests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - ) - - httpproxytests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - httpproxy.VariableName, - ) - - etcdtests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - etcd.VariableName, - ) - - extraapiservercertsanstests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - extraapiservercertsans.VariableName, - ) - - kubernetesimagerepositorytests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - clusterconfig.MetaVariableName, - kubernetesimagerepository.VariableName, - ) - - imageregistrycredentialstests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - mgr.GetClient(), - clusterconfig.MetaVariableName, - imageregistries.VariableName, - ) - - globalimageregistrymirrortests.TestGeneratePatches( - t, - metaPatchGeneratorFunc(mgr), - mgr.GetClient(), - clusterconfig.MetaVariableName, - mirrors.GlobalMirrorVariableName, - ) -} diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go similarity index 80% rename from pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go rename to pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go index 0b9003fc1..83d9f431e 100644 --- a/pkg/handlers/nutanix/mutation/prismcentralendpoint/tests/generate_patches.go +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go @@ -1,11 +1,12 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -package tests +package prismcentralendpoint import ( "testing" + . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" "k8s.io/utils/ptr" @@ -15,30 +16,33 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" ) // //nolint:lll // just a long string const testCertBundle = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVjekNDQTF1Z0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRUUZBRC4uQWtHQTFVRUJoTUNSMEl4CkV6QVJCZ05WQkFnVENsTnZiV1V0VTNSaGRHVXhGREFTQmdOVkJBb1RDMC4uMEVnVEhSa01UY3dOUVlEClZRUUxFeTVEYkdGemN5QXhJRkIxWW14cFl5QlFjbWx0WVhKNUlFTmxjbi4uWFJwYjI0Z1FYVjBhRzl5CmFYUjVNUlF3RWdZRFZRUURFd3RDWlhOMElFTkJJRXgwWkRBZUZ3MHdNRC4uVFV3TVRaYUZ3MHdNVEF5Ck1EUXhPVFV3TVRaYU1JR0hNUXN3Q1FZRFZRUUdFd0pIUWpFVE1CRUdBMS4uMjl0WlMxVGRHRjBaVEVVCk1CSUdBMVVFQ2hNTFFtVnpkQ0JEUVNCTWRHUXhOekExQmdOVkJBc1RMay4uREVnVUhWaWJHbGpJRkJ5CmFXMWhjbmtnUTJWeWRHbG1hV05oZEdsdmJpQkJkWFJvYjNKcGRIa3hGRC4uQU1UQzBKbGMzUWdRMEVnClRIUmtNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZy4uVHoybXI3U1ppQU1mUXl1CnZCak05T2lKalJhelhCWjFCalA1Q0UvV20vUnI1MDBQUksrTGg5eDVlSi4uL0FOQkUwc1RLMFpzREdNCmFrMm0xZzdvcnVJM2RZM1ZIcUl4RlR6MFRhMWQrTkFqd25MZTRuT2I3Ly4uazA1U2hoQnJKR0JLS3hiCjhuMTA0by81cDhIQXNaUGR6YkZNSXlOakp6Qk0ybzV5NUExM3dpTGl0RS4uZnlZa1F6YXhDdzBBd3psCmtWSGlJeUN1YUY0d2o1NzFwU3prdjZzdis0SURNYlQvWHBDbzhMNndUYS4uc2grZXRMRDZGdFRqWWJiCnJ2WjhSUU0xdGxLZG9NSGcycXhyYUFWKytITkJZbU5XczBkdUVkalViSi4uWEk5VHRuUzRvMUNrajdQCk9mbGppUUlEQVFBQm80SG5NSUhrTUIwR0ExVWREZ1FXQkJROHVyTUNSTC4uNUFrSXA5TkpISnc1VENCCnRBWURWUjBqQklHc01JR3BnQlE4dXJNQ1JMWVlNSFVLVTVBa0lwOU5KSC4uYVNCaWpDQmh6RUxNQWtHCkExVUVCaE1DUjBJeEV6QVJCZ05WQkFnVENsTnZiV1V0VTNSaGRHVXhGRC4uQW9UQzBKbGMzUWdRMEVnClRIUmtNVGN3TlFZRFZRUUxFeTVEYkdGemN5QXhJRkIxWW14cFl5QlFjbS4uRU5sY25ScFptbGpZWFJwCmIyNGdRWFYwYUc5eWFYUjVNUlF3RWdZRFZRUURFd3RDWlhOMElFTkJJRS4uREFNQmdOVkhSTUVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQkFVQUE0SUJBUUMxdVlCY3NTbmN3QS4uRENzUWVyNzcyQzJ1Y3BYCnhRVUUvQzBwV1dtNmdEa3dkNUQwRFNNREpScVYvd2VvWjR3QzZCNzNmNS4uYkxoR1lIYVhKZVNENktyClhjb093TGRTYUdtSllzbExLWkIzWklERXAwd1lUR2hndGViNkpGaVR0bi4uc2YyeGRyWWZQQ2lJQjdnCkJNQVY3R3pkYzRWc3BTNmxqckFoYmlpYXdkQmlRbFFtc0JlRno5SmtGNC4uYjNsOEJvR04rcU1hNTZZCkl0OHVuYTJnWTRsMk8vL29uODhyNUlXSmxtMUwwb0E4ZTRmUjJ5ckJIWC4uYWRzR2VGS2t5TnJ3R2kvCjd2UU1mWGRHc1JyWE5HUkduWCt2V0RaMy96V0kwam9EdENrTm5xRXBWbi4uSG9YCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=" -func TestGeneratePatches( - t *testing.T, - generatorFunc func() mutation.GeneratePatches, - variableName string, - variablePath ...string, -) { - t.Helper() - capitest.ValidateGeneratePatches( - t, - generatorFunc, - capitest.PatchTestDef{ +func TestPrismCentralEndpointPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "Nutanix Prism Central Endpoint mutator suite") +} + +var _ = Describe("Generate Nutanix Prism Central Endpoint patches", func() { + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { Name: "unset variable", }, - capitest.PatchTestDef{ + { Name: "all required fields set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.NutanixPrismCentralEndpointSpec{ Host: "prism-central.nutanix.com", Port: 9441, @@ -47,7 +51,8 @@ func TestGeneratePatches( Name: "credentials", }, }, - variablePath..., + nutanixclusterconfig.NutanixVariableName, + VariableName, ), }, RequestItem: request.NewNutanixClusterTemplateRequestItem(""), @@ -68,11 +73,11 @@ func TestGeneratePatches( }, }, }, - capitest.PatchTestDef{ + { Name: "additional trust bundle is set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( - variableName, + clusterconfig.MetaVariableName, v1alpha1.NutanixPrismCentralEndpointSpec{ Host: "prism-central.nutanix.com", Port: 9441, @@ -82,7 +87,8 @@ func TestGeneratePatches( }, AdditionalTrustBundle: ptr.To(testCertBundle), }, - variablePath..., + nutanixclusterconfig.NutanixVariableName, + VariableName, ), }, RequestItem: request.NewNutanixClusterTemplateRequestItem(""), @@ -104,5 +110,17 @@ func TestGeneratePatches( }, }, }, - ) -} + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/nutanix/mutation/suite_test.go b/pkg/handlers/nutanix/mutation/suite_test.go deleted file mode 100644 index 5188c91c7..000000000 --- a/pkg/handlers/nutanix/mutation/suite_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2024 D2iQ, Inc. All rights reserved. -// SPDX-License-Identifier: Apache-2.0 - -package mutation - -import ( - "context" - "fmt" - "testing" - - ctrl "sigs.k8s.io/controller-runtime" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/test/helpers" -) - -var ( - testEnv *helpers.TestEnvironment - ctx = ctrl.SetupSignalHandler() -) - -func TestMain(m *testing.M) { - setupCtx, cancel := context.WithCancel(ctx) - setup(setupCtx) - defer teardown(cancel) - m.Run() -} - -func setup(ctx context.Context) { - testEnvConfig := helpers.NewTestEnvironmentConfiguration() - var err error - testEnv, err = testEnvConfig.Build() - if err != nil { - panic(err) - } - go func() { - fmt.Println("Starting the manager") - if err := testEnv.StartManager(ctx); err != nil { - panic(fmt.Sprintf("Failed to start the envtest manager: %v", err)) - } - }() -} - -func teardown(cancel context.CancelFunc) { - cancel() - if err := testEnv.Stop(); err != nil { - panic(fmt.Sprintf("Failed to stop envtest: %v", err)) - } -} diff --git a/test/helpers/environment.go b/test/helpers/environment.go index 9d0e48263..a8a69cd38 100644 --- a/test/helpers/environment.go +++ b/test/helpers/environment.go @@ -9,27 +9,12 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "k8s.io/klog/v2" - "k8s.io/klog/v2/textlogger" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/log" ) var TestEnv *TestEnvironment // Initialize the test environment. BeforeSuite will be only executed if this package is loaded by the test. var _ = BeforeSuite(func(ctx SpecContext) { - By("Initialize loggers for testing") - // Uninitialized logger spits stacktrace as warning during test execution - logger := textlogger.NewLogger(textlogger.NewConfig()) - // use klog as the internal logger for this envtest environment. - log.SetLogger(logger) - // additionally force all of the controllers to use the Ginkgo logger. - ctrl.SetLogger(logger) - klog.InitFlags(nil) - // add logger for ginkgo - klog.SetOutput(GinkgoWriter) - By("Starting test environment") testEnvConfig := NewTestEnvironmentConfiguration() var err error diff --git a/test/helpers/envtest.go b/test/helpers/envtest.go index 190b8f009..9801cf740 100644 --- a/test/helpers/envtest.go +++ b/test/helpers/envtest.go @@ -130,6 +130,13 @@ func (t *TestEnvironmentConfiguration) Build() (*TestEnvironment, error) { }, nil } +// GetK8sClient returns a “live” k8s client that does will not invoke against controller cache. +// If a test is writeing an object, they are not immediately available to read since controller caches +// are not synchronized yet. +func (t *TestEnvironment) GetK8sClient() (client.Client, error) { + return client.New(t.Manager.GetConfig(), client.Options{Scheme: scheme.Scheme}) +} + // StartManager starts the test controller against the local API server. func (t *TestEnvironment) StartManager(ctx context.Context) error { return t.Manager.Start(ctx) From 8141a4c404ba182ec4de9292ac1258e3bf67477e Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Fri, 5 Apr 2024 15:01:15 -0700 Subject: [PATCH 71/87] feat: Make containerd restart its own patch (#18) * feat: Make containerd restart its own patch * fix: unit tests for kubeadmconfigtemplate with containerdrestart patch * fix: add comment for always add containerd patch * test: move unit test to their own package --------- Co-authored-by: Shalin Patel --- .../mutation/containerdrestart/inject.go | 86 ++++++++++++++++ .../mutation/containerdrestart/inject_test.go | 97 +++++++++++++++++++ .../mutation/containerdrestart/restart.go | 27 ++++++ .../templates/containerd-restart.sh | 0 pkg/handlers/generic/mutation/handlers.go | 10 ++ .../generic/mutation/mirrors/inject.go | 4 - .../generic/mutation/mirrors/inject_test.go | 16 --- .../generic/mutation/mirrors/mirror.go | 17 ---- 8 files changed, 220 insertions(+), 37 deletions(-) create mode 100644 pkg/handlers/generic/mutation/containerdrestart/inject.go create mode 100644 pkg/handlers/generic/mutation/containerdrestart/inject_test.go create mode 100644 pkg/handlers/generic/mutation/containerdrestart/restart.go rename pkg/handlers/generic/mutation/{mirrors => containerdrestart}/templates/containerd-restart.sh (100%) diff --git a/pkg/handlers/generic/mutation/containerdrestart/inject.go b/pkg/handlers/generic/mutation/containerdrestart/inject.go new file mode 100644 index 000000000..92edab3de --- /dev/null +++ b/pkg/handlers/generic/mutation/containerdrestart/inject.go @@ -0,0 +1,86 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +package containerdrestart + +import ( + "context" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" + controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches/selectors" +) + +type containerdRestartPatchHandler struct{} + +func NewPatch() *containerdRestartPatchHandler { + return &containerdRestartPatchHandler{} +} + +func (h *containerdRestartPatchHandler) Mutate( + ctx context.Context, + obj *unstructured.Unstructured, + vars map[string]apiextensionsv1.JSON, + holderRef runtimehooksv1.HolderReference, + clusterKey ctrlclient.ObjectKey, +) error { + log := ctrl.LoggerFrom(ctx).WithValues( + "holderRef", holderRef, + ) + + file, command := generateContainerdRestartScript() + + if err := patches.MutateIfApplicable( + obj, vars, &holderRef, selectors.ControlPlane(), log, + func(obj *controlplanev1.KubeadmControlPlaneTemplate) error { + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", ctrlclient.ObjectKeyFromObject(obj), + ).Info("adding containerd restart script to control plane kubeadm config spec") + obj.Spec.Template.Spec.KubeadmConfigSpec.Files = append( + obj.Spec.Template.Spec.KubeadmConfigSpec.Files, + file, + ) + + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", ctrlclient.ObjectKeyFromObject(obj), + ).Info("adding containerd restart command to control plane kubeadm config spec") + obj.Spec.Template.Spec.KubeadmConfigSpec.PreKubeadmCommands = append( + obj.Spec.Template.Spec.KubeadmConfigSpec.PreKubeadmCommands, + command, + ) + + return nil + }); err != nil { + return err + } + + if err := patches.MutateIfApplicable( + obj, vars, &holderRef, selectors.WorkersKubeadmConfigTemplateSelector(), log, + func(obj *bootstrapv1.KubeadmConfigTemplate) error { + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", ctrlclient.ObjectKeyFromObject(obj), + ).Info("adding containerd restart script to worker node kubeadm config template") + obj.Spec.Template.Spec.Files = append(obj.Spec.Template.Spec.Files, file) + + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", ctrlclient.ObjectKeyFromObject(obj), + ).Info("adding containerd restart command to worker node kubeadm config template") + obj.Spec.Template.Spec.PreKubeadmCommands = append(obj.Spec.Template.Spec.PreKubeadmCommands, command) + + return nil + }); err != nil { + return err + } + + return nil +} diff --git a/pkg/handlers/generic/mutation/containerdrestart/inject_test.go b/pkg/handlers/generic/mutation/containerdrestart/inject_test.go new file mode 100644 index 000000000..c654edc1d --- /dev/null +++ b/pkg/handlers/generic/mutation/containerdrestart/inject_test.go @@ -0,0 +1,97 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package containerdrestart + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" +) + +func TestContainerdRestartPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "Containerd restart mutator suite") +} + +var _ = Describe("Generate Containerd restart patches", func() { + // only add aws region patch + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "restart script and command added to control plane kubeadm config spec", + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", ContainerdRestartScriptOnRemote, + ), + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/preKubeadmCommands", + ValueMatcher: gomega.ContainElements( + ContainerdRestartScriptOnRemoteCommand, + ), + }, + }, + }, + { + Name: "restart script and command added to worker node kubeadm config template", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": "*", + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", ContainerdRestartScriptOnRemote, + ), + ), + }, + { + Operation: "add", + Path: "/spec/template/spec/preKubeadmCommands", + ValueMatcher: gomega.ContainElements( + ContainerdRestartScriptOnRemoteCommand, + ), + }, + }, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/generic/mutation/containerdrestart/restart.go b/pkg/handlers/generic/mutation/containerdrestart/restart.go new file mode 100644 index 000000000..8826cceed --- /dev/null +++ b/pkg/handlers/generic/mutation/containerdrestart/restart.go @@ -0,0 +1,27 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +package containerdrestart + +import ( + _ "embed" + + bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" +) + +const ( + ContainerdRestartScriptOnRemote = "/etc/containerd/restart.sh" + ContainerdRestartScriptOnRemoteCommand = "/bin/bash " + ContainerdRestartScriptOnRemote +) + +//go:embed templates/containerd-restart.sh +var containerdRestartScript []byte + +//nolint:gocritic // no need for named return values +func generateContainerdRestartScript() (bootstrapv1.File, string) { + return bootstrapv1.File{ + Path: ContainerdRestartScriptOnRemote, + Content: string(containerdRestartScript), + Permissions: "0700", + }, + ContainerdRestartScriptOnRemoteCommand +} diff --git a/pkg/handlers/generic/mutation/mirrors/templates/containerd-restart.sh b/pkg/handlers/generic/mutation/containerdrestart/templates/containerd-restart.sh similarity index 100% rename from pkg/handlers/generic/mutation/mirrors/templates/containerd-restart.sh rename to pkg/handlers/generic/mutation/containerdrestart/templates/containerd-restart.sh diff --git a/pkg/handlers/generic/mutation/handlers.go b/pkg/handlers/generic/mutation/handlers.go index bd71c8caa..9ec605971 100644 --- a/pkg/handlers/generic/mutation/handlers.go +++ b/pkg/handlers/generic/mutation/handlers.go @@ -9,6 +9,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/cni/calico" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/auditpolicy" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/containerdrestart" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/etcd" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/extraapiservercertsans" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/httpproxy" @@ -30,5 +31,14 @@ func MetaMutators(mgr manager.Manager) []mutation.MetaMutator { mirrors.NewPatch(mgr.GetClient()), calico.NewPatch(), users.NewPatch(), + + // Some patches may have changed containerd configuration. + // We must restart containerd for the configuration to take effect. + // Therefore, we must apply this patch last. + // + // Containerd restart and readiness altogether could take ~5s. + // We want to keep patch independent of each other and not share any state. + // Therefore, We must always apply this patch regardless any other patch modified containerd configuration. + containerdrestart.NewPatch(), } } diff --git a/pkg/handlers/generic/mutation/mirrors/inject.go b/pkg/handlers/generic/mutation/mirrors/inject.go index a1e5e8e3b..42ad077d0 100644 --- a/pkg/handlers/generic/mutation/mirrors/inject.go +++ b/pkg/handlers/generic/mutation/mirrors/inject.go @@ -191,10 +191,6 @@ func generateFilesAndCommands( } files = append(files, applyPatchesFile...) commands = append(commands, applyPatchesCommand) - // generate Containerd restart script and command - restartFile, restartCommand := generateContainerdRestartScript() - files = append(files, restartFile...) - commands = append(commands, restartCommand) return files, commands, err } diff --git a/pkg/handlers/generic/mutation/mirrors/inject_test.go b/pkg/handlers/generic/mutation/mirrors/inject_test.go index 3e7c9106d..24ca2ae17 100644 --- a/pkg/handlers/generic/mutation/mirrors/inject_test.go +++ b/pkg/handlers/generic/mutation/mirrors/inject_test.go @@ -75,9 +75,6 @@ var _ = Describe("Generate Global mirror patches", func() { gomega.HaveKeyWithValue( "path", "/etc/containerd/apply-patches.sh", ), - gomega.HaveKeyWithValue( - "path", "/etc/containerd/restart.sh", - ), ), }, { @@ -85,7 +82,6 @@ var _ = Describe("Generate Global mirror patches", func() { Path: "/spec/template/spec/kubeadmConfigSpec/preKubeadmCommands", ValueMatcher: gomega.ContainElements( "/bin/bash /etc/containerd/apply-patches.sh", - "/bin/bash /etc/containerd/restart.sh", ), }, }, @@ -124,9 +120,6 @@ var _ = Describe("Generate Global mirror patches", func() { gomega.HaveKeyWithValue( "path", "/etc/containerd/apply-patches.sh", ), - gomega.HaveKeyWithValue( - "path", "/etc/containerd/restart.sh", - ), ), }, { @@ -134,7 +127,6 @@ var _ = Describe("Generate Global mirror patches", func() { Path: "/spec/template/spec/kubeadmConfigSpec/preKubeadmCommands", ValueMatcher: gomega.ContainElements( "/bin/bash /etc/containerd/apply-patches.sh", - "/bin/bash /etc/containerd/restart.sh", ), }, }, @@ -173,9 +165,6 @@ var _ = Describe("Generate Global mirror patches", func() { gomega.HaveKeyWithValue( "path", "/etc/containerd/apply-patches.sh", ), - gomega.HaveKeyWithValue( - "path", "/etc/containerd/restart.sh", - ), ), }, { @@ -183,7 +172,6 @@ var _ = Describe("Generate Global mirror patches", func() { Path: "/spec/template/spec/preKubeadmCommands", ValueMatcher: gomega.ContainElements( "/bin/bash /etc/containerd/apply-patches.sh", - "/bin/bash /etc/containerd/restart.sh", ), }, }, @@ -230,9 +218,6 @@ var _ = Describe("Generate Global mirror patches", func() { gomega.HaveKeyWithValue( "path", "/etc/containerd/apply-patches.sh", ), - gomega.HaveKeyWithValue( - "path", "/etc/containerd/restart.sh", - ), ), }, { @@ -240,7 +225,6 @@ var _ = Describe("Generate Global mirror patches", func() { Path: "/spec/template/spec/preKubeadmCommands", ValueMatcher: gomega.ContainElements( "/bin/bash /etc/containerd/apply-patches.sh", - "/bin/bash /etc/containerd/restart.sh", ), }, }, diff --git a/pkg/handlers/generic/mutation/mirrors/mirror.go b/pkg/handlers/generic/mutation/mirrors/mirror.go index ff14c2b62..8ab281f9c 100644 --- a/pkg/handlers/generic/mutation/mirrors/mirror.go +++ b/pkg/handlers/generic/mutation/mirrors/mirror.go @@ -28,9 +28,6 @@ const ( containerdPatchesDirOnRemote = "/etc/containerd/cre.d" containerdApplyPatchesScriptOnRemote = "/etc/containerd/apply-patches.sh" containerdApplyPatchesScriptOnRemoteCommand = "/bin/bash " + containerdApplyPatchesScriptOnRemote - - containerdRestartScriptOnRemote = "/etc/containerd/restart.sh" - containerdRestartScriptOnRemoteCommand = "/bin/bash " + containerdRestartScriptOnRemote ) var ( @@ -50,9 +47,6 @@ var ( //go:embed templates/containerd-apply-patches.sh.gotmpl containerdApplyConfigPatchesScript []byte - - //go:embed templates/containerd-restart.sh - containerdRestartScript []byte ) type mirrorConfig struct { @@ -226,14 +220,3 @@ func generateContainerdApplyPatchesScript() ([]cabpkv1.File, string, error) { }, }, containerdApplyPatchesScriptOnRemoteCommand, nil } - -//nolint:gocritic // no need for named return values -func generateContainerdRestartScript() ([]cabpkv1.File, string) { - return []cabpkv1.File{ - { - Path: containerdRestartScriptOnRemote, - Content: string(containerdRestartScript), - Permissions: "0700", - }, - }, containerdRestartScriptOnRemoteCommand -} From 2b1e7ec0c98c8020506e9c00e2736979c82dbdf4 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Tue, 9 Apr 2024 16:22:20 +0100 Subject: [PATCH 72/87] build(deps): Bump golang.org/x/net to v0.24.0 (#42) --- api/go.mod | 2 +- api/go.sum | 8 ++++---- common/go.mod | 6 +++--- common/go.sum | 12 ++++++------ go.mod | 8 ++++---- go.sum | 16 ++++++++-------- hack/third-party/caaph/go.mod | 6 +++--- hack/third-party/caaph/go.sum | 12 ++++++------ hack/third-party/cabpk/go.mod | 4 ++-- hack/third-party/cabpk/go.sum | 8 ++++---- hack/third-party/capa/go.mod | 6 +++--- hack/third-party/capa/go.sum | 12 ++++++------ hack/third-party/capd/go.mod | 2 +- hack/third-party/capd/go.sum | 4 ++-- hack/third-party/capx/go.mod | 6 +++--- hack/third-party/capx/go.sum | 12 ++++++------ make/go.mk | 15 ++++++++++----- 17 files changed, 72 insertions(+), 67 deletions(-) diff --git a/api/go.mod b/api/go.mod index d41dcf73a..bc15c10d6 100644 --- a/api/go.mod +++ b/api/go.mod @@ -34,7 +34,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pkg/errors v0.9.1 // indirect - golang.org/x/net v0.19.0 // indirect + golang.org/x/net v0.24.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/api/go.sum b/api/go.sum index 1aa5ecc1d..0974afbd1 100644 --- a/api/go.sum +++ b/api/go.sum @@ -501,8 +501,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -583,8 +583,8 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/common/go.mod b/common/go.mod index 9fd75ed65..c17bce065 100644 --- a/common/go.mod +++ b/common/go.mod @@ -65,11 +65,11 @@ require ( github.com/stoewer/go-strcase v1.2.0 // indirect github.com/valyala/fastjson v1.6.4 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/net v0.19.0 // indirect + golang.org/x/net v0.24.0 // indirect golang.org/x/oauth2 v0.14.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.16.1 // indirect diff --git a/common/go.sum b/common/go.sum index d6c26d887..c3fe85b1e 100644 --- a/common/go.sum +++ b/common/go.sum @@ -587,8 +587,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -673,13 +673,13 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/go.mod b/go.mod index 6f4844444..8459609da 100644 --- a/go.mod +++ b/go.mod @@ -117,14 +117,14 @@ require ( github.com/subosito/gotenv v1.6.0 // indirect github.com/valyala/fastjson v1.6.4 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.18.0 // indirect + golang.org/x/crypto v0.22.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.20.0 // indirect + golang.org/x/net v0.24.0 // indirect golang.org/x/oauth2 v0.14.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.16.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.17.0 // indirect diff --git a/go.sum b/go.sum index bbd861b14..a3a31052a 100644 --- a/go.sum +++ b/go.sum @@ -629,8 +629,8 @@ golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -718,8 +718,8 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -813,14 +813,14 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/hack/third-party/caaph/go.mod b/hack/third-party/caaph/go.mod index 05dd21818..d908667ab 100644 --- a/hack/third-party/caaph/go.mod +++ b/hack/third-party/caaph/go.mod @@ -43,10 +43,10 @@ require ( github.com/stretchr/testify v1.8.4 // indirect go.uber.org/goleak v1.3.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/net v0.19.0 // indirect + golang.org/x/net v0.24.0 // indirect golang.org/x/oauth2 v0.14.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect diff --git a/hack/third-party/caaph/go.sum b/hack/third-party/caaph/go.sum index d7c5c8cae..1ac84ef41 100644 --- a/hack/third-party/caaph/go.sum +++ b/hack/third-party/caaph/go.sum @@ -126,8 +126,8 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0= golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -138,10 +138,10 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/hack/third-party/cabpk/go.mod b/hack/third-party/cabpk/go.mod index d4c0700c0..d792835be 100644 --- a/hack/third-party/cabpk/go.mod +++ b/hack/third-party/cabpk/go.mod @@ -35,8 +35,8 @@ require ( github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/procfs v0.11.1 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/net v0.18.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/hack/third-party/cabpk/go.sum b/hack/third-party/cabpk/go.sum index 4c41d4fbe..f05bc632d 100644 --- a/hack/third-party/cabpk/go.sum +++ b/hack/third-party/cabpk/go.sum @@ -94,8 +94,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -103,8 +103,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= diff --git a/hack/third-party/capa/go.mod b/hack/third-party/capa/go.mod index 5045470dc..768cdfa73 100644 --- a/hack/third-party/capa/go.mod +++ b/hack/third-party/capa/go.mod @@ -46,10 +46,10 @@ require ( github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect - golang.org/x/net v0.21.0 // indirect + golang.org/x/net v0.24.0 // indirect golang.org/x/oauth2 v0.17.0 // indirect - golang.org/x/sys v0.17.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect diff --git a/hack/third-party/capa/go.sum b/hack/third-party/capa/go.sum index 61db925b3..f005c1b2d 100644 --- a/hack/third-party/capa/go.sum +++ b/hack/third-party/capa/go.sum @@ -124,8 +124,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -139,12 +139,12 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/hack/third-party/capd/go.mod b/hack/third-party/capd/go.mod index c9391b46d..3a5d52fe0 100644 --- a/hack/third-party/capd/go.mod +++ b/hack/third-party/capd/go.mod @@ -26,7 +26,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pkg/errors v0.9.1 // indirect - golang.org/x/net v0.18.0 // indirect + golang.org/x/net v0.24.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/hack/third-party/capd/go.sum b/hack/third-party/capd/go.sum index ee07964be..d645a2e73 100644 --- a/hack/third-party/capd/go.sum +++ b/hack/third-party/capd/go.sum @@ -77,8 +77,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/hack/third-party/capx/go.mod b/hack/third-party/capx/go.mod index 0c5771a41..8ef00494c 100644 --- a/hack/third-party/capx/go.mod +++ b/hack/third-party/capx/go.mod @@ -41,10 +41,10 @@ require ( github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/net v0.18.0 // indirect + golang.org/x/net v0.24.0 // indirect golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/term v0.14.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect diff --git a/hack/third-party/capx/go.sum b/hack/third-party/capx/go.sum index 93f909ca6..fa1c645bf 100644 --- a/hack/third-party/capx/go.sum +++ b/hack/third-party/capx/go.sum @@ -598,8 +598,8 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -694,13 +694,13 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/make/go.mk b/make/go.mk index 84afa2988..afba74a9f 100644 --- a/make/go.mk +++ b/make/go.mk @@ -5,8 +5,9 @@ # to be private (not available publicly) and should therefore not use the proxy or checksum database export GOPRIVATE ?= -ALL_GO_SUBMODULES := $(shell PATH='$(PATH)'; find -mindepth 2 -maxdepth 2 -name go.mod -printf '%P\n' | sort) +ALL_GO_SUBMODULES := $(shell find -mindepth 2 -maxdepth 2 -name go.mod -printf '%P\n' | sort) GO_SUBMODULES_NO_DOCS := $(filter-out $(addsuffix /go.mod,docs),$(ALL_GO_SUBMODULES)) +THIRD_PARTY_GO_SUBMODULES := $(shell find hack/third-party -mindepth 2 -name go.mod -printf 'hack/third-party/%P\n' | sort) ifndef GOOS export GOOS := $(OS) @@ -146,12 +147,16 @@ endif ifneq ($(words $(GO_SUBMODULES_NO_DOCS)),0) mod-tidy: $(addprefix mod-tidy.,$(GO_SUBMODULES_NO_DOCS:/go.mod=)) endif +ifneq ($(words $(THIRD_PARTY_GO_SUBMODULES)),0) +mod-tidy: $(addprefix mod-tidy.,$(THIRD_PARTY_GO_SUBMODULES:/go.mod=)) +endif .PHONY: mod-tidy.% -mod-tidy.%: ## Runs go mod tidy for a specific module -mod-tidy.%: ; $(info $(M) running go mod tidy for $* module) - $(if $(filter-out root,$*),cd $* && )go mod tidy -v - $(if $(filter-out root,$*),cd $* && )go mod verify +.PHONY: mod-tidy.hack/third-party/% +mod-tidy.% mod-tidy.hack/third-party/%: ## Runs go mod tidy for a specific module +mod-tidy.% mod-tidy.hack/third-party/%: ; $(info $(M) running go mod tidy for $* module) + $(if $(filter-out root,$*),cd $(@:mod-tidy.%=%) && )go mod tidy -v + $(if $(filter-out root,$*),cd $(@:mod-tidy.%=%) && )go mod verify .PHONY: go-clean go-clean: ## Cleans go build, test and modules caches for all modules From e78e6f99ae95a253e82f893dcd043f7fae880ee7 Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Tue, 9 Apr 2024 08:28:59 -0700 Subject: [PATCH 73/87] build: add CSI configuration to Nutanix examples (#33) --- .../nutanix-cluster-calico-crs.yaml | 22 +++++++++++++++++++ .../nutanix-cluster-calico-helm-addon.yaml | 22 +++++++++++++++++++ .../nutanix-cluster-cilium-crs.yaml | 22 +++++++++++++++++++ .../nutanix-cluster-cilium-helm-addon.yaml | 22 +++++++++++++++++++ .../nutanix/csi-secret.yaml | 10 +++++++++ .../nutanix/cluster/kustomization.yaml.tmpl | 4 ++++ hack/examples/patches/nutanix/csi.yaml | 18 +++++++++++++++ 7 files changed, 120 insertions(+) create mode 100644 hack/examples/additional-resources/nutanix/csi-secret.yaml create mode 100644 hack/examples/patches/nutanix/csi.yaml diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 710f1a31c..3c52b964e 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -1,4 +1,13 @@ apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pe-creds-for-csi +stringData: + key: ${NUTANIX_PRISM_ELEMENT_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD} +--- +apiVersion: v1 data: nutanix-ccm.yaml: | --- @@ -317,6 +326,19 @@ spec: cni: provider: Calico strategy: ClusterResourceSet + csi: + defaultStorage: + providerName: nutanix + storageClassConfigName: nutanix-volume + providers: + - credentials: + name: ${CLUSTER_NAME}-pe-creds-for-csi + name: nutanix + storageClassConfig: + - name: nutanix-volume + parameters: + storageContainer: ${NUTANIX_STORAGE_CONTAINER_NAME} + strategy: HelmAddon nfd: strategy: ClusterResourceSet controlPlane: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index e49994c81..b28a8f68d 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -1,4 +1,13 @@ apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pe-creds-for-csi +stringData: + key: ${NUTANIX_PRISM_ELEMENT_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD} +--- +apiVersion: v1 data: nutanix-ccm.yaml: | --- @@ -317,6 +326,19 @@ spec: cni: provider: Calico strategy: HelmAddon + csi: + defaultStorage: + providerName: nutanix + storageClassConfigName: nutanix-volume + providers: + - credentials: + name: ${CLUSTER_NAME}-pe-creds-for-csi + name: nutanix + storageClassConfig: + - name: nutanix-volume + parameters: + storageContainer: ${NUTANIX_STORAGE_CONTAINER_NAME} + strategy: HelmAddon nfd: strategy: HelmAddon controlPlane: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index f089aa951..fb90c9254 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -1,4 +1,13 @@ apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pe-creds-for-csi +stringData: + key: ${NUTANIX_PRISM_ELEMENT_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD} +--- +apiVersion: v1 data: nutanix-ccm.yaml: | --- @@ -317,6 +326,19 @@ spec: cni: provider: Cilium strategy: ClusterResourceSet + csi: + defaultStorage: + providerName: nutanix + storageClassConfigName: nutanix-volume + providers: + - credentials: + name: ${CLUSTER_NAME}-pe-creds-for-csi + name: nutanix + storageClassConfig: + - name: nutanix-volume + parameters: + storageContainer: ${NUTANIX_STORAGE_CONTAINER_NAME} + strategy: HelmAddon nfd: strategy: ClusterResourceSet controlPlane: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 209c73674..7a5e4b048 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -1,4 +1,13 @@ apiVersion: v1 +kind: Secret +metadata: + labels: + cluster.x-k8s.io/provider: nutanix + name: ${CLUSTER_NAME}-pe-creds-for-csi +stringData: + key: ${NUTANIX_PRISM_ELEMENT_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD} +--- +apiVersion: v1 data: nutanix-ccm.yaml: | --- @@ -317,6 +326,19 @@ spec: cni: provider: Cilium strategy: HelmAddon + csi: + defaultStorage: + providerName: nutanix + storageClassConfigName: nutanix-volume + providers: + - credentials: + name: ${CLUSTER_NAME}-pe-creds-for-csi + name: nutanix + storageClassConfig: + - name: nutanix-volume + parameters: + storageContainer: ${NUTANIX_STORAGE_CONTAINER_NAME} + strategy: HelmAddon nfd: strategy: HelmAddon controlPlane: diff --git a/hack/examples/additional-resources/nutanix/csi-secret.yaml b/hack/examples/additional-resources/nutanix/csi-secret.yaml new file mode 100644 index 000000000..0011bfbe1 --- /dev/null +++ b/hack/examples/additional-resources/nutanix/csi-secret.yaml @@ -0,0 +1,10 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +--- +apiVersion: v1 +kind: Secret +metadata: + name: ${CLUSTER_NAME}-pe-creds-for-csi +stringData: + key: "${NUTANIX_PRISM_ELEMENT_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD}" diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index c957ef734..73844b6ac 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -5,6 +5,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: +- ../../../additional-resources/nutanix/csi-secret.yaml - https://raw.githubusercontent.com/nutanix-cloud-native/cluster-api-provider-nutanix/1a7cd69ba35de01e56dcf2dda7f31973111d2317/templates/cluster-template-topology.yaml sortOptions: @@ -25,6 +26,9 @@ patches: - target: kind: Cluster path: ../../../patches/cluster-autoscaler.yaml +- target: + kind: Cluster + path: ../../../patches/nutanix/csi.yaml - target: kind: Cluster path: ../../../patches/nutanix/initialize-variables.yaml diff --git a/hack/examples/patches/nutanix/csi.yaml b/hack/examples/patches/nutanix/csi.yaml new file mode 100644 index 000000000..fffac03ef --- /dev/null +++ b/hack/examples/patches/nutanix/csi.yaml @@ -0,0 +1,18 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +- op: "add" + path: "/spec/topology/variables/0/value/addons/csi" + value: + defaultStorage: + providerName: nutanix + storageClassConfigName: nutanix-volume + providers: + - name: nutanix + storageClassConfig: + - name: nutanix-volume + parameters: + storageContainer: ${NUTANIX_STORAGE_CONTAINER_NAME} + strategy: HelmAddon + credentials: + name: ${CLUSTER_NAME}-pe-creds-for-csi From cb8fadb8bc87e35ba31f3e02a2501bf38bb67daf Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Tue, 9 Apr 2024 08:29:58 -0700 Subject: [PATCH 74/87] fix: use a LocalObjectReference for credentials Secret (#37) Using a cross-namespace objectRef in the cluster API can lead to privilege escalation. A user with RBAC to read Secrets in one namespace can create a cluster, and copy any Secret from any other namespace to their workload cluster. --- api/v1alpha1/addon_types.go | 5 +---- api/v1alpha1/zz_generated.deepcopy.go | 2 +- pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 6f524159d..05c0d9145 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -164,7 +164,7 @@ type CSIProvider struct { Strategy AddonStrategy `json:"strategy"` // +optional - Credentials *corev1.SecretReference `json:"credentials,omitempty"` + Credentials *corev1.LocalObjectReference `json:"credentials,omitempty"` } type StorageClassConfig struct { @@ -257,9 +257,6 @@ func (CSIProvider) VariableSchema() clusterv1.VariableSchema { "name": { Type: "string", }, - "namespace": { - Type: "string", - }, }, }, "storageClassConfig": { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index a98f87d08..fe954a016 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -290,7 +290,7 @@ func (in *CSIProvider) DeepCopyInto(out *CSIProvider) { } if in.Credentials != nil { in, out := &in.Credentials, &out.Credentials - *out = new(v1.SecretReference) + *out = new(v1.LocalObjectReference) **out = **in } } diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 142189b47..5682f1a6d 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -87,8 +87,8 @@ func (n *NutanixCSI) Apply( Kind: "Secret", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: provider.Credentials.Name, - Name: provider.Credentials.Namespace, + Name: provider.Credentials.Name, + Namespace: req.Cluster.Namespace, }, } err := n.client.Get( From 0e91d4d05237983db360ae6987ed6ffaa0708e34 Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Tue, 9 Apr 2024 08:35:42 -0700 Subject: [PATCH 75/87] fix: the handlers should be changing user provided input (#35) --- .../nutanix/mutation/prismcentralendpoint/inject.go | 9 ++------- .../nutanix/mutation/prismcentralendpoint/inject_test.go | 4 ++-- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go index 808cb6fda..d8ed9b9f2 100644 --- a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go @@ -120,13 +120,8 @@ func (h *nutanixPrismCentralEndpoint) Mutate( Kind: credentials.NutanixTrustBundleKindString, Data: string(decoded), } - } - - // Always force insecure to false if additional trust bundle is provided. - // This ensures that the trust bundle is actually used to validate the connection. - if additionalTrustBundle != "" && prismCentral.Insecure { - log.Info("AdditionalTrustBundle is provided, setting insecure to false") - prismCentral.Insecure = false + // TODO: Consider always setting Insecure to false when AdditionalTrustBundle is set. + // But do it in a webhook and not hidden in this handler. } obj.Spec.Template.Spec.PrismCentral = prismCentral diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go index 83d9f431e..2b6a9e1ee 100644 --- a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go @@ -102,8 +102,8 @@ var _ = Describe("Generate Nutanix Prism Central Endpoint patches", func() { gomega.BeEquivalentTo("prism-central.nutanix.com"), ), gomega.HaveKeyWithValue("port", gomega.BeEquivalentTo(9441)), - // Assert the insecure field was set to false as the additional trust bundle is set - gomega.HaveKeyWithValue("insecure", false), + // Assert the insecure field was not modified when additional trust bundle is set. + gomega.HaveKeyWithValue("insecure", true), gomega.HaveKey("credentialRef"), gomega.HaveKey("additionalTrustBundle"), ), From f8198115ebc07c6f86ef19cfd3c9819e61e1af72 Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Tue, 9 Apr 2024 09:01:27 -0700 Subject: [PATCH 76/87] refactor: combine PC host and port into a single url var (#36) * refactor: combine PC host and port into a single url var This makes it simpler for clients to provide a single input field and not have to do any parsing to split the hostname and port. It also allows us to use API validation for bad input. * fixup! refactor: combine PC host and port into a single url var * fixup! refactor: combine PC host and port into a single url var * fixup! refactor: combine PC host and port into a single url var --- api/openapi/patterns/anchored.go | 4 + api/v1alpha1/nutanix_clusterconfig_types.go | 26 ++---- .../nutanix/prism-central-endpoint.md | 3 +- .../nutanix-cluster-calico-crs.yaml | 3 +- .../nutanix-cluster-calico-helm-addon.yaml | 3 +- .../nutanix-cluster-cilium-crs.yaml | 3 +- .../nutanix-cluster-cilium-helm-addon.yaml | 3 +- .../patches/nutanix/initialize-variables.yaml | 3 +- .../controlplaneendpoint/variables_test.go | 12 +-- .../mutation/prismcentralendpoint/inject.go | 35 +++++++- .../prismcentralendpoint/inject_test.go | 40 ++++++++- .../prismcentralendpoint/variables_test.go | 90 +++++++++++++++++-- 12 files changed, 177 insertions(+), 48 deletions(-) diff --git a/api/openapi/patterns/anchored.go b/api/openapi/patterns/anchored.go index 201dba17c..8f4a36dfe 100644 --- a/api/openapi/patterns/anchored.go +++ b/api/openapi/patterns/anchored.go @@ -6,3 +6,7 @@ package patterns func Anchored(pattern string) string { return "^" + pattern + "$" } + +func HTTPSURL() string { + return `^https://` +} diff --git a/api/v1alpha1/nutanix_clusterconfig_types.go b/api/v1alpha1/nutanix_clusterconfig_types.go index 6e39a6f88..9e1e975ca 100644 --- a/api/v1alpha1/nutanix_clusterconfig_types.go +++ b/api/v1alpha1/nutanix_clusterconfig_types.go @@ -8,11 +8,11 @@ import ( "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/openapi/patterns" ) const ( - PrismCentralPort = 9440 + DefaultPrismCentralPort = 9440 ) // NutanixSpec defines the desired state of NutanixCluster. @@ -39,11 +39,8 @@ func (NutanixSpec) VariableSchema() clusterv1.VariableSchema { } type NutanixPrismCentralEndpointSpec struct { - // host is the DNS name or IP address of the Nutanix Prism Central - Host string `json:"host"` - - // port is the port number to access the Nutanix Prism Central - Port int32 `json:"port"` + // The URL of Nutanix Prism Central, can be DNS name or an IP address + URL string `json:"url"` // use insecure connection to Prism Central endpoint // +optional @@ -65,17 +62,12 @@ func (NutanixPrismCentralEndpointSpec) VariableSchema() clusterv1.VariableSchema Description: "Nutanix Prism Central endpoint configuration", Type: "object", Properties: map[string]clusterv1.JSONSchemaProps{ - "host": { - Description: "the DNS name or IP address of the Nutanix Prism Central", + "url": { + Description: "The URL of Nutanix Prism Central, can be DNS name or an IP address", Type: "string", MinLength: ptr.To[int64](1), - }, - "port": { - Description: "The port number to access the Nutanix Prism Central", - Type: "integer", - Default: variables.MustMarshal(PrismCentralPort), - Minimum: ptr.To[int64](1), - Maximum: ptr.To[int64](65535), + Format: "uri", + Pattern: patterns.HTTPSURL(), }, "insecure": { Description: "Use insecure connection to Prism Central endpoint", @@ -103,7 +95,7 @@ func (NutanixPrismCentralEndpointSpec) VariableSchema() clusterv1.VariableSchema Required: []string{"name"}, }, }, - Required: []string{"host", "port", "credentials"}, + Required: []string{"url", "credentials"}, }, } } diff --git a/docs/content/customization/nutanix/prism-central-endpoint.md b/docs/content/customization/nutanix/prism-central-endpoint.md index 33d8af8fe..12196b79c 100644 --- a/docs/content/customization/nutanix/prism-central-endpoint.md +++ b/docs/content/customization/nutanix/prism-central-endpoint.md @@ -22,9 +22,8 @@ spec: prismCentralEndpoint: credentials: name: secret-name - host: x.x.x.x + url: https://x.x.x.x:9440 insecure: false - port: 9440 ``` Applying this configuration will result in the following value being set: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 3c52b964e..6f0758103 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -365,9 +365,8 @@ spec: prismCentralEndpoint: credentials: name: ${CLUSTER_NAME}-pc-creds - host: ${NUTANIX_ENDPOINT} insecure: ${NUTANIX_INSECURE} - port: 9440 + url: https://${NUTANIX_ENDPOINT}:9440 - name: workerConfig value: nutanix: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index b28a8f68d..e6c77a185 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -365,9 +365,8 @@ spec: prismCentralEndpoint: credentials: name: ${CLUSTER_NAME}-pc-creds - host: ${NUTANIX_ENDPOINT} insecure: ${NUTANIX_INSECURE} - port: 9440 + url: https://${NUTANIX_ENDPOINT}:9440 - name: workerConfig value: nutanix: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index fb90c9254..6b34119d0 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -365,9 +365,8 @@ spec: prismCentralEndpoint: credentials: name: ${CLUSTER_NAME}-pc-creds - host: ${NUTANIX_ENDPOINT} insecure: ${NUTANIX_INSECURE} - port: 9440 + url: https://${NUTANIX_ENDPOINT}:9440 - name: workerConfig value: nutanix: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 7a5e4b048..5552bcb62 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -365,9 +365,8 @@ spec: prismCentralEndpoint: credentials: name: ${CLUSTER_NAME}-pc-creds - host: ${NUTANIX_ENDPOINT} insecure: ${NUTANIX_INSECURE} - port: 9440 + url: https://${NUTANIX_ENDPOINT}:9440 - name: workerConfig value: nutanix: diff --git a/hack/examples/patches/nutanix/initialize-variables.yaml b/hack/examples/patches/nutanix/initialize-variables.yaml index 46a17d7d2..25f970e4e 100644 --- a/hack/examples/patches/nutanix/initialize-variables.yaml +++ b/hack/examples/patches/nutanix/initialize-variables.yaml @@ -11,9 +11,8 @@ host: ${CONTROL_PLANE_ENDPOINT_IP} port: 6443 prismCentralEndpoint: - host: ${NUTANIX_ENDPOINT} + url: https://${NUTANIX_ENDPOINT}:9440 insecure: ${NUTANIX_INSECURE} - port: 9440 credentials: name: ${CLUSTER_NAME}-pc-creds - op: "add" diff --git a/pkg/handlers/nutanix/mutation/controlplaneendpoint/variables_test.go b/pkg/handlers/nutanix/mutation/controlplaneendpoint/variables_test.go index 372e39564..eec2f61f9 100644 --- a/pkg/handlers/nutanix/mutation/controlplaneendpoint/variables_test.go +++ b/pkg/handlers/nutanix/mutation/controlplaneendpoint/variables_test.go @@ -4,6 +4,7 @@ package controlplaneendpoint import ( + "fmt" "testing" corev1 "k8s.io/api/core/v1" @@ -16,6 +17,8 @@ import ( nutanixclusterconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/clusterconfig" ) +var testPrismCentralURL = fmt.Sprintf("https://prism-central.nutanix.com:%d", v1alpha1.DefaultPrismCentralPort) + func TestVariableValidation(t *testing.T) { capitest.ValidateDiscoverVariables( t, @@ -33,8 +36,7 @@ func TestVariableValidation(t *testing.T) { }, // PrismCentralEndpoint is a required field and must always be set PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ - Host: "prism-central.nutanix.com", - Port: v1alpha1.PrismCentralPort, + URL: testPrismCentralURL, Credentials: corev1.LocalObjectReference{ Name: "credentials", }, @@ -52,8 +54,7 @@ func TestVariableValidation(t *testing.T) { }, // PrismCentralEndpoint is a required field and must always be set PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ - Host: "prism-central.nutanix.com", - Port: v1alpha1.PrismCentralPort, + URL: testPrismCentralURL, Credentials: corev1.LocalObjectReference{ Name: "credentials", }, @@ -72,8 +73,7 @@ func TestVariableValidation(t *testing.T) { }, // PrismCentralEndpoint is a required field and must always be set PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ - Host: "prism-central.nutanix.com", - Port: v1alpha1.PrismCentralPort, + URL: testPrismCentralURL, Credentials: corev1.LocalObjectReference{ Name: "credentials", }, diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go index d8ed9b9f2..40a5ab537 100644 --- a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go @@ -7,6 +7,8 @@ import ( "context" "encoding/base64" "fmt" + "net/url" + "strconv" "github.com/nutanix-cloud-native/prism-go-client/environment/credentials" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -97,9 +99,15 @@ func (h *nutanixPrismCentralEndpoint) Mutate( "patchedObjectName", client.ObjectKeyFromObject(obj), ).Info("setting prismCentralEndpoint in NutanixCluster spec") + var address string + var port int32 + address, port, err = parsePrismCentralURL(prismCentralEndpointVar.URL) + if err != nil { + return err + } prismCentral := &credentials.NutanixPrismEndpoint{ - Address: prismCentralEndpointVar.Host, - Port: prismCentralEndpointVar.Port, + Address: address, + Port: port, Insecure: prismCentralEndpointVar.Insecure, CredentialRef: &credentials.NutanixCredentialReference{ Kind: credentials.SecretKind, @@ -130,3 +138,26 @@ func (h *nutanixPrismCentralEndpoint) Mutate( }, ) } + +//nolint:gocritic // no need for named return values +func parsePrismCentralURL(in string) (string, int32, error) { + var prismCentralURL *url.URL + prismCentralURL, err := url.Parse(in) + if err != nil { + return "", -1, fmt.Errorf("error parsing Prism Central URL: %w", err) + } + + hostname := prismCentralURL.Hostname() + + // return early with the default port if no port is specified + if prismCentralURL.Port() == "" { + return hostname, v1alpha1.DefaultPrismCentralPort, nil + } + + port, err := strconv.ParseInt(prismCentralURL.Port(), 10, 32) + if err != nil { + return "", -1, fmt.Errorf("error converting port to int: %w", err) + } + + return hostname, int32(port), nil +} diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go index 2b6a9e1ee..ca7b695b2 100644 --- a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject_test.go @@ -44,8 +44,7 @@ var _ = Describe("Generate Nutanix Prism Central Endpoint patches", func() { capitest.VariableWithValue( clusterconfig.MetaVariableName, v1alpha1.NutanixPrismCentralEndpointSpec{ - Host: "prism-central.nutanix.com", - Port: 9441, + URL: "https://prism-central.nutanix.com:9441", Insecure: true, Credentials: corev1.LocalObjectReference{ Name: "credentials", @@ -73,14 +72,47 @@ var _ = Describe("Generate Nutanix Prism Central Endpoint patches", func() { }, }, }, + { + Name: "all required fields set without port", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + clusterconfig.MetaVariableName, + v1alpha1.NutanixPrismCentralEndpointSpec{ + URL: "https://prism-central.nutanix.com", + Insecure: true, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + nutanixclusterconfig.NutanixVariableName, + VariableName, + ), + }, + RequestItem: request.NewNutanixClusterTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "replace", + Path: "/spec/template/spec/prismCentral", + ValueMatcher: gomega.SatisfyAll( + gomega.HaveKeyWithValue( + "address", + gomega.BeEquivalentTo("prism-central.nutanix.com"), + ), + gomega.HaveKeyWithValue("port", gomega.BeEquivalentTo(v1alpha1.DefaultPrismCentralPort)), + gomega.HaveKeyWithValue("insecure", true), + gomega.HaveKey("credentialRef"), + gomega.Not(gomega.HaveKey("additionalTrustBundle")), + ), + }, + }, + }, { Name: "additional trust bundle is set", Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( clusterconfig.MetaVariableName, v1alpha1.NutanixPrismCentralEndpointSpec{ - Host: "prism-central.nutanix.com", - Port: 9441, + URL: "https://prism-central.nutanix.com:9441", Insecure: true, Credentials: corev1.LocalObjectReference{ Name: "credentials", diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/variables_test.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/variables_test.go index 318189001..0f8009218 100644 --- a/pkg/handlers/nutanix/mutation/prismcentralendpoint/variables_test.go +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/variables_test.go @@ -4,6 +4,7 @@ package prismcentralendpoint import ( + "fmt" "testing" corev1 "k8s.io/api/core/v1" @@ -24,12 +25,11 @@ func TestVariableValidation(t *testing.T) { true, nutanixclusterconfig.NewVariable, capitest.VariableTestDef{ - Name: "valid PC address and port", + Name: "valid PC URL", Vals: v1alpha1.ClusterConfigSpec{ Nutanix: &v1alpha1.NutanixSpec{ PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ - Host: "prism-central.nutanix.com", - Port: v1alpha1.PrismCentralPort, + URL: fmt.Sprintf("https://prism-central.nutanix.com:%d", v1alpha1.DefaultPrismCentralPort), Insecure: false, Credentials: corev1.LocalObjectReference{ Name: "credentials", @@ -44,11 +44,88 @@ func TestVariableValidation(t *testing.T) { }, }, capitest.VariableTestDef{ - Name: "empty PC address", + Name: "valid PC URL as an IP", Vals: v1alpha1.ClusterConfigSpec{ Nutanix: &v1alpha1.NutanixSpec{ PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ - Port: v1alpha1.PrismCentralPort, + URL: fmt.Sprintf("https://10.0.0.1:%d", v1alpha1.DefaultPrismCentralPort), + Insecure: false, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + // ControlPlaneEndpoint is a required field and must always be set + ControlPlaneEndpoint: clusterv1.APIEndpoint{ + Host: "10.20.100.10", + Port: 6443, + }, + }, + }, + }, + capitest.VariableTestDef{ + Name: "valid PC URL without a port", + Vals: v1alpha1.ClusterConfigSpec{ + Nutanix: &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + URL: "https://prism-central.nutanix.com", + Insecure: false, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + // ControlPlaneEndpoint is a required field and must always be set + ControlPlaneEndpoint: clusterv1.APIEndpoint{ + Host: "10.20.100.10", + Port: 6443, + }, + }, + }, + }, + capitest.VariableTestDef{ + Name: "empty PC URL", + Vals: v1alpha1.ClusterConfigSpec{ + Nutanix: &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + Insecure: false, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + // ControlPlaneEndpoint is a required field and must always be set + ControlPlaneEndpoint: clusterv1.APIEndpoint{ + Host: "10.20.100.10", + Port: 6443, + }, + }, + }, + ExpectError: true, + }, + capitest.VariableTestDef{ + Name: "http is not a valid PC URL", + Vals: v1alpha1.ClusterConfigSpec{ + Nutanix: &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + URL: "http://prism-central.nutanix.com", + Insecure: false, + Credentials: corev1.LocalObjectReference{ + Name: "credentials", + }, + }, + // ControlPlaneEndpoint is a required field and must always be set + ControlPlaneEndpoint: clusterv1.APIEndpoint{ + Host: "10.20.100.10", + Port: 6443, + }, + }, + }, + ExpectError: true, + }, + capitest.VariableTestDef{ + Name: "not a valid PC URL", + Vals: v1alpha1.ClusterConfigSpec{ + Nutanix: &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + URL: "not-a-valid-url", Insecure: false, Credentials: corev1.LocalObjectReference{ Name: "credentials", @@ -68,8 +145,7 @@ func TestVariableValidation(t *testing.T) { Vals: v1alpha1.ClusterConfigSpec{ Nutanix: &v1alpha1.NutanixSpec{ PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ - Host: "prism-central.nutanix.com", - Port: v1alpha1.PrismCentralPort, + URL: fmt.Sprintf("https://prism-central.nutanix.com:%d", v1alpha1.DefaultPrismCentralPort), Insecure: false, }, // ControlPlaneEndpoint is a required field and must always be set From 92184b08f53afba4b8f8ad0bc388457b62472df1 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Tue, 9 Apr 2024 18:05:26 +0100 Subject: [PATCH 77/87] ci: Always use latest go for govulncheck (#41) --- .github/workflows/checks.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index cf0fe6a74..4b51612d0 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -225,12 +225,11 @@ jobs: strategy: matrix: module: [api, common, .] + fail-fast: false steps: - - name: Check out code - uses: actions/checkout@v4 - - id: govulncheck uses: golang/govulncheck-action@v1 with: work-dir: ${{ matrix.module }} go-version-file: go.mod + check-latest: true From 5a384e3527d843b88ba958549ddb5b09c65e2448 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Tue, 9 Apr 2024 18:09:27 +0100 Subject: [PATCH 78/87] ci: Disable fail-fast for matrix jobs (#43) --- .github/workflows/checks.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 4b51612d0..8c19c9386 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -59,6 +59,7 @@ jobs: matrix: provider: - Docker + fail-fast: false uses: ./.github/workflows/e2e.yml with: provider: ${{ matrix.provider }} @@ -72,6 +73,7 @@ jobs: strategy: matrix: module: [api, common, .] + fail-fast: false steps: - name: Check out code uses: actions/checkout@v4 From 21f4055ed3a82a536532eef9c926bbc6c67a390a Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Tue, 9 Apr 2024 12:01:30 -0700 Subject: [PATCH 79/87] fix: Nutanix CSI credentials Secret creation (#34) The existing code created a ClusterResourceSet with the user provided Secret. However, that won't work unless that Secret has an embedded Secret in it. --- .../manifests/helm-addon-installation.yaml | 2 + .../generic/lifecycle/csi/aws-ebs/handler.go | 13 +- pkg/handlers/generic/lifecycle/csi/handler.go | 10 +- .../lifecycle/csi/nutanix-csi/handler.go | 94 +++++++----- pkg/handlers/generic/lifecycle/utils/scs.go | 52 +++++++ .../generic/lifecycle/utils/scs_test.go | 144 ++++++++++++++++++ .../generic/lifecycle/utils/secrets.go | 73 +++++++++ pkg/handlers/generic/lifecycle/utils/utils.go | 43 ------ .../generic/lifecycle/utils/utils_test.go | 122 --------------- 9 files changed, 341 insertions(+), 212 deletions(-) create mode 100644 pkg/handlers/generic/lifecycle/utils/scs.go create mode 100644 pkg/handlers/generic/lifecycle/utils/scs_test.go create mode 100644 pkg/handlers/generic/lifecycle/utils/secrets.go diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/helm-addon-installation.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/helm-addon-installation.yaml index b62635034..6dd0cd393 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/helm-addon-installation.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/helm-addon-installation.yaml @@ -8,5 +8,7 @@ metadata: name: '{{ .Values.hooks.csi.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.name }}' data: values.yaml: |- + # The Secret containing the credentials will be created by the handler. createSecret: false + secretName: nutanix-csi-credentials {{- end -}} diff --git a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go index 90072b3a2..c08ef0c18 100644 --- a/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go @@ -21,6 +21,11 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) +var defaultStorageClassParams = map[string]string{ + "csi.storage.k8s.io/fstype": "ext4", + "type": "gp3", +} + type AWSEBSConfig struct { *options.GlobalOptions defaultAWSEBSConfigMapName string @@ -81,14 +86,14 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { allStorageClasses := make([]runtime.Object, 0, len(configs)) - for _, c := range configs { - setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && + for _, config := range configs { + setAsDefault := config.Name == defaultStorageConfig.StorageClassConfigName && v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass( - c, - a.config.GlobalOptions.DefaultsNamespace(), + config, v1alpha1.AWSEBSProvisioner, setAsDefault, + defaultStorageClassParams, )) } cm, err := lifecycleutils.CreateConfigMapForCRS( diff --git a/pkg/handlers/generic/lifecycle/csi/handler.go b/pkg/handlers/generic/lifecycle/csi/handler.go index fd07767c6..178869808 100644 --- a/pkg/handlers/generic/lifecycle/csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/handler.go @@ -118,7 +118,7 @@ func (c *CSIHandler) AfterControlPlaneInitialized( ) continue } - log.Info(fmt.Sprintf("Creating csi provider %s", provider.Name)) + log.Info(fmt.Sprintf("Creating CSI provider %s", provider.Name)) err = handler.Apply( ctx, provider, @@ -129,11 +129,17 @@ func (c *CSIHandler) AfterControlPlaneInitialized( log.Error( err, fmt.Sprintf( - "failed to create %s csi driver object.", + "failed to delpoy %s CSI driver", provider.Name, ), ) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf( + "failed to deploy CSI driver: %v", + err, + ), + ) } } } diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 5682f1a6d..ff1119ac8 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -8,7 +8,6 @@ import ( "fmt" "github.com/spf13/pflag" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -24,16 +23,32 @@ import ( ) const ( - defaultHelmRepositoryURL = "https://nutanix.github.io/helm/" - defaultStorageHelmChartVersion = "v2.6.6" - defaultStorageHelmChartName = "nutanix-csi-storage" - defaultStorageHelmReleaseNameTemplate = "nutanix-csi-storage-%s" - - defaultSnapshotHelmChartVersion = "v6.3.2" - defaultSnapshotHelmChartName = "nutanix-csi-snapshot" - defaultSnapshotHelmReleaseNameTemplate = "nutanix-csi-snapshot-%s" + defaultHelmRepositoryURL = "https://nutanix.github.io/helm/" + defaultStorageHelmChartVersion = "v2.6.6" + defaultStorageHelmChartName = "nutanix-csi-storage" + defaultStorageHelmReleaseName = "nutanix-csi-storage" + defaultStorageHelmReleaseNamespace = "ntnx-system" + + defaultSnapshotHelmChartVersion = "v6.3.2" + defaultSnapshotHelmChartName = "nutanix-csi-snapshot" + defaultSnapshotHelmReleaseName = "nutanix-csi-snapshot" + defaultSnapshotHelmReleaseNamespace = "ntnx-system" + + //nolint:gosec // Does not contain hard coded credentials. + defaultCredentialsSecretName = "nutanix-csi-credentials" ) +var defaultStorageClassParameters = map[string]string{ + "storageType": "NutanixVolumes", + "csi.storage.k8s.io/fstype": "xfs", + "csi.storage.k8s.io/provisioner-secret-name": defaultCredentialsSecretName, + "csi.storage.k8s.io/provisioner-secret-namespace": defaultStorageHelmReleaseNamespace, + "csi.storage.k8s.io/node-publish-secret-name": defaultCredentialsSecretName, + "csi.storage.k8s.io/node-publish-secret-namespace": defaultStorageHelmReleaseNamespace, + "csi.storage.k8s.io/controller-expand-secret-name": defaultCredentialsSecretName, + "csi.storage.k8s.io/controller-expand-secret-namespace": defaultStorageHelmReleaseNamespace, +} + type NutanixCSIConfig struct { *options.GlobalOptions defaultValuesTemplateConfigMapName string @@ -80,42 +95,38 @@ func (n *NutanixCSI) Apply( default: return fmt.Errorf("stategy %s not implemented", strategy) } + if provider.Credentials != nil { - sec := &corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: corev1.SchemeGroupVersion.String(), - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: provider.Credentials.Name, - Namespace: req.Cluster.Namespace, - }, + key := ctrlclient.ObjectKey{ + Name: defaultCredentialsSecretName, + Namespace: defaultStorageHelmReleaseNamespace, } - err := n.client.Get( + err := lifecycleutils.CopySecretToRemoteCluster( ctx, - ctrlclient.ObjectKeyFromObject(sec), - sec, - ) - if err != nil { - return err - } - err = lifecycleutils.EnsureCRSForClusterFromObjects( - ctx, - fmt.Sprintf("nutanix-csi-credentials-crs-%s", req.Cluster.Name), n.client, + provider.Credentials.Name, + key, &req.Cluster, - sec, ) if err != nil { - return err + return fmt.Errorf( + "error creating credentials Secret for the Nutanix CSI driver: %w", + err, + ) } } - return n.createStorageClasses( + + err := n.createStorageClasses( ctx, provider.StorageClassConfig, &req.Cluster, defaultStorageConfig, ) + if err != nil { + return fmt.Errorf("error creating StorageClasses for the Nutanix CSI driver: %w", err) + } + + return nil } func (n *NutanixCSI) handleHelmAddonApply( @@ -149,8 +160,8 @@ func (n *NutanixCSI) handleHelmAddonApply( ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{clusterv1.ClusterNameLabel: req.Cluster.Name}, }, - ReleaseNamespace: req.Cluster.Namespace, - ReleaseName: fmt.Sprintf(defaultStorageHelmReleaseNameTemplate, req.Cluster.Name), + ReleaseNamespace: defaultStorageHelmReleaseNamespace, + ReleaseName: defaultStorageHelmReleaseName, Version: defaultStorageHelmChartVersion, ValuesTemplate: values, }, @@ -174,7 +185,7 @@ func (n *NutanixCSI) handleHelmAddonApply( }, ObjectMeta: metav1.ObjectMeta{ Namespace: req.Cluster.Namespace, - Name: "nutanix-csi-snapshot" + req.Cluster.Name, + Name: "nutanix-csi-snapshot-" + req.Cluster.Name, }, Spec: caaphv1.HelmChartProxySpec{ RepoURL: defaultHelmRepositoryURL, @@ -182,8 +193,8 @@ func (n *NutanixCSI) handleHelmAddonApply( ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{clusterv1.ClusterNameLabel: req.Cluster.Name}, }, - ReleaseNamespace: req.Cluster.Namespace, - ReleaseName: fmt.Sprintf(defaultSnapshotHelmReleaseNameTemplate, req.Cluster.Name), + ReleaseNamespace: defaultSnapshotHelmReleaseNamespace, + ReleaseName: defaultSnapshotHelmReleaseName, Version: defaultSnapshotHelmChartVersion, }, } @@ -205,20 +216,21 @@ func (n *NutanixCSI) handleHelmAddonApply( return nil } -func (n *NutanixCSI) createStorageClasses(ctx context.Context, +func (n *NutanixCSI) createStorageClasses( + ctx context.Context, configs []v1alpha1.StorageClassConfig, cluster *clusterv1.Cluster, defaultStorageConfig *v1alpha1.DefaultStorage, ) error { allStorageClasses := make([]runtime.Object, 0, len(configs)) - for _, c := range configs { - setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName && + for _, config := range configs { + setAsDefault := config.Name == defaultStorageConfig.StorageClassConfigName && v1alpha1.CSIProviderNutanix == defaultStorageConfig.ProviderName allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass( - c, - n.config.GlobalOptions.DefaultsNamespace(), + config, v1alpha1.NutanixProvisioner, setAsDefault, + defaultStorageClassParameters, )) } cm, err := lifecycleutils.CreateConfigMapForCRS( diff --git a/pkg/handlers/generic/lifecycle/utils/scs.go b/pkg/handlers/generic/lifecycle/utils/scs.go new file mode 100644 index 000000000..6bcb66bd3 --- /dev/null +++ b/pkg/handlers/generic/lifecycle/utils/scs.go @@ -0,0 +1,52 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + storagev1 "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" +) + +const ( + kindStorageClass = "StorageClass" +) + +func CreateStorageClass( + storageConfig v1alpha1.StorageClassConfig, + provisionerName v1alpha1.StorageProvisioner, + isDefault bool, + defaultParameters map[string]string, +) *storagev1.StorageClass { + parameters := make(map[string]string) + // set the defaults first so that user provided parameters can override them + for k, v := range defaultParameters { + parameters[k] = v + } + // set user provided parameters, overriding any defaults with the same key + for k, v := range storageConfig.Parameters { + parameters[k] = v + } + + sc := storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: kindStorageClass, + APIVersion: storagev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: storageConfig.Name, + }, + Provisioner: string(provisionerName), + Parameters: parameters, + VolumeBindingMode: ptr.To(storageConfig.VolumeBindingMode), + ReclaimPolicy: ptr.To(storageConfig.ReclaimPolicy), + AllowVolumeExpansion: ptr.To(storageConfig.AllowExpansion), + } + if isDefault { + sc.ObjectMeta.Annotations = defaultStorageClassMap + } + return &sc +} diff --git a/pkg/handlers/generic/lifecycle/utils/scs_test.go b/pkg/handlers/generic/lifecycle/utils/scs_test.go new file mode 100644 index 000000000..a75a5fdd8 --- /dev/null +++ b/pkg/handlers/generic/lifecycle/utils/scs_test.go @@ -0,0 +1,144 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + storagev1 "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" +) + +var ( + defaultParameters = map[string]string{ + "csi.storage.k8s.io/fstype": "ext4", + "type": "gp3", + } + userProviderParameters = map[string]string{ + "csi.storage.k8s.io/fstype": "xfs", + "flashMode": "ENABLED", + "storageContainer": "storage-container-name", + "chapAuth": "ENABLED", + "storageType": "NutanixVolumes", + "whitelistIPMode": "ENABLED", + "whitelistIPAddr": "1.1.1.1", + } + + combinedParameters = map[string]string{ + "csi.storage.k8s.io/fstype": "xfs", + "type": "gp3", + "flashMode": "ENABLED", + "storageContainer": "storage-container-name", + "chapAuth": "ENABLED", + "storageType": "NutanixVolumes", + "whitelistIPMode": "ENABLED", + "whitelistIPAddr": "1.1.1.1", + } +) + +func TestCreateStorageClass(t *testing.T) { + tests := []struct { + name string + storageConfig v1alpha1.StorageClassConfig + provisioner v1alpha1.StorageProvisioner + setAsDefault bool + defaultParameters map[string]string + expectedStorageClass *storagev1.StorageClass + }{ + { + name: "with only default parameters", + storageConfig: v1alpha1.StorageClassConfig{ + Name: "aws-ebs", + ReclaimPolicy: v1alpha1.VolumeReclaimDelete, + VolumeBindingMode: v1alpha1.VolumeBindingWaitForFirstConsumer, + Parameters: nil, + AllowExpansion: true, + }, + provisioner: v1alpha1.AWSEBSProvisioner, + defaultParameters: defaultParameters, + expectedStorageClass: &storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: kindStorageClass, + APIVersion: storagev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "aws-ebs", + }, + Parameters: defaultParameters, + ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), + VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), + Provisioner: string(v1alpha1.AWSEBSProvisioner), + AllowVolumeExpansion: ptr.To(true), + }, + }, + { + name: "with only user provided parameters", + storageConfig: v1alpha1.StorageClassConfig{ + Name: "nutanix-volumes", + ReclaimPolicy: v1alpha1.VolumeReclaimDelete, + VolumeBindingMode: v1alpha1.VolumeBindingWaitForFirstConsumer, + Parameters: userProviderParameters, + }, + provisioner: v1alpha1.NutanixProvisioner, + expectedStorageClass: &storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: kindStorageClass, + APIVersion: storagev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "nutanix-volumes", + }, + Parameters: userProviderParameters, + ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), + VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), + Provisioner: string(v1alpha1.NutanixProvisioner), + AllowVolumeExpansion: ptr.To(false), + }, + }, + { + name: "with both default and user provided parameters", + storageConfig: v1alpha1.StorageClassConfig{ + Name: "aws-ebs", + ReclaimPolicy: v1alpha1.VolumeReclaimDelete, + VolumeBindingMode: v1alpha1.VolumeBindingWaitForFirstConsumer, + Parameters: userProviderParameters, + AllowExpansion: true, + }, + provisioner: v1alpha1.AWSEBSProvisioner, + defaultParameters: defaultParameters, + expectedStorageClass: &storagev1.StorageClass{ + TypeMeta: metav1.TypeMeta{ + Kind: kindStorageClass, + APIVersion: storagev1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "aws-ebs", + }, + Parameters: combinedParameters, + ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), + VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), + Provisioner: string(v1alpha1.AWSEBSProvisioner), + AllowVolumeExpansion: ptr.To(true), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sc := CreateStorageClass( + tt.storageConfig, + tt.provisioner, + tt.setAsDefault, + tt.defaultParameters, + ) + if diff := cmp.Diff(sc, tt.expectedStorageClass); diff != "" { + t.Errorf("CreateStorageClass() mismatch (-want +got):\n%s", diff) + } + }) + } +} diff --git a/pkg/handlers/generic/lifecycle/utils/secrets.go b/pkg/handlers/generic/lifecycle/utils/secrets.go new file mode 100644 index 000000000..7c3660913 --- /dev/null +++ b/pkg/handlers/generic/lifecycle/utils/secrets.go @@ -0,0 +1,73 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + "fmt" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + "sigs.k8s.io/cluster-api/controllers/remote" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" +) + +// CopySecretToRemoteCluster will get the Secret from srcSecretName +// and create it on the remote cluster, copying Data and StringData to dstSecretKey Secret. +func CopySecretToRemoteCluster( + ctx context.Context, + cl ctrlclient.Client, + srcSecretName string, + dstSecretKey ctrlclient.ObjectKey, + cluster *clusterv1.Cluster, +) error { + sourceSecret := &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: srcSecretName, + Namespace: cluster.Namespace, + }, + } + err := cl.Get(ctx, ctrlclient.ObjectKeyFromObject(sourceSecret), sourceSecret) + if err != nil { + return err + } + + credentialsOnRemote := &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: dstSecretKey.Name, + Namespace: dstSecretKey.Namespace, + }, + Data: sourceSecret.Data, + StringData: sourceSecret.StringData, + } + + clusterKey := ctrlclient.ObjectKeyFromObject(cluster) + remoteClient, err := remote.NewClusterClient(ctx, "", cl, clusterKey) + if err != nil { + return fmt.Errorf("error creating client for remote cluster: %w", err) + } + + err = EnsureNamespace(ctx, remoteClient, dstSecretKey.Namespace) + if err != nil { + return fmt.Errorf("error creating namespace on the remote cluster: %w", err) + } + + err = client.ServerSideApply(ctx, remoteClient, credentialsOnRemote) + if err != nil { + return fmt.Errorf("error creating Secret on the remote cluster: %w", err) + } + + return nil +} diff --git a/pkg/handlers/generic/lifecycle/utils/utils.go b/pkg/handlers/generic/lifecycle/utils/utils.go index aa6d42b30..8a78b4d15 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils.go +++ b/pkg/handlers/generic/lifecycle/utils/utils.go @@ -6,26 +6,21 @@ package utils import ( "context" "fmt" - "maps" corev1 "k8s.io/api/core/v1" - storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" crsv1 "sigs.k8s.io/cluster-api/exp/addons/api/v1beta1" utilyaml "sigs.k8s.io/cluster-api/util/yaml" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" ) const ( - kindStorageClass = "StorageClass" defaultCRSConfigMapKey = "custom-resources.yaml" ) @@ -34,10 +29,6 @@ var ( defaultStorageClassMap = map[string]string{ defaultStorageClassKey: "true", } - defaultAWSStorageClassParams = map[string]string{ - "csi.storage.k8s.io/fstype": "ext4", - "type": "gp3", - } ) func EnsureCRSForClusterFromObjects( @@ -153,40 +144,6 @@ func RetrieveValuesTemplateConfigMap( return configMap, nil } -func CreateStorageClass( - storageConfig v1alpha1.StorageClassConfig, - defaultsNamespace string, - provisionerName v1alpha1.StorageProvisioner, - isDefault bool, -) *storagev1.StorageClass { - var params map[string]string - if provisionerName == v1alpha1.AWSEBSProvisioner { - params = defaultAWSStorageClassParams - } - if storageConfig.Parameters != nil { - params = maps.Clone(storageConfig.Parameters) - } - sc := storagev1.StorageClass{ - TypeMeta: metav1.TypeMeta{ - Kind: kindStorageClass, - APIVersion: storagev1.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: storageConfig.Name, - Namespace: defaultsNamespace, - }, - Provisioner: string(provisionerName), - Parameters: params, - VolumeBindingMode: ptr.To(storageConfig.VolumeBindingMode), - ReclaimPolicy: ptr.To(storageConfig.ReclaimPolicy), - AllowVolumeExpansion: ptr.To(storageConfig.AllowExpansion), - } - if isDefault { - sc.ObjectMeta.Annotations = defaultStorageClassMap - } - return &sc -} - func CreateConfigMapForCRS(configMapName, configMapNamespace string, objs ...runtime.Object, ) (*corev1.ConfigMap, error) { diff --git a/pkg/handlers/generic/lifecycle/utils/utils_test.go b/pkg/handlers/generic/lifecycle/utils/utils_test.go index 420ebe562..26ec622e6 100644 --- a/pkg/handlers/generic/lifecycle/utils/utils_test.go +++ b/pkg/handlers/generic/lifecycle/utils/utils_test.go @@ -6,134 +6,12 @@ package utils import ( "testing" - "github.com/google/go-cmp/cmp" corev1 "k8s.io/api/core/v1" storagev1 "k8s.io/api/storage/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/utils/ptr" - - "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" ) -func TestCreateStorageClass(t *testing.T) { - tests := []struct { - name string - defaultsNamespace string - storageConfig v1alpha1.StorageClassConfig - expectedStorageClass *storagev1.StorageClass - provisioner v1alpha1.StorageProvisioner - isDefault bool - }{ - { - name: "defaulting with AWS", - storageConfig: v1alpha1.StorageClassConfig{ - Name: "aws-ebs", - ReclaimPolicy: v1alpha1.VolumeReclaimDelete, - VolumeBindingMode: v1alpha1.VolumeBindingWaitForFirstConsumer, - Parameters: nil, - AllowExpansion: true, - }, - expectedStorageClass: &storagev1.StorageClass{ - TypeMeta: metav1.TypeMeta{ - Kind: kindStorageClass, - APIVersion: storagev1.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "aws-ebs", - Namespace: "default", - }, - Parameters: defaultAWSStorageClassParams, - ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), - VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), - Provisioner: string(v1alpha1.AWSEBSProvisioner), - AllowVolumeExpansion: ptr.To(true), - }, - provisioner: v1alpha1.AWSEBSProvisioner, - defaultsNamespace: "default", - }, - { - name: "nutanix for nutanix files", - storageConfig: v1alpha1.StorageClassConfig{ - Name: "nutanix-volumes", - ReclaimPolicy: v1alpha1.VolumeReclaimDelete, - VolumeBindingMode: v1alpha1.VolumeBindingWaitForFirstConsumer, - Parameters: map[string]string{ - "csi.storage.k8s.io/fstype": "ext4", - "flashMode": "ENABLED", - "storageContainer": "storage-container-name", - "chapAuth": "ENABLED", - "storageType": "NutanixVolumes", - "whitelistIPMode": "ENABLED", - "whitelistIPAddr": "1.1.1.1", - }, - }, - expectedStorageClass: &storagev1.StorageClass{ - TypeMeta: metav1.TypeMeta{ - Kind: kindStorageClass, - APIVersion: storagev1.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "nutanix-volumes", - Namespace: "default", - }, - Parameters: map[string]string{ - "csi.storage.k8s.io/fstype": "ext4", - "flashMode": "ENABLED", - "storageContainer": "storage-container-name", - "chapAuth": "ENABLED", - "storageType": "NutanixVolumes", - "whitelistIPMode": "ENABLED", - "whitelistIPAddr": "1.1.1.1", - }, - ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), - VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), - Provisioner: string(v1alpha1.NutanixProvisioner), - AllowVolumeExpansion: ptr.To(false), - }, - provisioner: v1alpha1.NutanixProvisioner, - defaultsNamespace: "default", - }, - { - name: "nutanix defaults", - storageConfig: v1alpha1.StorageClassConfig{ - Name: "nutanix-volumes", - ReclaimPolicy: v1alpha1.VolumeReclaimDelete, - VolumeBindingMode: v1alpha1.VolumeBindingWaitForFirstConsumer, - }, - expectedStorageClass: &storagev1.StorageClass{ - TypeMeta: metav1.TypeMeta{ - Kind: kindStorageClass, - APIVersion: storagev1.SchemeGroupVersion.String(), - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "nutanix-volumes", - Namespace: "default", - }, - ReclaimPolicy: ptr.To(corev1.PersistentVolumeReclaimDelete), - VolumeBindingMode: ptr.To(storagev1.VolumeBindingWaitForFirstConsumer), - Provisioner: string(v1alpha1.NutanixProvisioner), - AllowVolumeExpansion: ptr.To(false), - }, - provisioner: v1alpha1.NutanixProvisioner, - defaultsNamespace: "default", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - sc := CreateStorageClass( - tt.storageConfig, - tt.defaultsNamespace, - tt.provisioner, - false, - ) - if diff := cmp.Diff(sc, tt.expectedStorageClass); diff != "" { - t.Errorf("CreateStorageClass() mismatch (-want +got):\n%s", diff) - } - }) - } -} - func TestCreateConfigMapForCRS(t *testing.T) { tests := []struct { name string From 9b92854126613f5e82732e39804c74ab4087a02d Mon Sep 17 00:00:00 2001 From: Faiq Date: Tue, 9 Apr 2024 15:27:58 -0400 Subject: [PATCH 80/87] feat: get helm config from a well known configmap (#27) * ci: adds tooling to create configmap * feat: use a configmap to get helmchart info * fix: precommit issues * fix: typo in cilium * fix: remove workspace files * build: template name for configmap * refactor: names for helm chart info getter * refactor: use nutanix-storage name instead of nutnaix-csi * refactor: move to globaloptions * fix: adds snapshot to helm config * fix: comments after review * fix: adds a warning and removes ebs csi * fix: typo * fix: adds missing script file * fix: precommit --- .pre-commit-config.yaml | 8 +- .../README.md | 1 + ...aml => nutanix-storage-csi-configmap.yaml} | 6 +- .../templates/deployment.yaml | 1 + .../templates/helm-config.yaml | 37 ++++ .../values.yaml | 2 + go.mod | 2 +- hack/addons/add-warning-helm-configmap.sh | 23 +++ .../kustomization.yaml.tmpl | 19 ++ .../helm-values.yaml | 0 .../kustomization.yaml.tmpl | 2 +- hack/addons/update-nutanix-csi.sh | 26 +-- hack/tools/helm-cm/main.go | 167 ++++++++++++++++++ make/addons.mk | 20 ++- .../lifecycle/clusterautoscaler/handler.go | 39 +++- .../clusterautoscaler/strategy_helmaddon.go | 13 +- .../generic/lifecycle/cni/calico/handler.go | 50 ++++-- .../cni/calico/strategy_helmaddon.go | 16 +- .../generic/lifecycle/cni/cilium/handler.go | 47 +++-- .../cni/cilium/strategy_helmaddon.go | 20 +-- pkg/handlers/generic/lifecycle/config/cm.go | 94 ++++++++++ .../lifecycle/csi/nutanix-csi/handler.go | 66 +++---- pkg/handlers/generic/lifecycle/handlers.go | 33 +++- pkg/handlers/generic/lifecycle/nfd/handler.go | 35 +++- .../lifecycle/nfd/strategy_helmaddon.go | 15 +- pkg/handlers/options/global.go | 13 +- 26 files changed, 610 insertions(+), 145 deletions(-) rename charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/{nutanix-csi-configmap.yaml => nutanix-storage-csi-configmap.yaml} (99%) create mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml create mode 100755 hack/addons/add-warning-helm-configmap.sh create mode 100644 hack/addons/kustomize/nutanix-snapshot-csi/kustomization.yaml.tmpl rename hack/addons/kustomize/{nutanix-csi => nutanix-storage-csi}/helm-values.yaml (100%) rename hack/addons/kustomize/{nutanix-csi => nutanix-storage-csi}/kustomization.yaml.tmpl (89%) create mode 100644 hack/tools/helm-cm/main.go create mode 100644 pkg/handlers/generic/lifecycle/config/cm.go diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e9fc7bedb..643fdf161 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,6 +34,12 @@ repos: language: system files: "^(hack/addons/|charts/cluster-api-runtime-extensions-nutanix/templates/.+/manifests/|make/addons.mk$)" pass_filenames: false + - id: addons-configmap + name: addons-configmap + entry: make generate-helm-configmap + language: system + files: "^(hack/addons/|charts/cluster-api-runtime-extensions-nutanix/templates/.+|make/addons.mk$)" + pass_filenames: false - repo: https://github.com/tekwizely/pre-commit-golang rev: v1.0.0-rc.1 hooks: @@ -117,7 +123,7 @@ repos: name: License headers - YAML and Makefiles stages: [commit] files: (^Makefile|\.(ya?ml|mk))$ - exclude: ^(pkg/handlers/.+/embedded|examples|charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses)/.+\.ya?ml|docs/static/helm/index\.yaml$ + exclude: ^(pkg/handlers/.+/embedded|examples|charts/cluster-api-runtime-extensions-nutanix/defaultclusterclasses)/.+\.ya?ml|docs/static/helm/index\.yaml|charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml$ args: - --license-filepath - hack/license-header.txt diff --git a/charts/cluster-api-runtime-extensions-nutanix/README.md b/charts/cluster-api-runtime-extensions-nutanix/README.md index 4baba852b..46601fdf4 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/README.md +++ b/charts/cluster-api-runtime-extensions-nutanix/README.md @@ -31,6 +31,7 @@ A Helm chart for cluster-api-runtime-extensions-nutanix | deployDefaultClusterClasses | bool | `true` | | | deployment.replicas | int | `1` | | | env | object | `{}` | | +| helmAddonsConfigMap | string | `"default-helm-addons-config"` | | | hooks.clusterAutoscaler.crsStrategy.defaultInstallationConfigMap.name | string | `"cluster-autoscaler"` | | | hooks.clusterAutoscaler.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.clusterAutoscaler.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-cluster-autoscaler-helm-values-template"` | | diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-storage-csi-configmap.yaml similarity index 99% rename from charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml rename to charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-storage-csi-configmap.yaml index 03c2539b2..8353d3f9a 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-storage-csi-configmap.yaml @@ -3,11 +3,11 @@ #================================================================= # DO NOT EDIT THIS FILE -# IT HAS BEEN GENERATED BY /hack/addons/update-nutanix-csi.sh +# IT HAS BEEN GENERATED BY /hack/addons/update-nutanix-storage-csi.sh #================================================================= apiVersion: v1 data: - nutanix-csi.yaml: | + nutanix-storage-csi.yaml: | apiVersion: v1 kind: ServiceAccount metadata: @@ -540,4 +540,4 @@ data: kind: ConfigMap metadata: creationTimestamp: null - name: nutanix-csi + name: nutanix-storage-csi diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml index 1ce472756..b54b1d72d 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml @@ -30,6 +30,7 @@ spec: args: - --webhook-cert-dir=/runtimehooks-certs/ - --defaults-namespace=$(POD_NAMESPACE) + - --helm-addons-configmap={{ .Values.helmAddonsConfigMap }} - --cni.cilium.helm-addon.default-values-template-configmap-name={{ .Values.hooks.cni.cilium.helmAddonStrategy.defaultValueTemplateConfigMap.name }} - --nfd.helm-addon.default-values-template-configmap-name={{ .Values.hooks.nfd.helmAddonStrategy.defaultValueTemplateConfigMap.name }} {{- range $key, $value := .Values.extraArgs }} diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml new file mode 100644 index 000000000..255e8d69f --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -0,0 +1,37 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +#================================================================= +# DO NOT EDIT THIS FILE +# IT HAS BEEN GENERATED BY /hack/tools/helm-cm/main.go +#================================================================= +apiVersion: v1 +data: + cilium: | + ChartName: cilium + ChartVersion: 1.15.0 + RepositoryURL: https://helm.cilium.io/ + cluster-autoscaler: | + ChartName: cluster-autoscaler + ChartVersion: 9.35.0 + RepositoryURL: https://kubernetes.github.io/autoscaler + nfd: | + ChartName: node-feature-discovery + ChartVersion: 0.15.2 + RepositoryURL: https://kubernetes-sigs.github.io/node-feature-discovery/charts + nutanix-snapshot-csi: | + ChartName: nutanix-csi-snapshot + ChartVersion: v6.3.2 + RepositoryURL: https://nutanix.github.io/helm/ + nutanix-storage-csi: | + ChartName: nutanix-csi-storage + ChartVersion: v2.6.6 + RepositoryURL: https://nutanix.github.io/helm/ + tigera-operator: | + ChartName: tigera-operator + ChartVersion: v3.26.4 + RepositoryURL: https://docs.tigera.io/calico/charts +kind: ConfigMap +metadata: + creationTimestamp: null + name: {{ .Values.helmAddonsConfigMap }} diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.yaml b/charts/cluster-api-runtime-extensions-nutanix/values.yaml index 93b1df268..88ac607ea 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/values.yaml @@ -66,6 +66,8 @@ hooks: create: true name: default-cluster-autoscaler-helm-values-template +helmAddonsConfigMap: default-helm-addons-config + deployDefaultClusterClasses: true deployment: diff --git a/go.mod b/go.mod index 8459609da..d2777daae 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/onsi/gomega v1.31.1 github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 + gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.29.3 k8s.io/apiextensions-apiserver v0.29.3 k8s.io/apimachinery v0.29.3 @@ -135,7 +136,6 @@ require ( google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/cluster-bootstrap v0.29.3 // indirect k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect diff --git a/hack/addons/add-warning-helm-configmap.sh b/hack/addons/add-warning-helm-configmap.sh new file mode 100755 index 000000000..484c229fc --- /dev/null +++ b/hack/addons/add-warning-helm-configmap.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly SCRIPT_DIR + +# shellcheck source=hack/common.sh +source "${SCRIPT_DIR}/../common.sh" +ASSETS_DIR="$(mktemp -d -p "${TMPDIR:-/tmp}")" +mv "${GIT_REPO_ROOT}/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml" "${ASSETS_DIR}/helm-config.yaml" +# add warning not to edit file directly +cat <"${GIT_REPO_ROOT}/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml" +$(cat "${GIT_REPO_ROOT}/hack/license-header.yaml.txt") + +#================================================================= +# DO NOT EDIT THIS FILE +# IT HAS BEEN GENERATED BY /hack/tools/helm-cm/main.go +#================================================================= +$(cat "${ASSETS_DIR}/helm-config.yaml") +EOF + +sed -i s/placeholder/"{{ .Values.helmAddonsConfigMap }}"/g "${GIT_REPO_ROOT}/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml" diff --git a/hack/addons/kustomize/nutanix-snapshot-csi/kustomization.yaml.tmpl b/hack/addons/kustomize/nutanix-snapshot-csi/kustomization.yaml.tmpl new file mode 100644 index 000000000..7c1d21cdf --- /dev/null +++ b/hack/addons/kustomize/nutanix-snapshot-csi/kustomization.yaml.tmpl @@ -0,0 +1,19 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +metadata: + name: nutanix-csi-kustomize + +namespace: kube-system + +helmCharts: +- name: nutanix-csi-snapshot + repo: https://nutanix.github.io/helm/ + releaseName: nutanix-csi-storage + version: ${NUTANIX_SNAPSHOT_CSI_CHART_VERSION} + includeCRDs: true + skipTests: true + namespace: nutanix-system diff --git a/hack/addons/kustomize/nutanix-csi/helm-values.yaml b/hack/addons/kustomize/nutanix-storage-csi/helm-values.yaml similarity index 100% rename from hack/addons/kustomize/nutanix-csi/helm-values.yaml rename to hack/addons/kustomize/nutanix-storage-csi/helm-values.yaml diff --git a/hack/addons/kustomize/nutanix-csi/kustomization.yaml.tmpl b/hack/addons/kustomize/nutanix-storage-csi/kustomization.yaml.tmpl similarity index 89% rename from hack/addons/kustomize/nutanix-csi/kustomization.yaml.tmpl rename to hack/addons/kustomize/nutanix-storage-csi/kustomization.yaml.tmpl index bc838e438..2e67558f4 100644 --- a/hack/addons/kustomize/nutanix-csi/kustomization.yaml.tmpl +++ b/hack/addons/kustomize/nutanix-storage-csi/kustomization.yaml.tmpl @@ -13,7 +13,7 @@ helmCharts: - name: nutanix-csi-storage repo: https://nutanix.github.io/helm/ releaseName: nutanix-csi-storage - version: ${NUTANIX_CSI_CHART_VERSION} + version: ${NUTANIX_STORAGE_CSI_CHART_VERSION} valuesFile: helm-values.yaml includeCRDs: true skipTests: true diff --git a/hack/addons/update-nutanix-csi.sh b/hack/addons/update-nutanix-csi.sh index e18414a86..c6a488d7e 100755 --- a/hack/addons/update-nutanix-csi.sh +++ b/hack/addons/update-nutanix-csi.sh @@ -8,8 +8,8 @@ readonly SCRIPT_DIR # shellcheck source=hack/common.sh source "${SCRIPT_DIR}/../common.sh" -if [ -z "${NUTANIX_CSI_CHART_VERSION:-}" ]; then - echo "Missing environment variable: NUTANIX_CSI_CHART_VERSION" +if [ -z "${NUTANIX_STORAGE_CSI_CHART_VERSION:-}" ]; then + echo "Missing environment variable: NUTANIX_STORAGE_CSI_CHART_VERSION" exit 1 fi @@ -17,26 +17,26 @@ ASSETS_DIR="$(mktemp -d -p "${TMPDIR:-/tmp}")" readonly ASSETS_DIR trap_add "rm -rf ${ASSETS_DIR}" EXIT -readonly FILE_NAME="nutanix-csi.yaml" +readonly FILE_NAME="nutanix-storage-csi.yaml" -readonly KUSTOMIZE_BASE_DIR="${SCRIPT_DIR}/kustomize/nutanix-csi" -mkdir -p "${ASSETS_DIR}/nutanix-csi" -envsubst -no-unset <"${KUSTOMIZE_BASE_DIR}/kustomization.yaml.tmpl" >"${ASSETS_DIR}/nutanix-csi/kustomization.yaml" -cp -r "${KUSTOMIZE_BASE_DIR}"/*.yaml "${ASSETS_DIR}/nutanix-csi/" +readonly KUSTOMIZE_BASE_DIR="${SCRIPT_DIR}/kustomize/nutanix-storage-csi" +mkdir -p "${ASSETS_DIR}/nutanix-storage-csi" +envsubst -no-unset <"${KUSTOMIZE_BASE_DIR}/kustomization.yaml.tmpl" >"${ASSETS_DIR}/nutanix-storage-csi/kustomization.yaml" +cp -r "${KUSTOMIZE_BASE_DIR}"/*.yaml "${ASSETS_DIR}/nutanix-storage-csi/" -kustomize build --enable-helm "${ASSETS_DIR}/nutanix-csi/" >"${ASSETS_DIR}/${FILE_NAME}" +kustomize build --enable-helm "${ASSETS_DIR}/nutanix-storage-csi/" >"${ASSETS_DIR}/${FILE_NAME}" -kubectl create configmap nutanix-csi --dry-run=client --output yaml \ +kubectl create configmap nutanix-storage-csi --dry-run=client --output yaml \ --from-file "${ASSETS_DIR}/${FILE_NAME}" \ - >"${ASSETS_DIR}/nutanix-csi-configmap.yaml" + >"${ASSETS_DIR}/nutanix-storage-csi-configmap.yaml" # add warning not to edit file directly -cat <"${GIT_REPO_ROOT}/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-csi-configmap.yaml" +cat <"${GIT_REPO_ROOT}/charts/cluster-api-runtime-extensions-nutanix/templates/csi/nutanix/manifests/nutanix-storage-csi-configmap.yaml" $(cat "${GIT_REPO_ROOT}/hack/license-header.yaml.txt") #================================================================= # DO NOT EDIT THIS FILE -# IT HAS BEEN GENERATED BY /hack/addons/update-nutanix-csi.sh +# IT HAS BEEN GENERATED BY /hack/addons/update-nutanix-storage-csi.sh #================================================================= -$(cat "${ASSETS_DIR}/nutanix-csi-configmap.yaml") +$(cat "${ASSETS_DIR}/nutanix-storage-csi-configmap.yaml") EOF diff --git a/hack/tools/helm-cm/main.go b/hack/tools/helm-cm/main.go new file mode 100644 index 000000000..54f919e50 --- /dev/null +++ b/hack/tools/helm-cm/main.go @@ -0,0 +1,167 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "bytes" + "context" + "flag" + "fmt" + "io/fs" + "os" + "path" + "strings" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/yaml" + ctrl "sigs.k8s.io/controller-runtime" + yamlMarshal "sigs.k8s.io/yaml" +) + +const ( + createHelmAddonsConfigMap = "helm-addons" +) + +var log = ctrl.LoggerFrom(context.Background()) + +func main() { + args := os.Args + var ( + kustomizeDirectory string + outputFile string + ) + flagSet := flag.NewFlagSet(createHelmAddonsConfigMap, flag.ExitOnError) + flagSet.StringVar(&kustomizeDirectory, "kustomize-directory", "", + "Kustomize base directory for all addons") + flagSet.StringVar(&outputFile, "output-file", "", + "output file name to write config map to.") + err := flagSet.Parse(args[1:]) + if err != nil { + log.Error(err, "failed to parse args") + } + cm, err := createConfigMapFromDir(kustomizeDirectory) + if err != nil { + log.Error(err, "failed to create configMap") + return + } + b, err := yamlMarshal.Marshal(*cm) + if err != nil { + log.Error(err, "failed ") + } + fullOutputfilePath := outputFile + if !path.IsAbs(outputFile) { + wd, err := os.Getwd() + if err != nil { + log.Error(err, "failed") + } + fullOutputfilePath = path.Join(wd, outputFile) + } + f, err := os.OpenFile(fullOutputfilePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666) + if err != nil { + log.Error(err, "failed to create file") + } + defer f.Close() + _, err = bytes.NewBuffer(b).WriteTo(f) + if err != nil { + log.Error(err, "failed to write to file") + } +} + +type configMapInfo struct { + configMapFieldName string + RepositoryURL string `json:"RepositoryURL"` + ChartVersion string `json:"ChartVersion"` + ChartName string `json:"ChartName"` +} + +func createConfigMapFromDir(kustomizeDir string) (*corev1.ConfigMap, error) { + fullPath := kustomizeDir + if !path.IsAbs(fullPath) { + wd, err := os.Getwd() + if err != nil { + return nil, fmt.Errorf("failed to get wd %w", err) + } + fullPath = path.Join(wd, kustomizeDir) + } + configDirFS := os.DirFS(fullPath) + results := []configMapInfo{} + err := fs.WalkDir(configDirFS, ".", func(filepath string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if strings.Contains(filepath, "kustomization.yaml.tmpl") && !isIgnored(filepath) { + f, err := os.Open(path.Join(fullPath, filepath)) + if err != nil { + return fmt.Errorf("failed to open file: %w", err) + } + defer f.Close() + obj := make(map[string]interface{}) + err = yaml.NewYAMLOrJSONDecoder(f, 1024).Decode(&obj) + if err != nil { + return err + } + charts, ok := obj["helmCharts"] + if !ok { + log.Info("obj %v does not have field helmCharts. skipping \n", obj) + return nil + } + parsedCharts, ok := charts.([]interface{}) + if !ok { + return fmt.Errorf("charts obj %v is not of type []interface", charts) + } + info, ok := parsedCharts[0].(map[string]interface{}) + if !ok { + return fmt.Errorf("info obj %v is not of type map[string]interface", parsedCharts) + } + repo := info["repo"].(string) + name := info["name"].(string) + dirName := strings.Split(filepath, "/")[0] + i := configMapInfo{ + configMapFieldName: dirName, + RepositoryURL: repo, + ChartName: name, + } + versionEnvVar := info["version"].(string) + version := os.ExpandEnv(versionEnvVar) + i.ChartVersion = version + results = append(results, i) + return nil + } + return nil + }) + + finalCM := corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "placeholder", + }, + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ConfigMap", + }, + Data: make(map[string]string), + } + for _, res := range results { + d, err := yamlMarshal.Marshal(res) + if err != nil { + return &finalCM, err + } + finalCM.Data[res.configMapFieldName] = string(d) + } + return &finalCM, err +} + +var ignored = []string{ + "aws-ccm", + "aws-ebs-csi", +} + +func isIgnored(filepath string) bool { + for _, i := range ignored { + if strings.Contains(filepath, i) { + return true + } + } + return false +} diff --git a/make/addons.mk b/make/addons.mk index c09890922..648fc47d9 100644 --- a/make/addons.mk +++ b/make/addons.mk @@ -1,13 +1,14 @@ # Copyright 2023 D2iQ, Inc. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -export CALICO_VERSION := $(shell goprintconst -file pkg/handlers/generic/lifecycle/cni/calico/strategy_helmaddon.go -name defaultCalicoHelmChartVersion) -export CILIUM_VERSION := $(shell goprintconst -file pkg/handlers/generic/lifecycle/cni/cilium/strategy_helmaddon.go -name defaultCiliumHelmChartVersion) -export NODE_FEATURE_DISCOVERY_VERSION := $(shell goprintconst -file pkg/handlers/generic/lifecycle/nfd/strategy_helmaddon.go -name defaultHelmChartVersion) +export CALICO_VERSION := v3.26.4 +export CILIUM_VERSION := 1.15.0 +export NODE_FEATURE_DISCOVERY_VERSION := 0.15.2 export CLUSTER_AUTOSCALER_VERSION := 9.35.0 export AWS_CSI_SNAPSHOT_CONTROLLER_VERSION := v6.3.3 export AWS_EBS_CSI_CHART_VERSION := v2.28.1 -export NUTANIX_CSI_CHART_VERSION := v2.6.6 +export NUTANIX_STORAGE_CSI_CHART_VERSION := v2.6.6 +export NUTANIX_SNAPSHOT_CSI_CHART_VERSION := v6.3.2 # a map of AWS CCM versions export AWS_CCM_VERSION_127 := v1.27.1 export AWS_CCM_CHART_VERSION_127 := 0.0.8 @@ -15,7 +16,7 @@ export AWS_CCM_VERSION_128 := v1.28.1 export AWS_CCM_CHART_VERSION_128 := 0.0.8 .PHONY: addons.sync -addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler aws-ebs-csi aws-ccm.127 aws-ccm.128) +addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler aws-ebs-csi aws-ccm.127 nutanix-storage-csi aws-ccm.128) .PHONY: update-addon.calico update-addon.calico: ; $(info $(M) updating calico manifests) @@ -41,6 +42,11 @@ update-addon.aws-ebs-csi: ; $(info $(M) updating aws ebs csi manifests) update-addon.aws-ccm.%: ; $(info $(M) updating aws ccm $* manifests) ./hack/addons/update-aws-ccm.sh $(AWS_CCM_VERSION_$*) $(AWS_CCM_CHART_VERSION_$*) -.PHONY: update-addon.nutanix-csi -update-addon.nutanix-csi: ; $(info $(M) updating nutanix csi manifests) +.PHONY: update-addon.nutanix-storage-csi +update-addon.nutanix-storage-csi: ; $(info $(M) updating nutanix-storage csi manifests) ./hack/addons/update-nutanix-csi.sh + +.PHONY: generate-helm-configmap +generate-helm-configmap: + go run hack/tools/helm-cm/main.go -kustomize-directory="./hack/addons/kustomize" -output-file="./charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml" + ./hack/addons/add-warning-helm-configmap.sh diff --git a/pkg/handlers/generic/lifecycle/clusterautoscaler/handler.go b/pkg/handlers/generic/lifecycle/clusterautoscaler/handler.go index 6ad7c5925..a7110d40e 100644 --- a/pkg/handlers/generic/lifecycle/clusterautoscaler/handler.go +++ b/pkg/handlers/generic/lifecycle/clusterautoscaler/handler.go @@ -18,6 +18,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) @@ -43,8 +44,9 @@ func (c *Config) AddFlags(prefix string, flags *pflag.FlagSet) { } type DefaultClusterAutoscaler struct { - client ctrlclient.Client - config *Config + client ctrlclient.Client + config *Config + helmChartInfoGetter *config.HelmChartGetter variableName string // points to the global config variable variablePath []string // path of this variable on the global config variable @@ -58,12 +60,14 @@ var ( func New( c ctrlclient.Client, cfg *Config, + helmChartInfoGetter *config.HelmChartGetter, ) *DefaultClusterAutoscaler { return &DefaultClusterAutoscaler{ - client: c, - config: cfg, - variableName: clusterconfig.MetaVariableName, - variablePath: []string{"addons", v1alpha1.ClusterAutoscalerVariableName}, + client: c, + config: cfg, + helmChartInfoGetter: helmChartInfoGetter, + variableName: clusterconfig.MetaVariableName, + variablePath: []string{"addons", v1alpha1.ClusterAutoscalerVariableName}, } } @@ -117,9 +121,28 @@ func (n *DefaultClusterAutoscaler) AfterControlPlaneInitialized( client: n.client, } case v1alpha1.AddonStrategyHelmAddon: + helmChart, err := n.helmChartInfoGetter.For( + ctx, + log, + config.Autoscaler, + ) + if err != nil { + log.Error( + err, + "failed to get configmap with helm settings", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("failed to get config to create helm addon: %v", + err, + ), + ) + return + } strategy = helmAddonStrategy{ - config: n.config.helmAddonConfig, - client: n.client, + config: n.config.helmAddonConfig, + client: n.client, + helmChart: helmChart, } default: resp.SetStatus(runtimehooksv1.ResponseStatusFailure) diff --git a/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go b/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go index a22e69d2f..7f1ba5469 100644 --- a/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go +++ b/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go @@ -17,13 +17,11 @@ import ( caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" ) const ( - defaultHelmRepositoryURL = "https://kubernetes.github.io/autoscaler" - defaultHelmChartVersion = "9.35.0" - defaultHelmChartName = "cluster-autoscaler" defaultHelmReleaseNameTemplate = "cluster-autoscaler-%s" ) @@ -43,7 +41,8 @@ func (c *helmAddonConfig) AddFlags(prefix string, flags *pflag.FlagSet) { type helmAddonStrategy struct { config helmAddonConfig - client ctrlclient.Client + client ctrlclient.Client + helmChart *config.HelmChart } func (s helmAddonStrategy) apply( @@ -87,14 +86,14 @@ func (s helmAddonStrategy) apply( Name: "cluster-autoscaler-" + req.Cluster.Name, }, Spec: caaphv1.HelmChartProxySpec{ - RepoURL: defaultHelmRepositoryURL, - ChartName: defaultHelmChartName, + RepoURL: s.helmChart.Repository, + ChartName: s.helmChart.Name, ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{capiv1.ClusterNameLabel: targetCluster.Name}, }, ReleaseNamespace: req.Cluster.Namespace, ReleaseName: fmt.Sprintf(defaultHelmReleaseNameTemplate, req.Cluster.Name), - Version: defaultHelmChartVersion, + Version: s.helmChart.Version, ValuesTemplate: values, }, } diff --git a/pkg/handlers/generic/lifecycle/cni/calico/handler.go b/pkg/handlers/generic/lifecycle/cni/calico/handler.go index ed3b82259..3ff526d02 100644 --- a/pkg/handlers/generic/lifecycle/cni/calico/handler.go +++ b/pkg/handlers/generic/lifecycle/cni/calico/handler.go @@ -18,6 +18,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) @@ -43,8 +44,9 @@ func (c *CNIConfig) AddFlags(prefix string, flags *pflag.FlagSet) { } type CalicoCNI struct { - client ctrlclient.Client - config *CNIConfig + client ctrlclient.Client + config *CNIConfig + helmChartInfoGetter *config.HelmChartGetter variableName string variablePath []string @@ -58,20 +60,22 @@ var ( func New( c ctrlclient.Client, cfg *CNIConfig, + helmChartInfoGetter *config.HelmChartGetter, ) *CalicoCNI { return &CalicoCNI{ - client: c, - config: cfg, - variableName: clusterconfig.MetaVariableName, - variablePath: []string{"addons", v1alpha1.CNIVariableName}, + client: c, + config: cfg, + helmChartInfoGetter: helmChartInfoGetter, + variableName: clusterconfig.MetaVariableName, + variablePath: []string{"addons", v1alpha1.CNIVariableName}, } } -func (s *CalicoCNI) Name() string { +func (c *CalicoCNI) Name() string { return "CalicoCNI" } -func (s *CalicoCNI) AfterControlPlaneInitialized( +func (c *CalicoCNI) AfterControlPlaneInitialized( ctx context.Context, req *runtimehooksv1.AfterControlPlaneInitializedRequest, resp *runtimehooksv1.AfterControlPlaneInitializedResponse, @@ -85,7 +89,7 @@ func (s *CalicoCNI) AfterControlPlaneInitialized( varMap := variables.ClusterVariablesToVariablesMap(req.Cluster.Spec.Topology.Variables) - cniVar, found, err := variables.Get[v1alpha1.CNI](varMap, s.variableName, s.variablePath...) + cniVar, found, err := variables.Get[v1alpha1.CNI](varMap, c.variableName, c.variablePath...) if err != nil { log.Error( err, @@ -120,13 +124,31 @@ func (s *CalicoCNI) AfterControlPlaneInitialized( switch cniVar.Strategy { case v1alpha1.AddonStrategyClusterResourceSet: strategy = crsStrategy{ - config: s.config.crsConfig, - client: s.client, + config: c.config.crsConfig, + client: c.client, } case v1alpha1.AddonStrategyHelmAddon: + // this is tigera and not calico because we deploy calico via operataor + log.Info("fetching settings for tigera-operator-config") + helmChart, err := c.helmChartInfoGetter.For(ctx, log, config.Tigera) + if err != nil { + log.Error( + err, + "failed to get configmap with helm settings", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("failed to get configration to create helm addon: %v", + err, + ), + ) + return + } + log.Info(fmt.Sprintf("using settings %v to install helm chart config", helmChart)) strategy = helmAddonStrategy{ - config: s.config.helmAddonConfig, - client: s.client, + config: c.config.helmAddonConfig, + client: c.client, + helmChart: helmChart, } default: resp.SetStatus(runtimehooksv1.ResponseStatusFailure) @@ -134,7 +156,7 @@ func (s *CalicoCNI) AfterControlPlaneInitialized( return } - if err := strategy.apply(ctx, req, s.config.DefaultsNamespace(), log); err != nil { + if err := strategy.apply(ctx, req, c.config.DefaultsNamespace(), log); err != nil { resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage(err.Error()) return diff --git a/pkg/handlers/generic/lifecycle/cni/calico/strategy_helmaddon.go b/pkg/handlers/generic/lifecycle/cni/calico/strategy_helmaddon.go index 0495afee1..545f2fcef 100644 --- a/pkg/handlers/generic/lifecycle/cni/calico/strategy_helmaddon.go +++ b/pkg/handlers/generic/lifecycle/cni/calico/strategy_helmaddon.go @@ -18,12 +18,10 @@ import ( caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" ) const ( - defaultCalicoHelmRepositoryURL = "https://docs.tigera.io/calico/charts" - defaultCalicoHelmChartVersion = "v3.26.4" - defaultTigeraOperatorChartName = "tigera-operator" defaultTigeraOperatorReleaseName = "tigera-operator" defaultTigerOperatorNamespace = "tigera-operator" ) @@ -46,9 +44,9 @@ func (c *helmAddonConfig) AddFlags(prefix string, flags *pflag.FlagSet) { } type helmAddonStrategy struct { - config helmAddonConfig - - client ctrlclient.Client + config helmAddonConfig + helmChart *config.HelmChart + client ctrlclient.Client } func (s helmAddonStrategy) apply( @@ -92,14 +90,14 @@ func (s helmAddonStrategy) apply( Name: "calico-cni-installation-" + req.Cluster.Name, }, Spec: caaphv1.HelmChartProxySpec{ - RepoURL: defaultCalicoHelmRepositoryURL, - ChartName: defaultTigeraOperatorChartName, + RepoURL: s.helmChart.Repository, + ChartName: s.helmChart.Name, ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{capiv1.ClusterNameLabel: req.Cluster.Name}, }, ReleaseNamespace: defaultTigerOperatorNamespace, ReleaseName: defaultTigeraOperatorReleaseName, - Version: defaultCalicoHelmChartVersion, + Version: s.helmChart.Version, ValuesTemplate: valuesTemplateConfigMap.Data["values.yaml"], }, } diff --git a/pkg/handlers/generic/lifecycle/cni/cilium/handler.go b/pkg/handlers/generic/lifecycle/cni/cilium/handler.go index 1e7c7db3c..aef9b93a2 100644 --- a/pkg/handlers/generic/lifecycle/cni/cilium/handler.go +++ b/pkg/handlers/generic/lifecycle/cni/cilium/handler.go @@ -18,6 +18,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) @@ -43,8 +44,9 @@ func (c *CNIConfig) AddFlags(prefix string, flags *pflag.FlagSet) { } type CiliumCNI struct { - client ctrlclient.Client - config *CNIConfig + client ctrlclient.Client + config *CNIConfig + helmChartInfoGetter *config.HelmChartGetter variableName string variablePath []string @@ -58,20 +60,22 @@ var ( func New( c ctrlclient.Client, cfg *CNIConfig, + helmChartInfoGetter *config.HelmChartGetter, ) *CiliumCNI { return &CiliumCNI{ - client: c, - config: cfg, - variableName: clusterconfig.MetaVariableName, - variablePath: []string{"addons", v1alpha1.CNIVariableName}, + client: c, + config: cfg, + helmChartInfoGetter: helmChartInfoGetter, + variableName: clusterconfig.MetaVariableName, + variablePath: []string{"addons", v1alpha1.CNIVariableName}, } } -func (s *CiliumCNI) Name() string { +func (c *CiliumCNI) Name() string { return "CiliumCNI" } -func (s *CiliumCNI) AfterControlPlaneInitialized( +func (c *CiliumCNI) AfterControlPlaneInitialized( ctx context.Context, req *runtimehooksv1.AfterControlPlaneInitializedRequest, resp *runtimehooksv1.AfterControlPlaneInitializedResponse, @@ -85,7 +89,7 @@ func (s *CiliumCNI) AfterControlPlaneInitialized( varMap := variables.ClusterVariablesToVariablesMap(req.Cluster.Spec.Topology.Variables) - cniVar, found, err := variables.Get[v1alpha1.CNI](varMap, s.variableName, s.variablePath...) + cniVar, found, err := variables.Get[v1alpha1.CNI](varMap, c.variableName, c.variablePath...) if err != nil { log.Error( err, @@ -120,13 +124,28 @@ func (s *CiliumCNI) AfterControlPlaneInitialized( switch cniVar.Strategy { case v1alpha1.AddonStrategyClusterResourceSet: strategy = crsStrategy{ - config: s.config.crsConfig, - client: s.client, + config: c.config.crsConfig, + client: c.client, } case v1alpha1.AddonStrategyHelmAddon: + helmChart, err := c.helmChartInfoGetter.For(ctx, log, config.Cilium) + if err != nil { + log.Error( + err, + "failed to get configmap with helm settings", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("failed to get configration to create helm addon: %v", + err, + ), + ) + return + } strategy = helmAddonStrategy{ - config: s.config.helmAddonConfig, - client: s.client, + config: c.config.helmAddonConfig, + client: c.client, + helmChart: helmChart, } default: resp.SetStatus(runtimehooksv1.ResponseStatusFailure) @@ -134,7 +153,7 @@ func (s *CiliumCNI) AfterControlPlaneInitialized( return } - if err := strategy.apply(ctx, req, s.config.DefaultsNamespace(), log); err != nil { + if err := strategy.apply(ctx, req, c.config.DefaultsNamespace(), log); err != nil { resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage(err.Error()) return diff --git a/pkg/handlers/generic/lifecycle/cni/cilium/strategy_helmaddon.go b/pkg/handlers/generic/lifecycle/cni/cilium/strategy_helmaddon.go index ecf8fe3ab..b4ab4b29d 100644 --- a/pkg/handlers/generic/lifecycle/cni/cilium/strategy_helmaddon.go +++ b/pkg/handlers/generic/lifecycle/cni/cilium/strategy_helmaddon.go @@ -18,14 +18,12 @@ import ( caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" ) const ( - defaultCiliumHelmRepositoryURL = "https://helm.cilium.io/" - defaultCiliumHelmChartVersion = "1.15.0" - defaultCiliumChartName = "cilium" - defaultCiliumReleaseName = "cilium" - defaultCiliumNamespace = "kube-system" + defaultCiliumReleaseName = "cilium" + defaultCiliumNamespace = "kube-system" ) type helmAddonConfig struct { @@ -42,9 +40,9 @@ func (c *helmAddonConfig) AddFlags(prefix string, flags *pflag.FlagSet) { } type helmAddonStrategy struct { - config helmAddonConfig - - client ctrlclient.Client + config helmAddonConfig + client ctrlclient.Client + helmChart *config.HelmChart } func (s helmAddonStrategy) apply( @@ -72,14 +70,14 @@ func (s helmAddonStrategy) apply( Name: "cilium-cni-installation-" + req.Cluster.Name, }, Spec: caaphv1.HelmChartProxySpec{ - RepoURL: defaultCiliumHelmRepositoryURL, - ChartName: defaultCiliumChartName, + RepoURL: s.helmChart.Repository, + ChartName: s.helmChart.Name, ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{capiv1.ClusterNameLabel: req.Cluster.Name}, }, ReleaseNamespace: defaultCiliumNamespace, ReleaseName: defaultCiliumReleaseName, - Version: defaultCiliumHelmChartVersion, + Version: s.helmChart.Version, ValuesTemplate: valuesTemplateConfigMap.Data["values.yaml"], }, } diff --git a/pkg/handlers/generic/lifecycle/config/cm.go b/pkg/handlers/generic/lifecycle/config/cm.go new file mode 100644 index 000000000..5bb58caa8 --- /dev/null +++ b/pkg/handlers/generic/lifecycle/config/cm.go @@ -0,0 +1,94 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package config + +import ( + "context" + "fmt" + + "github.com/go-logr/logr" + "gopkg.in/yaml.v2" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +type Component string + +const ( + Autoscaler Component = "cluster-autoscaler" + Tigera Component = "tigera-operator" + Cilium Component = "cilium" + NFD Component = "nfd" + NutanixStorageCSI Component = "nutanix-storage-csi" + NutanixSnapshotCSI Component = "nutanix-snapshot-csi" +) + +type HelmChartGetter struct { + cl ctrlclient.Reader + cmName string + cmNamespace string +} + +type HelmChart struct { + Name string `yaml:"ChartName"` + Version string `yaml:"ChartVersion"` + Repository string `yaml:"RepositoryURL"` +} + +func NewHelmChartGetterFromConfigMap( + cmName, cmNamespace string, + cl ctrlclient.Reader, +) *HelmChartGetter { + return &HelmChartGetter{ + cl, + cmName, + cmNamespace, + } +} + +func (h *HelmChartGetter) get( + ctx context.Context, +) (*corev1.ConfigMap, error) { + cm := &corev1.ConfigMap{ + TypeMeta: metav1.TypeMeta{ + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ConfigMap", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: h.cmNamespace, + Name: h.cmName, + }, + } + err := h.cl.Get( + ctx, + ctrlclient.ObjectKeyFromObject(cm), + cm, + ) + return cm, err +} + +func (h *HelmChartGetter) For( + ctx context.Context, + log logr.Logger, + name Component, +) (*HelmChart, error) { + log.Info( + fmt.Sprintf("Fetching HelmChart info for %s from configmap %s/%s", + string(name), + h.cmName, + h.cmNamespace), + ) + cm, err := h.get(ctx) + if err != nil { + return nil, err + } + d, ok := cm.Data[string(name)] + if !ok { + return nil, fmt.Errorf("did not find key %s in %v", name, cm.Data) + } + var settings HelmChart + err = yaml.Unmarshal([]byte(d), &settings) + return &settings, err +} diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index ff1119ac8..6042e3f78 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -12,27 +12,24 @@ import ( "k8s.io/apimachinery/pkg/runtime" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) const ( - defaultHelmRepositoryURL = "https://nutanix.github.io/helm/" - defaultStorageHelmChartVersion = "v2.6.6" - defaultStorageHelmChartName = "nutanix-csi-storage" - defaultStorageHelmReleaseName = "nutanix-csi-storage" - defaultStorageHelmReleaseNamespace = "ntnx-system" + defaultStorageHelmReleaseNameTemplate = "nutanix-csi-storage-%s" + defaultStorageHelmReleaseNamespace = "ntnx-system" - defaultSnapshotHelmChartVersion = "v6.3.2" - defaultSnapshotHelmChartName = "nutanix-csi-snapshot" - defaultSnapshotHelmReleaseName = "nutanix-csi-snapshot" - defaultSnapshotHelmReleaseNamespace = "ntnx-system" + defaultSnapshotHelmReleaseNameTemplate = "nutanix-csi-snapshot-%s" + defaultSnapshotHelmReleaseNamespace = "ntnx-system" //nolint:gosec // Does not contain hard coded credentials. defaultCredentialsSecretName = "nutanix-csi-credentials" @@ -64,17 +61,20 @@ func (n *NutanixCSIConfig) AddFlags(prefix string, flags *pflag.FlagSet) { } type NutanixCSI struct { - client ctrlclient.Client - config *NutanixCSIConfig + client ctrlclient.Client + config *NutanixCSIConfig + helmChartInfoGetter *config.HelmChartGetter } func New( c ctrlclient.Client, cfg *NutanixCSIConfig, + helmChartInfoGetter *config.HelmChartGetter, ) *NutanixCSI { return &NutanixCSI{ - client: c, - config: cfg, + client: c, + config: cfg, + helmChartInfoGetter: helmChartInfoGetter, } } @@ -144,6 +144,14 @@ func (n *NutanixCSI) handleHelmAddonApply( ) } values := valuesTemplateConfigMap.Data["values.yaml"] + log := ctrl.LoggerFrom(ctx).WithValues( + "cluster", + ctrlclient.ObjectKeyFromObject(&req.Cluster), + ) + helmChart, err := n.helmChartInfoGetter.For(ctx, log, config.NutanixStorageCSI) + if err != nil { + return fmt.Errorf("failed to get values for nutanix-csi-config %w", err) + } hcp := &caaphv1.HelmChartProxy{ TypeMeta: metav1.TypeMeta{ @@ -155,14 +163,14 @@ func (n *NutanixCSI) handleHelmAddonApply( Name: "nutanix-csi-" + req.Cluster.Name, }, Spec: caaphv1.HelmChartProxySpec{ - RepoURL: defaultHelmRepositoryURL, - ChartName: defaultStorageHelmChartName, + RepoURL: helmChart.Repository, + ChartName: helmChart.Name, ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{clusterv1.ClusterNameLabel: req.Cluster.Name}, }, - ReleaseNamespace: defaultStorageHelmReleaseNamespace, - ReleaseName: defaultStorageHelmReleaseName, - Version: defaultStorageHelmChartVersion, + ReleaseNamespace: req.Cluster.Namespace, + ReleaseName: fmt.Sprintf(defaultStorageHelmReleaseNameTemplate, req.Cluster.Name), + Version: helmChart.Version, ValuesTemplate: values, }, } @@ -178,6 +186,11 @@ func (n *NutanixCSI) handleHelmAddonApply( return fmt.Errorf("failed to apply nutanix-csi installation HelmChartProxy: %w", err) } + snapshotHelmChart, err := n.helmChartInfoGetter.For(ctx, log, config.NutanixSnapshotCSI) + if err != nil { + return fmt.Errorf("failed to get values for nutanix-csi-config %w", err) + } + snapshotChart := &caaphv1.HelmChartProxy{ TypeMeta: metav1.TypeMeta{ APIVersion: caaphv1.GroupVersion.String(), @@ -188,24 +201,17 @@ func (n *NutanixCSI) handleHelmAddonApply( Name: "nutanix-csi-snapshot-" + req.Cluster.Name, }, Spec: caaphv1.HelmChartProxySpec{ - RepoURL: defaultHelmRepositoryURL, - ChartName: defaultSnapshotHelmChartName, + RepoURL: snapshotHelmChart.Repository, + ChartName: snapshotHelmChart.Name, ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{clusterv1.ClusterNameLabel: req.Cluster.Name}, }, - ReleaseNamespace: defaultSnapshotHelmReleaseNamespace, - ReleaseName: defaultSnapshotHelmReleaseName, - Version: defaultSnapshotHelmChartVersion, + ReleaseNamespace: req.Cluster.Namespace, + ReleaseName: fmt.Sprintf(defaultSnapshotHelmReleaseNameTemplate, req.Cluster.Name), + Version: snapshotHelmChart.Version, }, } - if err = controllerutil.SetOwnerReference(&req.Cluster, snapshotChart, n.client.Scheme()); err != nil { - return fmt.Errorf( - "failed to set owner reference on nutanix-csi installation HelmChartProxy: %w", - err, - ) - } - if err = client.ServerSideApply(ctx, n.client, snapshotChart); err != nil { return fmt.Errorf( "failed to apply nutanix-csi-snapshot installation HelmChartProxy: %w", diff --git a/pkg/handlers/generic/lifecycle/handlers.go b/pkg/handlers/generic/lifecycle/handlers.go index b3b0d22fb..77a2e7a6e 100644 --- a/pkg/handlers/generic/lifecycle/handlers.go +++ b/pkg/handlers/generic/lifecycle/handlers.go @@ -14,6 +14,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/clusterautoscaler" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/calico" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/cilium" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi" awsebs "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/aws-ebs" nutanixcsi "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/csi/nutanix-csi" @@ -23,6 +24,7 @@ import ( ) type Handlers struct { + globalOptions *options.GlobalOptions calicoCNIConfig *calico.CNIConfig ciliumCNIConfig *cilium.CNIConfig nfdConfig *nfd.Config @@ -32,9 +34,14 @@ type Handlers struct { awsccmConfig *awsccm.AWSCCMConfig } -func New(globalOptions *options.GlobalOptions) *Handlers { +func New( + globalOptions *options.GlobalOptions, +) *Handlers { return &Handlers{ - calicoCNIConfig: &calico.CNIConfig{GlobalOptions: globalOptions}, + globalOptions: globalOptions, + calicoCNIConfig: &calico.CNIConfig{ + GlobalOptions: globalOptions, + }, ciliumCNIConfig: &cilium.CNIConfig{GlobalOptions: globalOptions}, nfdConfig: &nfd.Config{GlobalOptions: globalOptions}, clusterAutoscalerConfig: &clusterautoscaler.Config{GlobalOptions: globalOptions}, @@ -45,19 +52,27 @@ func New(globalOptions *options.GlobalOptions) *Handlers { } func (h *Handlers) AllHandlers(mgr manager.Manager) []handlers.Named { + helmChartInfoGetter := config.NewHelmChartGetterFromConfigMap( + h.globalOptions.HelmAddonsConfigMapName(), + h.globalOptions.DefaultsNamespace(), + mgr.GetClient(), + ) csiHandlers := map[string]csi.CSIProvider{ - v1alpha1.CSIProviderAWSEBS: awsebs.New(mgr.GetClient(), h.ebsConfig), - v1alpha1.CSIProviderNutanix: nutanixcsi.New(mgr.GetClient(), h.nutnaixCSIConfig), + v1alpha1.CSIProviderAWSEBS: awsebs.New(mgr.GetClient(), h.ebsConfig), + v1alpha1.CSIProviderNutanix: nutanixcsi.New( + mgr.GetClient(), + h.nutnaixCSIConfig, + helmChartInfoGetter, + ), } ccmHandlers := map[string]ccm.CCMProvider{ v1alpha1.CCMProviderAWS: awsccm.New(mgr.GetClient(), h.awsccmConfig), } - return []handlers.Named{ - calico.New(mgr.GetClient(), h.calicoCNIConfig), - cilium.New(mgr.GetClient(), h.ciliumCNIConfig), - nfd.New(mgr.GetClient(), h.nfdConfig), - clusterautoscaler.New(mgr.GetClient(), h.clusterAutoscalerConfig), + calico.New(mgr.GetClient(), h.calicoCNIConfig, helmChartInfoGetter), + cilium.New(mgr.GetClient(), h.ciliumCNIConfig, helmChartInfoGetter), + nfd.New(mgr.GetClient(), h.nfdConfig, helmChartInfoGetter), + clusterautoscaler.New(mgr.GetClient(), h.clusterAutoscalerConfig, helmChartInfoGetter), servicelbgc.New(mgr.GetClient()), csi.New(mgr.GetClient(), csiHandlers), ccm.New(mgr.GetClient(), ccmHandlers), diff --git a/pkg/handlers/generic/lifecycle/nfd/handler.go b/pkg/handlers/generic/lifecycle/nfd/handler.go index baa3903d7..8eab1edc6 100644 --- a/pkg/handlers/generic/lifecycle/nfd/handler.go +++ b/pkg/handlers/generic/lifecycle/nfd/handler.go @@ -18,6 +18,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" ) @@ -43,8 +44,9 @@ func (c *Config) AddFlags(prefix string, flags *pflag.FlagSet) { } type DefaultNFD struct { - client ctrlclient.Client - config *Config + client ctrlclient.Client + config *Config + helmChartInfoGetter *config.HelmChartGetter variableName string // points to the global config variable variablePath []string // path of this variable on the global config variable @@ -58,12 +60,14 @@ var ( func New( c ctrlclient.Client, cfg *Config, + helmChartInfoGetter *config.HelmChartGetter, ) *DefaultNFD { return &DefaultNFD{ - client: c, - config: cfg, - variableName: clusterconfig.MetaVariableName, - variablePath: []string{"addons", v1alpha1.NFDVariableName}, + client: c, + config: cfg, + helmChartInfoGetter: helmChartInfoGetter, + variableName: clusterconfig.MetaVariableName, + variablePath: []string{"addons", v1alpha1.NFDVariableName}, } } @@ -112,9 +116,24 @@ func (n *DefaultNFD) AfterControlPlaneInitialized( client: n.client, } case v1alpha1.AddonStrategyHelmAddon: + helmChart, err := n.helmChartInfoGetter.For(ctx, log, config.NFD) + if err != nil { + log.Error( + err, + "failed to get configmap with helm settings", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("failed to get configration to create helm addon: %v", + err, + ), + ) + return + } strategy = helmAddonStrategy{ - config: n.config.helmAddonConfig, - client: n.client, + config: n.config.helmAddonConfig, + client: n.client, + helmChart: helmChart, } default: resp.SetStatus(runtimehooksv1.ResponseStatusFailure) diff --git a/pkg/handlers/generic/lifecycle/nfd/strategy_helmaddon.go b/pkg/handlers/generic/lifecycle/nfd/strategy_helmaddon.go index 602400017..4ef0834b3 100644 --- a/pkg/handlers/generic/lifecycle/nfd/strategy_helmaddon.go +++ b/pkg/handlers/generic/lifecycle/nfd/strategy_helmaddon.go @@ -18,12 +18,10 @@ import ( caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" ) const ( - defaultHelmRepositoryURL = "https://kubernetes-sigs.github.io/node-feature-discovery/charts" - defaultHelmChartVersion = "0.15.2" - defaultHelmChartName = "node-feature-discovery" defaultHelmReleaseName = "node-feature-discovery" defaultHelmReleaseNamespace = "node-feature-discovery" ) @@ -44,7 +42,8 @@ func (c *helmAddonConfig) AddFlags(prefix string, flags *pflag.FlagSet) { type helmAddonStrategy struct { config helmAddonConfig - client ctrlclient.Client + client ctrlclient.Client + helmChart *config.HelmChart } func (s helmAddonStrategy) apply( @@ -66,7 +65,7 @@ func (s helmAddonStrategy) apply( values += fmt.Sprintf(` image: tag: v%s-minimal -`, defaultHelmChartVersion) +`, s.helmChart.Version) hcp := &caaphv1.HelmChartProxy{ TypeMeta: metav1.TypeMeta{ @@ -78,14 +77,14 @@ image: Name: "node-feature-discovery-" + req.Cluster.Name, }, Spec: caaphv1.HelmChartProxySpec{ - RepoURL: defaultHelmRepositoryURL, - ChartName: defaultHelmChartName, + RepoURL: s.helmChart.Repository, + ChartName: s.helmChart.Name, ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{capiv1.ClusterNameLabel: req.Cluster.Name}, }, ReleaseNamespace: defaultHelmReleaseNamespace, ReleaseName: defaultHelmReleaseName, - Version: defaultHelmChartVersion, + Version: s.helmChart.Version, ValuesTemplate: values, }, } diff --git a/pkg/handlers/options/global.go b/pkg/handlers/options/global.go index e355a4366..6f1de11a9 100644 --- a/pkg/handlers/options/global.go +++ b/pkg/handlers/options/global.go @@ -13,7 +13,8 @@ func NewGlobalOptions() *GlobalOptions { } type GlobalOptions struct { - defaultsNamespace string + defaultsNamespace string + helmAddonsConfigMapName string } func (o *GlobalOptions) AddFlags(flags *pflag.FlagSet) { @@ -23,8 +24,18 @@ func (o *GlobalOptions) AddFlags(flags *pflag.FlagSet) { corev1.NamespaceDefault, "namespace for default configurations", ) + flags.StringVar( + &o.helmAddonsConfigMapName, + "helm-addons-configmap", + "default-helm-addons-config", + "Name of helm addons configmap", + ) } func (o *GlobalOptions) DefaultsNamespace() string { return o.defaultsNamespace } + +func (o *GlobalOptions) HelmAddonsConfigMapName() string { + return o.helmAddonsConfigMapName +} From c59f46a11857c96871959b4db77fa7133978602e Mon Sep 17 00:00:00 2001 From: Daniel Lipovetsky Date: Tue, 9 Apr 2024 15:52:13 -0700 Subject: [PATCH 81/87] feat: Add patch to configure containerd metrics (#44) * feat: Add patch to configure containerd metrics --- .../customization/generic/containerd-metrics | 12 +++ .../files/metrics-config.toml | 3 + .../mutation/containerdmetrics/inject.go | 73 ++++++++++++++++ .../mutation/containerdmetrics/inject_test.go | 83 +++++++++++++++++++ .../mutation/containerdmetrics/metrics.go | 32 +++++++ pkg/handlers/generic/mutation/handlers.go | 2 + 6 files changed, 205 insertions(+) create mode 100644 docs/content/customization/generic/containerd-metrics create mode 100644 pkg/handlers/generic/mutation/containerdmetrics/files/metrics-config.toml create mode 100644 pkg/handlers/generic/mutation/containerdmetrics/inject.go create mode 100644 pkg/handlers/generic/mutation/containerdmetrics/inject_test.go create mode 100644 pkg/handlers/generic/mutation/containerdmetrics/metrics.go diff --git a/docs/content/customization/generic/containerd-metrics b/docs/content/customization/generic/containerd-metrics new file mode 100644 index 000000000..b35c10927 --- /dev/null +++ b/docs/content/customization/generic/containerd-metrics @@ -0,0 +1,12 @@ ++++ +title = "Containerd metrics" ++++ + +Containerd exports metrics to a Prometheus endpoint. The metrics cover +containerd itself, its plugins, e.g. CRI, and information about the +containers managed by containerd. + +There are currently no configuration options for metrics, and this +customization will be automatically applied when the [provider-specific +cluster configuration patch]({{< ref ".." >}}) is included in the +`ClusterClass`. diff --git a/pkg/handlers/generic/mutation/containerdmetrics/files/metrics-config.toml b/pkg/handlers/generic/mutation/containerdmetrics/files/metrics-config.toml new file mode 100644 index 000000000..e1908f5aa --- /dev/null +++ b/pkg/handlers/generic/mutation/containerdmetrics/files/metrics-config.toml @@ -0,0 +1,3 @@ +[metrics] + address = "0.0.0.0:1338" + grpc_histogram = false diff --git a/pkg/handlers/generic/mutation/containerdmetrics/inject.go b/pkg/handlers/generic/mutation/containerdmetrics/inject.go new file mode 100644 index 000000000..d2c5bc954 --- /dev/null +++ b/pkg/handlers/generic/mutation/containerdmetrics/inject.go @@ -0,0 +1,73 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +package containerdmetrics + +import ( + "context" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" + controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + ctrl "sigs.k8s.io/controller-runtime" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches/selectors" +) + +type containerdMetricsPatchHandler struct{} + +func NewPatch() *containerdMetricsPatchHandler { + return &containerdMetricsPatchHandler{} +} + +func (h *containerdMetricsPatchHandler) Mutate( + ctx context.Context, + obj *unstructured.Unstructured, + vars map[string]apiextensionsv1.JSON, + holderRef runtimehooksv1.HolderReference, + _ ctrlclient.ObjectKey, +) error { + log := ctrl.LoggerFrom(ctx).WithValues( + "holderRef", holderRef, + ) + + metricsConfigDropIn := generateMetricsConfigDropIn() + + if err := patches.MutateIfApplicable( + obj, vars, &holderRef, selectors.ControlPlane(), log, + func(obj *controlplanev1.KubeadmControlPlaneTemplate) error { + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", ctrlclient.ObjectKeyFromObject(obj), + ).Info("adding containerd metrics config to control plane kubeadm config spec") + obj.Spec.Template.Spec.KubeadmConfigSpec.Files = append( + obj.Spec.Template.Spec.KubeadmConfigSpec.Files, + metricsConfigDropIn, + ) + + return nil + }); err != nil { + return err + } + + if err := patches.MutateIfApplicable( + obj, vars, &holderRef, selectors.WorkersKubeadmConfigTemplateSelector(), log, + func(obj *bootstrapv1.KubeadmConfigTemplate) error { + log.WithValues( + "patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(), + "patchedObjectName", ctrlclient.ObjectKeyFromObject(obj), + ).Info("adding containerd metrics config to worker node kubeadm config template") + obj.Spec.Template.Spec.Files = append( + obj.Spec.Template.Spec.Files, + metricsConfigDropIn) + + return nil + }); err != nil { + return err + } + + return nil +} diff --git a/pkg/handlers/generic/mutation/containerdmetrics/inject_test.go b/pkg/handlers/generic/mutation/containerdmetrics/inject_test.go new file mode 100644 index 000000000..20a531bba --- /dev/null +++ b/pkg/handlers/generic/mutation/containerdmetrics/inject_test.go @@ -0,0 +1,83 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package containerdmetrics + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request" +) + +func TestContainerdMetricsPatch(t *testing.T) { + gomega.RegisterFailHandler(Fail) + RunSpecs(t, "Containerd metrics mutator suite") +} + +var _ = Describe("Generate containerd metrics patches", func() { + // only add aws region patch + patchGenerator := func() mutation.GeneratePatches { + return mutation.NewMetaGeneratePatchesHandler("", NewPatch()).(mutation.GeneratePatches) + } + + testDefs := []capitest.PatchTestDef{ + { + Name: "containerd metrics config added to control plane kubeadm config spec", + RequestItem: request.NewKubeadmControlPlaneTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/kubeadmConfigSpec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", metricsConfigDropInFileOnRemote, + ), + ), + }, + }, + }, + { + Name: "containerd metrics config added to worker node kubeadm config template", + Vars: []runtimehooksv1.Variable{ + capitest.VariableWithValue( + "builtin", + map[string]any{ + "machineDeployment": map[string]any{ + "class": "*", + }, + }, + ), + }, + RequestItem: request.NewKubeadmConfigTemplateRequestItem(""), + ExpectedPatchMatchers: []capitest.JSONPatchMatcher{ + { + Operation: "add", + Path: "/spec/template/spec/files", + ValueMatcher: gomega.ContainElements( + gomega.HaveKeyWithValue( + "path", metricsConfigDropInFileOnRemote, + ), + ), + }, + }, + }, + } + + // create test node for each case + for testIdx := range testDefs { + tt := testDefs[testIdx] + It(tt.Name, func() { + capitest.AssertGeneratePatches( + GinkgoT(), + patchGenerator, + &tt, + ) + }) + } +}) diff --git a/pkg/handlers/generic/mutation/containerdmetrics/metrics.go b/pkg/handlers/generic/mutation/containerdmetrics/metrics.go new file mode 100644 index 000000000..d0ef0d0b4 --- /dev/null +++ b/pkg/handlers/generic/mutation/containerdmetrics/metrics.go @@ -0,0 +1,32 @@ +// Copyright 2024 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 +package containerdmetrics + +import ( + _ "embed" + "path" + + cabpkv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" +) + +const ( + // TODO Factor out this constant to a common package. + containerdPatchesDirOnRemote = "/etc/containerd/cre.d" +) + +var ( + //go:embed files/metrics-config.toml + metricsConfigDropIn []byte + metricsConfigDropInFileOnRemote = path.Join( + containerdPatchesDirOnRemote, + "metrics-config.toml", + ) +) + +func generateMetricsConfigDropIn() cabpkv1.File { + return cabpkv1.File{ + Path: metricsConfigDropInFileOnRemote, + Content: string(metricsConfigDropIn), + Permissions: "0600", + } +} diff --git a/pkg/handlers/generic/mutation/handlers.go b/pkg/handlers/generic/mutation/handlers.go index 9ec605971..c37babe6c 100644 --- a/pkg/handlers/generic/mutation/handlers.go +++ b/pkg/handlers/generic/mutation/handlers.go @@ -9,6 +9,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/aws/mutation/cni/calico" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/auditpolicy" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/containerdmetrics" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/containerdrestart" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/etcd" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/extraapiservercertsans" @@ -31,6 +32,7 @@ func MetaMutators(mgr manager.Manager) []mutation.MetaMutator { mirrors.NewPatch(mgr.GetClient()), calico.NewPatch(), users.NewPatch(), + containerdmetrics.NewPatch(), // Some patches may have changed containerd configuration. // We must restart containerd for the configuration to take effect. From a137bb5ed8e356980a02f6c64fb3fa05db0e0d8e Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Tue, 9 Apr 2024 16:00:57 -0700 Subject: [PATCH 82/87] fix: Nutanix CSI HelmChartProxy name and namespace (#45) --- .../generic/lifecycle/csi/nutanix-csi/handler.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go index 6042e3f78..f695eeae8 100644 --- a/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go +++ b/pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go @@ -25,11 +25,11 @@ import ( ) const ( - defaultStorageHelmReleaseNameTemplate = "nutanix-csi-storage-%s" - defaultStorageHelmReleaseNamespace = "ntnx-system" + defaultStorageHelmReleaseName = "nutanix-csi-storage" + defaultStorageHelmReleaseNamespace = "ntnx-system" - defaultSnapshotHelmReleaseNameTemplate = "nutanix-csi-snapshot-%s" - defaultSnapshotHelmReleaseNamespace = "ntnx-system" + defaultSnapshotHelmReleaseName = "nutanix-csi-snapshot" + defaultSnapshotHelmReleaseNamespace = "ntnx-system" //nolint:gosec // Does not contain hard coded credentials. defaultCredentialsSecretName = "nutanix-csi-credentials" @@ -168,8 +168,8 @@ func (n *NutanixCSI) handleHelmAddonApply( ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{clusterv1.ClusterNameLabel: req.Cluster.Name}, }, - ReleaseNamespace: req.Cluster.Namespace, - ReleaseName: fmt.Sprintf(defaultStorageHelmReleaseNameTemplate, req.Cluster.Name), + ReleaseNamespace: defaultStorageHelmReleaseNamespace, + ReleaseName: defaultStorageHelmReleaseName, Version: helmChart.Version, ValuesTemplate: values, }, @@ -206,8 +206,8 @@ func (n *NutanixCSI) handleHelmAddonApply( ClusterSelector: metav1.LabelSelector{ MatchLabels: map[string]string{clusterv1.ClusterNameLabel: req.Cluster.Name}, }, - ReleaseNamespace: req.Cluster.Namespace, - ReleaseName: fmt.Sprintf(defaultSnapshotHelmReleaseNameTemplate, req.Cluster.Name), + ReleaseNamespace: defaultSnapshotHelmReleaseNamespace, + ReleaseName: defaultSnapshotHelmReleaseName, Version: snapshotHelmChart.Version, }, } From bf3a644e7061b7fc592a8daed50fbf2bb75d395e Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Wed, 10 Apr 2024 16:32:37 +0100 Subject: [PATCH 83/87] build: Specify CAPI provider versions from go module versions (#47) This makes the deployment consistent as well as avoiding issues when providers are in the middle of a release. --- .../bases/docker/cluster/kustomization.yaml.tmpl | 2 +- .../bases/docker/clusterclass/kustomization.yaml.tmpl | 2 +- make/clusterctl.mk | 10 ++++++++-- make/examples.mk | 4 ---- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/hack/examples/bases/docker/cluster/kustomization.yaml.tmpl b/hack/examples/bases/docker/cluster/kustomization.yaml.tmpl index 34bea6a80..31e38ab76 100644 --- a/hack/examples/bases/docker/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/docker/cluster/kustomization.yaml.tmpl @@ -5,7 +5,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: -- https://github.com/kubernetes-sigs/cluster-api/releases/download/${CLUSTERCTL_VERSION}/cluster-template-development.yaml +- https://github.com/kubernetes-sigs/cluster-api/releases/download/${CAPI_VERSION}/cluster-template-development.yaml sortOptions: order: fifo diff --git a/hack/examples/bases/docker/clusterclass/kustomization.yaml.tmpl b/hack/examples/bases/docker/clusterclass/kustomization.yaml.tmpl index bfbef5ac5..56ca10a60 100644 --- a/hack/examples/bases/docker/clusterclass/kustomization.yaml.tmpl +++ b/hack/examples/bases/docker/clusterclass/kustomization.yaml.tmpl @@ -5,7 +5,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: -- https://github.com/kubernetes-sigs/cluster-api/releases/download/${CLUSTERCTL_VERSION}/clusterclass-quick-start.yaml +- https://github.com/kubernetes-sigs/cluster-api/releases/download/${CAPI_VERSION}/clusterclass-quick-start.yaml configurations: - kustomizeconfig.yaml diff --git a/make/clusterctl.mk b/make/clusterctl.mk index 0409eaa0e..a556f719e 100644 --- a/make/clusterctl.mk +++ b/make/clusterctl.mk @@ -1,8 +1,11 @@ # Copyright 2023 D2iQ, Inc. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +export CAPI_VERSION := $(shell go list -m -f '{{ .Version }}' sigs.k8s.io/cluster-api) +export CAPD_VERSION := $(shell go list -m -f '{{ .Version }}' sigs.k8s.io/cluster-api/test) export CAPA_VERSION := $(shell cd hack/third-party/capa && go list -m -f '{{ .Version }}' sigs.k8s.io/cluster-api-provider-aws/v2) export CAPX_VERSION := $(shell cd hack/third-party/capx && go list -m -f '{{ .Version }}' github.com/nutanix-cloud-native/cluster-api-provider-nutanix) +export CAAPH_VERSION := $(shell cd hack/third-party/caaph && go list -m -f '{{ .Version }}' sigs.k8s.io/cluster-api-addon-provider-helm) # Leave Nutanix credentials empty here and set it when creating the clusters .PHONY: clusterctl.init @@ -15,8 +18,11 @@ clusterctl.init: NUTANIX_ENDPOINT="" NUTANIX_PASSWORD="" NUTANIX_USER="" \ clusterctl init \ --kubeconfig=$(KIND_KUBECONFIG) \ - --infrastructure docker,aws:${CAPA_VERSION},nutanix:${CAPX_VERSION} \ - --addon helm \ + --core cluster-api:$(CAPI_VERSION) \ + --bootstrap kubeadm:$(CAPI_VERSION) \ + --control-plane kubeadm:$(CAPI_VERSION) \ + --infrastructure docker:$(CAPD_VERSION),aws:$(CAPA_VERSION),nutanix:$(CAPX_VERSION) \ + --addon helm:$(CAAPH_VERSION) \ --wait-providers .PHONY: clusterctl.delete diff --git a/make/examples.mk b/make/examples.mk index 3b7b9310a..b45306ece 100644 --- a/make/examples.mk +++ b/make/examples.mk @@ -3,10 +3,6 @@ export KUBERNETES_VERSION := v1.27.5 -export CLUSTERCTL_VERSION := $(shell clusterctl version -o short 2>/dev/null) -export CAPA_VERSION := $(shell cd hack/third-party/capa && go list -m -f '{{ .Version }}' sigs.k8s.io/cluster-api-provider-aws/v2) -export CAPX_VERSION := $(shell cd hack/third-party/capx && go list -m -f '{{ .Version }}' github.com/nutanix-cloud-native/cluster-api-provider-nutanix) - .PHONY: examples.sync examples.sync: ## Syncs the examples by fetching upstream examples and applying kustomize patches hack/examples/sync.sh From 3a83bd30c2d01f3b8b961e7d71867a6a463f93cf Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Wed, 10 Apr 2024 17:22:50 +0100 Subject: [PATCH 84/87] ci: Switch to jetify-com/devbox-install-action (#48) --- .github/workflows/checks.yml | 8 ++++---- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/devbox-update.yml | 2 +- .github/workflows/e2e.yml | 2 +- .github/workflows/github-pages.yml | 2 +- .github/workflows/release-tag.yml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 8c19c9386..f8f0f864f 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -31,7 +31,7 @@ jobs: uses: actions/checkout@v4 - name: Install devbox - uses: jetpack-io/devbox-install-action@v0.8.0 + uses: jetify-com/devbox-install-action@v0.9.0 with: enable-cache: true @@ -79,7 +79,7 @@ jobs: uses: actions/checkout@v4 - name: Install devbox - uses: jetpack-io/devbox-install-action@v0.8.0 + uses: jetify-com/devbox-install-action@v0.9.0 with: enable-cache: true @@ -120,7 +120,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - name: Install devbox - uses: jetpack-io/devbox-install-action@v0.8.0 + uses: jetify-com/devbox-install-action@v0.9.0 with: enable-cache: true @@ -154,7 +154,7 @@ jobs: fetch-depth: 0 - name: Install devbox - uses: jetpack-io/devbox-install-action@v0.8.0 + uses: jetify-com/devbox-install-action@v0.9.0 with: enable-cache: true diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 91260ca38..23eb02b0b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -35,7 +35,7 @@ jobs: languages: ${{ matrix.language }} - name: Install devbox - uses: jetpack-io/devbox-install-action@v0.8.0 + uses: jetify-com/devbox-install-action@v0.9.0 with: enable-cache: true diff --git a/.github/workflows/devbox-update.yml b/.github/workflows/devbox-update.yml index 8eec42817..a24925b38 100644 --- a/.github/workflows/devbox-update.yml +++ b/.github/workflows/devbox-update.yml @@ -27,7 +27,7 @@ jobs: uses: actions/checkout@v4 - name: Install devbox - uses: jetpack-io/devbox-install-action@v0.8.0 + uses: jetify-com/devbox-install-action@v0.9.0 with: enable-cache: true diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 16b4fda00..cf6cb77e0 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -22,7 +22,7 @@ jobs: fetch-depth: 0 - name: Install devbox - uses: jetpack-io/devbox-install-action@v0.8.0 + uses: jetify-com/devbox-install-action@v0.9.0 with: enable-cache: true diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index 26a262599..4c384f963 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -39,7 +39,7 @@ jobs: uses: actions/checkout@v4 - name: Install devbox - uses: jetpack-io/devbox-install-action@v0.8.0 + uses: jetify-com/devbox-install-action@v0.9.0 with: enable-cache: true diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 128142b58..4f559cab9 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -28,7 +28,7 @@ jobs: fetch-depth: 0 - name: Install devbox - uses: jetpack-io/devbox-install-action@v0.8.0 + uses: jetify-com/devbox-install-action@v0.9.0 with: enable-cache: true From 1137f86e0e999585a9fce530d7e5297ac9b5c663 Mon Sep 17 00:00:00 2001 From: Jimmi Dyson Date: Wed, 10 Apr 2024 17:26:06 +0100 Subject: [PATCH 85/87] ci: Update govulncheck task to use same version of go as project (#49) --- .github/workflows/checks.yml | 16 +++++++++++----- make/go.mk | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index f8f0f864f..56af76939 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -229,9 +229,15 @@ jobs: module: [api, common, .] fail-fast: false steps: - - id: govulncheck - uses: golang/govulncheck-action@v1 + - name: Checkout + uses: actions/checkout@v4 with: - work-dir: ${{ matrix.module }} - go-version-file: go.mod - check-latest: true + fetch-depth: 0 + + - name: Install devbox + uses: jetify-com/devbox-install-action@v0.9.0 + with: + enable-cache: true + + - id: govulncheck + run: devbox run -- make govulncheck.${{ matrix.module }} diff --git a/make/go.mk b/make/go.mk index afba74a9f..596b2e51c 100644 --- a/make/go.mk +++ b/make/go.mk @@ -212,4 +212,4 @@ endif .PHONY: ggovulncheck.% govulncheck.%: ## Runs golangci-lint for a specific module govulncheck.%: ; $(info $(M) running govulncheck on $* module) - $(if $(filter-out root,$*),cd $* && )govulncheck ./... + $(if $(filter-out root .,$*),cd $* && )govulncheck ./... From 05b8c1a06819ea06944a6afb34b4c6c668e97062 Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Wed, 10 Apr 2024 09:53:51 -0700 Subject: [PATCH 86/87] feat: deploy Nutanix CCM as an Addon (#38) * build: remove nutanix CCM from examples * build: add scripts to sync Nutanix CCM manifests * build: add CCM addon var to Nutanix examples * feat: deploy Nutanix CCM addon Aligns the method of deploying the CCM with all other addons. * fixup! build: add scripts to sync Nutanix CCM manifests * fixup! feat: deploy Nutanix CCM addon * build: remove unused CRS tooling for Nutanix CCM The CRS strategy is not supported for the Nutanix CCM, removing it until we actually need it. --- api/v1alpha1/addon_types.go | 24 +- api/v1alpha1/clusterconfig_types.go | 3 +- api/v1alpha1/nutanix_clusterconfig_types.go | 27 ++ api/v1alpha1/zz_generated.deepcopy.go | 7 +- .../README.md | 2 + .../manifests/helm-addon-installation.yaml | 20 ++ .../templates/helm-config.yaml | 4 + .../values.yaml | 6 + .../nutanix-cluster-calico-crs.yaml | 272 +----------------- .../nutanix-cluster-calico-helm-addon.yaml | 272 +----------------- .../nutanix-cluster-cilium-crs.yaml | 272 +----------------- .../nutanix-cluster-cilium-helm-addon.yaml | 272 +----------------- .../nutanix-ccm/kustomization.yaml.tmpl | 18 ++ .../nutanix/cluster/kustomization.yaml.tmpl | 20 ++ hack/examples/patches/nutanix/ccm.yaml | 8 + .../nutanix/remove-ccm/cluster-label.yaml | 5 + .../patches/nutanix/remove-ccm/crs-cm.yaml | 8 + .../patches/nutanix/remove-ccm/crs.yaml | 8 + .../patches/nutanix/remove-ccm/secret.yaml | 8 + make/addons.mk | 2 + .../generic/lifecycle/ccm/aws/handler.go | 2 + pkg/handlers/generic/lifecycle/ccm/handler.go | 28 +- .../generic/lifecycle/ccm/nutanix/handler.go | 201 +++++++++++++ .../lifecycle/ccm/nutanix/handler_test.go | 121 ++++++++ .../clusterautoscaler/strategy_helmaddon.go | 3 +- pkg/handlers/generic/lifecycle/config/cm.go | 1 + pkg/handlers/generic/lifecycle/handlers.go | 7 +- .../mutation/prismcentralendpoint/inject.go | 27 +- 28 files changed, 538 insertions(+), 1110 deletions(-) create mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/ccm/nutanix/manifests/helm-addon-installation.yaml create mode 100644 hack/addons/kustomize/nutanix-ccm/kustomization.yaml.tmpl create mode 100644 hack/examples/patches/nutanix/ccm.yaml create mode 100644 hack/examples/patches/nutanix/remove-ccm/cluster-label.yaml create mode 100644 hack/examples/patches/nutanix/remove-ccm/crs-cm.yaml create mode 100644 hack/examples/patches/nutanix/remove-ccm/crs.yaml create mode 100644 hack/examples/patches/nutanix/remove-ccm/secret.yaml create mode 100644 pkg/handlers/generic/lifecycle/ccm/nutanix/handler.go create mode 100644 pkg/handlers/generic/lifecycle/ccm/nutanix/handler_test.go diff --git a/api/v1alpha1/addon_types.go b/api/v1alpha1/addon_types.go index 05c0d9145..6cafdfdb1 100644 --- a/api/v1alpha1/addon_types.go +++ b/api/v1alpha1/addon_types.go @@ -308,12 +308,34 @@ func (CSI) VariableSchema() clusterv1.VariableSchema { } // CCM tells us to enable or disable the cloud provider interface. -type CCM struct{} +type CCM struct { + // A reference to the Secret for credential information for the target Prism Central instance + // +optional + Credentials *corev1.LocalObjectReference `json:"credentials"` +} func (CCM) VariableSchema() clusterv1.VariableSchema { + // TODO Validate credentials is set. + // This CCM is shared across all providers. + // Some of these providers may require credentials to be set, but we don't want to require it for all providers. + // The Nutanix CCM handler will fail in at runtime if credentials are not set. return clusterv1.VariableSchema{ OpenAPIV3Schema: clusterv1.JSONSchemaProps{ Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "credentials": { + Description: "A reference to the Secret for credential information" + + "for the target Prism Central instance", + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "name": { + Description: "The name of the Secret", + Type: "string", + }, + }, + Required: []string{"name"}, + }, + }, }, } } diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index ba7e012b0..5cee9a2fb 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -25,7 +25,8 @@ const ( CSIProviderAWSEBS = "aws-ebs" CSIProviderNutanix = "nutanix" - CCMProviderAWS = "aws" + CCMProviderAWS = "aws" + CCMProviderNutanix = "nutanix" ) // +kubebuilder:object:root=true diff --git a/api/v1alpha1/nutanix_clusterconfig_types.go b/api/v1alpha1/nutanix_clusterconfig_types.go index 9e1e975ca..5ca7fe760 100644 --- a/api/v1alpha1/nutanix_clusterconfig_types.go +++ b/api/v1alpha1/nutanix_clusterconfig_types.go @@ -4,6 +4,10 @@ package v1alpha1 import ( + "fmt" + "net/url" + "strconv" + corev1 "k8s.io/api/core/v1" "k8s.io/utils/ptr" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -99,3 +103,26 @@ func (NutanixPrismCentralEndpointSpec) VariableSchema() clusterv1.VariableSchema }, } } + +//nolint:gocritic // no need for named return values +func (s NutanixPrismCentralEndpointSpec) ParseURL() (string, int32, error) { + var prismCentralURL *url.URL + prismCentralURL, err := url.Parse(s.URL) + if err != nil { + return "", -1, fmt.Errorf("error parsing Prism Central URL: %w", err) + } + + hostname := prismCentralURL.Hostname() + + // return early with the default port if no port is specified + if prismCentralURL.Port() == "" { + return hostname, DefaultPrismCentralPort, nil + } + + port, err := strconv.ParseInt(prismCentralURL.Port(), 10, 32) + if err != nil { + return "", -1, fmt.Errorf("error converting port to int: %w", err) + } + + return hostname, int32(port), nil +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index fe954a016..3bd4d46f9 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -202,7 +202,7 @@ func (in *Addons) DeepCopyInto(out *Addons) { if in.CCM != nil { in, out := &in.CCM, &out.CCM *out = new(CCM) - **out = **in + (*in).DeepCopyInto(*out) } if in.CSIProviders != nil { in, out := &in.CSIProviders, &out.CSIProviders @@ -224,6 +224,11 @@ func (in *Addons) DeepCopy() *Addons { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CCM) DeepCopyInto(out *CCM) { *out = *in + if in.Credentials != nil { + in, out := &in.Credentials, &out.Credentials + *out = new(v1.LocalObjectReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CCM. diff --git a/charts/cluster-api-runtime-extensions-nutanix/README.md b/charts/cluster-api-runtime-extensions-nutanix/README.md index 46601fdf4..80c72c84b 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/README.md +++ b/charts/cluster-api-runtime-extensions-nutanix/README.md @@ -32,6 +32,8 @@ A Helm chart for cluster-api-runtime-extensions-nutanix | deployment.replicas | int | `1` | | | env | object | `{}` | | | helmAddonsConfigMap | string | `"default-helm-addons-config"` | | +| hooks.ccm.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | +| hooks.ccm.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-nutanix-ccm-helm-values-template"` | | | hooks.clusterAutoscaler.crsStrategy.defaultInstallationConfigMap.name | string | `"cluster-autoscaler"` | | | hooks.clusterAutoscaler.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | | | hooks.clusterAutoscaler.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-cluster-autoscaler-helm-values-template"` | | diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/ccm/nutanix/manifests/helm-addon-installation.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/ccm/nutanix/manifests/helm-addon-installation.yaml new file mode 100644 index 000000000..72c63a63d --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/ccm/nutanix/manifests/helm-addon-installation.yaml @@ -0,0 +1,20 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +{{- if .Values.hooks.ccm.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.create }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: '{{ .Values.hooks.ccm.nutanix.helmAddonStrategy.defaultValueTemplateConfigMap.name }}' +data: + values.yaml: |- + --- + prismCentralEndPoint: {{ `{{ .PrismCentralHost }}` }} + prismCentralPort: {{ `{{ .PrismCentralPort }}` }} + prismCentralInsecure: {{ `{{ .PrismCentralInsecure }}` }} + prismCentralAdditionalTrustBundle: {{ `"{{ or .PrismCentralAdditionalTrustBundle "" }}"` }} + + # The Secret containing the credentials will be created by the handler. + createSecret: false + secretName: nutanix-ccm-credentials +{{- end -}} diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml index 255e8d69f..4dc513cd4 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml @@ -19,6 +19,10 @@ data: ChartName: node-feature-discovery ChartVersion: 0.15.2 RepositoryURL: https://kubernetes-sigs.github.io/node-feature-discovery/charts + nutanix-ccm: | + ChartName: nutanix-cloud-provider + ChartVersion: 0.3.3 + RepositoryURL: https://nutanix.github.io/helm/ nutanix-snapshot-csi: | ChartName: nutanix-csi-snapshot ChartVersion: v6.3.2 diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.yaml b/charts/cluster-api-runtime-extensions-nutanix/values.yaml index 88ac607ea..eee0993af 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/values.yaml @@ -49,6 +49,12 @@ hooks: defaultValueTemplateConfigMap: create: true name: default-nutanix-csi-helm-values-template + ccm: + nutanix: + helmAddonStrategy: + defaultValueTemplateConfigMap: + create: true + name: default-nutanix-ccm-helm-values-template nfd: crsStrategy: defaultInstallationConfigMap: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml index 6f0758103..19356a534 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-crs.yaml @@ -8,226 +8,6 @@ stringData: key: ${NUTANIX_PRISM_ELEMENT_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD} --- apiVersion: v1 -data: - nutanix-ccm.yaml: | - --- - apiVersion: v1 - kind: ConfigMap - metadata: - name: nutanix-ccm-pc-trusted-ca-bundle - namespace: kube-system - binaryData: - ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - apiVersion: v1 - kind: ServiceAccount - metadata: - name: cloud-controller-manager - namespace: kube-system - --- - # Source: nutanix-cloud-provider/templates/cm.yaml - kind: ConfigMap - apiVersion: v1 - metadata: - name: nutanix-config - namespace: kube-system - data: - nutanix_config.json: |- - { - "prismCentral": { - "address": "${NUTANIX_ENDPOINT}", - "port": ${NUTANIX_PORT=9440}, - "insecure": ${NUTANIX_INSECURE=false}, - "credentialRef": { - "kind": "secret", - "name": "nutanix-creds", - "namespace": "kube-system" - }, - "additionalTrustBundle": { - "kind": "ConfigMap", - "name": "nutanix-ccm-pc-trusted-ca-bundle", - "namespace": "kube-system" - } - }, - "enableCustomLabeling": ${CCM_CUSTOM_LABEL=false}, - "topologyDiscovery": { - "type": "Prism" - } - } - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:cloud-controller-manager - rules: - - apiGroups: - - "" - resources: - - secrets - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - update - - apiGroups: - - "" - resources: - - nodes - verbs: - - "*" - - apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch - - apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create - - apiGroups: - - "" - resources: - - endpoints - verbs: - - create - - get - - list - - watch - - update - - apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - kind: ClusterRoleBinding - apiVersion: rbac.authorization.k8s.io/v1 - metadata: - name: system:cloud-controller-manager - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:cloud-controller-manager - subjects: - - kind: ServiceAccount - name: cloud-controller-manager - namespace: kube-system - --- - # Source: nutanix-cloud-provider/templates/cloud-provider-nutanix-deployment.yaml - apiVersion: apps/v1 - kind: Deployment - metadata: - labels: - k8s-app: nutanix-cloud-controller-manager - name: nutanix-cloud-controller-manager - namespace: kube-system - spec: - replicas: 1 - selector: - matchLabels: - k8s-app: nutanix-cloud-controller-manager - strategy: - type: Recreate - template: - metadata: - labels: - k8s-app: nutanix-cloud-controller-manager - spec: - hostNetwork: true - priorityClassName: system-cluster-critical - nodeSelector: - node-role.kubernetes.io/control-plane: "" - serviceAccountName: cloud-controller-manager - affinity: - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - k8s-app: nutanix-cloud-controller-manager - topologyKey: kubernetes.io/hostname - dnsPolicy: Default - tolerations: - - effect: NoSchedule - key: node-role.kubernetes.io/master - operator: Exists - - effect: NoSchedule - key: node-role.kubernetes.io/control-plane - operator: Exists - - effect: NoExecute - key: node.kubernetes.io/unreachable - operator: Exists - tolerationSeconds: 120 - - effect: NoExecute - key: node.kubernetes.io/not-ready - operator: Exists - tolerationSeconds: 120 - - effect: NoSchedule - key: node.cloudprovider.kubernetes.io/uninitialized - operator: Exists - - effect: NoSchedule - key: node.kubernetes.io/not-ready - operator: Exists - containers: - - image: "${CCM_REPO=ghcr.io/nutanix-cloud-native/cloud-provider-nutanix/controller}:${CCM_TAG=v0.3.2}" - imagePullPolicy: IfNotPresent - name: nutanix-cloud-controller-manager - env: - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - args: - - "--leader-elect=true" - - "--cloud-config=/etc/cloud/nutanix_config.json" - resources: - requests: - cpu: 100m - memory: 50Mi - volumeMounts: - - mountPath: /etc/cloud - name: nutanix-config-volume - readOnly: true - volumes: - - name: nutanix-config-volume - configMap: - name: nutanix-config -kind: ConfigMap -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm ---- -apiVersion: v1 kind: Secret metadata: labels: @@ -247,59 +27,10 @@ stringData: } ] --- -apiVersion: v1 -kind: Secret -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm-secret -stringData: - nutanix-ccm-secret.yaml: | - apiVersion: v1 - kind: Secret - metadata: - name: nutanix-creds - namespace: kube-system - stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - }, - "prismElements": null - } - } - ] -type: addons.cluster.x-k8s.io/resource-set ---- -apiVersion: addons.cluster.x-k8s.io/v1beta1 -kind: ClusterResourceSet -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm-crs -spec: - clusterSelector: - matchLabels: - ccm: nutanix - resources: - - kind: ConfigMap - name: nutanix-ccm - - kind: Secret - name: nutanix-ccm-secret - - kind: ConfigMap - name: nutanix-ccm-pc-trusted-ca-bundle - strategy: ApplyOnce ---- apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster metadata: labels: - ccm: nutanix cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} cluster.x-k8s.io/provider: nutanix name: ${CLUSTER_NAME} @@ -321,6 +52,9 @@ spec: - name: clusterConfig value: addons: + ccm: + credentials: + name: ${CLUSTER_NAME}-pc-creds clusterAutoscaler: strategy: ClusterResourceSet cni: diff --git a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml index e6c77a185..73c60a3c6 100644 --- a/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-calico-helm-addon.yaml @@ -8,226 +8,6 @@ stringData: key: ${NUTANIX_PRISM_ELEMENT_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD} --- apiVersion: v1 -data: - nutanix-ccm.yaml: | - --- - apiVersion: v1 - kind: ConfigMap - metadata: - name: nutanix-ccm-pc-trusted-ca-bundle - namespace: kube-system - binaryData: - ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - apiVersion: v1 - kind: ServiceAccount - metadata: - name: cloud-controller-manager - namespace: kube-system - --- - # Source: nutanix-cloud-provider/templates/cm.yaml - kind: ConfigMap - apiVersion: v1 - metadata: - name: nutanix-config - namespace: kube-system - data: - nutanix_config.json: |- - { - "prismCentral": { - "address": "${NUTANIX_ENDPOINT}", - "port": ${NUTANIX_PORT=9440}, - "insecure": ${NUTANIX_INSECURE=false}, - "credentialRef": { - "kind": "secret", - "name": "nutanix-creds", - "namespace": "kube-system" - }, - "additionalTrustBundle": { - "kind": "ConfigMap", - "name": "nutanix-ccm-pc-trusted-ca-bundle", - "namespace": "kube-system" - } - }, - "enableCustomLabeling": ${CCM_CUSTOM_LABEL=false}, - "topologyDiscovery": { - "type": "Prism" - } - } - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:cloud-controller-manager - rules: - - apiGroups: - - "" - resources: - - secrets - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - update - - apiGroups: - - "" - resources: - - nodes - verbs: - - "*" - - apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch - - apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create - - apiGroups: - - "" - resources: - - endpoints - verbs: - - create - - get - - list - - watch - - update - - apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - kind: ClusterRoleBinding - apiVersion: rbac.authorization.k8s.io/v1 - metadata: - name: system:cloud-controller-manager - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:cloud-controller-manager - subjects: - - kind: ServiceAccount - name: cloud-controller-manager - namespace: kube-system - --- - # Source: nutanix-cloud-provider/templates/cloud-provider-nutanix-deployment.yaml - apiVersion: apps/v1 - kind: Deployment - metadata: - labels: - k8s-app: nutanix-cloud-controller-manager - name: nutanix-cloud-controller-manager - namespace: kube-system - spec: - replicas: 1 - selector: - matchLabels: - k8s-app: nutanix-cloud-controller-manager - strategy: - type: Recreate - template: - metadata: - labels: - k8s-app: nutanix-cloud-controller-manager - spec: - hostNetwork: true - priorityClassName: system-cluster-critical - nodeSelector: - node-role.kubernetes.io/control-plane: "" - serviceAccountName: cloud-controller-manager - affinity: - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - k8s-app: nutanix-cloud-controller-manager - topologyKey: kubernetes.io/hostname - dnsPolicy: Default - tolerations: - - effect: NoSchedule - key: node-role.kubernetes.io/master - operator: Exists - - effect: NoSchedule - key: node-role.kubernetes.io/control-plane - operator: Exists - - effect: NoExecute - key: node.kubernetes.io/unreachable - operator: Exists - tolerationSeconds: 120 - - effect: NoExecute - key: node.kubernetes.io/not-ready - operator: Exists - tolerationSeconds: 120 - - effect: NoSchedule - key: node.cloudprovider.kubernetes.io/uninitialized - operator: Exists - - effect: NoSchedule - key: node.kubernetes.io/not-ready - operator: Exists - containers: - - image: "${CCM_REPO=ghcr.io/nutanix-cloud-native/cloud-provider-nutanix/controller}:${CCM_TAG=v0.3.2}" - imagePullPolicy: IfNotPresent - name: nutanix-cloud-controller-manager - env: - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - args: - - "--leader-elect=true" - - "--cloud-config=/etc/cloud/nutanix_config.json" - resources: - requests: - cpu: 100m - memory: 50Mi - volumeMounts: - - mountPath: /etc/cloud - name: nutanix-config-volume - readOnly: true - volumes: - - name: nutanix-config-volume - configMap: - name: nutanix-config -kind: ConfigMap -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm ---- -apiVersion: v1 kind: Secret metadata: labels: @@ -247,59 +27,10 @@ stringData: } ] --- -apiVersion: v1 -kind: Secret -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm-secret -stringData: - nutanix-ccm-secret.yaml: | - apiVersion: v1 - kind: Secret - metadata: - name: nutanix-creds - namespace: kube-system - stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - }, - "prismElements": null - } - } - ] -type: addons.cluster.x-k8s.io/resource-set ---- -apiVersion: addons.cluster.x-k8s.io/v1beta1 -kind: ClusterResourceSet -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm-crs -spec: - clusterSelector: - matchLabels: - ccm: nutanix - resources: - - kind: ConfigMap - name: nutanix-ccm - - kind: Secret - name: nutanix-ccm-secret - - kind: ConfigMap - name: nutanix-ccm-pc-trusted-ca-bundle - strategy: ApplyOnce ---- apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster metadata: labels: - ccm: nutanix cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} cluster.x-k8s.io/provider: nutanix name: ${CLUSTER_NAME} @@ -321,6 +52,9 @@ spec: - name: clusterConfig value: addons: + ccm: + credentials: + name: ${CLUSTER_NAME}-pc-creds clusterAutoscaler: strategy: HelmAddon cni: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml index 6b34119d0..ebb5825cc 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-crs.yaml @@ -8,226 +8,6 @@ stringData: key: ${NUTANIX_PRISM_ELEMENT_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD} --- apiVersion: v1 -data: - nutanix-ccm.yaml: | - --- - apiVersion: v1 - kind: ConfigMap - metadata: - name: nutanix-ccm-pc-trusted-ca-bundle - namespace: kube-system - binaryData: - ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - apiVersion: v1 - kind: ServiceAccount - metadata: - name: cloud-controller-manager - namespace: kube-system - --- - # Source: nutanix-cloud-provider/templates/cm.yaml - kind: ConfigMap - apiVersion: v1 - metadata: - name: nutanix-config - namespace: kube-system - data: - nutanix_config.json: |- - { - "prismCentral": { - "address": "${NUTANIX_ENDPOINT}", - "port": ${NUTANIX_PORT=9440}, - "insecure": ${NUTANIX_INSECURE=false}, - "credentialRef": { - "kind": "secret", - "name": "nutanix-creds", - "namespace": "kube-system" - }, - "additionalTrustBundle": { - "kind": "ConfigMap", - "name": "nutanix-ccm-pc-trusted-ca-bundle", - "namespace": "kube-system" - } - }, - "enableCustomLabeling": ${CCM_CUSTOM_LABEL=false}, - "topologyDiscovery": { - "type": "Prism" - } - } - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:cloud-controller-manager - rules: - - apiGroups: - - "" - resources: - - secrets - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - update - - apiGroups: - - "" - resources: - - nodes - verbs: - - "*" - - apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch - - apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create - - apiGroups: - - "" - resources: - - endpoints - verbs: - - create - - get - - list - - watch - - update - - apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - kind: ClusterRoleBinding - apiVersion: rbac.authorization.k8s.io/v1 - metadata: - name: system:cloud-controller-manager - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:cloud-controller-manager - subjects: - - kind: ServiceAccount - name: cloud-controller-manager - namespace: kube-system - --- - # Source: nutanix-cloud-provider/templates/cloud-provider-nutanix-deployment.yaml - apiVersion: apps/v1 - kind: Deployment - metadata: - labels: - k8s-app: nutanix-cloud-controller-manager - name: nutanix-cloud-controller-manager - namespace: kube-system - spec: - replicas: 1 - selector: - matchLabels: - k8s-app: nutanix-cloud-controller-manager - strategy: - type: Recreate - template: - metadata: - labels: - k8s-app: nutanix-cloud-controller-manager - spec: - hostNetwork: true - priorityClassName: system-cluster-critical - nodeSelector: - node-role.kubernetes.io/control-plane: "" - serviceAccountName: cloud-controller-manager - affinity: - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - k8s-app: nutanix-cloud-controller-manager - topologyKey: kubernetes.io/hostname - dnsPolicy: Default - tolerations: - - effect: NoSchedule - key: node-role.kubernetes.io/master - operator: Exists - - effect: NoSchedule - key: node-role.kubernetes.io/control-plane - operator: Exists - - effect: NoExecute - key: node.kubernetes.io/unreachable - operator: Exists - tolerationSeconds: 120 - - effect: NoExecute - key: node.kubernetes.io/not-ready - operator: Exists - tolerationSeconds: 120 - - effect: NoSchedule - key: node.cloudprovider.kubernetes.io/uninitialized - operator: Exists - - effect: NoSchedule - key: node.kubernetes.io/not-ready - operator: Exists - containers: - - image: "${CCM_REPO=ghcr.io/nutanix-cloud-native/cloud-provider-nutanix/controller}:${CCM_TAG=v0.3.2}" - imagePullPolicy: IfNotPresent - name: nutanix-cloud-controller-manager - env: - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - args: - - "--leader-elect=true" - - "--cloud-config=/etc/cloud/nutanix_config.json" - resources: - requests: - cpu: 100m - memory: 50Mi - volumeMounts: - - mountPath: /etc/cloud - name: nutanix-config-volume - readOnly: true - volumes: - - name: nutanix-config-volume - configMap: - name: nutanix-config -kind: ConfigMap -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm ---- -apiVersion: v1 kind: Secret metadata: labels: @@ -247,59 +27,10 @@ stringData: } ] --- -apiVersion: v1 -kind: Secret -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm-secret -stringData: - nutanix-ccm-secret.yaml: | - apiVersion: v1 - kind: Secret - metadata: - name: nutanix-creds - namespace: kube-system - stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - }, - "prismElements": null - } - } - ] -type: addons.cluster.x-k8s.io/resource-set ---- -apiVersion: addons.cluster.x-k8s.io/v1beta1 -kind: ClusterResourceSet -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm-crs -spec: - clusterSelector: - matchLabels: - ccm: nutanix - resources: - - kind: ConfigMap - name: nutanix-ccm - - kind: Secret - name: nutanix-ccm-secret - - kind: ConfigMap - name: nutanix-ccm-pc-trusted-ca-bundle - strategy: ApplyOnce ---- apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster metadata: labels: - ccm: nutanix cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} cluster.x-k8s.io/provider: nutanix name: ${CLUSTER_NAME} @@ -321,6 +52,9 @@ spec: - name: clusterConfig value: addons: + ccm: + credentials: + name: ${CLUSTER_NAME}-pc-creds clusterAutoscaler: strategy: ClusterResourceSet cni: diff --git a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml index 5552bcb62..cedeee8ea 100644 --- a/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml +++ b/examples/capi-quick-start/nutanix-cluster-cilium-helm-addon.yaml @@ -8,226 +8,6 @@ stringData: key: ${NUTANIX_PRISM_ELEMENT_ENDPOINT}:${NUTANIX_PORT}:${NUTANIX_USER}:${NUTANIX_PASSWORD} --- apiVersion: v1 -data: - nutanix-ccm.yaml: | - --- - apiVersion: v1 - kind: ConfigMap - metadata: - name: nutanix-ccm-pc-trusted-ca-bundle - namespace: kube-system - binaryData: - ca.crt: ${NUTANIX_ADDITIONAL_TRUST_BUNDLE=""} - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - apiVersion: v1 - kind: ServiceAccount - metadata: - name: cloud-controller-manager - namespace: kube-system - --- - # Source: nutanix-cloud-provider/templates/cm.yaml - kind: ConfigMap - apiVersion: v1 - metadata: - name: nutanix-config - namespace: kube-system - data: - nutanix_config.json: |- - { - "prismCentral": { - "address": "${NUTANIX_ENDPOINT}", - "port": ${NUTANIX_PORT=9440}, - "insecure": ${NUTANIX_INSECURE=false}, - "credentialRef": { - "kind": "secret", - "name": "nutanix-creds", - "namespace": "kube-system" - }, - "additionalTrustBundle": { - "kind": "ConfigMap", - "name": "nutanix-ccm-pc-trusted-ca-bundle", - "namespace": "kube-system" - } - }, - "enableCustomLabeling": ${CCM_CUSTOM_LABEL=false}, - "topologyDiscovery": { - "type": "Prism" - } - } - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - annotations: - rbac.authorization.kubernetes.io/autoupdate: "true" - name: system:cloud-controller-manager - rules: - - apiGroups: - - "" - resources: - - secrets - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - update - - apiGroups: - - "" - resources: - - nodes - verbs: - - "*" - - apiGroups: - - "" - resources: - - nodes/status - verbs: - - patch - - apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create - - apiGroups: - - "" - resources: - - endpoints - verbs: - - create - - get - - list - - watch - - update - - apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - --- - # Source: nutanix-cloud-provider/templates/rbac.yaml - kind: ClusterRoleBinding - apiVersion: rbac.authorization.k8s.io/v1 - metadata: - name: system:cloud-controller-manager - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: system:cloud-controller-manager - subjects: - - kind: ServiceAccount - name: cloud-controller-manager - namespace: kube-system - --- - # Source: nutanix-cloud-provider/templates/cloud-provider-nutanix-deployment.yaml - apiVersion: apps/v1 - kind: Deployment - metadata: - labels: - k8s-app: nutanix-cloud-controller-manager - name: nutanix-cloud-controller-manager - namespace: kube-system - spec: - replicas: 1 - selector: - matchLabels: - k8s-app: nutanix-cloud-controller-manager - strategy: - type: Recreate - template: - metadata: - labels: - k8s-app: nutanix-cloud-controller-manager - spec: - hostNetwork: true - priorityClassName: system-cluster-critical - nodeSelector: - node-role.kubernetes.io/control-plane: "" - serviceAccountName: cloud-controller-manager - affinity: - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - k8s-app: nutanix-cloud-controller-manager - topologyKey: kubernetes.io/hostname - dnsPolicy: Default - tolerations: - - effect: NoSchedule - key: node-role.kubernetes.io/master - operator: Exists - - effect: NoSchedule - key: node-role.kubernetes.io/control-plane - operator: Exists - - effect: NoExecute - key: node.kubernetes.io/unreachable - operator: Exists - tolerationSeconds: 120 - - effect: NoExecute - key: node.kubernetes.io/not-ready - operator: Exists - tolerationSeconds: 120 - - effect: NoSchedule - key: node.cloudprovider.kubernetes.io/uninitialized - operator: Exists - - effect: NoSchedule - key: node.kubernetes.io/not-ready - operator: Exists - containers: - - image: "${CCM_REPO=ghcr.io/nutanix-cloud-native/cloud-provider-nutanix/controller}:${CCM_TAG=v0.3.2}" - imagePullPolicy: IfNotPresent - name: nutanix-cloud-controller-manager - env: - - name: POD_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - args: - - "--leader-elect=true" - - "--cloud-config=/etc/cloud/nutanix_config.json" - resources: - requests: - cpu: 100m - memory: 50Mi - volumeMounts: - - mountPath: /etc/cloud - name: nutanix-config-volume - readOnly: true - volumes: - - name: nutanix-config-volume - configMap: - name: nutanix-config -kind: ConfigMap -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm ---- -apiVersion: v1 kind: Secret metadata: labels: @@ -247,59 +27,10 @@ stringData: } ] --- -apiVersion: v1 -kind: Secret -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm-secret -stringData: - nutanix-ccm-secret.yaml: | - apiVersion: v1 - kind: Secret - metadata: - name: nutanix-creds - namespace: kube-system - stringData: - credentials: | - [ - { - "type": "basic_auth", - "data": { - "prismCentral":{ - "username": "${NUTANIX_USER}", - "password": "${NUTANIX_PASSWORD}" - }, - "prismElements": null - } - } - ] -type: addons.cluster.x-k8s.io/resource-set ---- -apiVersion: addons.cluster.x-k8s.io/v1beta1 -kind: ClusterResourceSet -metadata: - labels: - cluster.x-k8s.io/provider: nutanix - name: nutanix-ccm-crs -spec: - clusterSelector: - matchLabels: - ccm: nutanix - resources: - - kind: ConfigMap - name: nutanix-ccm - - kind: Secret - name: nutanix-ccm-secret - - kind: ConfigMap - name: nutanix-ccm-pc-trusted-ca-bundle - strategy: ApplyOnce ---- apiVersion: cluster.x-k8s.io/v1beta1 kind: Cluster metadata: labels: - ccm: nutanix cluster.x-k8s.io/cluster-name: ${CLUSTER_NAME} cluster.x-k8s.io/provider: nutanix name: ${CLUSTER_NAME} @@ -321,6 +52,9 @@ spec: - name: clusterConfig value: addons: + ccm: + credentials: + name: ${CLUSTER_NAME}-pc-creds clusterAutoscaler: strategy: HelmAddon cni: diff --git a/hack/addons/kustomize/nutanix-ccm/kustomization.yaml.tmpl b/hack/addons/kustomize/nutanix-ccm/kustomization.yaml.tmpl new file mode 100644 index 000000000..2758a25c6 --- /dev/null +++ b/hack/addons/kustomize/nutanix-ccm/kustomization.yaml.tmpl @@ -0,0 +1,18 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +metadata: + name: nutanix-ccm-kustomize + +helmCharts: +- name: nutanix-cloud-provider + namespace: kube-system + repo: https://nutanix.github.io/helm/ + releaseName: nutanix-ccm + version: ${NUTANIX_CCM_CHART_VERSION} + valuesFile: helm-values.yaml + includeCRDs: true + skipTests: true diff --git a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl index 73844b6ac..4db679840 100644 --- a/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl +++ b/hack/examples/bases/nutanix/cluster/kustomization.yaml.tmpl @@ -29,6 +29,9 @@ patches: - target: kind: Cluster path: ../../../patches/nutanix/csi.yaml +- target: + kind: Cluster + path: ../../../patches/nutanix/ccm.yaml - target: kind: Cluster path: ../../../patches/nutanix/initialize-variables.yaml @@ -38,3 +41,20 @@ patches: kind: ConfigMap name: ".*-pc-trusted-ca-bundle" path: ../../../patches/nutanix/remove-additional-trust-bundle/cm.yaml + +# Remove CCM CRS +- target: + kind: Secret + name: nutanix-ccm-secret + path: ../../../patches/nutanix/remove-ccm/secret.yaml +- target: + kind: ClusterResourceSet + name: nutanix-ccm-crs + path: ../../../patches/nutanix/remove-ccm/crs.yaml +- target: + kind: ConfigMap + name: nutanix-ccm + path: ../../../patches/nutanix/remove-ccm/crs-cm.yaml +- target: + kind: Cluster + path: ../../../patches/nutanix/remove-ccm/cluster-label.yaml diff --git a/hack/examples/patches/nutanix/ccm.yaml b/hack/examples/patches/nutanix/ccm.yaml new file mode 100644 index 000000000..3518d101f --- /dev/null +++ b/hack/examples/patches/nutanix/ccm.yaml @@ -0,0 +1,8 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +- op: "add" + path: "/spec/topology/variables/0/value/addons/ccm" + value: + credentials: + name: ${CLUSTER_NAME}-pc-creds diff --git a/hack/examples/patches/nutanix/remove-ccm/cluster-label.yaml b/hack/examples/patches/nutanix/remove-ccm/cluster-label.yaml new file mode 100644 index 000000000..ce92832f7 --- /dev/null +++ b/hack/examples/patches/nutanix/remove-ccm/cluster-label.yaml @@ -0,0 +1,5 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +- op: "remove" + path: "/metadata/labels/ccm" diff --git a/hack/examples/patches/nutanix/remove-ccm/crs-cm.yaml b/hack/examples/patches/nutanix/remove-ccm/crs-cm.yaml new file mode 100644 index 000000000..0721f0c2a --- /dev/null +++ b/hack/examples/patches/nutanix/remove-ccm/crs-cm.yaml @@ -0,0 +1,8 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +$patch: delete +apiVersion: v1 +kind: ConfigMap +metadata: + name: nutanix-ccm diff --git a/hack/examples/patches/nutanix/remove-ccm/crs.yaml b/hack/examples/patches/nutanix/remove-ccm/crs.yaml new file mode 100644 index 000000000..30b6604af --- /dev/null +++ b/hack/examples/patches/nutanix/remove-ccm/crs.yaml @@ -0,0 +1,8 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +$patch: delete +apiVersion: addons.cluster.x-k8s.io/v1beta1 +kind: ClusterResourceSet +metadata: + name: nutanix-ccm-crs diff --git a/hack/examples/patches/nutanix/remove-ccm/secret.yaml b/hack/examples/patches/nutanix/remove-ccm/secret.yaml new file mode 100644 index 000000000..c8c852d3c --- /dev/null +++ b/hack/examples/patches/nutanix/remove-ccm/secret.yaml @@ -0,0 +1,8 @@ +# Copyright 2024 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +$patch: delete +apiVersion: v1 +kind: Secret +metadata: + name: nutanix-ccm-secret diff --git a/make/addons.mk b/make/addons.mk index 648fc47d9..36ae1b33e 100644 --- a/make/addons.mk +++ b/make/addons.mk @@ -15,6 +15,8 @@ export AWS_CCM_CHART_VERSION_127 := 0.0.8 export AWS_CCM_VERSION_128 := v1.28.1 export AWS_CCM_CHART_VERSION_128 := 0.0.8 +export NUTANIX_CCM_CHART_VERSION := 0.3.3 + .PHONY: addons.sync addons.sync: $(addprefix update-addon.,calico cilium nfd cluster-autoscaler aws-ebs-csi aws-ccm.127 nutanix-storage-csi aws-ccm.128) diff --git a/pkg/handlers/generic/lifecycle/ccm/aws/handler.go b/pkg/handlers/generic/lifecycle/ccm/aws/handler.go index fa37fd1db..626de46fb 100644 --- a/pkg/handlers/generic/lifecycle/ccm/aws/handler.go +++ b/pkg/handlers/generic/lifecycle/ccm/aws/handler.go @@ -15,6 +15,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" @@ -56,6 +57,7 @@ func New( func (a *AWSCCM) Apply( ctx context.Context, cluster *clusterv1.Cluster, + _ *v1alpha1.ClusterConfigSpec, ) error { log := ctrl.LoggerFrom(ctx).WithValues( "cluster", diff --git a/pkg/handlers/generic/lifecycle/ccm/handler.go b/pkg/handlers/generic/lifecycle/ccm/handler.go index 08d8372f0..29a22eb5d 100644 --- a/pkg/handlers/generic/lifecycle/ccm/handler.go +++ b/pkg/handlers/generic/lifecycle/ccm/handler.go @@ -25,7 +25,7 @@ const ( ) type CCMProvider interface { - Apply(context.Context, *clusterv1.Cluster) error + Apply(context.Context, *clusterv1.Cluster, *v1alpha1.ClusterConfigSpec) error } type CCMHandler struct { @@ -78,7 +78,7 @@ func (c *CCMHandler) AfterControlPlaneInitialized( ) resp.SetStatus(runtimehooksv1.ResponseStatusFailure) resp.SetMessage( - fmt.Sprintf("failed to read CCM provider from cluster definition: %v", + fmt.Sprintf("failed to read CCM from cluster definition: %v", err, ), ) @@ -88,17 +88,39 @@ func (c *CCMHandler) AfterControlPlaneInitialized( log.V(4).Info("Skipping CCM handler.") return } + + clusterConfigVar, _, err := variables.Get[v1alpha1.ClusterConfigSpec]( + varMap, + clusterconfig.MetaVariableName, + ) + if err != nil { + log.Error( + err, + "failed to read clusterConfig variable from cluster definition", + ) + resp.SetStatus(runtimehooksv1.ResponseStatusFailure) + resp.SetMessage( + fmt.Sprintf("failed to read clusterConfig variable from cluster definition: %v", + err, + ), + ) + return + } + infraKind := req.Cluster.Spec.InfrastructureRef.Kind log.Info(fmt.Sprintf("finding CCM handler for %s", infraKind)) var handler CCMProvider switch { case strings.Contains(strings.ToLower(infraKind), v1alpha1.CCMProviderAWS): handler = c.ProviderHandler[v1alpha1.CCMProviderAWS] + case strings.Contains(strings.ToLower(infraKind), v1alpha1.CCMProviderNutanix): + handler = c.ProviderHandler[v1alpha1.CCMProviderNutanix] default: log.Info(fmt.Sprintf("No CCM handler provided for infra kind %s", infraKind)) return } - err = handler.Apply(ctx, &req.Cluster) + + err = handler.Apply(ctx, &req.Cluster, &clusterConfigVar) if err != nil { log.Error( err, diff --git a/pkg/handlers/generic/lifecycle/ccm/nutanix/handler.go b/pkg/handlers/generic/lifecycle/ccm/nutanix/handler.go new file mode 100644 index 000000000..93c325d88 --- /dev/null +++ b/pkg/handlers/generic/lifecycle/ccm/nutanix/handler.go @@ -0,0 +1,201 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package nutanix + +import ( + "bytes" + "context" + "errors" + "fmt" + "text/template" + + "github.com/spf13/pflag" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + ctrl "sigs.k8s.io/controller-runtime" + ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/config" + lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" +) + +const ( + defaultHelmReleaseName = "nutanix-ccm" + defaultHelmReleaseNamespace = "kube-system" + + // This is the name of the Secret on the remote cluster that should match what is defined in Helm values. + //nolint:gosec // Does not contain hard coded credentials. + defaultCredentialsSecretName = "nutanix-ccm-credentials" +) + +var ErrMissingCredentials = errors.New("name of the Secret containing PC credentials must be set") + +type Config struct { + *options.GlobalOptions + + defaultValuesTemplateConfigMapName string +} + +func (c *Config) AddFlags(prefix string, flags *pflag.FlagSet) { + flags.StringVar( + &c.defaultValuesTemplateConfigMapName, + prefix+".default-values-template-configmap-name", + "default-nutanix-ccm-helm-values-template", + "default values ConfigMap name", + ) +} + +type provider struct { + client ctrlclient.Client + config *Config + helmChartInfoGetter *config.HelmChartGetter +} + +func New( + c ctrlclient.Client, + cfg *Config, + helmChartInfoGetter *config.HelmChartGetter, +) *provider { + return &provider{ + client: c, + config: cfg, + helmChartInfoGetter: helmChartInfoGetter, + } +} + +func (p *provider) Apply( + ctx context.Context, + cluster *clusterv1.Cluster, + clusterConfig *v1alpha1.ClusterConfigSpec, +) error { + // No need to check for nil values in the struct, this function will only be called if CCM is not nil + if clusterConfig.Addons.CCM.Credentials == nil { + return ErrMissingCredentials + } + + valuesTemplateConfigMap, err := lifecycleutils.RetrieveValuesTemplateConfigMap( + ctx, + p.client, + p.config.defaultValuesTemplateConfigMapName, + p.config.DefaultsNamespace(), + ) + if err != nil { + return fmt.Errorf( + "failed to retrieve Nutanix CCM installation values template ConfigMap for cluster: %w", + err, + ) + } + + // It's possible to have the credentials Secret be created by the Helm chart. + // However, that would leave the credentials visible in the HelmChartProxy. + // Instead, we'll create the Secret on the remote cluster and reference it in the Helm values. + if clusterConfig.Addons.CCM.Credentials != nil { + key := ctrlclient.ObjectKey{ + Name: defaultCredentialsSecretName, + Namespace: defaultHelmReleaseNamespace, + } + err = lifecycleutils.CopySecretToRemoteCluster( + ctx, + p.client, + clusterConfig.Addons.CCM.Credentials.Name, + key, + cluster, + ) + if err != nil { + return fmt.Errorf( + "error creating Nutanix CCM Credentials Secret on the remote cluster: %w", + err, + ) + } + } + + log := ctrl.LoggerFrom(ctx).WithValues( + "cluster", + ctrlclient.ObjectKeyFromObject(cluster), + ) + helmChart, err := p.helmChartInfoGetter.For(ctx, log, config.NutanixCCM) + if err != nil { + return fmt.Errorf("failed to get values for nutanix-ccm-config %w", err) + } + + values := valuesTemplateConfigMap.Data["values.yaml"] + // The configMap will contain the Helm values, but templated with fields that need to be filled in. + values, err = templateValues(clusterConfig, values) + if err != nil { + return fmt.Errorf("failed to template Helm values read from ConfigMap: %w", err) + } + + hcp := &caaphv1.HelmChartProxy{ + TypeMeta: metav1.TypeMeta{ + APIVersion: caaphv1.GroupVersion.String(), + Kind: "HelmChartProxy", + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: cluster.Namespace, + Name: "nutanix-ccm-" + cluster.Name, + }, + Spec: caaphv1.HelmChartProxySpec{ + RepoURL: helmChart.Repository, + ChartName: helmChart.Name, + ClusterSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{clusterv1.ClusterNameLabel: cluster.Name}, + }, + ReleaseNamespace: defaultHelmReleaseNamespace, + ReleaseName: defaultHelmReleaseName, + Version: helmChart.Version, + ValuesTemplate: values, + }, + } + + if err = controllerutil.SetOwnerReference(cluster, hcp, p.client.Scheme()); err != nil { + return fmt.Errorf( + "failed to set owner reference on nutanix-ccm installation HelmChartProxy: %w", + err, + ) + } + + if err = client.ServerSideApply(ctx, p.client, hcp); err != nil { + return fmt.Errorf("failed to apply nutanix-ccm installation HelmChartProxy: %w", err) + } + + return nil +} + +func templateValues(clusterConfig *v1alpha1.ClusterConfigSpec, text string) (string, error) { + helmValuesTemplate, err := template.New("").Parse(text) + if err != nil { + return "", fmt.Errorf("failed to parse Helm values template: %w", err) + } + + type input struct { + PrismCentralHost string + PrismCentralPort int32 + PrismCentralInsecure bool + PrismCentralAdditionalTrustBundle *string + } + + address, port, err := clusterConfig.Nutanix.PrismCentralEndpoint.ParseURL() + if err != nil { + return "", err + } + templateInput := input{ + PrismCentralHost: address, + PrismCentralPort: port, + PrismCentralInsecure: clusterConfig.Nutanix.PrismCentralEndpoint.Insecure, + PrismCentralAdditionalTrustBundle: clusterConfig.Nutanix.PrismCentralEndpoint.AdditionalTrustBundle, + } + + var b bytes.Buffer + err = helmValuesTemplate.Execute(&b, templateInput) + if err != nil { + return "", fmt.Errorf("failed setting PrismCentral configuration in template: %w", err) + } + + return b.String(), nil +} diff --git a/pkg/handlers/generic/lifecycle/ccm/nutanix/handler_test.go b/pkg/handlers/generic/lifecycle/ccm/nutanix/handler_test.go new file mode 100644 index 000000000..5e8869c9a --- /dev/null +++ b/pkg/handlers/generic/lifecycle/ccm/nutanix/handler_test.go @@ -0,0 +1,121 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package nutanix + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + "k8s.io/utils/ptr" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" +) + +const ( + in = `--- +prismCentralEndPoint: {{ .PrismCentralHost }} +prismCentralPort: {{ .PrismCentralPort }} +prismCentralInsecure: {{ .PrismCentralInsecure }} +prismCentralAdditionalTrustBundle: "{{ or .PrismCentralAdditionalTrustBundle "" }}" + +# The Secret containing the credentials will be created by the handler. +createSecret: false +secretName: nutanix-ccm-credentials +` + //nolint:lll // just a long string + testCertBundle = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVjekNDQTF1Z0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRUUZBRC4uQWtHQTFVRUJoTUNSMEl4CkV6QVJCZ05WQkFnVENsTnZiV1V0VTNSaGRHVXhGREFTQmdOVkJBb1RDMC4uMEVnVEhSa01UY3dOUVlEClZRUUxFeTVEYkdGemN5QXhJRkIxWW14cFl5QlFjbWx0WVhKNUlFTmxjbi4uWFJwYjI0Z1FYVjBhRzl5CmFYUjVNUlF3RWdZRFZRUURFd3RDWlhOMElFTkJJRXgwWkRBZUZ3MHdNRC4uVFV3TVRaYUZ3MHdNVEF5Ck1EUXhPVFV3TVRaYU1JR0hNUXN3Q1FZRFZRUUdFd0pIUWpFVE1CRUdBMS4uMjl0WlMxVGRHRjBaVEVVCk1CSUdBMVVFQ2hNTFFtVnpkQ0JEUVNCTWRHUXhOekExQmdOVkJBc1RMay4uREVnVUhWaWJHbGpJRkJ5CmFXMWhjbmtnUTJWeWRHbG1hV05oZEdsdmJpQkJkWFJvYjNKcGRIa3hGRC4uQU1UQzBKbGMzUWdRMEVnClRIUmtNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZy4uVHoybXI3U1ppQU1mUXl1CnZCak05T2lKalJhelhCWjFCalA1Q0UvV20vUnI1MDBQUksrTGg5eDVlSi4uL0FOQkUwc1RLMFpzREdNCmFrMm0xZzdvcnVJM2RZM1ZIcUl4RlR6MFRhMWQrTkFqd25MZTRuT2I3Ly4uazA1U2hoQnJKR0JLS3hiCjhuMTA0by81cDhIQXNaUGR6YkZNSXlOakp6Qk0ybzV5NUExM3dpTGl0RS4uZnlZa1F6YXhDdzBBd3psCmtWSGlJeUN1YUY0d2o1NzFwU3prdjZzdis0SURNYlQvWHBDbzhMNndUYS4uc2grZXRMRDZGdFRqWWJiCnJ2WjhSUU0xdGxLZG9NSGcycXhyYUFWKytITkJZbU5XczBkdUVkalViSi4uWEk5VHRuUzRvMUNrajdQCk9mbGppUUlEQVFBQm80SG5NSUhrTUIwR0ExVWREZ1FXQkJROHVyTUNSTC4uNUFrSXA5TkpISnc1VENCCnRBWURWUjBqQklHc01JR3BnQlE4dXJNQ1JMWVlNSFVLVTVBa0lwOU5KSC4uYVNCaWpDQmh6RUxNQWtHCkExVUVCaE1DUjBJeEV6QVJCZ05WQkFnVENsTnZiV1V0VTNSaGRHVXhGRC4uQW9UQzBKbGMzUWdRMEVnClRIUmtNVGN3TlFZRFZRUUxFeTVEYkdGemN5QXhJRkIxWW14cFl5QlFjbS4uRU5sY25ScFptbGpZWFJwCmIyNGdRWFYwYUc5eWFYUjVNUlF3RWdZRFZRUURFd3RDWlhOMElFTkJJRS4uREFNQmdOVkhSTUVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQkFVQUE0SUJBUUMxdVlCY3NTbmN3QS4uRENzUWVyNzcyQzJ1Y3BYCnhRVUUvQzBwV1dtNmdEa3dkNUQwRFNNREpScVYvd2VvWjR3QzZCNzNmNS4uYkxoR1lIYVhKZVNENktyClhjb093TGRTYUdtSllzbExLWkIzWklERXAwd1lUR2hndGViNkpGaVR0bi4uc2YyeGRyWWZQQ2lJQjdnCkJNQVY3R3pkYzRWc3BTNmxqckFoYmlpYXdkQmlRbFFtc0JlRno5SmtGNC4uYjNsOEJvR04rcU1hNTZZCkl0OHVuYTJnWTRsMk8vL29uODhyNUlXSmxtMUwwb0E4ZTRmUjJ5ckJIWC4uYWRzR2VGS2t5TnJ3R2kvCjd2UU1mWGRHc1JyWE5HUkduWCt2V0RaMy96V0kwam9EdENrTm5xRXBWbi4uSG9YCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=" +) + +const ( + //nolint:lll // just a long string + expectedWithAdditionalTrustBundle = `--- +prismCentralEndPoint: prism-central.nutanix.com +prismCentralPort: 9440 +prismCentralInsecure: false +prismCentralAdditionalTrustBundle: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVjekNDQTF1Z0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRUUZBRC4uQWtHQTFVRUJoTUNSMEl4CkV6QVJCZ05WQkFnVENsTnZiV1V0VTNSaGRHVXhGREFTQmdOVkJBb1RDMC4uMEVnVEhSa01UY3dOUVlEClZRUUxFeTVEYkdGemN5QXhJRkIxWW14cFl5QlFjbWx0WVhKNUlFTmxjbi4uWFJwYjI0Z1FYVjBhRzl5CmFYUjVNUlF3RWdZRFZRUURFd3RDWlhOMElFTkJJRXgwWkRBZUZ3MHdNRC4uVFV3TVRaYUZ3MHdNVEF5Ck1EUXhPVFV3TVRaYU1JR0hNUXN3Q1FZRFZRUUdFd0pIUWpFVE1CRUdBMS4uMjl0WlMxVGRHRjBaVEVVCk1CSUdBMVVFQ2hNTFFtVnpkQ0JEUVNCTWRHUXhOekExQmdOVkJBc1RMay4uREVnVUhWaWJHbGpJRkJ5CmFXMWhjbmtnUTJWeWRHbG1hV05oZEdsdmJpQkJkWFJvYjNKcGRIa3hGRC4uQU1UQzBKbGMzUWdRMEVnClRIUmtNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZy4uVHoybXI3U1ppQU1mUXl1CnZCak05T2lKalJhelhCWjFCalA1Q0UvV20vUnI1MDBQUksrTGg5eDVlSi4uL0FOQkUwc1RLMFpzREdNCmFrMm0xZzdvcnVJM2RZM1ZIcUl4RlR6MFRhMWQrTkFqd25MZTRuT2I3Ly4uazA1U2hoQnJKR0JLS3hiCjhuMTA0by81cDhIQXNaUGR6YkZNSXlOakp6Qk0ybzV5NUExM3dpTGl0RS4uZnlZa1F6YXhDdzBBd3psCmtWSGlJeUN1YUY0d2o1NzFwU3prdjZzdis0SURNYlQvWHBDbzhMNndUYS4uc2grZXRMRDZGdFRqWWJiCnJ2WjhSUU0xdGxLZG9NSGcycXhyYUFWKytITkJZbU5XczBkdUVkalViSi4uWEk5VHRuUzRvMUNrajdQCk9mbGppUUlEQVFBQm80SG5NSUhrTUIwR0ExVWREZ1FXQkJROHVyTUNSTC4uNUFrSXA5TkpISnc1VENCCnRBWURWUjBqQklHc01JR3BnQlE4dXJNQ1JMWVlNSFVLVTVBa0lwOU5KSC4uYVNCaWpDQmh6RUxNQWtHCkExVUVCaE1DUjBJeEV6QVJCZ05WQkFnVENsTnZiV1V0VTNSaGRHVXhGRC4uQW9UQzBKbGMzUWdRMEVnClRIUmtNVGN3TlFZRFZRUUxFeTVEYkdGemN5QXhJRkIxWW14cFl5QlFjbS4uRU5sY25ScFptbGpZWFJwCmIyNGdRWFYwYUc5eWFYUjVNUlF3RWdZRFZRUURFd3RDWlhOMElFTkJJRS4uREFNQmdOVkhSTUVCVEFECkFRSC9NQTBHQ1NxR1NJYjNEUUVCQkFVQUE0SUJBUUMxdVlCY3NTbmN3QS4uRENzUWVyNzcyQzJ1Y3BYCnhRVUUvQzBwV1dtNmdEa3dkNUQwRFNNREpScVYvd2VvWjR3QzZCNzNmNS4uYkxoR1lIYVhKZVNENktyClhjb093TGRTYUdtSllzbExLWkIzWklERXAwd1lUR2hndGViNkpGaVR0bi4uc2YyeGRyWWZQQ2lJQjdnCkJNQVY3R3pkYzRWc3BTNmxqckFoYmlpYXdkQmlRbFFtc0JlRno5SmtGNC4uYjNsOEJvR04rcU1hNTZZCkl0OHVuYTJnWTRsMk8vL29uODhyNUlXSmxtMUwwb0E4ZTRmUjJ5ckJIWC4uYWRzR2VGS2t5TnJ3R2kvCjd2UU1mWGRHc1JyWE5HUkduWCt2V0RaMy96V0kwam9EdENrTm5xRXBWbi4uSG9YCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=" + +# The Secret containing the credentials will be created by the handler. +createSecret: false +secretName: nutanix-ccm-credentials +` + + expectedWithoutAdditionalTrustBundle = `--- +prismCentralEndPoint: prism-central.nutanix.com +prismCentralPort: 9440 +prismCentralInsecure: true +prismCentralAdditionalTrustBundle: "" + +# The Secret containing the credentials will be created by the handler. +createSecret: false +secretName: nutanix-ccm-credentials +` +) + +func Test_templateValues(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + clusterConfig *v1alpha1.ClusterConfigSpec + in string + expected string + }{ + { + name: "With AdditionalTrustBundle set", + clusterConfig: &v1alpha1.ClusterConfigSpec{ + GenericClusterConfig: v1alpha1.GenericClusterConfig{ + Addons: &v1alpha1.Addons{ + CCM: &v1alpha1.CCM{ + Credentials: &corev1.LocalObjectReference{ + Name: "creds", + }, + }, + }, + }, + Nutanix: &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + URL: fmt.Sprintf("https://prism-central.nutanix.com:%d", v1alpha1.DefaultPrismCentralPort), + AdditionalTrustBundle: ptr.To(testCertBundle), + }, + }, + }, + in: in, + expected: expectedWithAdditionalTrustBundle, + }, + { + name: "Without an AdditionalTrustBundle set", + clusterConfig: &v1alpha1.ClusterConfigSpec{ + GenericClusterConfig: v1alpha1.GenericClusterConfig{ + Addons: &v1alpha1.Addons{ + CCM: &v1alpha1.CCM{ + Credentials: &corev1.LocalObjectReference{ + Name: "creds", + }, + }, + }, + }, + Nutanix: &v1alpha1.NutanixSpec{ + PrismCentralEndpoint: v1alpha1.NutanixPrismCentralEndpointSpec{ + URL: fmt.Sprintf("https://prism-central.nutanix.com:%d", v1alpha1.DefaultPrismCentralPort), + Insecure: true, + }, + }, + }, + in: in, + expected: expectedWithoutAdditionalTrustBundle, + }, + } + for idx := range tests { + tt := tests[idx] + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + out, err := templateValues(tt.clusterConfig, tt.in) + require.NoError(t, err) + assert.Equal(t, tt.expected, out) + }) + } +} diff --git a/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go b/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go index 7f1ba5469..246c52992 100644 --- a/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go +++ b/pkg/handlers/generic/lifecycle/clusterautoscaler/strategy_helmaddon.go @@ -56,7 +56,8 @@ func (s helmAddonStrategy) apply( ctx, s.client, s.config.defaultValuesTemplateConfigMapName, - defaultsNamespace) + defaultsNamespace, + ) if err != nil { return fmt.Errorf( "failed to retrieve cluster-autoscaler installation values template ConfigMap for cluster: %w", diff --git a/pkg/handlers/generic/lifecycle/config/cm.go b/pkg/handlers/generic/lifecycle/config/cm.go index 5bb58caa8..89b44fa20 100644 --- a/pkg/handlers/generic/lifecycle/config/cm.go +++ b/pkg/handlers/generic/lifecycle/config/cm.go @@ -23,6 +23,7 @@ const ( NFD Component = "nfd" NutanixStorageCSI Component = "nutanix-storage-csi" NutanixSnapshotCSI Component = "nutanix-snapshot-csi" + NutanixCCM Component = "nutanix-ccm" ) type HelmChartGetter struct { diff --git a/pkg/handlers/generic/lifecycle/handlers.go b/pkg/handlers/generic/lifecycle/handlers.go index 77a2e7a6e..0452ec4fc 100644 --- a/pkg/handlers/generic/lifecycle/handlers.go +++ b/pkg/handlers/generic/lifecycle/handlers.go @@ -11,6 +11,7 @@ import ( "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm" awsccm "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm/aws" + nutanixccm "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/ccm/nutanix" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/clusterautoscaler" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/calico" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/cni/cilium" @@ -32,6 +33,7 @@ type Handlers struct { ebsConfig *awsebs.AWSEBSConfig nutnaixCSIConfig *nutanixcsi.NutanixCSIConfig awsccmConfig *awsccm.AWSCCMConfig + nutanixCCMConfig *nutanixccm.Config } func New( @@ -48,6 +50,7 @@ func New( ebsConfig: &awsebs.AWSEBSConfig{GlobalOptions: globalOptions}, awsccmConfig: &awsccm.AWSCCMConfig{GlobalOptions: globalOptions}, nutnaixCSIConfig: &nutanixcsi.NutanixCSIConfig{GlobalOptions: globalOptions}, + nutanixCCMConfig: &nutanixccm.Config{GlobalOptions: globalOptions}, } } @@ -66,7 +69,8 @@ func (h *Handlers) AllHandlers(mgr manager.Manager) []handlers.Named { ), } ccmHandlers := map[string]ccm.CCMProvider{ - v1alpha1.CCMProviderAWS: awsccm.New(mgr.GetClient(), h.awsccmConfig), + v1alpha1.CCMProviderAWS: awsccm.New(mgr.GetClient(), h.awsccmConfig), + v1alpha1.CCMProviderNutanix: nutanixccm.New(mgr.GetClient(), h.nutanixCCMConfig, helmChartInfoGetter), } return []handlers.Named{ calico.New(mgr.GetClient(), h.calicoCNIConfig, helmChartInfoGetter), @@ -87,4 +91,5 @@ func (h *Handlers) AddFlags(flagSet *pflag.FlagSet) { h.ebsConfig.AddFlags("awsebs", pflag.CommandLine) h.awsccmConfig.AddFlags("awsccm", pflag.CommandLine) h.nutnaixCSIConfig.AddFlags("nutanixcsi", flagSet) + h.nutanixCCMConfig.AddFlags("nutanixccm", flagSet) } diff --git a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go index 40a5ab537..0e9350477 100644 --- a/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go +++ b/pkg/handlers/nutanix/mutation/prismcentralendpoint/inject.go @@ -7,8 +7,6 @@ import ( "context" "encoding/base64" "fmt" - "net/url" - "strconv" "github.com/nutanix-cloud-native/prism-go-client/environment/credentials" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -101,7 +99,7 @@ func (h *nutanixPrismCentralEndpoint) Mutate( var address string var port int32 - address, port, err = parsePrismCentralURL(prismCentralEndpointVar.URL) + address, port, err = prismCentralEndpointVar.ParseURL() if err != nil { return err } @@ -138,26 +136,3 @@ func (h *nutanixPrismCentralEndpoint) Mutate( }, ) } - -//nolint:gocritic // no need for named return values -func parsePrismCentralURL(in string) (string, int32, error) { - var prismCentralURL *url.URL - prismCentralURL, err := url.Parse(in) - if err != nil { - return "", -1, fmt.Errorf("error parsing Prism Central URL: %w", err) - } - - hostname := prismCentralURL.Hostname() - - // return early with the default port if no port is specified - if prismCentralURL.Port() == "" { - return hostname, v1alpha1.DefaultPrismCentralPort, nil - } - - port, err := strconv.ParseInt(prismCentralURL.Port(), 10, 32) - if err != nil { - return "", -1, fmt.Errorf("error converting port to int: %w", err) - } - - return hostname, int32(port), nil -} From cba0297d9c56c9d5f1d76aef0803b8b5b7cd9391 Mon Sep 17 00:00:00 2001 From: Dimitri Koshkin Date: Sun, 7 Apr 2024 20:02:17 -0700 Subject: [PATCH 87/87] feat: deploy mutating webhook --- api/v1alpha1/clusterconfig_types.go | 9 ++ api/v1alpha1/node_types.go | 14 +- api/variables/variables.go | 59 ++++++++ .../README.md | 3 + .../templates/certificates.yaml | 6 +- .../templates/deployment.yaml | 18 ++- .../templates/extensionconfig.yaml | 2 +- .../templates/webhook-service.yaml | 26 ++++ .../templates/webhook.yaml | 32 ++++ .../values.yaml | 6 + cmd/main.go | 19 +++ common/pkg/server/server.go | 6 +- make/go.mk | 5 +- webhooks/cluster.go | 142 ++++++++++++++++++ webhooks/webhooks.go | 26 ++++ 15 files changed, 358 insertions(+), 15 deletions(-) create mode 100644 api/variables/variables.go create mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/webhook-service.yaml create mode 100644 charts/cluster-api-runtime-extensions-nutanix/templates/webhook.yaml create mode 100644 webhooks/cluster.go create mode 100644 webhooks/webhooks.go diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go index 5cee9a2fb..f19b35ea8 100644 --- a/api/v1alpha1/clusterconfig_types.go +++ b/api/v1alpha1/clusterconfig_types.go @@ -12,6 +12,7 @@ import ( clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/openapi/patterns" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables" ) type StorageProvisioner string @@ -94,6 +95,14 @@ func (s ClusterConfigSpec) VariableSchema() clusterv1.VariableSchema { //nolint: return clusterConfigProps } +func (s *ClusterConfigSpec) ToClusterVariable(name string) (*clusterv1.ClusterVariable, error) { + return variables.MarshalToClusterVariable(name, s) +} + +func (s *ClusterConfigSpec) FromClusterVariable(clusterVariable *clusterv1.ClusterVariable) error { + return variables.UnmarshalClusterVariable(clusterVariable, s) +} + // GenericClusterConfig defines the generic cluster configdesired. type GenericClusterConfig struct { // +optional diff --git a/api/v1alpha1/node_types.go b/api/v1alpha1/node_types.go index f2d3c6bf3..f1046445e 100644 --- a/api/v1alpha1/node_types.go +++ b/api/v1alpha1/node_types.go @@ -8,16 +8,18 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables" ) -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // NodeConfig is the Schema for the workerconfigs API. type NodeConfig struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - //+optional + // +optional Spec NodeConfigSpec `json:"spec,omitempty"` } @@ -63,6 +65,14 @@ func (s NodeConfigSpec) VariableSchema() clusterv1.VariableSchema { return nodeConfigProps } +func (s *NodeConfigSpec) ToClusterVariable(name string) (*clusterv1.ClusterVariable, error) { + return variables.MarshalToClusterVariable(name, s) +} + +func (s *NodeConfigSpec) FromClusterVariable(clusterVariable *clusterv1.ClusterVariable) error { + return variables.UnmarshalClusterVariable(clusterVariable, s) +} + type GenericNodeConfig struct{} func (GenericNodeConfig) VariableSchema() clusterv1.VariableSchema { diff --git a/api/variables/variables.go b/api/variables/variables.go new file mode 100644 index 000000000..a570410f5 --- /dev/null +++ b/api/variables/variables.go @@ -0,0 +1,59 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package variables + +import ( + "encoding/json" + "fmt" + + v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" +) + +func MarshalToClusterVariable[T any](name string, obj T) (*clusterv1.ClusterVariable, error) { + marshaled, err := json.Marshal(obj) + if err != nil { + return nil, fmt.Errorf("failed to marshal variable value %q: %w", name, err) + } + return &clusterv1.ClusterVariable{ + Name: name, + Value: v1.JSON{Raw: marshaled}, + }, nil +} + +func UnmarshalClusterVariable[T any](clusterVariable *clusterv1.ClusterVariable, obj *T) error { + err := json.Unmarshal(clusterVariable.Value.Raw, obj) + if err != nil { + return fmt.Errorf("error unmarshalling variable: %w", err) + } + + return nil +} + +func GetClusterVariableByName( + name string, + clusterVariables []clusterv1.ClusterVariable, +) (*clusterv1.ClusterVariable, int) { + for i, clusterVar := range clusterVariables { + if clusterVar.Name == name { + return &clusterVar, i + } + } + return nil, -1 +} + +func GetMachineDeploymentVariableByName( + name string, + machineDeploymentVariables *clusterv1.MachineDeploymentVariables, +) (*clusterv1.ClusterVariable, int) { + if machineDeploymentVariables == nil { + return nil, -1 + } + for i, mdVar := range machineDeploymentVariables.Overrides { + if mdVar.Name == name { + return &mdVar, i + } + } + return nil, -1 +} diff --git a/charts/cluster-api-runtime-extensions-nutanix/README.md b/charts/cluster-api-runtime-extensions-nutanix/README.md index 80c72c84b..5bbea1aec 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/README.md +++ b/charts/cluster-api-runtime-extensions-nutanix/README.md @@ -77,3 +77,6 @@ A Helm chart for cluster-api-runtime-extensions-nutanix | service.port | int | `443` | | | service.type | string | `"ClusterIP"` | | | tolerations | list | `[{"effect":"NoSchedule","key":"node-role.kubernetes.io/master","operator":"Equal"},{"effect":"NoSchedule","key":"node-role.kubernetes.io/control-plane","operator":"Equal"}]` | Kubernetes pod tolerations | +| webhooks.service.annotations | object | `{}` | | +| webhooks.service.port | int | `443` | | +| webhooks.service.type | string | `"ClusterIP"` | | diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/certificates.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/certificates.yaml index e07fcc3dc..aa8891313 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/certificates.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/certificates.yaml @@ -4,7 +4,7 @@ apiVersion: cert-manager.io/v1 kind: Certificate metadata: - name: {{ template "chart.name" . }}-runtimehooks-tls + name: {{ template "chart.name" . }}-service-cert namespace: {{ .Release.Namespace }} labels: {{- include "chart.labels" . | nindent 4 }} @@ -12,7 +12,9 @@ spec: dnsNames: - {{ template "chart.name" . }}-runtimehooks.{{ .Release.Namespace }}.svc - {{ template "chart.name" . }}-runtimehooks.{{ .Release.Namespace }}.svc.cluster.local + - {{ template "chart.name" . }}-webhook-service.{{ .Release.Namespace }}.svc + - {{ template "chart.name" . }}-webhook-service.{{ .Release.Namespace }}.svc.cluster.local issuerRef: kind: {{ .Values.certificates.issuer.kind }} name: {{ template "chart.issuerName" . }} - secretName: {{ template "chart.name" . }}-runtimehooks-tls + secretName: {{ template "chart.name" . }}-service-cert diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml index b54b1d72d..1b86dc255 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/deployment.yaml @@ -28,11 +28,14 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default $.Chart.AppVersion }}" imagePullPolicy: "{{ .Values.image.pullPolicy }}" args: - - --webhook-cert-dir=/runtimehooks-certs/ + - --runtime-webhook-port=9444 + - --runtime-webhook-cert-dir=/tmp/k8s-webhook-server/serving-certs/ - --defaults-namespace=$(POD_NAMESPACE) - --helm-addons-configmap={{ .Values.helmAddonsConfigMap }} - --cni.cilium.helm-addon.default-values-template-configmap-name={{ .Values.hooks.cni.cilium.helmAddonStrategy.defaultValueTemplateConfigMap.name }} - --nfd.helm-addon.default-values-template-configmap-name={{ .Values.hooks.nfd.helmAddonStrategy.defaultValueTemplateConfigMap.name }} + - --webhook-port=9443 + - --webhook-cert-dir=/tmp/k8s-webhook-server/serving-certs/ {{- range $key, $value := .Values.extraArgs }} - --{{ $key }}={{ $value }} {{- end }} @@ -43,9 +46,12 @@ spec: {{- end }} {{- end }} ports: - - containerPort: 9443 + - containerPort: 9444 name: runtimehooks protocol: TCP + - containerPort: 9443 + name: webhook-server + protocol: TCP - containerPort: 8080 name: metrics protocol: TCP @@ -62,8 +68,8 @@ spec: {{- toYaml . | nindent 10 }} {{- end }} volumeMounts: - - mountPath: /runtimehooks-certs - name: runtimehooks-cert + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert readOnly: true livenessProbe: httpGet: @@ -81,7 +87,7 @@ spec: {{- toYaml . | nindent 8}} {{- end }} volumes: - - name: runtimehooks-cert + - name: cert secret: defaultMode: 420 - secretName: {{ template "chart.name" . }}-runtimehooks-tls + secretName: {{ template "chart.name" . }}-service-cert diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/extensionconfig.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/extensionconfig.yaml index 4f6005b48..535568a19 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/templates/extensionconfig.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/extensionconfig.yaml @@ -5,7 +5,7 @@ apiVersion: runtime.cluster.x-k8s.io/v1alpha1 kind: ExtensionConfig metadata: annotations: - runtime.cluster.x-k8s.io/inject-ca-from-secret: {{ .Release.Namespace }}/{{ template "chart.name" . }}-runtimehooks-tls + runtime.cluster.x-k8s.io/inject-ca-from-secret: {{ .Release.Namespace }}/{{ template "chart.name" . }}-service-cert name: {{ template "chart.name" . }} namespace: {{ .Release.Namespace }} spec: diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/webhook-service.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/webhook-service.yaml new file mode 100644 index 000000000..056648bc9 --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/webhook-service.yaml @@ -0,0 +1,26 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: v1 +kind: Service +metadata: + annotations: + {{- with .Values.webhooks.service.annotations }} + {{ toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "chart.labels" . | nindent 4 }} + name: {{ template "chart.name" . }}-webhook-service + namespace: {{ .Release.Namespace }} +spec: + type: {{.Values.webhooks.service.type}} + ports: + - name: https + port: {{ .Values.webhooks.service.port }} + protocol: TCP + targetPort: webhook-server + {{- if and .Values.webhooks.service.nodePort (eq "NodePort" .Values.service.type) }} + nodePort: {{ .Values.webhooks.service.nodePort }} + {{- end }} + selector: + {{- include "chart.selectorLabels" . | nindent 4 }} diff --git a/charts/cluster-api-runtime-extensions-nutanix/templates/webhook.yaml b/charts/cluster-api-runtime-extensions-nutanix/templates/webhook.yaml new file mode 100644 index 000000000..3454aa81e --- /dev/null +++ b/charts/cluster-api-runtime-extensions-nutanix/templates/webhook.yaml @@ -0,0 +1,32 @@ +# Copyright 2023 D2iQ, Inc. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +metadata: + name: {{ template "chart.name" . }}-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ template "chart.name" . }}-service-cert +webhooks: +- admissionReviewVersions: + - v1 + - v1beta1 + clientConfig: + service: + name: {{ template "chart.name" . }}-webhook-service + namespace: {{ .Release.Namespace }} + path: /mutate-cluster-x-k8s-io-v1beta1-cluster + failurePolicy: Fail + matchPolicy: Equivalent + name: default.cluster.cluster.x-k8s.io + rules: + - apiGroups: + - cluster.x-k8s.io + apiVersions: + - v1beta1 + operations: + - CREATE + - UPDATE + resources: + - clusters + sideEffects: None diff --git a/charts/cluster-api-runtime-extensions-nutanix/values.yaml b/charts/cluster-api-runtime-extensions-nutanix/values.yaml index eee0993af..519ea518a 100644 --- a/charts/cluster-api-runtime-extensions-nutanix/values.yaml +++ b/charts/cluster-api-runtime-extensions-nutanix/values.yaml @@ -128,3 +128,9 @@ tolerations: # -- Priority class to be used for the pod. priorityClassName: system-cluster-critical + +webhooks: + service: + annotations: {} + type: ClusterIP + port: 443 diff --git a/cmd/main.go b/cmd/main.go index f43f3ff7e..39887e02e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -23,6 +23,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/healthz" "sigs.k8s.io/controller-runtime/pkg/manager" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "sigs.k8s.io/controller-runtime/pkg/webhook" caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" @@ -38,6 +39,7 @@ import ( nutanixmutation "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/mutation" nutanixworkerconfig "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/nutanix/workerconfig" "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/webhooks" ) func main() { @@ -80,6 +82,9 @@ func main() { runtimeWebhookServerOpts := server.NewServerOptions() + // mutating/validating webhook server options + webhookServerOpts := webhooks.NewOptions() + globalOptions := options.NewGlobalOptions() genericLifecycleHandlers := lifecycle.New(globalOptions) @@ -89,6 +94,7 @@ func main() { logsv1.AddFlags(logOptions, pflag.CommandLine) globalOptions.AddFlags(pflag.CommandLine) runtimeWebhookServerOpts.AddFlags(pflag.CommandLine) + webhookServerOpts.AddFlags(pflag.CommandLine) genericLifecycleHandlers.AddFlags(pflag.CommandLine) pflag.CommandLine.SetNormalizeFunc(cliflag.WordSepNormalizeFunc) pflag.CommandLine.AddGoFlagSet(flag.CommandLine) @@ -105,6 +111,14 @@ func main() { // Add the klog logger in the context. ctrl.SetLogger(klog.Background()) + // Setup mutating/validating webhook server + mgrOptions.WebhookServer = webhook.NewServer( + webhook.Options{ + Port: webhookServerOpts.WebhookPort, + CertDir: webhookServerOpts.WebhookCertDir, + }, + ) + signalCtx := ctrl.SetupSignalHandler() mgr, err := newManager(mgrOptions) @@ -154,6 +168,11 @@ func main() { os.Exit(1) } + if err := (&webhooks.Cluster{}).SetupWebhookWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create webhook", "webhook", "Cluster") + os.Exit(1) + } + if err := mgr.Start(signalCtx); err != nil { setupLog.Error(err, "unable to start controller manager") os.Exit(1) diff --git a/common/pkg/server/server.go b/common/pkg/server/server.go index cdafc567d..0c56d95ed 100644 --- a/common/pkg/server/server.go +++ b/common/pkg/server/server.go @@ -48,13 +48,13 @@ func NewServerOptions() *ServerOptions { } func (s *ServerOptions) AddFlags(fs *pflag.FlagSet) { - fs.IntVar(&s.webhookPort, "webhook-port", s.webhookPort, "Webhook Server port") + fs.IntVar(&s.webhookPort, "runtime-webhook-port", s.webhookPort, "Runtime webhook server port") fs.StringVar( &s.webhookCertDir, - "webhook-cert-dir", + "runtime-webhook-cert-dir", s.webhookCertDir, - "Runtime hooks server cert dir.", + "Runtime webhook server cert dir", ) } diff --git a/make/go.mk b/make/go.mk index 596b2e51c..d405e33f0 100644 --- a/make/go.mk +++ b/make/go.mk @@ -190,7 +190,10 @@ go-fix.%: ; $(info $(M) go fixing $* module) go-generate: ## Runs go generate go-generate: ; $(info $(M) running go generate) go generate -x ./... - controller-gen paths="./..." rbac:headerFile="hack/license-header.yaml.txt",roleName=cluster-api-runtime-extensions-nutanix-manager-role output:rbac:artifacts:config=charts/cluster-api-runtime-extensions-nutanix/templates + controller-gen \ + paths="./..." \ + rbac:headerFile="hack/license-header.yaml.txt",roleName=cluster-api-runtime-extensions-nutanix-manager-role \ + output:rbac:artifacts:config=charts/cluster-api-runtime-extensions-nutanix/templates sed --in-place 's/cluster-api-runtime-extensions-nutanix-manager-role/{{ include "chart.name" . }}-manager-role/' charts/cluster-api-runtime-extensions-nutanix/templates/role.yaml controller-gen paths="./api/v1alpha1/..." object:headerFile="hack/license-header.go.txt" output:object:artifacts:config=/dev/null $(MAKE) go-fix diff --git a/webhooks/cluster.go b/webhooks/cluster.go new file mode 100644 index 000000000..0bdea09a7 --- /dev/null +++ b/webhooks/cluster.go @@ -0,0 +1,142 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package webhooks + +import ( + "context" + "fmt" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/webhook" + + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/variables" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/clusterconfig" + "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/workerconfig" +) + +// +kubebuilder:webhook:verbs=create;update,path=/mutate-cluster-x-k8s-io-v1beta1-cluster,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=cluster.x-k8s.io,resources=clusters,versions=v1beta1,name=default.cluster.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1 + +// Cluster implements a defaulting webhook for Cluster. +type Cluster struct{} + +var _ webhook.CustomDefaulter = &Cluster{} + +// SetupWebhookWithManager sets up Cluster webhooks. +func (webhook *Cluster) SetupWebhookWithManager(mgr ctrl.Manager) error { + return ctrl.NewWebhookManagedBy(mgr). + For(&clusterv1.Cluster{}). + WithDefaulter(webhook). + Complete() +} + +// Default satisfies the defaulting webhook interface. +func (webhook *Cluster) Default(_ context.Context, obj runtime.Object) error { + // We gather all defaulting errors and return them together. + var allErrs field.ErrorList + + cluster, ok := obj.(*clusterv1.Cluster) + if !ok { + return apierrors.NewBadRequest(fmt.Sprintf("expected a Cluster but got a %T", obj)) + } + + if cluster.Spec.Topology == nil || + len(cluster.Spec.Topology.Variables) == 0 { + return nil + } + + // Set defaults for 'clusterConfig' variable from spec.topology.variables + clusterConfigVariable, clusterConfigVariableIndex := variables.GetClusterVariableByName( + clusterconfig.MetaVariableName, + cluster.Spec.Topology.Variables, + ) + if clusterConfigVariable != nil { + clusterConfigSpec := &v1alpha1.ClusterConfigSpec{} + err := clusterConfigSpec.FromClusterVariable(clusterConfigVariable) + if err != nil { + return fmt.Errorf("failed to unmarshal ClusterConfigSpec from ClusterVariable: %w", err) + } + errs := defaultClusterConfig(clusterConfigSpec) + if len(errs) > 1 { + allErrs = append(allErrs, errs...) + } + clusterConfigVariable, err = clusterConfigSpec.ToClusterVariable(clusterconfig.MetaVariableName) + if err != nil { + return fmt.Errorf("failed to marshal ClusterConfigSpec to ClusterVariable: %w", err) + } + cluster.Spec.Topology.Variables[clusterConfigVariableIndex] = *clusterConfigVariable + + } + + // Set defaults from 'workerConfig' variable from spec.topology.variables + workerConfigVariable, workerConfigVariableIndex := variables.GetClusterVariableByName( + workerconfig.MetaVariableName, + cluster.Spec.Topology.Variables, + ) + if workerConfigVariable != nil { + workerConfigSpec := &v1alpha1.NodeConfigSpec{} + err := workerConfigSpec.FromClusterVariable(workerConfigVariable) + if err != nil { + return fmt.Errorf("failed to unmarshal NodeConfigSpec from WorkerVariable: %w", err) + } + errs := defaultWorkerConfig(workerConfigSpec) + if len(errs) > 1 { + allErrs = append(allErrs, errs...) + } + workerConfigVariable, err = workerConfigSpec.ToClusterVariable(workerconfig.MetaVariableName) + if err != nil { + return fmt.Errorf("failed to marshal NodeConfigSpec to WorkerVariable: %w", err) + } + cluster.Spec.Topology.Variables[workerConfigVariableIndex] = *workerConfigVariable + } + + // Set defaults for 'workerConfig' variable from spec.topology.workers.machineDeployments.variables.overrides + if cluster.Spec.Topology.Workers != nil { + for i, md := range cluster.Spec.Topology.Workers.MachineDeployments { + mdWorkerConfigVariable, mdWorkerConfigVariableIndex := variables.GetMachineDeploymentVariableByName( + workerconfig.MetaVariableName, + md.Variables, + ) + if mdWorkerConfigVariable != nil { + workerConfigSpec := &v1alpha1.NodeConfigSpec{} + err := workerConfigSpec.FromClusterVariable(mdWorkerConfigVariable) + if err != nil { + return fmt.Errorf("failed to unmarshal NodeConfigSpec from WorkerVariable: %w", err) + } + errs := defaultWorkerConfig(workerConfigSpec) + if len(errs) > 1 { + allErrs = append(allErrs, errs...) + } + mdWorkerConfigVariable, err = workerConfigSpec.ToClusterVariable(workerconfig.MetaVariableName) + if err != nil { + return fmt.Errorf("failed to marshal NodeConfigSpec to WorkerVariable: %w", err) + } + cluster.Spec.Topology.Workers.MachineDeployments[i].Variables.Overrides[mdWorkerConfigVariableIndex] = + *mdWorkerConfigVariable + } + } + } + + if len(allErrs) > 0 { + return apierrors.NewInvalid(clusterv1.GroupVersion.WithKind("Cluster").GroupKind(), cluster.Name, allErrs) + } + + return nil +} + +func defaultClusterConfig(clusterConfig *v1alpha1.ClusterConfigSpec) field.ErrorList { + // Set defaults for clusterConfig variable here. + + return nil +} + +func defaultWorkerConfig(workerConfig *v1alpha1.NodeConfigSpec) field.ErrorList { + // Set defaults for workerConfig variable here. + + return nil +} diff --git a/webhooks/webhooks.go b/webhooks/webhooks.go new file mode 100644 index 000000000..f1390fa51 --- /dev/null +++ b/webhooks/webhooks.go @@ -0,0 +1,26 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package webhooks + +import "github.com/spf13/pflag" + +type Options struct { + WebhookPort int + WebhookCertDir string +} + +func NewOptions() *Options { + return &Options{} +} + +func (s *Options) AddFlags(fs *pflag.FlagSet) { + fs.IntVar(&s.WebhookPort, "webhook-port", s.WebhookPort, "Webhook server port") + + fs.StringVar( + &s.WebhookCertDir, + "webhook-cert-dir", + s.WebhookCertDir, + "Webhook server cert dir", + ) +}