diff --git a/.gitignore b/.gitignore index 03feea596..355a0abc3 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,5 @@ public/ resources/ node_modules/ .hugo_build.lock + +/cluster.yaml diff --git a/.golangci.yml b/.golangci.yml index d4ae37ba4..3d698e04e 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -81,3 +81,7 @@ issues: - source: "^// \\+kubebuilder:" linters: - lll + # Idiomatic to use init functions to register APIs with scheme + - path: "api/*" + linters: + - gochecknoinits diff --git a/.goreleaser.yml b/.goreleaser.yml index 2f1057c65..fa6db6b79 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -28,7 +28,7 @@ gomod: builds: - id: capi-runtime-extensions - dir: ./cmd/capi-runtime-extensions + dir: ./cmd env: - CGO_ENABLED=0 flags: diff --git a/PROJECT b/PROJECT index 32e925b7b..601c7ca52 100644 --- a/PROJECT +++ b/PROJECT @@ -7,4 +7,13 @@ layout: - go.kubebuilder.io/v4 projectName: capi-runtime-extensions repo: github.com/d2iq-labs/capi-runtime-extensions +resources: +- api: + crdVersion: v1 + namespaced: true + domain: labs.d2iq.io + group: capiext.labs.d2iq.io + kind: ClusterConfig + path: github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/api/v1alpha1/clusterconfig_types.go b/api/v1alpha1/clusterconfig_types.go new file mode 100644 index 000000000..7d06efa20 --- /dev/null +++ b/api/v1alpha1/clusterconfig_types.go @@ -0,0 +1,111 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" + + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/openapi/patterns" +) + +//+kubebuilder:object:root=true + +// ClusterConfig is the Schema for the clusterconfigs API. +type ClusterConfig struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec ClusterConfigSpec `json:"spec,omitempty"` +} + +// ClusterConfigSpec defines the desired state of ClusterConfig. +type ClusterConfigSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // +optional + Proxy *HTTPProxy `json:"proxy,omitempty"` + + // +optional + ExtraAPIServerCertSANs ExtraAPIServerCertSANs `json:"extraAPIServerCertSANs,omitempty"` +} + +func (ClusterConfigSpec) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Description: "Cluster configuration", + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "proxy": HTTPProxy{}.VariableSchema().OpenAPIV3Schema, + "extraAPIServerCertSANs": ExtraAPIServerCertSANs{}.VariableSchema().OpenAPIV3Schema, + }, + }, + } +} + +// HTTPProxy required for providing proxy configuration. +type HTTPProxy struct { + // HTTP proxy. + HTTP string `json:"http,omitempty"` + + // HTTPS proxy. + HTTPS string `json:"https,omitempty"` + + // AdditionalNo Proxy list that will be added to the automatically calculated + // values that will apply no_proxy configuration for cluster internal network. + // Default values: localhost,127.0.0.1,,,kubernetes + // ,kubernetes.default,.svc,.svc. + AdditionalNo []string `json:"additionalNo"` +} + +func (HTTPProxy) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Type: "object", + Properties: map[string]clusterv1.JSONSchemaProps{ + "http": { + Description: "HTTP proxy value.", + Type: "string", + }, + "https": { + Description: "HTTPS proxy value.", + Type: "string", + }, + "additionalNo": { + Description: "Additional No Proxy list that will be added to the automatically calculated " + + "values required for cluster internal network. " + + "Default value: localhost,127.0.0.1,,,kubernetes," + + "kubernetes.default,.svc,.svc.", + Type: "array", + Items: &clusterv1.JSONSchemaProps{ + Type: "string", + }, + }, + }, + }, + } +} + +// ExtraAPIServerCertSANs required for providing API server cert SANs. +type ExtraAPIServerCertSANs []string + +func (ExtraAPIServerCertSANs) VariableSchema() clusterv1.VariableSchema { + return clusterv1.VariableSchema{ + OpenAPIV3Schema: clusterv1.JSONSchemaProps{ + Description: "Extra Subject Alternative Names for the API Server signing cert", + Type: "array", + UniqueItems: true, + Items: &clusterv1.JSONSchemaProps{ + Type: "string", + Pattern: patterns.Anchored(patterns.DNS1123Subdomain), + }, + }, + } +} + +// +kubebuilder:object:root=true +func init() { + SchemeBuilder.Register(&ClusterConfig{}) +} diff --git a/api/v1alpha1/doc.go b/api/v1alpha1/doc.go new file mode 100644 index 000000000..122e5b179 --- /dev/null +++ b/api/v1alpha1/doc.go @@ -0,0 +1,11 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Package v1alpha1 contains API Schema definitions for the CAPI extensions v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=capiext.labs.d2iq.io +// +//go:generate -command CTRLGEN controller-gen paths="./..." +//go:generate CTRLGEN rbac:headerFile="../../hack/license-header.yaml.txt",roleName=capi-runtime-extensions-manager-role output:rbac:artifacts:config=../../charts/capi-runtime-extensions/templates +//go:generate CTRLGEN object:headerFile="../../hack/license-header.go.txt" output:object:artifacts:config=/dev/null +package v1alpha1 diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go index 01dfd85a8..69bcc9943 100644 --- a/api/v1alpha1/groupversion_info.go +++ b/api/v1alpha1/groupversion_info.go @@ -1,9 +1,6 @@ // Copyright 2023 D2iQ, Inc. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -// Package v1alpha1 contains API Schema definitions for the CAPI extensions v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=capiext.labs.d2iq.io package v1alpha1 import ( @@ -11,9 +8,11 @@ import ( "sigs.k8s.io/controller-runtime/pkg/scheme" ) +const APIGroup = "capiext.labs.d2iq.io" + var ( // GroupVersion is group version used to register these objects. - GroupVersion = schema.GroupVersion{Group: "capiext.labs.d2iq.io", Version: "v1alpha1"} + GroupVersion = schema.GroupVersion{Group: APIGroup, Version: "v1alpha1"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme. SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 2574de927..74953e7a8 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -7,7 +7,99 @@ package v1alpha1 -import () +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterConfig) DeepCopyInto(out *ClusterConfig) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterConfig. +func (in *ClusterConfig) DeepCopy() *ClusterConfig { + if in == nil { + return nil + } + out := new(ClusterConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterConfig) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterConfigSpec) DeepCopyInto(out *ClusterConfigSpec) { + *out = *in + if in.Proxy != nil { + in, out := &in.Proxy, &out.Proxy + *out = new(HTTPProxy) + (*in).DeepCopyInto(*out) + } + if in.ExtraAPIServerCertSANs != nil { + in, out := &in.ExtraAPIServerCertSANs, &out.ExtraAPIServerCertSANs + *out = make(ExtraAPIServerCertSANs, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterConfigSpec. +func (in *ClusterConfigSpec) DeepCopy() *ClusterConfigSpec { + if in == nil { + return nil + } + out := new(ClusterConfigSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in ExtraAPIServerCertSANs) DeepCopyInto(out *ExtraAPIServerCertSANs) { + { + in := &in + *out = make(ExtraAPIServerCertSANs, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtraAPIServerCertSANs. +func (in ExtraAPIServerCertSANs) DeepCopy() ExtraAPIServerCertSANs { + if in == nil { + return nil + } + out := new(ExtraAPIServerCertSANs) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPProxy) DeepCopyInto(out *HTTPProxy) { + *out = *in + if in.AdditionalNo != nil { + in, out := &in.AdditionalNo, &out.AdditionalNo + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPProxy. +func (in *HTTPProxy) DeepCopy() *HTTPProxy { + if in == nil { + return nil + } + out := new(HTTPProxy) + 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) { diff --git a/cmd/capi-runtime-extensions/main.go b/cmd/main.go similarity index 86% rename from cmd/capi-runtime-extensions/main.go rename to cmd/main.go index 115e09db2..5908d1b48 100644 --- a/cmd/capi-runtime-extensions/main.go +++ b/cmd/main.go @@ -26,7 +26,10 @@ import ( "sigs.k8s.io/controller-runtime/pkg/manager" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/server" + "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/auditpolicy" + "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/clusterconfig" "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/cni/calico" "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/extraapiservercertsans" "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/httpproxy" @@ -130,12 +133,29 @@ func main() { runtimeWebhookServer := server.NewServer( runtimeWebhookServerOpts, + servicelbgc.New(mgr.GetClient()), + calico.New(mgr.GetClient(), calicoCNIConfig), + httpproxy.NewVariable(), - httpproxy.NewPatch(mgr.GetClient()), + httpproxy.NewPatch(mgr.GetClient(), httpproxy.VariableName), + extraapiservercertsans.NewVariable(), - extraapiservercertsans.NewPatch(), + extraapiservercertsans.NewPatch(extraapiservercertsans.VariableName), + + auditpolicy.NewPatch(), + + clusterconfig.NewVariable(), + mutation.NewMetaGeneratePatchesHandler( + "clusterConfigPatch", + httpproxy.NewPatch(mgr.GetClient(), clusterconfig.VariableName, httpproxy.VariableName), + extraapiservercertsans.NewPatch( + clusterconfig.VariableName, + extraapiservercertsans.VariableName, + ), + auditpolicy.NewPatch(), + ), ) if err := mgr.Add(runtimeWebhookServer); err != nil { setupLog.Error(err, "unable to add runtime webhook server runnable to controller manager") diff --git a/common/pkg/capi/clustertopology/handlers/mutation/meta.go b/common/pkg/capi/clustertopology/handlers/mutation/meta.go new file mode 100644 index 000000000..28681a027 --- /dev/null +++ b/common/pkg/capi/clustertopology/handlers/mutation/meta.go @@ -0,0 +1,52 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package mutation + +import ( + "context" + "strings" + + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers" +) + +type metaGeneratePatches struct { + name string + wrappedHandlers []GeneratePatches +} + +func NewMetaGeneratePatchesHandler(name string, gp ...GeneratePatches) handlers.Named { + return metaGeneratePatches{ + name: name, + wrappedHandlers: gp, + } +} + +func (mgp metaGeneratePatches) Name() string { + return mgp.name +} + +func (mgp metaGeneratePatches) GeneratePatches( + ctx context.Context, + req *runtimehooksv1.GeneratePatchesRequest, + resp *runtimehooksv1.GeneratePatchesResponse, +) { + for _, h := range mgp.wrappedHandlers { + wrappedResp := &runtimehooksv1.GeneratePatchesResponse{} + h.GeneratePatches(ctx, req, wrappedResp) + resp.Items = append(resp.Items, wrappedResp.Items...) + if wrappedResp.Message != "" { + resp.Message = strings.TrimPrefix(resp.Message+"\n"+wrappedResp.Message, "\n") + } + resp.Status = wrappedResp.Status + if resp.Status == runtimehooksv1.ResponseStatusFailure { + return + } + } + + if resp.Status == "" { + resp.Status = runtimehooksv1.ResponseStatusSuccess + } +} diff --git a/common/pkg/capi/clustertopology/handlers/mutation/meta_test.go b/common/pkg/capi/clustertopology/handlers/mutation/meta_test.go new file mode 100644 index 000000000..f31f26ed0 --- /dev/null +++ b/common/pkg/capi/clustertopology/handlers/mutation/meta_test.go @@ -0,0 +1,242 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package mutation + +import ( + "context" + "testing" + + "github.com/onsi/gomega" + runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" +) + +type testHandler struct { + resp *runtimehooksv1.GeneratePatchesResponse +} + +var _ GeneratePatches = &testHandler{} + +func (h *testHandler) GeneratePatches( + _ context.Context, + _ *runtimehooksv1.GeneratePatchesRequest, + resp *runtimehooksv1.GeneratePatchesResponse, +) { + resp.Items = append(resp.Items, h.resp.Items...) + resp.Message = h.resp.Message + resp.Status = h.resp.Status +} + +func TestMetaGeneratePatches(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + wrappedHandlers []GeneratePatches + expectedResponse *runtimehooksv1.GeneratePatchesResponse + }{{ + name: "no handlers", + expectedResponse: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusSuccess, + }, + }, + }, { + name: "single success handler", + wrappedHandlers: []GeneratePatches{ + &testHandler{ + resp: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusSuccess, + Message: "This is a success", + }, + Items: []runtimehooksv1.GeneratePatchesResponseItem{{ + UID: "1234", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is a patch`), + }}, + }, + }, + }, + expectedResponse: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusSuccess, + Message: "This is a success", + }, + Items: []runtimehooksv1.GeneratePatchesResponseItem{{ + UID: "1234", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is a patch`), + }}, + }, + }, { + name: "single failure handler", + wrappedHandlers: []GeneratePatches{ + &testHandler{ + resp: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusFailure, + Message: "This is a failure", + }, + }, + }, + }, + expectedResponse: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusFailure, + Message: "This is a failure", + }, + }, + }, { + name: "multiple success handlers", + wrappedHandlers: []GeneratePatches{ + &testHandler{ + resp: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusSuccess, + Message: "This is a success", + }, + Items: []runtimehooksv1.GeneratePatchesResponseItem{{ + UID: "1234", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is a patch`), + }, { + UID: "12345", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is another patch`), + }}, + }, + }, + &testHandler{ + resp: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusSuccess, + Message: "This is also a success", + }, + Items: []runtimehooksv1.GeneratePatchesResponseItem{{ + UID: "123456", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is also a patch`), + }}, + }, + }, + }, + expectedResponse: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusSuccess, + Message: `This is a success +This is also a success`, + }, + Items: []runtimehooksv1.GeneratePatchesResponseItem{{ + UID: "1234", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is a patch`), + }, { + UID: "12345", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is another patch`), + }, { + UID: "123456", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is also a patch`), + }}, + }, + }, { + name: "success handler followed by failure handler", + wrappedHandlers: []GeneratePatches{ + &testHandler{ + resp: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusSuccess, + Message: "This is a success", + }, + Items: []runtimehooksv1.GeneratePatchesResponseItem{{ + UID: "1234", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is a patch`), + }, { + UID: "12345", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is another patch`), + }}, + }, + }, + &testHandler{ + resp: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusFailure, + Message: "This is a failure", + }, + }, + }, + }, + expectedResponse: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusFailure, + Message: `This is a success +This is a failure`, + }, + Items: []runtimehooksv1.GeneratePatchesResponseItem{{ + UID: "1234", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is a patch`), + }, { + UID: "12345", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is another patch`), + }}, + }, + }, { + name: "failure handler followed by success handler", + wrappedHandlers: []GeneratePatches{ + &testHandler{ + resp: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusFailure, + Message: "This is a failure", + }, + }, + }, + &testHandler{ + resp: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusSuccess, + Message: "This is a success", + }, + Items: []runtimehooksv1.GeneratePatchesResponseItem{{ + UID: "1234", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is a patch`), + }, { + UID: "12345", + PatchType: runtimehooksv1.JSONPatchType, + Patch: []byte(`this is another patch`), + }}, + }, + }, + }, + expectedResponse: &runtimehooksv1.GeneratePatchesResponse{ + CommonResponse: runtimehooksv1.CommonResponse{ + Status: runtimehooksv1.ResponseStatusFailure, + Message: `This is a failure`, + }, + }, + }} + + for idx := range tests { + tt := tests[idx] + + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + g := gomega.NewWithT(t) + + h := NewMetaGeneratePatchesHandler("", tt.wrappedHandlers...).(GeneratePatches) + + resp := &runtimehooksv1.GeneratePatchesResponse{} + h.GeneratePatches(context.Background(), &runtimehooksv1.GeneratePatchesRequest{}, resp) + + g.Expect(resp).To(gomega.Equal(tt.expectedResponse)) + }) + } +} diff --git a/docs/content/cluster-config.md b/docs/content/cluster-config.md new file mode 100644 index 000000000..e6fb577c1 --- /dev/null +++ b/docs/content/cluster-config.md @@ -0,0 +1,50 @@ +--- +title: "Cluster Config" +--- + +The Cluster Config handlers wrap all the other mutation handlers in a convenient single patch for inclusion in your +ClusterClasses, allowing for a single configuration variable with nested values. This provides the most flexibility +with the least configuration. The included patches are usable individually, but require declaring all the individual +patch and variable handlers in the ClusterClass. + +To enable the API server certificate SANs enable the `clusterconfigvars` and `clusterconfigpatch` +external patches on `ClusterClass`. + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: ClusterClass +metadata: + name: +spec: + patches: + - name: cluster-config + external: + generateExtension: "clusterconfigpatch." + discoverVariablesExtension: "clusterconfigvars." +``` + +On the cluster resource then specify desired certificate SANs values: + +```yaml +apiVersion: cluster.x-k8s.io/v1beta1 +kind: Cluster +metadata: + name: +spec: + topology: + variables: + - name: clusterConfig + value: + extraAPIServerCertSANs: + - a.b.c.example.com + - d.e.f.example.com + proxy: + http: http://example.com + https: https://example.com + additionalNo: + - no-proxy-1.example.com + - no-proxy-2.example.com +``` + +Applying this configuration will result in the certificate SANs being correctly set in the +`KubeadmControlPlaneTemplate`. diff --git a/make/go.mk b/make/go.mk index 0623f1c69..7b93d1d85 100644 --- a/make/go.mk +++ b/make/go.mk @@ -177,11 +177,6 @@ go-fix.%: ; $(info $(M) go fixing $* module) go-generate: ## Runs go generate go-generate: ; $(info $(M) running go generate) go generate -x ./... - controller-gen \ - rbac:headerFile="hack/license-header.yaml.txt",roleName=capi-runtime-extensions-manager-role \ - object:headerFile="hack/license-header.go.txt" \ - output:rbac:artifacts:config=charts/capi-runtime-extensions/templates \ - paths="./..." $(MAKE) go-fix .PHONY: go-mod-upgrade diff --git a/pkg/handlers/clusterconfig/variables.go b/pkg/handlers/clusterconfig/variables.go new file mode 100644 index 000000000..8ca7af592 --- /dev/null +++ b/pkg/handlers/clusterconfig/variables.go @@ -0,0 +1,51 @@ +// Copyright 2023 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/capi-runtime-extensions/api/v1alpha1" + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers" + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation" +) + +var ( + _ handlers.Named = &clusterConfigVariableHandler{} + _ mutation.DiscoverVariables = &clusterConfigVariableHandler{} +) + +const ( + // VariableName is http proxy external patch variable name. + VariableName = "clusterConfig" + + // HandlerNameVariable is the name of the variable handler. + HandlerNameVariable = "ClusterConfigVars" +) + +func NewVariable() *clusterConfigVariableHandler { + return &clusterConfigVariableHandler{} +} + +type clusterConfigVariableHandler struct{} + +func (h *clusterConfigVariableHandler) Name() string { + return HandlerNameVariable +} + +func (h *clusterConfigVariableHandler) DiscoverVariables( + ctx context.Context, + _ *runtimehooksv1.DiscoverVariablesRequest, + resp *runtimehooksv1.DiscoverVariablesResponse, +) { + resp.Variables = append(resp.Variables, clusterv1.ClusterClassVariable{ + Name: VariableName, + Required: false, + Schema: v1alpha1.ClusterConfigSpec{}.VariableSchema(), + }) + resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) +} diff --git a/pkg/handlers/clusterconfig/variables_test.go b/pkg/handlers/clusterconfig/variables_test.go new file mode 100644 index 000000000..a67cd30aa --- /dev/null +++ b/pkg/handlers/clusterconfig/variables_test.go @@ -0,0 +1,65 @@ +// Copyright 2023 D2iQ, Inc. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package clusterconfig + +import ( + "testing" + + "k8s.io/utils/ptr" + + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest" +) + +func TestVariableValidation(t *testing.T) { + capitest.ValidateDiscoverVariables( + t, + VariableName, + ptr.To(v1alpha1.ClusterConfigSpec{}.VariableSchema()), + NewVariable, + capitest.VariableTestDef{ + Name: "valid proxy config only", + Vals: v1alpha1.ClusterConfigSpec{ + Proxy: &v1alpha1.HTTPProxy{ + HTTP: "http://a.b.c.example.com", + HTTPS: "https://a.b.c.example.com", + AdditionalNo: []string{"d.e.f.example.com"}, + }, + }, + }, + capitest.VariableTestDef{ + Name: "single valid SAN", + Vals: v1alpha1.ClusterConfigSpec{ + ExtraAPIServerCertSANs: v1alpha1.ExtraAPIServerCertSANs{"a.b.c.example.com"}, + }, + }, + capitest.VariableTestDef{ + Name: "single invalid SAN", + Vals: v1alpha1.ClusterConfigSpec{ + ExtraAPIServerCertSANs: v1alpha1.ExtraAPIServerCertSANs{"invalid:san"}, + }, + ExpectError: true, + }, + capitest.VariableTestDef{ + Name: "duplicate valid SANs", + Vals: v1alpha1.ClusterConfigSpec{ + ExtraAPIServerCertSANs: v1alpha1.ExtraAPIServerCertSANs{ + "a.b.c.example.com", + "a.b.c.example.com", + }, + }, + ExpectError: true, + }, capitest.VariableTestDef{ + Name: "valid config", + Vals: v1alpha1.ClusterConfigSpec{ + Proxy: &v1alpha1.HTTPProxy{ + HTTP: "http://a.b.c.example.com", + HTTPS: "https://a.b.c.example.com", + AdditionalNo: []string{"d.e.f.example.com"}, + }, + ExtraAPIServerCertSANs: v1alpha1.ExtraAPIServerCertSANs{"a.b.c.example.com"}, + }, + }, + ) +} diff --git a/pkg/handlers/extraapiservercertsans/inject.go b/pkg/handlers/extraapiservercertsans/inject.go index 3817a0a74..7ae6d4520 100644 --- a/pkg/handlers/extraapiservercertsans/inject.go +++ b/pkg/handlers/extraapiservercertsans/inject.go @@ -17,6 +17,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/patches" @@ -30,7 +31,9 @@ const ( ) type extraAPIServerCertSANsPatchHandler struct { - decoder runtime.Decoder + decoder runtime.Decoder + variableName string + variableFieldPath []string } var ( @@ -38,7 +41,10 @@ var ( _ mutation.GeneratePatches = &extraAPIServerCertSANsPatchHandler{} ) -func NewPatch() *extraAPIServerCertSANsPatchHandler { +func NewPatch( + variableName string, + variableFieldPath ...string, +) *extraAPIServerCertSANsPatchHandler { scheme := runtime.NewScheme() _ = bootstrapv1.AddToScheme(scheme) _ = controlplanev1.AddToScheme(scheme) @@ -47,6 +53,8 @@ func NewPatch() *extraAPIServerCertSANsPatchHandler { controlplanev1.GroupVersion, bootstrapv1.GroupVersion, ), + variableName: variableName, + variableFieldPath: variableFieldPath, } } @@ -74,9 +82,10 @@ func (h *extraAPIServerCertSANsPatchHandler) GeneratePatches( "holderRef", holderRef, ) - extraAPIServerCertSANsVar, found, err := variables.Get[ExtraAPIServerCertSANsVariables]( + extraAPIServerCertSANsVar, found, err := variables.Get[v1alpha1.ExtraAPIServerCertSANs]( vars, - VariableName, + h.variableName, + h.variableFieldPath..., ) if err != nil { return err @@ -88,7 +97,9 @@ func (h *extraAPIServerCertSANsPatchHandler) GeneratePatches( log = log.WithValues( "variableName", - VariableName, + h.variableName, + "variableFieldPath", + h.variableFieldPath, "variableValue", extraAPIServerCertSANsVar, ) diff --git a/pkg/handlers/extraapiservercertsans/inject_test.go b/pkg/handlers/extraapiservercertsans/inject_test.go index 3f50578a8..a0a25e28b 100644 --- a/pkg/handlers/extraapiservercertsans/inject_test.go +++ b/pkg/handlers/extraapiservercertsans/inject_test.go @@ -9,13 +9,15 @@ import ( . "github.com/onsi/gomega" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" + "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest" ) func TestGeneratePatches(t *testing.T) { capitest.ValidateGeneratePatches( t, - NewPatch, + func() mutation.GeneratePatches { return NewPatch(VariableName) }, capitest.PatchTestDef{ Name: "unset variable", }, @@ -24,7 +26,7 @@ func TestGeneratePatches(t *testing.T) { Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( VariableName, - ExtraAPIServerCertSANsVariables{"a.b.c.example.com", "d.e.f.example.com"}, + v1alpha1.ExtraAPIServerCertSANs{"a.b.c.example.com", "d.e.f.example.com"}, ), }, RequestItem: capitest.NewKubeadmControlPlaneTemplateRequestItem(), diff --git a/pkg/handlers/extraapiservercertsans/variables.go b/pkg/handlers/extraapiservercertsans/variables.go index 41ca5aaed..01e1b0dd8 100644 --- a/pkg/handlers/extraapiservercertsans/variables.go +++ b/pkg/handlers/extraapiservercertsans/variables.go @@ -9,9 +9,9 @@ import ( clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation" - "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/openapi/patterns" ) var ( @@ -42,29 +42,10 @@ func (h *extraAPIServerCertSANsVariableHandler) DiscoverVariables( _ *runtimehooksv1.DiscoverVariablesRequest, resp *runtimehooksv1.DiscoverVariablesResponse, ) { - variable := ExtraAPIServerCertSANsVariables{} resp.Variables = append(resp.Variables, clusterv1.ClusterClassVariable{ Name: VariableName, Required: false, - Schema: variable.VariableSchema(), + Schema: v1alpha1.ExtraAPIServerCertSANs{}.VariableSchema(), }) resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) } - -// ExtraAPIServerCertSANsVariables required for providing API server cert SANs. -type ExtraAPIServerCertSANsVariables []string - -// VariableSchema provides Cluster Class variable schema definition. -func (ExtraAPIServerCertSANsVariables) VariableSchema() clusterv1.VariableSchema { - return clusterv1.VariableSchema{ - OpenAPIV3Schema: clusterv1.JSONSchemaProps{ - Description: "Extra Subject Alternative Names for the API Server signing cert", - Type: "array", - UniqueItems: true, - Items: &clusterv1.JSONSchemaProps{ - Type: "string", - Pattern: patterns.Anchored(patterns.DNS1123Subdomain), - }, - }, - } -} diff --git a/pkg/handlers/extraapiservercertsans/variables_test.go b/pkg/handlers/extraapiservercertsans/variables_test.go index ddc175e08..1b5a15b5d 100644 --- a/pkg/handlers/extraapiservercertsans/variables_test.go +++ b/pkg/handlers/extraapiservercertsans/variables_test.go @@ -8,6 +8,7 @@ import ( "k8s.io/utils/ptr" + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest" ) @@ -15,7 +16,7 @@ func TestVariableValidation(t *testing.T) { capitest.ValidateDiscoverVariables( t, VariableName, - ptr.To(ExtraAPIServerCertSANsVariables{}.VariableSchema()), + ptr.To(v1alpha1.ExtraAPIServerCertSANs{}.VariableSchema()), NewVariable, capitest.VariableTestDef{ Name: "single valid SAN", diff --git a/pkg/handlers/httpproxy/inject.go b/pkg/handlers/httpproxy/inject.go index 332d0f682..a5ed930dc 100644 --- a/pkg/handlers/httpproxy/inject.go +++ b/pkg/handlers/httpproxy/inject.go @@ -21,6 +21,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/patches" @@ -40,6 +41,9 @@ const ( type httpProxyPatchHandler struct { decoder runtime.Decoder client ctrlclient.Reader + + variableName string + variableFieldPath []string } var ( @@ -47,7 +51,11 @@ var ( _ mutation.GeneratePatches = &httpProxyPatchHandler{} ) -func NewPatch(cl ctrlclient.Reader) *httpProxyPatchHandler { +func NewPatch( + cl ctrlclient.Reader, + variableName string, + variableFieldPath ...string, +) *httpProxyPatchHandler { scheme := runtime.NewScheme() _ = bootstrapv1.AddToScheme(scheme) _ = controlplanev1.AddToScheme(scheme) @@ -56,7 +64,9 @@ func NewPatch(cl ctrlclient.Reader) *httpProxyPatchHandler { controlplanev1.GroupVersion, bootstrapv1.GroupVersion, ), - client: cl, + client: cl, + variableName: variableName, + variableFieldPath: variableFieldPath, } } @@ -90,9 +100,10 @@ func (h *httpProxyPatchHandler) GeneratePatches( "holderRef", holderRef, ) - httpProxyVariable, found, err := variables.Get[HTTPProxyVariables]( + httpProxyVariable, found, err := variables.Get[v1alpha1.HTTPProxy]( vars, - VariableName, + h.variableName, + h.variableFieldPath..., ) if err != nil { return err @@ -102,7 +113,14 @@ func (h *httpProxyPatchHandler) GeneratePatches( return nil } - log = log.WithValues("variableName", VariableName, "variableValue", httpProxyVariable) + log = log.WithValues( + "variableName", + h.variableName, + "variableFieldPath", + h.variableFieldPath, + "variableValue", + httpProxyVariable, + ) if err := patches.Generate( obj, vars, &holderRef, selectors.ControlPlane(), log, diff --git a/pkg/handlers/httpproxy/inject_test.go b/pkg/handlers/httpproxy/inject_test.go index 90c762184..7085e3de4 100644 --- a/pkg/handlers/httpproxy/inject_test.go +++ b/pkg/handlers/httpproxy/inject_test.go @@ -13,6 +13,7 @@ import ( runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" "sigs.k8s.io/controller-runtime/pkg/client/fake" + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest" ) @@ -21,7 +22,7 @@ func TestGeneratePatches(t *testing.T) { t, func() *httpProxyPatchHandler { fakeClient := fake.NewClientBuilder().Build() - return NewPatch(fakeClient) + return NewPatch(fakeClient, VariableName) }, capitest.PatchTestDef{ Name: "unset variable", @@ -31,7 +32,7 @@ func TestGeneratePatches(t *testing.T) { Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( VariableName, - HTTPProxyVariables{ + v1alpha1.HTTPProxy{ HTTP: "http://example.com", HTTPS: "https://example.com", AdditionalNo: []string{"no-proxy.example.com"}, @@ -58,7 +59,7 @@ func TestGeneratePatches(t *testing.T) { Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( VariableName, - HTTPProxyVariables{ + v1alpha1.HTTPProxy{ HTTP: "http://example.com", HTTPS: "https://example.com", AdditionalNo: []string{"no-proxy.example.com"}, @@ -85,7 +86,7 @@ func TestGeneratePatches(t *testing.T) { Vars: []runtimehooksv1.Variable{ capitest.VariableWithValue( VariableName, - HTTPProxyVariables{ + v1alpha1.HTTPProxy{ HTTP: "http://example.com", HTTPS: "https://example.com", AdditionalNo: []string{"no-proxy.example.com"}, diff --git a/pkg/handlers/httpproxy/systemd_proxy_config.go b/pkg/handlers/httpproxy/systemd_proxy_config.go index ddec0c414..a654a37f2 100644 --- a/pkg/handlers/httpproxy/systemd_proxy_config.go +++ b/pkg/handlers/httpproxy/systemd_proxy_config.go @@ -10,6 +10,8 @@ import ( "text/template" bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" + + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" ) var ( @@ -26,7 +28,7 @@ var ( } ) -func generateSystemdFiles(vars HTTPProxyVariables, noProxy []string) []bootstrapv1.File { +func generateSystemdFiles(vars v1alpha1.HTTPProxy, noProxy []string) []bootstrapv1.File { if vars.HTTP == "" && vars.HTTPS == "" && len(vars.AdditionalNo) == 0 { return nil } diff --git a/pkg/handlers/httpproxy/systemd_proxy_config_test.go b/pkg/handlers/httpproxy/systemd_proxy_config_test.go index f89347b02..b79fc985a 100644 --- a/pkg/handlers/httpproxy/systemd_proxy_config_test.go +++ b/pkg/handlers/httpproxy/systemd_proxy_config_test.go @@ -8,6 +8,8 @@ import ( . "github.com/onsi/gomega" bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" + + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" ) func TestGenerateSystemdFiles(t *testing.T) { @@ -15,7 +17,7 @@ func TestGenerateSystemdFiles(t *testing.T) { tests := []struct { name string - vars HTTPProxyVariables + vars v1alpha1.HTTPProxy noProxy []string expectedContents string }{ @@ -23,7 +25,7 @@ func TestGenerateSystemdFiles(t *testing.T) { name: "no proxy configuration", }, { name: "all vars set", - vars: HTTPProxyVariables{ + vars: v1alpha1.HTTPProxy{ HTTP: "http://example.com", HTTPS: "https://example.com", AdditionalNo: []string{ @@ -40,7 +42,7 @@ Environment="no_proxy=no-proxy.example.com" `, }, { name: "http only", - vars: HTTPProxyVariables{ + vars: v1alpha1.HTTPProxy{ HTTP: "http://example.com", }, expectedContents: `[Service] @@ -49,7 +51,7 @@ Environment="http_proxy=http://example.com" `, }, { name: "https only", - vars: HTTPProxyVariables{ + vars: v1alpha1.HTTPProxy{ HTTPS: "https://example.com", }, expectedContents: `[Service] @@ -58,7 +60,7 @@ Environment="https_proxy=https://example.com" `, }, { name: "no proxy only", - vars: HTTPProxyVariables{ + vars: v1alpha1.HTTPProxy{ AdditionalNo: []string{ "no-proxy.example.com", }, @@ -69,7 +71,7 @@ Environment="no_proxy=no-proxy.example.com" `, }, { name: "multiple no proxy only", - vars: HTTPProxyVariables{ + vars: v1alpha1.HTTPProxy{ AdditionalNo: []string{ "no-proxy.example.com", "no-proxy-1.example.com", @@ -81,7 +83,7 @@ Environment="no_proxy=no-proxy.example.com,no-proxy-1.example.com" `, }, { name: "default no proxy values", - vars: HTTPProxyVariables{ + vars: v1alpha1.HTTPProxy{ AdditionalNo: []string{ "no-proxy.example.com", "no-proxy-1.example.com", diff --git a/pkg/handlers/httpproxy/variables.go b/pkg/handlers/httpproxy/variables.go index fdf7c46d6..5acc349af 100644 --- a/pkg/handlers/httpproxy/variables.go +++ b/pkg/handlers/httpproxy/variables.go @@ -9,6 +9,7 @@ import ( clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation" ) @@ -41,55 +42,10 @@ func (h *httpProxyVariableHandler) DiscoverVariables( _ *runtimehooksv1.DiscoverVariablesRequest, resp *runtimehooksv1.DiscoverVariablesResponse, ) { - variable := HTTPProxyVariables{} resp.Variables = append(resp.Variables, clusterv1.ClusterClassVariable{ Name: VariableName, Required: false, - Schema: variable.VariableSchema(), + Schema: v1alpha1.HTTPProxy{}.VariableSchema(), }) resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) } - -// HTTPProxyVariables required for providing proxy configuration. -type HTTPProxyVariables struct { - // HTTP proxy. - HTTP string `json:"http,omitempty"` - - // HTTPS proxy. - HTTPS string `json:"https,omitempty"` - - // AdditionalNo Proxy list that will be added to the automatically calculated - // values that will apply no_proxy configuration for cluster internal network. - // Default values: localhost,127.0.0.1,,,kubernetes - // ,kubernetes.default,.svc,.svc. - AdditionalNo []string `json:"additionalNo"` -} - -// VariableSchema provides Cluster Class variable schema definition. -func (HTTPProxyVariables) VariableSchema() clusterv1.VariableSchema { - return clusterv1.VariableSchema{ - OpenAPIV3Schema: clusterv1.JSONSchemaProps{ - Type: "object", - Properties: map[string]clusterv1.JSONSchemaProps{ - "http": { - Description: "HTTP proxy value.", - Type: "string", - }, - "https": { - Description: "HTTPS proxy value.", - Type: "string", - }, - "additionalNo": { - Description: "Additional No Proxy list that will be added to the automatically calculated " + - "values that will apply no_proxy configuration for cluster internal network. " + - "Default value: localhost,127.0.0.1,,,kubernetes," + - "kubernetes.default,.svc,.svc.", - Type: "array", - Items: &clusterv1.JSONSchemaProps{ - Type: "string", - }, - }, - }, - }, - } -} diff --git a/pkg/handlers/httpproxy/variables_test.go b/pkg/handlers/httpproxy/variables_test.go index 8f794366e..1c7085e5b 100644 --- a/pkg/handlers/httpproxy/variables_test.go +++ b/pkg/handlers/httpproxy/variables_test.go @@ -8,6 +8,7 @@ import ( "k8s.io/utils/ptr" + "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest" ) @@ -15,11 +16,11 @@ func TestVariableValidation(t *testing.T) { capitest.ValidateDiscoverVariables( t, VariableName, - ptr.To(HTTPProxyVariables{}.VariableSchema()), + ptr.To(v1alpha1.HTTPProxy{}.VariableSchema()), NewVariable, capitest.VariableTestDef{ Name: "valid values", - Vals: HTTPProxyVariables{ + Vals: v1alpha1.HTTPProxy{ HTTP: "http://a.b.c.example.com", HTTPS: "https://a.b.c.example.com", AdditionalNo: []string{"d.e.f.example.com"}, diff --git a/pkg/handlers/metadata.go b/pkg/handlers/metadata.go index 4f1d77ad8..14db4fc4c 100644 --- a/pkg/handlers/metadata.go +++ b/pkg/handlers/metadata.go @@ -3,8 +3,8 @@ package handlers -const ( - MetadataDomain = "capiext.labs.d2iq.io" +import "github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1" - CAPIProviderLabel = MetadataDomain + "/capi-provider" +const ( + MetadataDomain = v1alpha1.APIGroup )