From da9c7207e097476a22c71933098d3143c8ba017d Mon Sep 17 00:00:00 2001 From: Maliz Date: Wed, 12 Apr 2023 15:51:18 -0700 Subject: [PATCH 01/10] draft of adding sameness group CRD --- CONTRIBUTING.md | 4 +- control-plane/PROJECT | 13 + control-plane/api/common/common.go | 1 + .../api/v1alpha1/samenessgroups_types.go | 224 ++++++++++++++ .../api/v1alpha1/samenessgroups_types_test.go | 288 ++++++++++++++++++ .../api/v1alpha1/samenessgroups_webhook.go | 61 ++++ .../v1alpha1/servicedefaults_types_test.go | 2 +- .../api/v1alpha1/zz_generated.deepcopy.go | 124 ++++++++ ...consul.hashicorp.com_exportedservices.yaml | 3 - .../consul.hashicorp.com_ingressgateways.yaml | 3 - .../bases/consul.hashicorp.com_meshes.yaml | 3 - ...consul.hashicorp.com_peeringacceptors.yaml | 3 - .../consul.hashicorp.com_peeringdialers.yaml | 3 - .../consul.hashicorp.com_proxydefaults.yaml | 23 +- .../consul.hashicorp.com_samenessgroups.yaml | 118 +++++++ .../consul.hashicorp.com_servicedefaults.yaml | 3 - ...onsul.hashicorp.com_serviceintentions.yaml | 3 - ...consul.hashicorp.com_serviceresolvers.yaml | 20 +- .../consul.hashicorp.com_servicerouters.yaml | 3 - ...consul.hashicorp.com_servicesplitters.yaml | 3 - ...sul.hashicorp.com_terminatinggateways.yaml | 3 - control-plane/config/crd/kustomization.yaml | 21 ++ control-plane/config/crd/kustomizeconfig.yaml | 17 ++ .../cainjection_in_samenessgroups.yaml | 8 + .../patches/webhook_in_samenessgroups.yaml | 17 ++ control-plane/config/rbac/role.yaml | 23 +- .../rbac/samenessgroups_editor_role.yaml | 24 ++ .../rbac/samenessgroups_viewer_role.yaml | 20 ++ .../consul_v1alpha1_samenessgroups.yaml | 10 + control-plane/config/webhook/manifests.yaml | 24 +- .../configentry_controller.go | 2 +- .../configentry_controller_ent_test.go | 64 ++-- .../configentry_controller_test.go | 117 ++++++- .../exportedservices_controller.go | 2 +- .../exportedservices_controller_ent_test.go | 20 +- .../ingressgateway_controller.go | 2 +- .../mesh_controller.go | 2 +- .../proxydefaults_controller.go | 2 +- .../controllers/samenessgroups_controller.go | 41 +++ .../servicedefaults_controller.go | 2 +- .../serviceintentions_controller.go | 2 +- .../serviceresolver_controller.go | 2 +- .../servicerouter_controller.go | 2 +- .../servicesplitter_controller.go | 2 +- .../terminatinggateway_controller.go | 2 +- control-plane/go.mod | 4 + control-plane/main.go | 3 +- .../subcommand/inject-connect/command.go | 39 ++- 48 files changed, 1242 insertions(+), 140 deletions(-) create mode 100644 control-plane/api/v1alpha1/samenessgroups_types.go create mode 100644 control-plane/api/v1alpha1/samenessgroups_types_test.go create mode 100644 control-plane/api/v1alpha1/samenessgroups_webhook.go create mode 100644 control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml create mode 100644 control-plane/config/crd/kustomization.yaml create mode 100644 control-plane/config/crd/kustomizeconfig.yaml create mode 100644 control-plane/config/crd/patches/cainjection_in_samenessgroups.yaml create mode 100644 control-plane/config/crd/patches/webhook_in_samenessgroups.yaml create mode 100644 control-plane/config/rbac/samenessgroups_editor_role.yaml create mode 100644 control-plane/config/rbac/samenessgroups_viewer_role.yaml create mode 100644 control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml rename control-plane/{controller => controllers}/configentry_controller.go (99%) rename control-plane/{controller => controllers}/configentry_controller_ent_test.go (91%) rename control-plane/{controller => controllers}/configentry_controller_test.go (94%) rename control-plane/{controller => controllers}/exportedservices_controller.go (98%) rename control-plane/{controller => controllers}/exportedservices_controller_ent_test.go (95%) rename control-plane/{controller => controllers}/ingressgateway_controller.go (98%) rename control-plane/{controller => controllers}/mesh_controller.go (98%) rename control-plane/{controller => controllers}/proxydefaults_controller.go (98%) create mode 100644 control-plane/controllers/samenessgroups_controller.go rename control-plane/{controller => controllers}/servicedefaults_controller.go (98%) rename control-plane/{controller => controllers}/serviceintentions_controller.go (98%) rename control-plane/{controller => controllers}/serviceresolver_controller.go (98%) rename control-plane/{controller => controllers}/servicerouter_controller.go (98%) rename control-plane/{controller => controllers}/servicesplitter_controller.go (98%) rename control-plane/{controller => controllers}/terminatinggateway_controller.go (98%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8e634e323e..0a5790e022 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -167,7 +167,7 @@ rebase the branch on main, fixing any conflicts along the way before the code ca ```bash operator-sdk create api --group consul --version v1alpha1 --kind IngressGateway --controller --namespaced=true --make=false --resource=true ``` -1. Re-order the file so it looks like: +1. Re-order the generated ingressgateway_types.go file, so it looks like: ```go func init() { SchemeBuilder.Register(&IngressGateway{}, &IngressGatewayList{}) @@ -320,8 +320,6 @@ rebase the branch on main, fixing any conflicts along the way before the code ca ### Controller 1. Delete the file `control-plane/controllers/suite_test.go`. We don't write suite tests, just unit tests. -1. Move `control-plane/controllers/ingressgateway_controller.go` to `control-plane/controller` directory. -1. Delete the `control-plane/controllers` directory. 1. Rename `Reconciler` to `Controller`, e.g. `IngressGatewayReconciler` => `IngressGatewayController` 1. Use the existing controller files as a guide and make this file match. 1. Add your controller as a case in the tests in `configentry_controller_test.go`: diff --git a/control-plane/PROJECT b/control-plane/PROJECT index c11e857849..cfe6b1e621 100644 --- a/control-plane/PROJECT +++ b/control-plane/PROJECT @@ -1,3 +1,7 @@ +# Code generated by tool. DO NOT EDIT. +# This file is used to track the info used to scaffold your project +# and allow the plugins properly work. +# More info: https://book.kubebuilder.io/reference/project-config.html domain: hashicorp.com layout: - go.kubebuilder.io/v2 @@ -77,4 +81,13 @@ resources: kind: PeeringDialer path: github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1beta1 + namespaced: true + controller: true + domain: hashicorp.com + group: consul + kind: SamenessGroups + path: github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/control-plane/api/common/common.go b/control-plane/api/common/common.go index 2c579ba715..1c9283dc3e 100644 --- a/control-plane/api/common/common.go +++ b/control-plane/api/common/common.go @@ -14,6 +14,7 @@ const ( ExportedServices string = "exportedservices" IngressGateway string = "ingressgateway" TerminatingGateway string = "terminatinggateway" + SamenessGroups string = "samenessgroups" Global string = "global" Mesh string = "mesh" diff --git a/control-plane/api/v1alpha1/samenessgroups_types.go b/control-plane/api/v1alpha1/samenessgroups_types.go new file mode 100644 index 0000000000..d34d0b8459 --- /dev/null +++ b/control-plane/api/v1alpha1/samenessgroups_types.go @@ -0,0 +1,224 @@ +package v1alpha1 + +import ( + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/hashicorp/consul-k8s/control-plane/api/common" + "github.com/hashicorp/consul/api" + capi "github.com/hashicorp/consul/api" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +const ( + SamenessGroupsKubeKind string = "samenessgroups" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +func init() { + SchemeBuilder.Register(&SamenessGroups{}, &SamenessGroupsList{}) +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// SamenessGroups is the Schema for the samenessgroups API +// +kubebuilder:printcolumn:name="Synced",type="string",JSONPath=".status.conditions[?(@.type==\"Synced\")].status",description="The sync status of the resource with Consul" +// +kubebuilder:printcolumn:name="Last Synced",type="date",JSONPath=".status.lastSyncedTime",description="The last successful synced time of the resource with Consul" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the resource" +// +kubebuilder:resource:shortName="sameness-groups" +type SamenessGroups struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + Spec SamenessGroupsSpec `json:"spec,omitempty"` + Status `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// SamenessGroupsList contains a list of SamenessGroups +type SamenessGroupsList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []SamenessGroups `json:"items"` +} + +// SamenessGroupsSpec defines the desired state of SamenessGroups +type SamenessGroupsSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + // DefaultForFailover is + DefaultForFailover bool `json:"defaultForFailover,omitempty"` + // IncludeLocal + IncludeLocal bool `json:"includeLocal,omitempty"` + // Members + Members []SamenessGroupMember `json:"members,omitempty"` +} + +type SamenessGroupMember struct { + Partition string `json:"partition,omitempty"` + Peer string `json:"peer,omitempty"` +} + +func (in *SamenessGroups) GetObjectMeta() metav1.ObjectMeta { + return in.ObjectMeta +} + +func (in *SamenessGroups) AddFinalizer(name string) { + in.ObjectMeta.Finalizers = append(in.Finalizers(), name) +} + +func (in *SamenessGroups) RemoveFinalizer(name string) { + var newFinalizers []string + for _, oldF := range in.Finalizers() { + if oldF != name { + newFinalizers = append(newFinalizers, oldF) + } + } + in.ObjectMeta.Finalizers = newFinalizers +} + +func (in *SamenessGroups) Finalizers() []string { + return in.ObjectMeta.Finalizers +} + +func (in *SamenessGroups) ConsulKind() string { + return capi.SamenessGroup +} + +func (in *SamenessGroups) ConsulGlobalResource() bool { + return false +} + +func (in *SamenessGroups) ConsulMirroringNS() string { + return common.DefaultConsulNamespace +} + +func (in *SamenessGroups) KubeKind() string { + return SamenessGroupsKubeKind +} + +func (in *SamenessGroups) ConsulName() string { + return in.ObjectMeta.Name +} + +func (in *SamenessGroups) KubernetesName() string { + return in.ObjectMeta.Name +} + +func (in *SamenessGroups) SetSyncedCondition(status corev1.ConditionStatus, reason, message string) { + in.Status.Conditions = Conditions{ + { + Type: ConditionSynced, + Status: status, + LastTransitionTime: metav1.Now(), + Reason: reason, + Message: message, + }, + } +} + +func (in *SamenessGroups) SetLastSyncedTime(time *metav1.Time) { + in.Status.LastSyncedTime = time +} + +func (in *SamenessGroups) SyncedCondition() (status corev1.ConditionStatus, reason, message string) { + cond := in.Status.GetCondition(ConditionSynced) + if cond == nil { + return corev1.ConditionUnknown, "", "" + } + return cond.Status, cond.Reason, cond.Message +} + +func (in *SamenessGroups) SyncedConditionStatus() corev1.ConditionStatus { + cond := in.Status.GetCondition(ConditionSynced) + if cond == nil { + return corev1.ConditionUnknown + } + return cond.Status +} + +func (in *SamenessGroups) ToConsul(datacenter string) api.ConfigEntry { + //consulConfig := in.convertConfig() + return &capi.SamenessGroupConfigEntry{ + Kind: in.ConsulKind(), + Name: in.ConsulName(), + DefaultForFailover: in.Spec.DefaultForFailover, + IncludeLocal: in.Spec.IncludeLocal, + Members: SamenessGroupMembers(in.Spec.Members).toConsul(), + Meta: meta(datacenter), + } +} + +func (in *SamenessGroups) MatchesConsul(candidate api.ConfigEntry) bool { + configEntry, ok := candidate.(*capi.SamenessGroupConfigEntry) + if !ok { + return false + } + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.SamenessGroupConfigEntry{}, "Partition", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty(), + cmp.Comparer(transparentProxyConfigComparer)) +} + +func (in *SamenessGroups) Validate(consulMeta common.ConsulMeta) error { + var allErrs field.ErrorList + path := field.NewPath("spec") + + allErrs = append(allErrs, SamenessGroupMembers(in.Spec.Members).validate(path.Child("envoyExtensions"))...) + + if len(allErrs) > 0 { + return apierrors.NewInvalid( + schema.GroupKind{Group: ConsulHashicorpGroup, Kind: SamenessGroupsKubeKind}, + in.KubernetesName(), allErrs) + } + + return nil +} + +// DefaultNamespaceFields has no behaviour here as sameness-groups have no namespace specific fields. +func (in *SamenessGroups) DefaultNamespaceFields(_ common.ConsulMeta) { +} + +type SamenessGroupMembers []SamenessGroupMember + +func (in SamenessGroupMembers) toConsul() []capi.SamenessGroupMember { + if in == nil { + return nil + } + + outMembers := make([]capi.SamenessGroupMember, 0, len(in)) + for _, e := range in { + consulMember := capi.SamenessGroupMember{ + Peer: e.Peer, + Partition: e.Partition, + } + outMembers = append(outMembers, consulMember) + } + return outMembers +} + +func (in SamenessGroupMembers) validate(path *field.Path) field.ErrorList { + if len(in) == 0 { + return nil + } + + var errs field.ErrorList + for i, e := range in { + if err := e.validate(path.Child("envoyExtension").Index(i)); err != nil { + errs = append(errs, err) + } + } + + return errs +} + +func (in SamenessGroupMember) validate(path *field.Path) *field.Error { + + //TODO + return nil +} diff --git a/control-plane/api/v1alpha1/samenessgroups_types_test.go b/control-plane/api/v1alpha1/samenessgroups_types_test.go new file mode 100644 index 0000000000..d2a0df1d15 --- /dev/null +++ b/control-plane/api/v1alpha1/samenessgroups_types_test.go @@ -0,0 +1,288 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package v1alpha1 + +import ( + "github.com/hashicorp/consul-k8s/control-plane/api/common" + capi "github.com/hashicorp/consul/api" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "testing" + "time" +) + +func TestSamenessGroups_ToConsul(t *testing.T) { + cases := map[string]struct { + input *SamenessGroups + expected *capi.SamenessGroupConfigEntry + }{ + "empty fields": { + &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: SamenessGroupsSpec{}, + }, + &capi.SamenessGroupConfigEntry{ + Name: "foo", + Kind: capi.SamenessGroup, + Meta: map[string]string{ + common.SourceKey: common.SourceValue, + common.DatacenterKey: "datacenter", + }, + }, + }, + "every field set": { + &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []SamenessGroupMember{ + { + Peer: "dc1", + Partition: "default", + }, + }, + }, + }, + &capi.SamenessGroupConfigEntry{ + Name: "foo", + Kind: capi.SamenessGroup, + Meta: map[string]string{ + common.SourceKey: common.SourceValue, + common.DatacenterKey: "datacenter", + }, + DefaultForFailover: true, + IncludeLocal: true, + Members: []capi.SamenessGroupMember{ + { + Peer: "dc1", + Partition: "default", + }, + }, + }, + }, + } + for name, testCase := range cases { + t.Run(name, func(t *testing.T) { + output := testCase.input.ToConsul("datacenter") + require.Equal(t, testCase.expected, output) + }) + } +} + +func TestSamenessGroups_MatchesConsul(t *testing.T) { + cases := map[string]struct { + internal *SamenessGroups + consul capi.ConfigEntry + matches bool + }{ + "empty fields matches": { + &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-test-sameness-group", + }, + Spec: SamenessGroupsSpec{}, + }, + &capi.SamenessGroupConfigEntry{ + Kind: capi.SamenessGroup, + Name: "my-test-sameness-group", + CreateIndex: 1, + ModifyIndex: 2, + Meta: map[string]string{ + common.SourceKey: common.SourceValue, + common.DatacenterKey: "datacenter", + }, + }, + true, + }, + "all fields populated matches": { + &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-test-sameness-group", + }, + Spec: SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []SamenessGroupMember{ + { + Peer: "dc1", + Partition: "default", + }, + }, + }, + }, + &capi.SamenessGroupConfigEntry{ + Kind: capi.SamenessGroup, + Name: "my-test-sameness-group", + CreateIndex: 1, + ModifyIndex: 2, + Meta: map[string]string{ + common.SourceKey: common.SourceValue, + common.DatacenterKey: "datacenter", + }, + DefaultForFailover: true, + IncludeLocal: true, + Members: []capi.SamenessGroupMember{ + { + Peer: "dc1", + Partition: "default", + }, + }, + }, + true, + }, + } + + for name, testCase := range cases { + t.Run(name, func(t *testing.T) { + require.Equal(t, testCase.matches, testCase.internal.MatchesConsul(testCase.consul)) + }) + } +} + +func TestSamenessGroups_Validate(t *testing.T) { + cases := map[string]struct { + input *SamenessGroups + partitionsEnabled bool + expectedErrMsg string + }{ + "valid": { + input: &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-sameness-group", + }, + Spec: SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []SamenessGroupMember{ + { + Peer: "dc1", + Partition: "default", + }, + }, + }, + }, + partitionsEnabled: true, + expectedErrMsg: "", + }, + } + + for name, testCase := range cases { + t.Run(name, func(t *testing.T) { + err := testCase.input.Validate(common.ConsulMeta{}) + if testCase.expectedErrMsg != "" { + require.EqualError(t, err, testCase.expectedErrMsg) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestSamenessGroups_GetObjectMeta(t *testing.T) { + meta := metav1.ObjectMeta{ + Name: "name", + } + samenessGroups := &SamenessGroups{ + ObjectMeta: meta, + } + require.Equal(t, meta, samenessGroups.GetObjectMeta()) +} + +func TestSamenessGroups_AddFinalizer(t *testing.T) { + samenessGroups := &SamenessGroups{} + samenessGroups.AddFinalizer("finalizer") + require.Equal(t, []string{"finalizer"}, samenessGroups.ObjectMeta.Finalizers) +} + +func TestSamenessGroups_RemoveFinalizer(t *testing.T) { + samenessGroups := &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Finalizers: []string{"f1", "f2"}, + }, + } + samenessGroups.RemoveFinalizer("f1") + require.Equal(t, []string{"f2"}, samenessGroups.ObjectMeta.Finalizers) +} + +func TestSamenessGroups_ConsulKind(t *testing.T) { + require.Equal(t, capi.SamenessGroup, (&SamenessGroups{}).ConsulKind()) +} + +func TestSamenessGroups_ConsulGlobalResource(t *testing.T) { + require.False(t, (&SamenessGroups{}).ConsulGlobalResource()) +} + +func TestSamenessGroups_ConsulMirroringNS(t *testing.T) { + +} + +func TestSamenessGroups_KubeKind(t *testing.T) { + require.Equal(t, "samenessgroups", (&SamenessGroups{}).KubeKind()) +} + +func TestSamenessGroups_ConsulName(t *testing.T) { + require.Equal(t, "foo", (&SamenessGroups{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) +} + +func TestSamenessGroups_KubernetesName(t *testing.T) { + require.Equal(t, "foo", (&SamenessGroups{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) +} + +func TestSamenessGroups_SetSyncedCondition(t *testing.T) { + samenessGroups := &SamenessGroups{} + samenessGroups.SetSyncedCondition(corev1.ConditionTrue, "reason", "message") + + require.Equal(t, corev1.ConditionTrue, samenessGroups.Status.Conditions[0].Status) + require.Equal(t, "reason", samenessGroups.Status.Conditions[0].Reason) + require.Equal(t, "message", samenessGroups.Status.Conditions[0].Message) + now := metav1.Now() + require.True(t, samenessGroups.Status.Conditions[0].LastTransitionTime.Before(&now)) +} + +func TestSamenessGroups_SetLastSyncedTime(t *testing.T) { + samenessGroups := &SamenessGroups{} + syncedTime := metav1.NewTime(time.Now()) + samenessGroups.SetLastSyncedTime(&syncedTime) + + require.Equal(t, &syncedTime, samenessGroups.Status.LastSyncedTime) +} + +func TestSamenessGroups_GetSyncedConditionStatus(t *testing.T) { + cases := []corev1.ConditionStatus{ + corev1.ConditionUnknown, + corev1.ConditionFalse, + corev1.ConditionTrue, + } + for _, status := range cases { + t.Run(string(status), func(t *testing.T) { + samenessGroups := &SamenessGroups{ + Status: Status{ + Conditions: []Condition{{ + Type: ConditionSynced, + Status: status, + }}, + }, + } + + require.Equal(t, status, samenessGroups.SyncedConditionStatus()) + }) + } +} + +func TestSamenessGroups_SyncedConditionStatusWhenStatusNil(t *testing.T) { + require.Equal(t, corev1.ConditionUnknown, (&SamenessGroups{}).SyncedConditionStatus()) +} + +func TestSamenessGroups_SyncedConditionWhenStatusNil(t *testing.T) { + status, reason, message := (&SamenessGroups{}).SyncedCondition() + require.Equal(t, corev1.ConditionUnknown, status) + require.Equal(t, "", reason) + require.Equal(t, "", message) +} diff --git a/control-plane/api/v1alpha1/samenessgroups_webhook.go b/control-plane/api/v1alpha1/samenessgroups_webhook.go new file mode 100644 index 0000000000..c7bbe9adf1 --- /dev/null +++ b/control-plane/api/v1alpha1/samenessgroups_webhook.go @@ -0,0 +1,61 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package v1alpha1 + +import ( + "context" + "net/http" + + "github.com/go-logr/logr" + "github.com/hashicorp/consul-k8s/control-plane/api/common" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +// +kubebuilder:object:generate=false + +type SamenessGroupsWebhook struct { + Logger logr.Logger + + // ConsulMeta contains metadata specific to the Consul installation. + ConsulMeta common.ConsulMeta + + decoder *admission.Decoder + client.Client +} + +// NOTE: The path value in the below line is the path to the webhook. +// If it is updated, run code-gen, update subcommand/controller/command.go +// and the consul-helm value for the path to the webhook. +// +// NOTE: The below line cannot be combined with any other comment. If it is it will break the code generation. +// +// +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-samenessgroups,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=samenessgroups,versions=v1alpha1,name=mutate-samenessgroups.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 + +func (v *SamenessGroupsWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { + var resource SamenessGroups + err := v.decoder.Decode(req, &resource) + if err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + return common.ValidateConfigEntry(ctx, req, v.Logger, v, &resource, v.ConsulMeta) +} + +func (v *SamenessGroupsWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { + var resourceList SamenessGroupsList + if err := v.Client.List(ctx, &resourceList); err != nil { + return nil, err + } + var entries []common.ConfigEntryResource + for _, item := range resourceList.Items { + entries = append(entries, common.ConfigEntryResource(&item)) + } + return entries, nil +} + +func (v *SamenessGroupsWebhook) InjectDecoder(d *admission.Decoder) error { + v.decoder = d + return nil +} diff --git a/control-plane/api/v1alpha1/servicedefaults_types_test.go b/control-plane/api/v1alpha1/servicedefaults_types_test.go index 9f9e7ebbda..69b749decd 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types_test.go +++ b/control-plane/api/v1alpha1/servicedefaults_types_test.go @@ -1296,7 +1296,7 @@ func TestServiceDefaults_ConsulName(t *testing.T) { } func TestServiceDefaults_KubernetesName(t *testing.T) { - require.Equal(t, "foo", (&ServiceDefaults{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) + require.Equal(t, "foo", (&ServiceDefaults{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) } func TestServiceDefaults_ConsulNamespace(t *testing.T) { diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index d12db29d14..fdc82be6b3 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -255,6 +255,26 @@ func (in *ExposePath) DeepCopy() *ExposePath { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FailoverPolicy) DeepCopyInto(out *FailoverPolicy) { + *out = *in + if in.Regions != nil { + in, out := &in.Regions, &out.Regions + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FailoverPolicy. +func (in *FailoverPolicy) DeepCopy() *FailoverPolicy { + if in == nil { + return nil + } + out := new(FailoverPolicy) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GatewayServiceTLSConfig) DeepCopyInto(out *GatewayServiceTLSConfig) { *out = *in @@ -1272,6 +1292,11 @@ func (in *ProxyDefaultsSpec) DeepCopyInto(out *ProxyDefaultsSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.FailoverPolicy != nil { + in, out := &in.FailoverPolicy, &out.FailoverPolicy + *out = new(FailoverPolicy) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyDefaultsSpec. @@ -1299,6 +1324,100 @@ func (in *RingHashConfig) DeepCopy() *RingHashConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamenessGroupMember) DeepCopyInto(out *SamenessGroupMember) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupMember. +func (in *SamenessGroupMember) DeepCopy() *SamenessGroupMember { + if in == nil { + return nil + } + out := new(SamenessGroupMember) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SamenessGroups) DeepCopyInto(out *SamenessGroups) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroups. +func (in *SamenessGroups) DeepCopy() *SamenessGroups { + if in == nil { + return nil + } + out := new(SamenessGroups) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SamenessGroups) 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 *SamenessGroupsList) DeepCopyInto(out *SamenessGroupsList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]SamenessGroups, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupsList. +func (in *SamenessGroupsList) DeepCopy() *SamenessGroupsList { + if in == nil { + return nil + } + out := new(SamenessGroupsList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *SamenessGroupsList) 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 *SamenessGroupsSpec) DeepCopyInto(out *SamenessGroupsSpec) { + *out = *in + if in.Members != nil { + in, out := &in.Members, &out.Members + *out = make([]SamenessGroupMember, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupsSpec. +func (in *SamenessGroupsSpec) DeepCopy() *SamenessGroupsSpec { + if in == nil { + return nil + } + out := new(SamenessGroupsSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Secret) DeepCopyInto(out *Secret) { *out = *in @@ -1594,6 +1713,11 @@ func (in *ServiceResolverFailover) DeepCopyInto(out *ServiceResolverFailover) { *out = make([]ServiceResolverFailoverTarget, len(*in)) copy(*out, *in) } + if in.Policy != nil { + in, out := &in.Policy, &out.Policy + *out = new(FailoverPolicy) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceResolverFailover. diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml index 6352ac3af1..da1a66fd74 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml index fd8ebc86ff..16ac322090 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml index 4850ad152e..7ad173afbf 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml index 50df179f04..e782ef472f 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml index 01e4363f14..d5103252a5 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml index 0f90e95e16..0e99844e74 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -139,20 +136,12 @@ spec: type: object type: array type: object - failoverPolicy: - description: FailoverPolicy specifies the exact mechanism used for failover. - properties: - mode: - description: Mode specifies the type of failover that will be performed. - Valid values are "sequential", "" (equivalent to "sequential") and "order-by-locality". - type: string - regions: - description: The ordered list of the regions of the failover targets. - Valid values can be "us-west-1", "us-west-2", and so on. - items: - type: string - type: array - type: object + failoverPolicy: + description: FailoverPolicy specifies the exact mechanism used for + failover. + items: + type: string + type: string meshGateway: description: MeshGateway controls the default mesh gateway configuration for this service. diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml new file mode 100644 index 0000000000..43e23b7bd6 --- /dev/null +++ b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml @@ -0,0 +1,118 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: samenessgroups.consul.hashicorp.com +spec: + group: consul.hashicorp.com + names: + kind: SamenessGroups + listKind: SamenessGroupsList + plural: samenessgroups + shortNames: + - sameness-groups + singular: samenessgroups + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The sync status of the resource with Consul + jsonPath: .status.conditions[?(@.type=="Synced")].status + name: Synced + type: string + - description: The last successful synced time of the resource with Consul + jsonPath: .status.lastSyncedTime + name: Last Synced + type: date + - description: The age of the resource + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: SamenessGroups is the Schema for the samenessgroups API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: SamenessGroupsSpec defines the desired state of SamenessGroups + properties: + defaultForFailover: + description: DefaultForFailover is + type: boolean + includeLocal: + description: IncludeLocal + type: boolean + members: + description: Members + items: + properties: + partition: + type: string + peer: + type: string + type: object + type: array + type: object + status: + properties: + conditions: + description: Conditions indicate the latest available observations + of a resource's current state. + items: + description: 'Conditions define a readiness condition for a Consul + resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties' + properties: + lastTransitionTime: + description: LastTransitionTime is the last time the condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of condition. + type: string + required: + - status + - type + type: object + type: array + lastSyncedTime: + description: LastSyncedTime is the last time the resource successfully + synced with Consul. + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml index 7744a8fe7a..4f335a923d 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml index 8e186af1a7..a0cc7a6343 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml index a36784cc77..f177172e31 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -76,19 +73,10 @@ spec: the current namespace is used. type: string policy: - description: FailoverPolicy specifies the exact mechanism used for failover. - properties: - mode: - description: Mode specifies the type of failover that will be performed. - Valid values are "sequential", "" (equivalent to "sequential") and "order-by-locality". - type: string - regions: - description: The ordered list of the regions of the failover targets. - Valid values can be "us-west-1", "us-west-2", and so on. - items: - type: string - type: array - type: object + description: Policy specifies the exact mechanism used for failover. + items: + type: string + type: string service: description: Service is the service to resolve instead of the default as the failover group of instances during failover. diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml index 5b9c9d3c1f..de071bd0ef 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml index aa2b592c94..df8bbbfbdf 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml index b465cd9494..8e6c449ef8 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/kustomization.yaml b/control-plane/config/crd/kustomization.yaml new file mode 100644 index 0000000000..b20f5e9f96 --- /dev/null +++ b/control-plane/config/crd/kustomization.yaml @@ -0,0 +1,21 @@ +# This kustomization.yaml is not intended to be run by itself, +# since it depends on service name and namespace that are out of this kustomize package. +# It should be run by config/default +resources: +- bases/consul.hashicorp.com_samenessgroups.yaml +#+kubebuilder:scaffold:crdkustomizeresource + +patchesStrategicMerge: +# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. +# patches here are for enabling the conversion webhook for each CRD +- patches/webhook_in_samenessgroups.yaml +#+kubebuilder:scaffold:crdkustomizewebhookpatch + +# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. +# patches here are for enabling the CA injection for each CRD +#- patches/cainjection_in_samenessgroups.yaml +#+kubebuilder:scaffold:crdkustomizecainjectionpatch + +# the following config is for teaching kustomize how to do kustomization for CRDs. +configurations: +- kustomizeconfig.yaml diff --git a/control-plane/config/crd/kustomizeconfig.yaml b/control-plane/config/crd/kustomizeconfig.yaml new file mode 100644 index 0000000000..6f83d9a94b --- /dev/null +++ b/control-plane/config/crd/kustomizeconfig.yaml @@ -0,0 +1,17 @@ +# This file is for teaching kustomize how to substitute name and namespace reference in CRD +nameReference: +- kind: Service + version: v1 + fieldSpecs: + - kind: CustomResourceDefinition + group: apiextensions.k8s.io + path: spec/conversion/webhookClientConfig/service/name + +namespace: +- kind: CustomResourceDefinition + group: apiextensions.k8s.io + path: spec/conversion/webhookClientConfig/service/namespace + create: false + +varReference: +- path: metadata/annotations diff --git a/control-plane/config/crd/patches/cainjection_in_samenessgroups.yaml b/control-plane/config/crd/patches/cainjection_in_samenessgroups.yaml new file mode 100644 index 0000000000..65471762e1 --- /dev/null +++ b/control-plane/config/crd/patches/cainjection_in_samenessgroups.yaml @@ -0,0 +1,8 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: samenessgroups.consul.hashicorp.com diff --git a/control-plane/config/crd/patches/webhook_in_samenessgroups.yaml b/control-plane/config/crd/patches/webhook_in_samenessgroups.yaml new file mode 100644 index 0000000000..6e385469d3 --- /dev/null +++ b/control-plane/config/crd/patches/webhook_in_samenessgroups.yaml @@ -0,0 +1,17 @@ +# The following patch enables conversion webhook for CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: samenessgroups.consul.hashicorp.com +spec: + conversion: + strategy: Webhook + webhookClientConfig: + # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, + # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) + caBundle: Cg== + service: + namespace: system + name: webhook-service + path: /convert diff --git a/control-plane/config/rbac/role.yaml b/control-plane/config/rbac/role.yaml index 245f09568f..562eb5f9f9 100644 --- a/control-plane/config/rbac/role.yaml +++ b/control-plane/config/rbac/role.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -146,6 +143,26 @@ rules: - get - patch - update +- apiGroups: + - consul.hashicorp.com + resources: + - samenessgroups + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - consul.hashicorp.com + resources: + - samenessgroups/status + verbs: + - get + - patch + - update - apiGroups: - consul.hashicorp.com resources: diff --git a/control-plane/config/rbac/samenessgroups_editor_role.yaml b/control-plane/config/rbac/samenessgroups_editor_role.yaml new file mode 100644 index 0000000000..7d7055ffae --- /dev/null +++ b/control-plane/config/rbac/samenessgroups_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit samenessgroups. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: samenessgroups-editor-role +rules: +- apiGroups: + - consul.hashicorp.com + resources: + - samenessgroups + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - consul.hashicorp.com + resources: + - samenessgroups/status + verbs: + - get diff --git a/control-plane/config/rbac/samenessgroups_viewer_role.yaml b/control-plane/config/rbac/samenessgroups_viewer_role.yaml new file mode 100644 index 0000000000..874253f83b --- /dev/null +++ b/control-plane/config/rbac/samenessgroups_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view samenessgroups. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: samenessgroups-viewer-role +rules: +- apiGroups: + - consul.hashicorp.com + resources: + - samenessgroups + verbs: + - get + - list + - watch +- apiGroups: + - consul.hashicorp.com + resources: + - samenessgroups/status + verbs: + - get diff --git a/control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml b/control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml new file mode 100644 index 0000000000..f072beba51 --- /dev/null +++ b/control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml @@ -0,0 +1,10 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: SamenessGroups +metadata: + name: samenessgroups-sample +spec: + defaultForFailover: true + includeLocal: true + members: + - peer: dc1 + partition: default diff --git a/control-plane/config/webhook/manifests.yaml b/control-plane/config/webhook/manifests.yaml index d064b50acb..b0787f4a43 100644 --- a/control-plane/config/webhook/manifests.yaml +++ b/control-plane/config/webhook/manifests.yaml @@ -1,6 +1,3 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - --- apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration @@ -134,6 +131,27 @@ webhooks: resources: - proxydefaults sideEffects: None +- admissionReviewVersions: + - v1beta1 + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-v1alpha1-samenessgroups + failurePolicy: Fail + name: mutate-samenessgroups.consul.hashicorp.com + rules: + - apiGroups: + - consul.hashicorp.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - samenessgroups + sideEffects: None - admissionReviewVersions: - v1beta1 - v1 diff --git a/control-plane/controller/configentry_controller.go b/control-plane/controllers/configentry_controller.go similarity index 99% rename from control-plane/controller/configentry_controller.go rename to control-plane/controllers/configentry_controller.go index 593fb1514f..c2c6da9071 100644 --- a/control-plane/controller/configentry_controller.go +++ b/control-plane/controllers/configentry_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/controller/configentry_controller_ent_test.go b/control-plane/controllers/configentry_controller_ent_test.go similarity index 91% rename from control-plane/controller/configentry_controller_ent_test.go rename to control-plane/controllers/configentry_controller_ent_test.go index cfe9985e56..bc4d555a9a 100644 --- a/control-plane/controller/configentry_controller_ent_test.go +++ b/control-plane/controllers/configentry_controller_ent_test.go @@ -3,7 +3,7 @@ //go:build enterprise -package controller_test +package controllers_test import ( "context" @@ -15,7 +15,7 @@ import ( logrtest "github.com/go-logr/logr/testing" "github.com/hashicorp/consul-k8s/control-plane/api/common" "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/controller" + "github.com/hashicorp/consul-k8s/control-plane/controllers" "github.com/hashicorp/consul-k8s/control-plane/helper/test" capi "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" @@ -88,7 +88,7 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T ConsulKind string ConsulNamespace string KubeResource common.ConfigEntryResource - GetController func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler + GetController func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler AssertValidConfig func(entry capi.ConfigEntry) bool }{ "namespaced": { @@ -102,8 +102,8 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T Protocol: "http", }, }, - GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { - return &controller.ServiceDefaultsController{ + GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { + return &controllers.ServiceDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -132,8 +132,8 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T }, }, }, - GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { - return &controller.ProxyDefaultsController{ + GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { + return &controllers.ProxyDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -170,8 +170,8 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T }, }, }, - GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { - return &controller.ServiceIntentionsController{ + GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { + return &controllers.ServiceIntentionsController{ Client: client, Log: logger, Scheme: scheme, @@ -206,7 +206,7 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T fakeClient, logrtest.TestLogger{T: t}, s, - &controller.ConfigEntryController{ + &controllers.ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, @@ -299,7 +299,7 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T ConsulKind string ConsulNamespace string KubeResource common.ConfigEntryResource - GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler + GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler AssertValidConfigFunc func(entry capi.ConfigEntry) bool WriteConfigEntryFunc func(consulClient *capi.Client, namespace string) error UpdateResourceFunc func(client client.Client, ctx context.Context, in common.ConfigEntryResource) error @@ -310,15 +310,15 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: c.SourceKubeNS, - Finalizers: []string{controller.FinalizerName}, + Finalizers: []string{controllers.FinalizerName}, }, Spec: v1alpha1.ServiceDefaultsSpec{ Protocol: "http", }, }, ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { - return &controller.ServiceDefaultsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { + return &controllers.ServiceDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -352,7 +352,7 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: common.Global, Namespace: c.SourceKubeNS, - Finalizers: []string{controller.FinalizerName}, + Finalizers: []string{controllers.FinalizerName}, }, Spec: v1alpha1.ProxyDefaultsSpec{ MeshGateway: v1alpha1.MeshGateway{ @@ -361,8 +361,8 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T }, }, ConsulNamespace: common.DefaultConsulNamespace, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { - return &controller.ProxyDefaultsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { + return &controllers.ProxyDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -398,7 +398,7 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: c.SourceKubeNS, - Finalizers: []string{controller.FinalizerName}, + Finalizers: []string{controllers.FinalizerName}, }, Spec: v1alpha1.ServiceIntentionsSpec{ Destination: v1alpha1.IntentionDestination{ @@ -415,8 +415,8 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T }, }, ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { - return &controller.ServiceIntentionsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { + return &controllers.ServiceIntentionsController{ Client: client, Log: logger, Scheme: scheme, @@ -468,7 +468,7 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T fakeClient, logrtest.TestLogger{T: t}, s, - &controller.ConfigEntryController{ + &controllers.ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, @@ -577,7 +577,7 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T ConsulKind string ConsulNamespace string KubeResource common.ConfigEntryResource - GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler + GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler WriteConfigEntryFunc func(consulClient *capi.Client, namespace string) error }{ "namespaced": { @@ -588,7 +588,7 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: c.SourceKubeNS, - Finalizers: []string{controller.FinalizerName}, + Finalizers: []string{controllers.FinalizerName}, DeletionTimestamp: &metav1.Time{Time: time.Now()}, }, Spec: v1alpha1.ServiceDefaultsSpec{ @@ -596,8 +596,8 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T }, }, ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { - return &controller.ServiceDefaultsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { + return &controllers.ServiceDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -621,7 +621,7 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: common.Global, Namespace: c.SourceKubeNS, - Finalizers: []string{controller.FinalizerName}, + Finalizers: []string{controllers.FinalizerName}, DeletionTimestamp: &metav1.Time{Time: time.Now()}, }, Spec: v1alpha1.ProxyDefaultsSpec{ @@ -631,8 +631,8 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T }, }, ConsulNamespace: common.DefaultConsulNamespace, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { - return &controller.ProxyDefaultsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { + return &controllers.ProxyDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -658,7 +658,7 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: c.SourceKubeNS, - Finalizers: []string{controller.FinalizerName}, + Finalizers: []string{controllers.FinalizerName}, DeletionTimestamp: &metav1.Time{Time: time.Now()}, }, Spec: v1alpha1.ServiceIntentionsSpec{ @@ -676,8 +676,8 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T }, }, ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controller.ConfigEntryController) reconcile.Reconciler { - return &controller.ServiceIntentionsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { + return &controllers.ServiceIntentionsController{ Client: client, Log: logger, Scheme: scheme, @@ -717,7 +717,7 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T fakeClient, logrtest.TestLogger{T: t}, s, - &controller.ConfigEntryController{ + &controllers.ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, diff --git a/control-plane/controller/configentry_controller_test.go b/control-plane/controllers/configentry_controller_test.go similarity index 94% rename from control-plane/controller/configentry_controller_test.go rename to control-plane/controllers/configentry_controller_test.go index 47f28f02d1..c71753424f 100644 --- a/control-plane/controller/configentry_controller_test.go +++ b/control-plane/controllers/configentry_controller_test.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" @@ -431,6 +431,45 @@ func TestConfigEntryControllers_createsConfigEntry(t *testing.T) { require.Equal(t, "sni", resource.Services[0].SNI) }, }, + { + kubeKind: "SamenessGroups", + consulKind: capi.SamenessGroup, + configEntryResource: &v1alpha1.SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: kubeNS, + }, + Spec: v1alpha1.SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []v1alpha1.SamenessGroupMember{ + { + Peer: "dc1", + Partition: "default", + }, + }, + }, + }, + reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { + return &SamenessGroupsController{ + Client: client, + Log: logger, + ConfigEntryController: &ConfigEntryController{ + ConsulClientConfig: cfg, + ConsulServerConnMgr: watcher, + DatacenterName: datacenterName, + }, + } + }, + compare: func(t *testing.T, consulEntry capi.ConfigEntry) { + resource, ok := consulEntry.(*capi.SamenessGroupConfigEntry) + require.True(t, ok, "cast error") + require.Equal(t, true, resource.DefaultForFailover) + require.Equal(t, true, resource.IncludeLocal) + require.Equal(t, "dc1", resource.Members[0].Peer) + require.Equal(t, "default", resource.Members[0].Partition) + }, + }, } for _, c := range cases { @@ -908,6 +947,49 @@ func TestConfigEntryControllers_updatesConfigEntry(t *testing.T) { require.Equal(t, "new-sni", resource.Services[0].SNI) }, }, + { + kubeKind: "SamenessGroups", + consulKind: capi.SamenessGroup, + configEntryResource: &v1alpha1.SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: kubeNS, + }, + Spec: v1alpha1.SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []v1alpha1.SamenessGroupMember{ + { + Peer: "dc1", + Partition: "default", + }, + }, + }, + }, + reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { + return &SamenessGroupsController{ + Client: client, + Log: logger, + ConfigEntryController: &ConfigEntryController{ + ConsulClientConfig: cfg, + ConsulServerConnMgr: watcher, + DatacenterName: datacenterName, + }, + } + }, + updateF: func(resource common.ConfigEntryResource) { + sg := resource.(*v1alpha1.SamenessGroups) + sg.Spec.IncludeLocal = false + }, + compare: func(t *testing.T, consulEntry capi.ConfigEntry) { + resource, ok := consulEntry.(*capi.SamenessGroupConfigEntry) + require.True(t, ok, "cast error") + require.Equal(t, true, resource.DefaultForFailover) + require.Equal(t, false, resource.IncludeLocal) + require.Equal(t, "dc1", resource.Members[0].Peer) + require.Equal(t, "default", resource.Members[0].Partition) + }, + }, } for _, c := range cases { @@ -1309,6 +1391,39 @@ func TestConfigEntryControllers_deletesConfigEntry(t *testing.T) { } }, }, + { + kubeKind: "SamenessGroups", + consulKind: capi.SamenessGroup, + configEntryResourceWithDeletion: &v1alpha1.SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: kubeNS, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + Finalizers: []string{FinalizerName}, + }, + Spec: v1alpha1.SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []v1alpha1.SamenessGroupMember{ + { + Peer: "dc1", + Partition: "default", + }, + }, + }, + }, + reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { + return &SamenessGroupsController{ + Client: client, + Log: logger, + ConfigEntryController: &ConfigEntryController{ + ConsulClientConfig: cfg, + ConsulServerConnMgr: watcher, + DatacenterName: datacenterName, + }, + } + }, + }, } for _, c := range cases { diff --git a/control-plane/controller/exportedservices_controller.go b/control-plane/controllers/exportedservices_controller.go similarity index 98% rename from control-plane/controller/exportedservices_controller.go rename to control-plane/controllers/exportedservices_controller.go index 90d7261d9a..e72b743a1f 100644 --- a/control-plane/controller/exportedservices_controller.go +++ b/control-plane/controllers/exportedservices_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/controller/exportedservices_controller_ent_test.go b/control-plane/controllers/exportedservices_controller_ent_test.go similarity index 95% rename from control-plane/controller/exportedservices_controller_ent_test.go rename to control-plane/controllers/exportedservices_controller_ent_test.go index aba193bdd9..40ab5d1e1e 100644 --- a/control-plane/controller/exportedservices_controller_ent_test.go +++ b/control-plane/controllers/exportedservices_controller_ent_test.go @@ -3,7 +3,7 @@ //go:build enterprise -package controller_test +package controllers_test import ( "context" @@ -14,7 +14,7 @@ import ( logrtest "github.com/go-logr/logr/testing" "github.com/hashicorp/consul-k8s/control-plane/api/common" "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/controller" + "github.com/hashicorp/consul-k8s/control-plane/controllers" "github.com/hashicorp/consul-k8s/control-plane/helper/test" capi "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" @@ -103,11 +103,11 @@ func TestExportedServicesController_createsExportedServices(tt *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(exportedServices).Build() - controller := &controller.ExportedServicesController{ + controller := &controllers.ExportedServicesController{ Client: fakeClient, Log: logrtest.TestLogger{T: t}, Scheme: s, - ConfigEntryController: &controller.ConfigEntryController{ + ConfigEntryController: &controllers.ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, @@ -195,7 +195,7 @@ func TestExportedServicesController_updatesExportedServices(tt *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: c.SourceKubeNS, - Finalizers: []string{controller.FinalizerName}, + Finalizers: []string{controllers.FinalizerName}, }, Spec: v1alpha1.ExportedServicesSpec{ Services: []v1alpha1.ExportedService{ @@ -218,11 +218,11 @@ func TestExportedServicesController_updatesExportedServices(tt *testing.T) { consulClient := testClient.APIClient fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(exportedServices).Build() - controller := &controller.ExportedServicesController{ + controller := &controllers.ExportedServicesController{ Client: fakeClient, Log: logrtest.TestLogger{T: t}, Scheme: s, - ConfigEntryController: &controller.ConfigEntryController{ + ConfigEntryController: &controllers.ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, @@ -332,7 +332,7 @@ func TestExportedServicesController_deletesExportedServices(tt *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: c.SourceKubeNS, - Finalizers: []string{controller.FinalizerName}, + Finalizers: []string{controllers.FinalizerName}, DeletionTimestamp: &metav1.Time{Time: time.Now()}, }, Spec: v1alpha1.ExportedServicesSpec{ @@ -356,11 +356,11 @@ func TestExportedServicesController_deletesExportedServices(tt *testing.T) { fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(exportedServices).Build() - controller := &controller.ExportedServicesController{ + controller := &controllers.ExportedServicesController{ Client: fakeClient, Log: logrtest.TestLogger{T: t}, Scheme: s, - ConfigEntryController: &controller.ConfigEntryController{ + ConfigEntryController: &controllers.ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, diff --git a/control-plane/controller/ingressgateway_controller.go b/control-plane/controllers/ingressgateway_controller.go similarity index 98% rename from control-plane/controller/ingressgateway_controller.go rename to control-plane/controllers/ingressgateway_controller.go index fffc3c5a06..faa728dd4f 100644 --- a/control-plane/controller/ingressgateway_controller.go +++ b/control-plane/controllers/ingressgateway_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/controller/mesh_controller.go b/control-plane/controllers/mesh_controller.go similarity index 98% rename from control-plane/controller/mesh_controller.go rename to control-plane/controllers/mesh_controller.go index 9f7d8cd7c8..92839d0104 100644 --- a/control-plane/controller/mesh_controller.go +++ b/control-plane/controllers/mesh_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/controller/proxydefaults_controller.go b/control-plane/controllers/proxydefaults_controller.go similarity index 98% rename from control-plane/controller/proxydefaults_controller.go rename to control-plane/controllers/proxydefaults_controller.go index 7499928ea4..1415da8688 100644 --- a/control-plane/controller/proxydefaults_controller.go +++ b/control-plane/controllers/proxydefaults_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/controllers/samenessgroups_controller.go b/control-plane/controllers/samenessgroups_controller.go new file mode 100644 index 0000000000..5af637fdde --- /dev/null +++ b/control-plane/controllers/samenessgroups_controller.go @@ -0,0 +1,41 @@ +package controllers + +import ( + "context" + "k8s.io/apimachinery/pkg/types" + + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" +) + +// SamenessGroupsController reconciles a SamenessGroups object +type SamenessGroupsController struct { + client.Client + Log logr.Logger + Scheme *runtime.Scheme + ConfigEntryController *ConfigEntryController +} + +//+kubebuilder:rbac:groups=consul.hashicorp.com,resources=samenessgroups,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=consul.hashicorp.com,resources=samenessgroups/status,verbs=get;update;patch + +func (r *SamenessGroupsController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + return r.ConfigEntryController.ReconcileEntry(ctx, r, req, &consulv1alpha1.SamenessGroups{}) +} + +func (r *SamenessGroupsController) Logger(name types.NamespacedName) logr.Logger { + return r.Log.WithValues("request", name) +} + +func (r *SamenessGroupsController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + return r.Status().Update(ctx, obj, opts...) +} + +// SetupWithManager sets up the controller with the Manager. +func (r *SamenessGroupsController) SetupWithManager(mgr ctrl.Manager) error { + return setupWithManager(mgr, &consulv1alpha1.SamenessGroups{}, r) +} diff --git a/control-plane/controller/servicedefaults_controller.go b/control-plane/controllers/servicedefaults_controller.go similarity index 98% rename from control-plane/controller/servicedefaults_controller.go rename to control-plane/controllers/servicedefaults_controller.go index b96ff7e566..9c2dbe683d 100644 --- a/control-plane/controller/servicedefaults_controller.go +++ b/control-plane/controllers/servicedefaults_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/controller/serviceintentions_controller.go b/control-plane/controllers/serviceintentions_controller.go similarity index 98% rename from control-plane/controller/serviceintentions_controller.go rename to control-plane/controllers/serviceintentions_controller.go index 43298a23f7..30dcb63f81 100644 --- a/control-plane/controller/serviceintentions_controller.go +++ b/control-plane/controllers/serviceintentions_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/controller/serviceresolver_controller.go b/control-plane/controllers/serviceresolver_controller.go similarity index 98% rename from control-plane/controller/serviceresolver_controller.go rename to control-plane/controllers/serviceresolver_controller.go index cca014ab50..f82c4d42a2 100644 --- a/control-plane/controller/serviceresolver_controller.go +++ b/control-plane/controllers/serviceresolver_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/controller/servicerouter_controller.go b/control-plane/controllers/servicerouter_controller.go similarity index 98% rename from control-plane/controller/servicerouter_controller.go rename to control-plane/controllers/servicerouter_controller.go index 6ed1e52fad..831179eee9 100644 --- a/control-plane/controller/servicerouter_controller.go +++ b/control-plane/controllers/servicerouter_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/controller/servicesplitter_controller.go b/control-plane/controllers/servicesplitter_controller.go similarity index 98% rename from control-plane/controller/servicesplitter_controller.go rename to control-plane/controllers/servicesplitter_controller.go index dc5e2a8dd3..1dd89dc278 100644 --- a/control-plane/controller/servicesplitter_controller.go +++ b/control-plane/controllers/servicesplitter_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/controller/terminatinggateway_controller.go b/control-plane/controllers/terminatinggateway_controller.go similarity index 98% rename from control-plane/controller/terminatinggateway_controller.go rename to control-plane/controllers/terminatinggateway_controller.go index 10af041c39..9550a2d04f 100644 --- a/control-plane/controller/terminatinggateway_controller.go +++ b/control-plane/controllers/terminatinggateway_controller.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package controller +package controllers import ( "context" diff --git a/control-plane/go.mod b/control-plane/go.mod index b139e1cd3f..23900deb46 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -25,6 +25,8 @@ require ( github.com/mitchellh/cli v1.1.0 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.5.0 + github.com/onsi/ginkgo v1.16.4 + github.com/onsi/gomega v1.17.0 github.com/stretchr/testify v1.7.2 go.uber.org/zap v1.19.0 golang.org/x/text v0.3.8 @@ -108,6 +110,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 // indirect + github.com/nxadm/tail v1.4.8 // indirect github.com/oklog/run v1.0.0 // indirect github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect @@ -144,6 +147,7 @@ require ( gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/resty.v1 v1.12.0 // indirect gopkg.in/square/go-jose.v2 v2.5.1 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.22.2 // indirect diff --git a/control-plane/main.go b/control-plane/main.go index a4ccc9630c..64ccd5d43a 100644 --- a/control-plane/main.go +++ b/control-plane/main.go @@ -7,8 +7,9 @@ import ( "log" "os" - "github.com/hashicorp/consul-k8s/control-plane/version" "github.com/mitchellh/cli" + + "github.com/hashicorp/consul-k8s/control-plane/version" ) func main() { diff --git a/control-plane/subcommand/inject-connect/command.go b/control-plane/subcommand/inject-connect/command.go index e570832ee9..6c12cacaea 100644 --- a/control-plane/subcommand/inject-connect/command.go +++ b/control-plane/subcommand/inject-connect/command.go @@ -21,7 +21,7 @@ import ( "github.com/hashicorp/consul-k8s/control-plane/connect-inject/controllers/peering" "github.com/hashicorp/consul-k8s/control-plane/connect-inject/metrics" "github.com/hashicorp/consul-k8s/control-plane/connect-inject/webhook" - "github.com/hashicorp/consul-k8s/control-plane/controller" + "github.com/hashicorp/consul-k8s/control-plane/controllers" mutatingwebhookconfiguration "github.com/hashicorp/consul-k8s/control-plane/helper/mutating-webhook-configuration" "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" @@ -456,7 +456,7 @@ func (c *Command) Run(args []string) int { Prefix: c.flagK8SNSMirroringPrefix, } - configEntryReconciler := &controller.ConfigEntryController{ + configEntryReconciler := &controllers.ConfigEntryController{ ConsulClientConfig: c.consul.ConsulClientConfig(), ConsulServerConnMgr: watcher, DatacenterName: c.consul.Datacenter, @@ -466,7 +466,7 @@ func (c *Command) Run(args []string) int { NSMirroringPrefix: c.flagK8SNSMirroringPrefix, CrossNSACLPolicy: c.flagCrossNamespaceACLPolicy, } - if err = (&controller.ServiceDefaultsController{ + if err = (&controllers.ServiceDefaultsController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceDefaults), @@ -475,7 +475,7 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceDefaults) return 1 } - if err = (&controller.ServiceResolverController{ + if err = (&controllers.ServiceResolverController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceResolver), @@ -484,7 +484,7 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceResolver) return 1 } - if err = (&controller.ProxyDefaultsController{ + if err = (&controllers.ProxyDefaultsController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), Log: ctrl.Log.WithName("controller").WithName(apicommon.ProxyDefaults), @@ -493,7 +493,7 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.ProxyDefaults) return 1 } - if err = (&controller.MeshController{ + if err = (&controllers.MeshController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), Log: ctrl.Log.WithName("controller").WithName(apicommon.Mesh), @@ -502,7 +502,7 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.Mesh) return 1 } - if err = (&controller.ExportedServicesController{ + if err = (&controllers.ExportedServicesController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), Log: ctrl.Log.WithName("controller").WithName(apicommon.ExportedServices), @@ -511,7 +511,7 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.ExportedServices) return 1 } - if err = (&controller.ServiceRouterController{ + if err = (&controllers.ServiceRouterController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceRouter), @@ -520,7 +520,7 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceRouter) return 1 } - if err = (&controller.ServiceSplitterController{ + if err = (&controllers.ServiceSplitterController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceSplitter), @@ -529,7 +529,7 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceSplitter) return 1 } - if err = (&controller.ServiceIntentionsController{ + if err = (&controllers.ServiceIntentionsController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), Log: ctrl.Log.WithName("controller").WithName(apicommon.ServiceIntentions), @@ -538,7 +538,7 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.ServiceIntentions) return 1 } - if err = (&controller.IngressGatewayController{ + if err = (&controllers.IngressGatewayController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), Log: ctrl.Log.WithName("controller").WithName(apicommon.IngressGateway), @@ -547,7 +547,7 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.IngressGateway) return 1 } - if err = (&controller.TerminatingGatewayController{ + if err = (&controllers.TerminatingGatewayController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), Log: ctrl.Log.WithName("controller").WithName(apicommon.TerminatingGateway), @@ -556,6 +556,15 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.TerminatingGateway) return 1 } + if err = (&controllers.SamenessGroupsController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(apicommon.SamenessGroups), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", apicommon.SamenessGroups) + return 1 + } if err = mgr.AddReadyzCheck("ready", webhook.ReadinessCheck{CertDir: c.flagCertDir}.Ready); err != nil { setupLog.Error(err, "unable to create readiness check", "controller", endpoints.Controller{}) @@ -706,6 +715,12 @@ func (c *Command) Run(args []string) int { Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.TerminatingGateway), ConsulMeta: consulMeta, }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-samenessgroups", + &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.SamenessGroupsWebhook{ + Client: mgr.GetClient(), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.SamenessGroups), + ConsulMeta: consulMeta, + }}) if c.flagEnableWebhookCAUpdate { err = c.updateWebhookCABundle(ctx) From b43ab8c3a00746c8a7179d7fc8c03e6c844abf7c Mon Sep 17 00:00:00 2001 From: Maliz Date: Thu, 13 Apr 2023 09:36:06 -0700 Subject: [PATCH 02/10] move sameness group tests to ent test file --- .../configentry_controller_ent_test.go | 382 ++++++++++++++++-- .../configentry_controller_test.go | 115 ------ 2 files changed, 347 insertions(+), 150 deletions(-) diff --git a/control-plane/controllers/configentry_controller_ent_test.go b/control-plane/controllers/configentry_controller_ent_test.go index bc4d555a9a..10adcebdd7 100644 --- a/control-plane/controllers/configentry_controller_ent_test.go +++ b/control-plane/controllers/configentry_controller_ent_test.go @@ -3,7 +3,7 @@ //go:build enterprise -package controllers_test +package controllers import ( "context" @@ -15,7 +15,7 @@ import ( logrtest "github.com/go-logr/logr/testing" "github.com/hashicorp/consul-k8s/control-plane/api/common" "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" - "github.com/hashicorp/consul-k8s/control-plane/controllers" + "github.com/hashicorp/consul-k8s/control-plane/consul" "github.com/hashicorp/consul-k8s/control-plane/helper/test" capi "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" @@ -29,11 +29,323 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" ) -// NOTE: We're not testing each controller type here because that's done in +// NOTE: We're not testing each controller type here because that's mostly done in // the OSS tests and it would result in too many permutations. Instead -// we're only testing with the ServiceDefaults and ProxyDefaults controller which will exercise -// all the namespaces code for config entries that are namespaced and those that +// we're only testing with the ServiceDefaults and ProxyDefaults controllers which +// will exercise all the namespaces code for config entries that are namespaced and those that // exist in the global namespace. +// We also test Enterprise only features like SamenessGroups + +func TestConfigEntryController_createsConfigEntry(t *testing.T) { + t.Parallel() + kubeNS := "default" + + cases := []struct { + kubeKind string + consulKind string + consulPrereqs []capi.ConfigEntry + configEntryResource common.ConfigEntryResource + reconciler func(client.Client, *consul.Config, consul.ServerConnectionManager, logr.Logger) testReconciler + compare func(t *testing.T, consul capi.ConfigEntry) + }{ + { + kubeKind: "SamenessGroups", + consulKind: capi.SamenessGroup, + configEntryResource: &v1alpha1.SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: kubeNS, + }, + Spec: v1alpha1.SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []v1alpha1.SamenessGroupMember{ + { + Peer: "dc1", + Partition: "", + }, + }, + }, + }, + reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { + return &SamenessGroupsController{ + Client: client, + Log: logger, + ConfigEntryController: &ConfigEntryController{ + ConsulClientConfig: cfg, + ConsulServerConnMgr: watcher, + DatacenterName: datacenterName, + }, + } + }, + compare: func(t *testing.T, consulEntry capi.ConfigEntry) { + resource, ok := consulEntry.(*capi.SamenessGroupConfigEntry) + require.True(t, ok, "cast error") + require.Equal(t, true, resource.DefaultForFailover) + require.Equal(t, true, resource.IncludeLocal) + require.Equal(t, "dc1", resource.Members[0].Peer) + require.Equal(t, "", resource.Members[0].Partition) + }, + }, + } + + for _, c := range cases { + t.Run(c.kubeKind, func(t *testing.T) { + req := require.New(t) + ctx := context.Background() + + s := runtime.NewScheme() + s.AddKnownTypes(v1alpha1.GroupVersion, c.configEntryResource) + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(c.configEntryResource).Build() + + testClient := test.TestServerWithMockConnMgrWatcher(t, nil) + testClient.TestServer.WaitForServiceIntentions(t) + consulClient := testClient.APIClient + + for _, configEntry := range c.consulPrereqs { + written, _, err := consulClient.ConfigEntries().Set(configEntry, nil) + req.NoError(err) + req.True(written) + } + + r := c.reconciler(fakeClient, testClient.Cfg, testClient.Watcher, logrtest.TestLogger{T: t}) + namespacedName := types.NamespacedName{ + Namespace: kubeNS, + Name: c.configEntryResource.KubernetesName(), + } + resp, err := r.Reconcile(ctx, ctrl.Request{ + NamespacedName: namespacedName, + }) + req.NoError(err) + req.False(resp.Requeue) + + cfg, _, err := consulClient.ConfigEntries().Get(c.consulKind, c.configEntryResource.ConsulName(), nil) + req.NoError(err) + req.Equal(c.configEntryResource.ConsulName(), cfg.GetName()) + c.compare(t, cfg) + + // Check that the status is "synced". + err = fakeClient.Get(ctx, namespacedName, c.configEntryResource) + req.NoError(err) + req.Equal(corev1.ConditionTrue, c.configEntryResource.SyncedConditionStatus()) + + // Check that the finalizer is added. + req.Contains(c.configEntryResource.Finalizers(), FinalizerName) + }) + } +} + +func TestConfigEntryController_updatesConfigEntry(t *testing.T) { + t.Parallel() + kubeNS := "default" + + cases := []struct { + kubeKind string + consulKind string + consulPrereqs []capi.ConfigEntry + configEntryResource common.ConfigEntryResource + reconciler func(client.Client, *consul.Config, consul.ServerConnectionManager, logr.Logger) testReconciler + updateF func(common.ConfigEntryResource) + compare func(t *testing.T, consul capi.ConfigEntry) + }{ + { + kubeKind: "SamenessGroups", + consulKind: capi.SamenessGroup, + configEntryResource: &v1alpha1.SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: kubeNS, + }, + Spec: v1alpha1.SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []v1alpha1.SamenessGroupMember{ + { + Peer: "dc1", + Partition: "", + }, + }, + }, + }, + reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { + return &SamenessGroupsController{ + Client: client, + Log: logger, + ConfigEntryController: &ConfigEntryController{ + ConsulClientConfig: cfg, + ConsulServerConnMgr: watcher, + DatacenterName: datacenterName, + }, + } + }, + updateF: func(resource common.ConfigEntryResource) { + sg := resource.(*v1alpha1.SamenessGroups) + sg.Spec.IncludeLocal = false + }, + compare: func(t *testing.T, consulEntry capi.ConfigEntry) { + resource, ok := consulEntry.(*capi.SamenessGroupConfigEntry) + require.True(t, ok, "cast error") + require.Equal(t, true, resource.DefaultForFailover) + require.Equal(t, false, resource.IncludeLocal) + require.Equal(t, "dc1", resource.Members[0].Peer) + require.Equal(t, "", resource.Members[0].Partition) + }, + }, + } + + for _, c := range cases { + t.Run(c.kubeKind, func(t *testing.T) { + req := require.New(t) + ctx := context.Background() + + s := runtime.NewScheme() + s.AddKnownTypes(v1alpha1.GroupVersion, c.configEntryResource) + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(c.configEntryResource).Build() + + testClient := test.TestServerWithMockConnMgrWatcher(t, nil) + testClient.TestServer.WaitForServiceIntentions(t) + consulClient := testClient.APIClient + + // Create any prereqs. + for _, configEntry := range c.consulPrereqs { + written, _, err := consulClient.ConfigEntries().Set(configEntry, nil) + req.NoError(err) + req.True(written) + } + + // We haven't run reconcile yet so we must create the config entry + // in Consul ourselves. + { + written, _, err := consulClient.ConfigEntries().Set(c.configEntryResource.ToConsul(datacenterName), nil) + req.NoError(err) + req.True(written) + } + + // Now run reconcile which should update the entry in Consul. + { + namespacedName := types.NamespacedName{ + Namespace: kubeNS, + Name: c.configEntryResource.KubernetesName(), + } + // First get it so we have the latest revision number. + err := fakeClient.Get(ctx, namespacedName, c.configEntryResource) + req.NoError(err) + + // Update the entry in Kube and run reconcile. + c.updateF(c.configEntryResource) + err = fakeClient.Update(ctx, c.configEntryResource) + req.NoError(err) + r := c.reconciler(fakeClient, testClient.Cfg, testClient.Watcher, logrtest.TestLogger{T: t}) + resp, err := r.Reconcile(ctx, ctrl.Request{ + NamespacedName: namespacedName, + }) + req.NoError(err) + req.False(resp.Requeue) + + // Now check that the object in Consul is as expected. + cfg, _, err := consulClient.ConfigEntries().Get(c.consulKind, c.configEntryResource.ConsulName(), nil) + req.NoError(err) + req.Equal(c.configEntryResource.ConsulName(), cfg.GetName()) + c.compare(t, cfg) + } + }) + } +} + +func TestConfigEntryController_deletesConfigEntry(t *testing.T) { + t.Parallel() + kubeNS := "default" + + cases := []struct { + kubeKind string + consulKind string + consulPrereq []capi.ConfigEntry + configEntryResourceWithDeletion common.ConfigEntryResource + reconciler func(client.Client, *consul.Config, consul.ServerConnectionManager, logr.Logger) testReconciler + }{ + { + kubeKind: "SamenessGroups", + consulKind: capi.SamenessGroup, + configEntryResourceWithDeletion: &v1alpha1.SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: kubeNS, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + Finalizers: []string{FinalizerName}, + }, + Spec: v1alpha1.SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []v1alpha1.SamenessGroupMember{ + { + Peer: "dc1", + Partition: "", + }, + }, + }, + }, + reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { + return &SamenessGroupsController{ + Client: client, + Log: logger, + ConfigEntryController: &ConfigEntryController{ + ConsulClientConfig: cfg, + ConsulServerConnMgr: watcher, + DatacenterName: datacenterName, + }, + } + }, + }, + } + + for _, c := range cases { + t.Run(c.kubeKind, func(t *testing.T) { + req := require.New(t) + + s := runtime.NewScheme() + s.AddKnownTypes(v1alpha1.GroupVersion, c.configEntryResourceWithDeletion) + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(c.configEntryResourceWithDeletion).Build() + + testClient := test.TestServerWithMockConnMgrWatcher(t, nil) + testClient.TestServer.WaitForServiceIntentions(t) + consulClient := testClient.APIClient + + // Create any prereqs. + for _, configEntry := range c.consulPrereq { + written, _, err := consulClient.ConfigEntries().Set(configEntry, nil) + req.NoError(err) + req.True(written) + } + + // We haven't run reconcile yet so we must create the config entry + // in Consul ourselves. + { + written, _, err := consulClient.ConfigEntries().Set(c.configEntryResourceWithDeletion.ToConsul(datacenterName), nil) + req.NoError(err) + req.True(written) + } + + // Now run reconcile. It's marked for deletion so this should delete it. + { + namespacedName := types.NamespacedName{ + Namespace: kubeNS, + Name: c.configEntryResourceWithDeletion.KubernetesName(), + } + r := c.reconciler(fakeClient, testClient.Cfg, testClient.Watcher, logrtest.TestLogger{T: t}) + resp, err := r.Reconcile(context.Background(), ctrl.Request{ + NamespacedName: namespacedName, + }) + req.NoError(err) + req.False(resp.Requeue) + + _, _, err = consulClient.ConfigEntries().Get(c.consulKind, c.configEntryResourceWithDeletion.ConsulName(), nil) + req.EqualError(err, + fmt.Sprintf("Unexpected response code: 404 (Config entry not found for %q / %q)", + c.consulKind, c.configEntryResourceWithDeletion.ConsulName())) + } + }) + } +} func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T) { tt.Parallel() @@ -88,7 +400,7 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T ConsulKind string ConsulNamespace string KubeResource common.ConfigEntryResource - GetController func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler + GetController func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler AssertValidConfig func(entry capi.ConfigEntry) bool }{ "namespaced": { @@ -102,8 +414,8 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T Protocol: "http", }, }, - GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { - return &controllers.ServiceDefaultsController{ + GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { + return &ServiceDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -132,8 +444,8 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T }, }, }, - GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { - return &controllers.ProxyDefaultsController{ + GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { + return &ProxyDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -170,8 +482,8 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T }, }, }, - GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { - return &controllers.ServiceIntentionsController{ + GetController: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { + return &ServiceIntentionsController{ Client: client, Log: logger, Scheme: scheme, @@ -206,7 +518,7 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T fakeClient, logrtest.TestLogger{T: t}, s, - &controllers.ConfigEntryController{ + &ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, @@ -299,7 +611,7 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T ConsulKind string ConsulNamespace string KubeResource common.ConfigEntryResource - GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler + GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler AssertValidConfigFunc func(entry capi.ConfigEntry) bool WriteConfigEntryFunc func(consulClient *capi.Client, namespace string) error UpdateResourceFunc func(client client.Client, ctx context.Context, in common.ConfigEntryResource) error @@ -310,15 +622,15 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: c.SourceKubeNS, - Finalizers: []string{controllers.FinalizerName}, + Finalizers: []string{FinalizerName}, }, Spec: v1alpha1.ServiceDefaultsSpec{ Protocol: "http", }, }, ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { - return &controllers.ServiceDefaultsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { + return &ServiceDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -352,7 +664,7 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: common.Global, Namespace: c.SourceKubeNS, - Finalizers: []string{controllers.FinalizerName}, + Finalizers: []string{FinalizerName}, }, Spec: v1alpha1.ProxyDefaultsSpec{ MeshGateway: v1alpha1.MeshGateway{ @@ -361,8 +673,8 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T }, }, ConsulNamespace: common.DefaultConsulNamespace, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { - return &controllers.ProxyDefaultsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { + return &ProxyDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -398,7 +710,7 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: c.SourceKubeNS, - Finalizers: []string{controllers.FinalizerName}, + Finalizers: []string{FinalizerName}, }, Spec: v1alpha1.ServiceIntentionsSpec{ Destination: v1alpha1.IntentionDestination{ @@ -415,8 +727,8 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T }, }, ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { - return &controllers.ServiceIntentionsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { + return &ServiceIntentionsController{ Client: client, Log: logger, Scheme: scheme, @@ -468,7 +780,7 @@ func TestConfigEntryController_updatesConfigEntry_consulNamespaces(tt *testing.T fakeClient, logrtest.TestLogger{T: t}, s, - &controllers.ConfigEntryController{ + &ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, @@ -577,7 +889,7 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T ConsulKind string ConsulNamespace string KubeResource common.ConfigEntryResource - GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler + GetControllerFunc func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler WriteConfigEntryFunc func(consulClient *capi.Client, namespace string) error }{ "namespaced": { @@ -588,7 +900,7 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: c.SourceKubeNS, - Finalizers: []string{controllers.FinalizerName}, + Finalizers: []string{FinalizerName}, DeletionTimestamp: &metav1.Time{Time: time.Now()}, }, Spec: v1alpha1.ServiceDefaultsSpec{ @@ -596,8 +908,8 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T }, }, ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { - return &controllers.ServiceDefaultsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { + return &ServiceDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -621,7 +933,7 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: common.Global, Namespace: c.SourceKubeNS, - Finalizers: []string{controllers.FinalizerName}, + Finalizers: []string{FinalizerName}, DeletionTimestamp: &metav1.Time{Time: time.Now()}, }, Spec: v1alpha1.ProxyDefaultsSpec{ @@ -631,8 +943,8 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T }, }, ConsulNamespace: common.DefaultConsulNamespace, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { - return &controllers.ProxyDefaultsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { + return &ProxyDefaultsController{ Client: client, Log: logger, Scheme: scheme, @@ -658,7 +970,7 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: c.SourceKubeNS, - Finalizers: []string{controllers.FinalizerName}, + Finalizers: []string{FinalizerName}, DeletionTimestamp: &metav1.Time{Time: time.Now()}, }, Spec: v1alpha1.ServiceIntentionsSpec{ @@ -676,8 +988,8 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T }, }, ConsulNamespace: c.ExpConsulNS, - GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *controllers.ConfigEntryController) reconcile.Reconciler { - return &controllers.ServiceIntentionsController{ + GetControllerFunc: func(client client.Client, logger logr.Logger, scheme *runtime.Scheme, cont *ConfigEntryController) reconcile.Reconciler { + return &ServiceIntentionsController{ Client: client, Log: logger, Scheme: scheme, @@ -717,7 +1029,7 @@ func TestConfigEntryController_deletesConfigEntry_consulNamespaces(tt *testing.T fakeClient, logrtest.TestLogger{T: t}, s, - &controllers.ConfigEntryController{ + &ConfigEntryController{ ConsulClientConfig: testClient.Cfg, ConsulServerConnMgr: testClient.Watcher, EnableConsulNamespaces: true, diff --git a/control-plane/controllers/configentry_controller_test.go b/control-plane/controllers/configentry_controller_test.go index c71753424f..494715cf4f 100644 --- a/control-plane/controllers/configentry_controller_test.go +++ b/control-plane/controllers/configentry_controller_test.go @@ -431,45 +431,6 @@ func TestConfigEntryControllers_createsConfigEntry(t *testing.T) { require.Equal(t, "sni", resource.Services[0].SNI) }, }, - { - kubeKind: "SamenessGroups", - consulKind: capi.SamenessGroup, - configEntryResource: &v1alpha1.SamenessGroups{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - }, - Spec: v1alpha1.SamenessGroupsSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []v1alpha1.SamenessGroupMember{ - { - Peer: "dc1", - Partition: "default", - }, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &SamenessGroupsController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - compare: func(t *testing.T, consulEntry capi.ConfigEntry) { - resource, ok := consulEntry.(*capi.SamenessGroupConfigEntry) - require.True(t, ok, "cast error") - require.Equal(t, true, resource.DefaultForFailover) - require.Equal(t, true, resource.IncludeLocal) - require.Equal(t, "dc1", resource.Members[0].Peer) - require.Equal(t, "default", resource.Members[0].Partition) - }, - }, } for _, c := range cases { @@ -947,49 +908,6 @@ func TestConfigEntryControllers_updatesConfigEntry(t *testing.T) { require.Equal(t, "new-sni", resource.Services[0].SNI) }, }, - { - kubeKind: "SamenessGroups", - consulKind: capi.SamenessGroup, - configEntryResource: &v1alpha1.SamenessGroups{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - }, - Spec: v1alpha1.SamenessGroupsSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []v1alpha1.SamenessGroupMember{ - { - Peer: "dc1", - Partition: "default", - }, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &SamenessGroupsController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - updateF: func(resource common.ConfigEntryResource) { - sg := resource.(*v1alpha1.SamenessGroups) - sg.Spec.IncludeLocal = false - }, - compare: func(t *testing.T, consulEntry capi.ConfigEntry) { - resource, ok := consulEntry.(*capi.SamenessGroupConfigEntry) - require.True(t, ok, "cast error") - require.Equal(t, true, resource.DefaultForFailover) - require.Equal(t, false, resource.IncludeLocal) - require.Equal(t, "dc1", resource.Members[0].Peer) - require.Equal(t, "default", resource.Members[0].Partition) - }, - }, } for _, c := range cases { @@ -1391,39 +1309,6 @@ func TestConfigEntryControllers_deletesConfigEntry(t *testing.T) { } }, }, - { - kubeKind: "SamenessGroups", - consulKind: capi.SamenessGroup, - configEntryResourceWithDeletion: &v1alpha1.SamenessGroups{ - ObjectMeta: metav1.ObjectMeta{ - Name: "foo", - Namespace: kubeNS, - DeletionTimestamp: &metav1.Time{Time: time.Now()}, - Finalizers: []string{FinalizerName}, - }, - Spec: v1alpha1.SamenessGroupsSpec{ - DefaultForFailover: true, - IncludeLocal: true, - Members: []v1alpha1.SamenessGroupMember{ - { - Peer: "dc1", - Partition: "default", - }, - }, - }, - }, - reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &SamenessGroupsController{ - Client: client, - Log: logger, - ConfigEntryController: &ConfigEntryController{ - ConsulClientConfig: cfg, - ConsulServerConnMgr: watcher, - DatacenterName: datacenterName, - }, - } - }, - }, } for _, c := range cases { From d9b0540d07513e8aa184b91456495637f1cdb7be Mon Sep 17 00:00:00 2001 From: Maliz Date: Thu, 13 Apr 2023 12:48:22 -0700 Subject: [PATCH 03/10] update tests --- .../api/v1alpha1/samenessgroups_types.go | 49 ++++++---- .../api/v1alpha1/samenessgroups_types_test.go | 92 ++++++++++++++++--- .../configentry_controller_ent_test.go | 2 +- 3 files changed, 111 insertions(+), 32 deletions(-) diff --git a/control-plane/api/v1alpha1/samenessgroups_types.go b/control-plane/api/v1alpha1/samenessgroups_types.go index d34d0b8459..bc7b833695 100644 --- a/control-plane/api/v1alpha1/samenessgroups_types.go +++ b/control-plane/api/v1alpha1/samenessgroups_types.go @@ -1,6 +1,7 @@ package v1alpha1 import ( + "encoding/json" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/hashicorp/consul-k8s/control-plane/api/common" @@ -169,7 +170,24 @@ func (in *SamenessGroups) Validate(consulMeta common.ConsulMeta) error { var allErrs field.ErrorList path := field.NewPath("spec") - allErrs = append(allErrs, SamenessGroupMembers(in.Spec.Members).validate(path.Child("envoyExtensions"))...) + asJSON, _ := json.Marshal(in) + if in == nil { + allErrs = append(allErrs, field.Invalid(path, string(asJSON), "config entry is nil")) + } + if in.Name == "" { + allErrs = append(allErrs, field.Invalid(path.Child("name"), in.Name, "sameness groups must have a name defined")) + } + + if len(in.Spec.Members) == 0 { + asJSON, _ := json.Marshal(in.Spec.Members) + allErrs = append(allErrs, field.Invalid(path.Child("members"), string(asJSON), "sameness groups must have at least one member")) + } + + for i, m := range in.Spec.Members { + if err := m.validate(path.Child("members").Index(i)); err != nil { + allErrs = append(allErrs, err) + } + } if len(allErrs) > 0 { return apierrors.NewInvalid( @@ -202,23 +220,22 @@ func (in SamenessGroupMembers) toConsul() []capi.SamenessGroupMember { return outMembers } -func (in SamenessGroupMembers) validate(path *field.Path) field.ErrorList { - if len(in) == 0 { - return nil - } +func (in *SamenessGroupMember) validate(path *field.Path) *field.Error { + asJSON, _ := json.Marshal(in) - var errs field.ErrorList - for i, e := range in { - if err := e.validate(path.Child("envoyExtension").Index(i)); err != nil { - errs = append(errs, err) - } + if in == nil { + return field.Invalid(path, string(asJSON), "sameness group member is nil") } - - return errs + if in.isEmpty() { + return field.Invalid(path, string(asJSON), "sameness group members must specify either partition or peer") + } + // We do not allow referencing peer connections in other partitions. + if in.Peer != "" && in.Partition != "" { + return field.Invalid(path, string(asJSON), "sameness group members cannot specify both partition and peer in the same entry") + } + return nil } -func (in SamenessGroupMember) validate(path *field.Path) *field.Error { - - //TODO - return nil +func (in *SamenessGroupMember) isEmpty() bool { + return in.Peer == "" && in.Partition == "" } diff --git a/control-plane/api/v1alpha1/samenessgroups_types_test.go b/control-plane/api/v1alpha1/samenessgroups_types_test.go index d2a0df1d15..f624800b37 100644 --- a/control-plane/api/v1alpha1/samenessgroups_types_test.go +++ b/control-plane/api/v1alpha1/samenessgroups_types_test.go @@ -44,8 +44,10 @@ func TestSamenessGroups_ToConsul(t *testing.T) { IncludeLocal: true, Members: []SamenessGroupMember{ { - Peer: "dc1", - Partition: "default", + Peer: "peer2", + }, + { + Partition: "p2", }, }, }, @@ -61,8 +63,10 @@ func TestSamenessGroups_ToConsul(t *testing.T) { IncludeLocal: true, Members: []capi.SamenessGroupMember{ { - Peer: "dc1", - Partition: "default", + Peer: "peer2", + }, + { + Partition: "p2", }, }, }, @@ -111,17 +115,17 @@ func TestSamenessGroups_MatchesConsul(t *testing.T) { IncludeLocal: true, Members: []SamenessGroupMember{ { - Peer: "dc1", - Partition: "default", + Peer: "peer2", + }, + { + Partition: "p2", }, }, }, }, &capi.SamenessGroupConfigEntry{ - Kind: capi.SamenessGroup, - Name: "my-test-sameness-group", - CreateIndex: 1, - ModifyIndex: 2, + Kind: capi.SamenessGroup, + Name: "my-test-sameness-group", Meta: map[string]string{ common.SourceKey: common.SourceValue, common.DatacenterKey: "datacenter", @@ -130,8 +134,10 @@ func TestSamenessGroups_MatchesConsul(t *testing.T) { IncludeLocal: true, Members: []capi.SamenessGroupMember{ { - Peer: "dc1", - Partition: "default", + Peer: "peer2", + }, + { + Partition: "p2", }, }, }, @@ -162,8 +168,12 @@ func TestSamenessGroups_Validate(t *testing.T) { IncludeLocal: true, Members: []SamenessGroupMember{ { - Peer: "dc1", - Partition: "default", + Peer: "peer2", + Partition: "", + }, + { + Peer: "", + Partition: "p2", }, }, }, @@ -171,13 +181,65 @@ func TestSamenessGroups_Validate(t *testing.T) { partitionsEnabled: true, expectedErrMsg: "", }, + "invalid - with peer and partition both": { + input: &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-sameness-group", + }, + Spec: SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []SamenessGroupMember{ + { + Peer: "peer2", + Partition: "p2", + }, + }, + }, + }, + partitionsEnabled: true, + expectedErrMsg: "sameness group members cannot specify both partition and peer in the same entry", + }, + "invalid - no name": { + input: &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{}, + Spec: SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []SamenessGroupMember{ + { + Peer: "peer2", + }, + { + Partition: "p2", + }, + }, + }, + }, + partitionsEnabled: true, + expectedErrMsg: "sameness groups must have a name defined", + }, + "invalid - empty members": { + input: &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-sameness-group", + }, + Spec: SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []SamenessGroupMember{}, + }, + }, + partitionsEnabled: true, + expectedErrMsg: "sameness groups must have at least one member", + }, } for name, testCase := range cases { t.Run(name, func(t *testing.T) { err := testCase.input.Validate(common.ConsulMeta{}) if testCase.expectedErrMsg != "" { - require.EqualError(t, err, testCase.expectedErrMsg) + require.ErrorContains(t, err, testCase.expectedErrMsg) } else { require.NoError(t, err) } diff --git a/control-plane/controllers/configentry_controller_ent_test.go b/control-plane/controllers/configentry_controller_ent_test.go index 10adcebdd7..18c16902d4 100644 --- a/control-plane/controllers/configentry_controller_ent_test.go +++ b/control-plane/controllers/configentry_controller_ent_test.go @@ -34,7 +34,7 @@ import ( // we're only testing with the ServiceDefaults and ProxyDefaults controllers which // will exercise all the namespaces code for config entries that are namespaced and those that // exist in the global namespace. -// We also test Enterprise only features like SamenessGroups +// We also test Enterprise only features like SamenessGroups. func TestConfigEntryController_createsConfigEntry(t *testing.T) { t.Parallel() From b3db2927198b737ba8f025fb2be497a144c7b811 Mon Sep 17 00:00:00 2001 From: Maliz Date: Thu, 13 Apr 2023 16:00:26 -0700 Subject: [PATCH 04/10] fix lint issues --- control-plane/api/v1alpha1/samenessgroups_types.go | 4 ++-- control-plane/controllers/samenessgroups_controller.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/control-plane/api/v1alpha1/samenessgroups_types.go b/control-plane/api/v1alpha1/samenessgroups_types.go index bc7b833695..459af2b118 100644 --- a/control-plane/api/v1alpha1/samenessgroups_types.go +++ b/control-plane/api/v1alpha1/samenessgroups_types.go @@ -42,14 +42,14 @@ type SamenessGroups struct { //+kubebuilder:object:root=true -// SamenessGroupsList contains a list of SamenessGroups +// SamenessGroupsList contains a list of SamenessGroups. type SamenessGroupsList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []SamenessGroups `json:"items"` } -// SamenessGroupsSpec defines the desired state of SamenessGroups +// SamenessGroupsSpec defines the desired state of SamenessGroups. type SamenessGroupsSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file diff --git a/control-plane/controllers/samenessgroups_controller.go b/control-plane/controllers/samenessgroups_controller.go index 5af637fdde..97d4e5230c 100644 --- a/control-plane/controllers/samenessgroups_controller.go +++ b/control-plane/controllers/samenessgroups_controller.go @@ -12,7 +12,7 @@ import ( consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" ) -// SamenessGroupsController reconciles a SamenessGroups object +// SamenessGroupsController reconciles a SamenessGroups object. type SamenessGroupsController struct { client.Client Log logr.Logger From 32da2a9e897946fb7b08d889a9fdbd3f1b770889 Mon Sep 17 00:00:00 2001 From: Maliz Date: Thu, 13 Apr 2023 22:42:47 -0700 Subject: [PATCH 05/10] generate yaml and update helm charts --- CONTRIBUTING.md | 6 +- .../templates/connect-inject-clusterrole.yaml | 2 + ...t-inject-mutatingwebhookconfiguration.yaml | 21 +++ .../consul/templates/crd-proxydefaults.yaml | 14 +- .../consul/templates/crd-samenessgroups.yaml | 126 ++++++++++++++++++ .../templates/crd-serviceresolvers.yaml | 11 +- control-plane/api/v1alpha1/shared_types.go | 6 +- .../consul.hashicorp.com_proxydefaults.yaml | 14 +- .../consul.hashicorp.com_samenessgroups.yaml | 2 +- ...consul.hashicorp.com_serviceresolvers.yaml | 14 +- .../consul_v1alpha1_samenessgroups.yaml | 4 +- 11 files changed, 192 insertions(+), 28 deletions(-) create mode 100644 charts/consul/templates/crd-samenessgroups.yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0a5790e022..3745c80bac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -393,13 +393,13 @@ rebase the branch on main, fixing any conflicts along the way before the code ca ``` ### Updating Helm chart -1. Update `charts/consul/templates/controller-mutatingwebhookconfiguration` with the webhook for this resource +1. Update `charts/consul/templates/connect-inject-mutatingwebhookconfiguration` with the webhook for this resource using the updated `control-plane/config/webhook/manifests.v1beta1.yaml` and replacing `clientConfig.service.name/namespace` with the templated strings shown below to match the other webhooks.: ```yaml - clientConfig: service: - name: {{ template "consul.fullname" . }}-controller-webhook + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} path: /mutate-v1alpha1-ingressgateway failurePolicy: Fail @@ -419,7 +419,7 @@ rebase the branch on main, fixing any conflicts along the way before the code ca - ingressgateways sideEffects: None ``` -1. Update `charts/consul/templates/controller-clusterrole.yaml` to allow the controller to +1. Update `charts/consul/templates/connect-inject-clusterrole.yaml` to allow the controller to manage your resource type. ### Testing A New CRD diff --git a/charts/consul/templates/connect-inject-clusterrole.yaml b/charts/consul/templates/connect-inject-clusterrole.yaml index f2e12f0ad9..e383e5ce28 100644 --- a/charts/consul/templates/connect-inject-clusterrole.yaml +++ b/charts/consul/templates/connect-inject-clusterrole.yaml @@ -24,6 +24,7 @@ rules: - serviceintentions - ingressgateways - terminatinggateways + - samenessgroups {{- if .Values.global.peering.enabled }} - peeringacceptors - peeringdialers @@ -49,6 +50,7 @@ rules: - serviceintentions/status - ingressgateways/status - terminatinggateways/status + - samenessgroups/status {{- if .Values.global.peering.enabled }} - peeringacceptors/status - peeringdialers/status diff --git a/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml b/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml index afcfd3800f..489f20ac18 100644 --- a/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml +++ b/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml @@ -291,5 +291,26 @@ webhooks: admissionReviewVersions: - "v1beta1" - "v1" +- admissionReviewVersions: + - v1beta1 + - v1 + clientConfig: + service: + name: {{ template "consul.fullname" . }}-connect-injector + namespace: {{ .Release.Namespace }} + path: /mutate-v1alpha1-samenessgroups + failurePolicy: Fail + name: mutate-samenessgroups.consul.hashicorp.com + rules: + - apiGroups: + - consul.hashicorp.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - samenessgroups + sideEffects: None {{- end }} {{- end }} diff --git a/charts/consul/templates/crd-proxydefaults.yaml b/charts/consul/templates/crd-proxydefaults.yaml index aaaa3228a1..892451ad4e 100644 --- a/charts/consul/templates/crd-proxydefaults.yaml +++ b/charts/consul/templates/crd-proxydefaults.yaml @@ -143,16 +143,16 @@ spec: type: object type: array type: object - failoverPolicy: - description: FailoverPolicy specifies the exact mechanism used for failover. + failoverPolicy: + description: FailoverPolicy specifies the exact mechanism used for + failover. properties: mode: - description: Mode specifies the type of failover that will be performed. - Valid values are "sequential", "" (equivalent to "sequential") and "order-by-locality". + description: Mode specifies the type of failover that will be + performed. Valid values are "sequential", "" (equivalent to + "sequential") and "order-by-locality". type: string - regions: - description: The ordered list of the regions of the failover targets. - Valid values can be "us-west-1", "us-west-2", and so on. + regions: items: type: string type: array diff --git a/charts/consul/templates/crd-samenessgroups.yaml b/charts/consul/templates/crd-samenessgroups.yaml new file mode 100644 index 0000000000..e85eb5b9be --- /dev/null +++ b/charts/consul/templates/crd-samenessgroups.yaml @@ -0,0 +1,126 @@ +{{- if .Values.connectInject.enabled }} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.8.0 + creationTimestamp: null + name: samenessgroups.consul.hashicorp.com + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: crd +spec: + group: consul.hashicorp.com + names: + kind: SamenessGroups + listKind: SamenessGroupsList + plural: samenessgroups + shortNames: + - sameness-groups + singular: samenessgroups + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The sync status of the resource with Consul + jsonPath: .status.conditions[?(@.type=="Synced")].status + name: Synced + type: string + - description: The last successful synced time of the resource with Consul + jsonPath: .status.lastSyncedTime + name: Last Synced + type: date + - description: The age of the resource + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: SamenessGroups is the Schema for the samenessgroups API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: SamenessGroupsSpec defines the desired state of SamenessGroups. + properties: + defaultForFailover: + description: DefaultForFailover is + type: boolean + includeLocal: + description: IncludeLocal + type: boolean + members: + description: Members + items: + properties: + partition: + type: string + peer: + type: string + type: object + type: array + type: object + status: + properties: + conditions: + description: Conditions indicate the latest available observations + of a resource's current state. + items: + description: 'Conditions define a readiness condition for a Consul + resource. See: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties' + properties: + lastTransitionTime: + description: LastTransitionTime is the last time the condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of condition. + type: string + required: + - status + - type + type: object + type: array + lastSyncedTime: + description: LastSyncedTime is the last time the resource successfully + synced with Consul. + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +{{- end }} diff --git a/charts/consul/templates/crd-serviceresolvers.yaml b/charts/consul/templates/crd-serviceresolvers.yaml index 842506d642..90f4588dde 100644 --- a/charts/consul/templates/crd-serviceresolvers.yaml +++ b/charts/consul/templates/crd-serviceresolvers.yaml @@ -80,15 +80,14 @@ spec: the current namespace is used. type: string policy: - description: FailoverPolicy specifies the exact mechanism used for failover. + description: Policy specifies the exact mechanism used for failover. properties: mode: - description: Mode specifies the type of failover that will be performed. - Valid values are "sequential", "" (equivalent to "sequential") and "order-by-locality". + description: Mode specifies the type of failover that will + be performed. Valid values are "sequential", "" (equivalent + to "sequential") and "order-by-locality". type: string - regions: - description: The ordered list of the regions of the failover targets. - Valid values can be "us-west-1", "us-west-2", and so on. + regions: items: type: string type: array diff --git a/control-plane/api/v1alpha1/shared_types.go b/control-plane/api/v1alpha1/shared_types.go index fdac9a3fea..0c00b8d8a9 100644 --- a/control-plane/api/v1alpha1/shared_types.go +++ b/control-plane/api/v1alpha1/shared_types.go @@ -248,9 +248,9 @@ func (in EnvoyExtension) validate(path *field.Path) *field.Error { // FailoverPolicy specifies the exact mechanism used for failover. type FailoverPolicy struct { // Mode specifies the type of failover that will be performed. Valid values are - // "default", "" (equivalent to "default") and "order-by-locality". - Mode string `json:",omitempty"` - Regions []string `json:",omitempty"` + // "sequential", "" (equivalent to "sequential") and "order-by-locality". + Mode string `json:"mode,omitempty"` + Regions []string `json:"regions,omitempty"` } func (in *FailoverPolicy) toConsul() *capi.ServiceResolverFailoverPolicy { diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml index 0e99844e74..ff2ee17b51 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml @@ -139,9 +139,17 @@ spec: failoverPolicy: description: FailoverPolicy specifies the exact mechanism used for failover. - items: - type: string - type: string + properties: + mode: + description: Mode specifies the type of failover that will be + performed. Valid values are "sequential", "" (equivalent to + "sequential") and "order-by-locality". + type: string + regions: + items: + type: string + type: array + type: object meshGateway: description: MeshGateway controls the default mesh gateway configuration for this service. diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml index 43e23b7bd6..7b7e711f43 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml @@ -48,7 +48,7 @@ spec: metadata: type: object spec: - description: SamenessGroupsSpec defines the desired state of SamenessGroups + description: SamenessGroupsSpec defines the desired state of SamenessGroups. properties: defaultForFailover: description: DefaultForFailover is diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml index f177172e31..3a3313529d 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml @@ -74,9 +74,17 @@ spec: type: string policy: description: Policy specifies the exact mechanism used for failover. - items: - type: string - type: string + properties: + mode: + description: Mode specifies the type of failover that will + be performed. Valid values are "sequential", "" (equivalent + to "sequential") and "order-by-locality". + type: string + regions: + items: + type: string + type: array + type: object service: description: Service is the service to resolve instead of the default as the failover group of instances during failover. diff --git a/control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml b/control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml index f072beba51..151a2b63a8 100644 --- a/control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml +++ b/control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml @@ -6,5 +6,5 @@ spec: defaultForFailover: true includeLocal: true members: - - peer: dc1 - partition: default + - peer: peer2 + - partition: p2 From 97d0f2cfef7aaf89b41fd083c4cd813ce994fbbb Mon Sep 17 00:00:00 2001 From: Maliz Date: Fri, 14 Apr 2023 14:59:52 -0700 Subject: [PATCH 06/10] update field descriptions and validation and its test --- .../consul/templates/crd-samenessgroups.yaml | 6 +-- .../api/v1alpha1/samenessgroups_types.go | 36 +++++++++++++---- .../api/v1alpha1/samenessgroups_types_test.go | 40 +++++++++++++++++++ .../consul.hashicorp.com_samenessgroups.yaml | 6 +-- 4 files changed, 74 insertions(+), 14 deletions(-) diff --git a/charts/consul/templates/crd-samenessgroups.yaml b/charts/consul/templates/crd-samenessgroups.yaml index e85eb5b9be..f2e32866d7 100644 --- a/charts/consul/templates/crd-samenessgroups.yaml +++ b/charts/consul/templates/crd-samenessgroups.yaml @@ -58,13 +58,13 @@ spec: description: SamenessGroupsSpec defines the desired state of SamenessGroups. properties: defaultForFailover: - description: DefaultForFailover is + description: 'DefaultForFailover indicates that upstream requests to members of the given sameness group will implicitly failover between members of this sameness group.' type: boolean includeLocal: - description: IncludeLocal + description: 'IncludeLocal is used to include the local partition as the first member of the sameness group.' type: boolean members: - description: Members + description: 'Members are the partitions and peers that are part of the sameness group.' items: properties: partition: diff --git a/control-plane/api/v1alpha1/samenessgroups_types.go b/control-plane/api/v1alpha1/samenessgroups_types.go index 459af2b118..847524d6fb 100644 --- a/control-plane/api/v1alpha1/samenessgroups_types.go +++ b/control-plane/api/v1alpha1/samenessgroups_types.go @@ -51,14 +51,14 @@ type SamenessGroupsList struct { // SamenessGroupsSpec defines the desired state of SamenessGroups. type SamenessGroupsSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - - // DefaultForFailover is + // DefaultForFailover indicates that upstream requests to members of the given sameness group will implicitly failover between members of this sameness group. + // When DefaultForFailover is true, the local partition must be a member of the sameness group or IncludeLocal must be set to true. DefaultForFailover bool `json:"defaultForFailover,omitempty"` - // IncludeLocal + // IncludeLocal is used to include the local partition as the first member of the sameness group. + // The local partition can only be a member of a single sameness group. IncludeLocal bool `json:"includeLocal,omitempty"` - // Members + // Members are the partitions and peers that are part of the sameness group. + // If a member of a sameness group does not exist, it will be ignored. Members []SamenessGroupMember `json:"members,omitempty"` } @@ -170,23 +170,43 @@ func (in *SamenessGroups) Validate(consulMeta common.ConsulMeta) error { var allErrs field.ErrorList path := field.NewPath("spec") - asJSON, _ := json.Marshal(in) if in == nil { - allErrs = append(allErrs, field.Invalid(path, string(asJSON), "config entry is nil")) + return nil } if in.Name == "" { allErrs = append(allErrs, field.Invalid(path.Child("name"), in.Name, "sameness groups must have a name defined")) } + partition := consulMeta.Partition + includesLocal := in.Spec.IncludeLocal + + if in.ObjectMeta.Namespace != "default" && in.ObjectMeta.Namespace != "" { + allErrs = append(allErrs, field.Invalid(path.Child("name"), consulMeta.DestinationNamespace, "sameness groups must reside in the default namespace")) + } + if len(in.Spec.Members) == 0 { asJSON, _ := json.Marshal(in.Spec.Members) allErrs = append(allErrs, field.Invalid(path.Child("members"), string(asJSON), "sameness groups must have at least one member")) } + seenMembers := make(map[SamenessGroupMember]struct{}) for i, m := range in.Spec.Members { + if partition == m.Partition { + includesLocal = true + } if err := m.validate(path.Child("members").Index(i)); err != nil { allErrs = append(allErrs, err) } + if _, ok := seenMembers[m]; ok { + asJSON, _ := json.Marshal(m) + allErrs = append(allErrs, field.Invalid(path.Child("members").Index(i), string(asJSON), "sameness group members must be unique")) + } + seenMembers[m] = struct{}{} + + } + + if !includesLocal { + allErrs = append(allErrs, field.Invalid(path.Child("members"), in.Spec.IncludeLocal, "the local partition must be a member of sameness groups")) } if len(allErrs) > 0 { diff --git a/control-plane/api/v1alpha1/samenessgroups_types_test.go b/control-plane/api/v1alpha1/samenessgroups_types_test.go index f624800b37..70e8ff9426 100644 --- a/control-plane/api/v1alpha1/samenessgroups_types_test.go +++ b/control-plane/api/v1alpha1/samenessgroups_types_test.go @@ -233,6 +233,46 @@ func TestSamenessGroups_Validate(t *testing.T) { partitionsEnabled: true, expectedErrMsg: "sameness groups must have at least one member", }, + "invalid - not unique members": { + input: &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-sameness-group", + }, + Spec: SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []SamenessGroupMember{ + { + Peer: "peer2", + }, + { + Peer: "peer2", + }, + }, + }, + }, + partitionsEnabled: true, + expectedErrMsg: "sameness group members must be unique", + }, + "invalid - not in default namespace": { + input: &SamenessGroups{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-sameness-group", + Namespace: "non-default", + }, + Spec: SamenessGroupsSpec{ + DefaultForFailover: true, + IncludeLocal: true, + Members: []SamenessGroupMember{ + { + Peer: "peer2", + }, + }, + }, + }, + partitionsEnabled: true, + expectedErrMsg: "sameness groups must reside in the default namespace", + }, } for name, testCase := range cases { diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml index 7b7e711f43..5e3b02e59a 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml @@ -51,13 +51,13 @@ spec: description: SamenessGroupsSpec defines the desired state of SamenessGroups. properties: defaultForFailover: - description: DefaultForFailover is + description: 'DefaultForFailover indicates that upstream requests to members of the given sameness group will implicitly failover between members of this sameness group.' type: boolean includeLocal: - description: IncludeLocal + description: 'IncludeLocal is used to include the local partition as the first member of the sameness group.' type: boolean members: - description: Members + description: 'Members are the partitions and peers that are part of the sameness group.' items: properties: partition: From 3d21c8905de9b61d63b09f5114544f4771438928 Mon Sep 17 00:00:00 2001 From: Maliz Date: Mon, 17 Apr 2023 11:18:32 -0700 Subject: [PATCH 07/10] remove unwanted files, add license comments back --- .../consul/templates/crd-proxydefaults.yaml | 2 ++ .../api/v1alpha1/samenessgroups_types.go | 2 ++ control-plane/api/v1alpha1/shared_types.go | 4 +++- ...consul.hashicorp.com_exportedservices.yaml | 3 +++ .../consul.hashicorp.com_ingressgateways.yaml | 3 +++ .../bases/consul.hashicorp.com_meshes.yaml | 3 +++ ...consul.hashicorp.com_peeringacceptors.yaml | 3 +++ .../consul.hashicorp.com_peeringdialers.yaml | 3 +++ .../consul.hashicorp.com_proxydefaults.yaml | 5 ++++ .../consul.hashicorp.com_samenessgroups.yaml | 3 +++ .../consul.hashicorp.com_servicedefaults.yaml | 3 +++ ...onsul.hashicorp.com_serviceintentions.yaml | 3 +++ ...consul.hashicorp.com_serviceresolvers.yaml | 3 +++ .../consul.hashicorp.com_servicerouters.yaml | 3 +++ ...consul.hashicorp.com_servicesplitters.yaml | 3 +++ ...sul.hashicorp.com_terminatinggateways.yaml | 3 +++ control-plane/config/crd/kustomization.yaml | 21 ---------------- control-plane/config/crd/kustomizeconfig.yaml | 17 ------------- .../cainjection_in_samenessgroups.yaml | 8 ------- .../patches/webhook_in_samenessgroups.yaml | 17 ------------- .../rbac/samenessgroups_editor_role.yaml | 24 ------------------- .../rbac/samenessgroups_viewer_role.yaml | 20 ---------------- .../consul_v1alpha1_samenessgroups.yaml | 10 -------- .../configentry_controller_ent_test.go | 6 ++--- 24 files changed, 51 insertions(+), 121 deletions(-) delete mode 100644 control-plane/config/crd/kustomization.yaml delete mode 100644 control-plane/config/crd/kustomizeconfig.yaml delete mode 100644 control-plane/config/crd/patches/cainjection_in_samenessgroups.yaml delete mode 100644 control-plane/config/crd/patches/webhook_in_samenessgroups.yaml delete mode 100644 control-plane/config/rbac/samenessgroups_editor_role.yaml delete mode 100644 control-plane/config/rbac/samenessgroups_viewer_role.yaml delete mode 100644 control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml diff --git a/charts/consul/templates/crd-proxydefaults.yaml b/charts/consul/templates/crd-proxydefaults.yaml index 892451ad4e..6bb1234066 100644 --- a/charts/consul/templates/crd-proxydefaults.yaml +++ b/charts/consul/templates/crd-proxydefaults.yaml @@ -153,6 +153,8 @@ spec: "sequential") and "order-by-locality". type: string regions: + description: The ordered list of the regions of the failover targets. + Valid values can be "us-west-1", "us-west-2", and so on. items: type: string type: array diff --git a/control-plane/api/v1alpha1/samenessgroups_types.go b/control-plane/api/v1alpha1/samenessgroups_types.go index 847524d6fb..065c76248a 100644 --- a/control-plane/api/v1alpha1/samenessgroups_types.go +++ b/control-plane/api/v1alpha1/samenessgroups_types.go @@ -63,6 +63,8 @@ type SamenessGroupsSpec struct { } type SamenessGroupMember struct { + // The partitions and peers that are part of the sameness group. + // A sameness group member cannot define both peer and partition at the same time. Partition string `json:"partition,omitempty"` Peer string `json:"peer,omitempty"` } diff --git a/control-plane/api/v1alpha1/shared_types.go b/control-plane/api/v1alpha1/shared_types.go index 0c00b8d8a9..98eb3f1b20 100644 --- a/control-plane/api/v1alpha1/shared_types.go +++ b/control-plane/api/v1alpha1/shared_types.go @@ -249,7 +249,9 @@ func (in EnvoyExtension) validate(path *field.Path) *field.Error { type FailoverPolicy struct { // Mode specifies the type of failover that will be performed. Valid values are // "sequential", "" (equivalent to "sequential") and "order-by-locality". - Mode string `json:"mode,omitempty"` + Mode string `json:"mode,omitempty"` + // Regions is the ordered list of the regions of the failover targets. + // Valid values can be "us-west-1", "us-west-2", and so on. Regions []string `json:"regions,omitempty"` } diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml index da1a66fd74..6352ac3af1 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml index 16ac322090..fd8ebc86ff 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml index 7ad173afbf..4850ad152e 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_meshes.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml index e782ef472f..50df179f04 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_peeringacceptors.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml index d5103252a5..01e4363f14 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_peeringdialers.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml index ff2ee17b51..c66b5fdd0f 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition @@ -146,6 +149,8 @@ spec: "sequential") and "order-by-locality". type: string regions: + description: The ordered list of the regions of the failover targets. + Valid values can be "us-west-1", "us-west-2", and so on. items: type: string type: array diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml index 5e3b02e59a..bd49205a98 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml index 4f335a923d..7744a8fe7a 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml index a0cc7a6343..8e186af1a7 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml index 3a3313529d..9a2711383d 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml index de071bd0ef..5b9c9d3c1f 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml index df8bbbfbdf..aa2b592c94 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml index 8e6c449ef8..b465cd9494 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml @@ -1,3 +1,6 @@ +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + --- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition diff --git a/control-plane/config/crd/kustomization.yaml b/control-plane/config/crd/kustomization.yaml deleted file mode 100644 index b20f5e9f96..0000000000 --- a/control-plane/config/crd/kustomization.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# This kustomization.yaml is not intended to be run by itself, -# since it depends on service name and namespace that are out of this kustomize package. -# It should be run by config/default -resources: -- bases/consul.hashicorp.com_samenessgroups.yaml -#+kubebuilder:scaffold:crdkustomizeresource - -patchesStrategicMerge: -# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. -# patches here are for enabling the conversion webhook for each CRD -- patches/webhook_in_samenessgroups.yaml -#+kubebuilder:scaffold:crdkustomizewebhookpatch - -# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. -# patches here are for enabling the CA injection for each CRD -#- patches/cainjection_in_samenessgroups.yaml -#+kubebuilder:scaffold:crdkustomizecainjectionpatch - -# the following config is for teaching kustomize how to do kustomization for CRDs. -configurations: -- kustomizeconfig.yaml diff --git a/control-plane/config/crd/kustomizeconfig.yaml b/control-plane/config/crd/kustomizeconfig.yaml deleted file mode 100644 index 6f83d9a94b..0000000000 --- a/control-plane/config/crd/kustomizeconfig.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# This file is for teaching kustomize how to substitute name and namespace reference in CRD -nameReference: -- kind: Service - version: v1 - fieldSpecs: - - kind: CustomResourceDefinition - group: apiextensions.k8s.io - path: spec/conversion/webhookClientConfig/service/name - -namespace: -- kind: CustomResourceDefinition - group: apiextensions.k8s.io - path: spec/conversion/webhookClientConfig/service/namespace - create: false - -varReference: -- path: metadata/annotations diff --git a/control-plane/config/crd/patches/cainjection_in_samenessgroups.yaml b/control-plane/config/crd/patches/cainjection_in_samenessgroups.yaml deleted file mode 100644 index 65471762e1..0000000000 --- a/control-plane/config/crd/patches/cainjection_in_samenessgroups.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# The following patch adds a directive for certmanager to inject CA into the CRD -# CRD conversion requires k8s 1.13 or later. -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) - name: samenessgroups.consul.hashicorp.com diff --git a/control-plane/config/crd/patches/webhook_in_samenessgroups.yaml b/control-plane/config/crd/patches/webhook_in_samenessgroups.yaml deleted file mode 100644 index 6e385469d3..0000000000 --- a/control-plane/config/crd/patches/webhook_in_samenessgroups.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# The following patch enables conversion webhook for CRD -# CRD conversion requires k8s 1.13 or later. -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - name: samenessgroups.consul.hashicorp.com -spec: - conversion: - strategy: Webhook - webhookClientConfig: - # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, - # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) - caBundle: Cg== - service: - namespace: system - name: webhook-service - path: /convert diff --git a/control-plane/config/rbac/samenessgroups_editor_role.yaml b/control-plane/config/rbac/samenessgroups_editor_role.yaml deleted file mode 100644 index 7d7055ffae..0000000000 --- a/control-plane/config/rbac/samenessgroups_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit samenessgroups. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: samenessgroups-editor-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - samenessgroups - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - samenessgroups/status - verbs: - - get diff --git a/control-plane/config/rbac/samenessgroups_viewer_role.yaml b/control-plane/config/rbac/samenessgroups_viewer_role.yaml deleted file mode 100644 index 874253f83b..0000000000 --- a/control-plane/config/rbac/samenessgroups_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view samenessgroups. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: samenessgroups-viewer-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - samenessgroups - verbs: - - get - - list - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - samenessgroups/status - verbs: - - get diff --git a/control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml b/control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml deleted file mode 100644 index 151a2b63a8..0000000000 --- a/control-plane/config/samples/consul_v1alpha1_samenessgroups.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: consul.hashicorp.com/v1alpha1 -kind: SamenessGroups -metadata: - name: samenessgroups-sample -spec: - defaultForFailover: true - includeLocal: true - members: - - peer: peer2 - - partition: p2 diff --git a/control-plane/controllers/configentry_controller_ent_test.go b/control-plane/controllers/configentry_controller_ent_test.go index 18c16902d4..10a0a93ef3 100644 --- a/control-plane/controllers/configentry_controller_ent_test.go +++ b/control-plane/controllers/configentry_controller_ent_test.go @@ -36,7 +36,7 @@ import ( // exist in the global namespace. // We also test Enterprise only features like SamenessGroups. -func TestConfigEntryController_createsConfigEntry(t *testing.T) { +func TestConfigEntryController_createsEntConfigEntry(t *testing.T) { t.Parallel() kubeNS := "default" @@ -135,7 +135,7 @@ func TestConfigEntryController_createsConfigEntry(t *testing.T) { } } -func TestConfigEntryController_updatesConfigEntry(t *testing.T) { +func TestConfigEntryController_updatesEntConfigEntry(t *testing.T) { t.Parallel() kubeNS := "default" @@ -252,7 +252,7 @@ func TestConfigEntryController_updatesConfigEntry(t *testing.T) { } } -func TestConfigEntryController_deletesConfigEntry(t *testing.T) { +func TestConfigEntryController_deletesEntConfigEntry(t *testing.T) { t.Parallel() kubeNS := "default" From 0b295d08e749fa106a7a9ec9c73bab7197fe8f82 Mon Sep 17 00:00:00 2001 From: Maliz Date: Mon, 17 Apr 2023 20:15:52 -0700 Subject: [PATCH 08/10] rename samenessgroups to samenessgroup --- ...t-inject-mutatingwebhookconfiguration.yaml | 4 +- .../consul/templates/crd-samenessgroups.yaml | 14 ++-- .../templates/crd-serviceresolvers.yaml | 2 + control-plane/PROJECT | 2 +- control-plane/api/common/common.go | 2 +- ...groups_types.go => samenessgroup_types.go} | 63 ++++++++-------- ...es_test.go => samenessgroup_types_test.go} | 72 +++++++++---------- ...ps_webhook.go => samenessgroup_webhook.go} | 14 ++-- .../api/v1alpha1/zz_generated.deepcopy.go | 28 ++++---- .../consul.hashicorp.com_samenessgroups.yaml | 14 ++-- ...consul.hashicorp.com_serviceresolvers.yaml | 2 + control-plane/config/webhook/manifests.yaml | 4 +- .../configentry_controller_ent_test.go | 26 +++---- .../controllers/samenessgroups_controller.go | 16 ++--- .../subcommand/inject-connect/command.go | 12 ++-- 15 files changed, 139 insertions(+), 136 deletions(-) rename control-plane/api/v1alpha1/{samenessgroups_types.go => samenessgroup_types.go} (79%) rename control-plane/api/v1alpha1/{samenessgroups_types_test.go => samenessgroup_types_test.go} (85%) rename control-plane/api/v1alpha1/{samenessgroups_webhook.go => samenessgroup_webhook.go} (76%) diff --git a/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml b/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml index 489f20ac18..b68efdb9f8 100644 --- a/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml +++ b/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml @@ -298,9 +298,9 @@ webhooks: service: name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} - path: /mutate-v1alpha1-samenessgroups + path: /mutate-v1alpha1-samenessgroup failurePolicy: Fail - name: mutate-samenessgroups.consul.hashicorp.com + name: mutate-samenessgroup.consul.hashicorp.com rules: - apiGroups: - consul.hashicorp.com diff --git a/charts/consul/templates/crd-samenessgroups.yaml b/charts/consul/templates/crd-samenessgroups.yaml index f2e32866d7..df206f2a8c 100644 --- a/charts/consul/templates/crd-samenessgroups.yaml +++ b/charts/consul/templates/crd-samenessgroups.yaml @@ -6,7 +6,7 @@ metadata: annotations: controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null - name: samenessgroups.consul.hashicorp.com + name: samenessgroup.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} @@ -16,12 +16,12 @@ metadata: spec: group: consul.hashicorp.com names: - kind: SamenessGroups - listKind: SamenessGroupsList + kind: SamenessGroup + listKind: SamenessGroupList plural: samenessgroups shortNames: - - sameness-groups - singular: samenessgroups + - sameness-group + singular: samenessgroup scope: Namespaced versions: - additionalPrinterColumns: @@ -40,7 +40,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: SamenessGroups is the Schema for the samenessgroups API + description: SamenessGroup is the Schema for the samenessgroups API properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation @@ -55,7 +55,7 @@ spec: metadata: type: object spec: - description: SamenessGroupsSpec defines the desired state of SamenessGroups. + description: SamenessGroupSpec defines the desired state of SamenessGroup. properties: defaultForFailover: description: 'DefaultForFailover indicates that upstream requests to members of the given sameness group will implicitly failover between members of this sameness group.' diff --git a/charts/consul/templates/crd-serviceresolvers.yaml b/charts/consul/templates/crd-serviceresolvers.yaml index 90f4588dde..1942b79b8f 100644 --- a/charts/consul/templates/crd-serviceresolvers.yaml +++ b/charts/consul/templates/crd-serviceresolvers.yaml @@ -88,6 +88,8 @@ spec: to "sequential") and "order-by-locality". type: string regions: + description: The ordered list of the regions of the failover targets. + Valid values can be "us-west-1", "us-west-2", and so on. items: type: string type: array diff --git a/control-plane/PROJECT b/control-plane/PROJECT index cfe6b1e621..eb653ad34a 100644 --- a/control-plane/PROJECT +++ b/control-plane/PROJECT @@ -87,7 +87,7 @@ resources: controller: true domain: hashicorp.com group: consul - kind: SamenessGroups + kind: SamenessGroup path: github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1 version: v1alpha1 version: "3" diff --git a/control-plane/api/common/common.go b/control-plane/api/common/common.go index 1c9283dc3e..4faeccada1 100644 --- a/control-plane/api/common/common.go +++ b/control-plane/api/common/common.go @@ -14,7 +14,7 @@ const ( ExportedServices string = "exportedservices" IngressGateway string = "ingressgateway" TerminatingGateway string = "terminatinggateway" - SamenessGroups string = "samenessgroups" + SamenessGroup string = "samenessgroup" Global string = "global" Mesh string = "mesh" diff --git a/control-plane/api/v1alpha1/samenessgroups_types.go b/control-plane/api/v1alpha1/samenessgroup_types.go similarity index 79% rename from control-plane/api/v1alpha1/samenessgroups_types.go rename to control-plane/api/v1alpha1/samenessgroup_types.go index 065c76248a..7f5f194150 100644 --- a/control-plane/api/v1alpha1/samenessgroups_types.go +++ b/control-plane/api/v1alpha1/samenessgroup_types.go @@ -15,42 +15,42 @@ import ( ) const ( - SamenessGroupsKubeKind string = "samenessgroups" + SamenessGroupKubeKind string = "samenessgroup" ) // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. func init() { - SchemeBuilder.Register(&SamenessGroups{}, &SamenessGroupsList{}) + SchemeBuilder.Register(&SamenessGroup{}, &SamenessGroupList{}) } //+kubebuilder:object:root=true //+kubebuilder:subresource:status -// SamenessGroups is the Schema for the samenessgroups API +// SamenessGroup is the Schema for the samenessgroups API // +kubebuilder:printcolumn:name="Synced",type="string",JSONPath=".status.conditions[?(@.type==\"Synced\")].status",description="The sync status of the resource with Consul" // +kubebuilder:printcolumn:name="Last Synced",type="date",JSONPath=".status.lastSyncedTime",description="The last successful synced time of the resource with Consul" // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="The age of the resource" -// +kubebuilder:resource:shortName="sameness-groups" -type SamenessGroups struct { +// +kubebuilder:resource:shortName="sameness-group" +type SamenessGroup struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec SamenessGroupsSpec `json:"spec,omitempty"` + Spec SamenessGroupSpec `json:"spec,omitempty"` Status `json:"status,omitempty"` } //+kubebuilder:object:root=true -// SamenessGroupsList contains a list of SamenessGroups. -type SamenessGroupsList struct { +// SamenessGroupList contains a list of SamenessGroup. +type SamenessGroupList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []SamenessGroups `json:"items"` + Items []SamenessGroup `json:"items"` } -// SamenessGroupsSpec defines the desired state of SamenessGroups. -type SamenessGroupsSpec struct { +// SamenessGroupSpec defines the desired state of SamenessGroup. +type SamenessGroupSpec struct { // DefaultForFailover indicates that upstream requests to members of the given sameness group will implicitly failover between members of this sameness group. // When DefaultForFailover is true, the local partition must be a member of the sameness group or IncludeLocal must be set to true. DefaultForFailover bool `json:"defaultForFailover,omitempty"` @@ -69,15 +69,15 @@ type SamenessGroupMember struct { Peer string `json:"peer,omitempty"` } -func (in *SamenessGroups) GetObjectMeta() metav1.ObjectMeta { +func (in *SamenessGroup) GetObjectMeta() metav1.ObjectMeta { return in.ObjectMeta } -func (in *SamenessGroups) AddFinalizer(name string) { +func (in *SamenessGroup) AddFinalizer(name string) { in.ObjectMeta.Finalizers = append(in.Finalizers(), name) } -func (in *SamenessGroups) RemoveFinalizer(name string) { +func (in *SamenessGroup) RemoveFinalizer(name string) { var newFinalizers []string for _, oldF := range in.Finalizers() { if oldF != name { @@ -87,35 +87,35 @@ func (in *SamenessGroups) RemoveFinalizer(name string) { in.ObjectMeta.Finalizers = newFinalizers } -func (in *SamenessGroups) Finalizers() []string { +func (in *SamenessGroup) Finalizers() []string { return in.ObjectMeta.Finalizers } -func (in *SamenessGroups) ConsulKind() string { +func (in *SamenessGroup) ConsulKind() string { return capi.SamenessGroup } -func (in *SamenessGroups) ConsulGlobalResource() bool { +func (in *SamenessGroup) ConsulGlobalResource() bool { return false } -func (in *SamenessGroups) ConsulMirroringNS() string { +func (in *SamenessGroup) ConsulMirroringNS() string { return common.DefaultConsulNamespace } -func (in *SamenessGroups) KubeKind() string { - return SamenessGroupsKubeKind +func (in *SamenessGroup) KubeKind() string { + return SamenessGroupKubeKind } -func (in *SamenessGroups) ConsulName() string { +func (in *SamenessGroup) ConsulName() string { return in.ObjectMeta.Name } -func (in *SamenessGroups) KubernetesName() string { +func (in *SamenessGroup) KubernetesName() string { return in.ObjectMeta.Name } -func (in *SamenessGroups) SetSyncedCondition(status corev1.ConditionStatus, reason, message string) { +func (in *SamenessGroup) SetSyncedCondition(status corev1.ConditionStatus, reason, message string) { in.Status.Conditions = Conditions{ { Type: ConditionSynced, @@ -127,11 +127,11 @@ func (in *SamenessGroups) SetSyncedCondition(status corev1.ConditionStatus, reas } } -func (in *SamenessGroups) SetLastSyncedTime(time *metav1.Time) { +func (in *SamenessGroup) SetLastSyncedTime(time *metav1.Time) { in.Status.LastSyncedTime = time } -func (in *SamenessGroups) SyncedCondition() (status corev1.ConditionStatus, reason, message string) { +func (in *SamenessGroup) SyncedCondition() (status corev1.ConditionStatus, reason, message string) { cond := in.Status.GetCondition(ConditionSynced) if cond == nil { return corev1.ConditionUnknown, "", "" @@ -139,7 +139,7 @@ func (in *SamenessGroups) SyncedCondition() (status corev1.ConditionStatus, reas return cond.Status, cond.Reason, cond.Message } -func (in *SamenessGroups) SyncedConditionStatus() corev1.ConditionStatus { +func (in *SamenessGroup) SyncedConditionStatus() corev1.ConditionStatus { cond := in.Status.GetCondition(ConditionSynced) if cond == nil { return corev1.ConditionUnknown @@ -147,8 +147,7 @@ func (in *SamenessGroups) SyncedConditionStatus() corev1.ConditionStatus { return cond.Status } -func (in *SamenessGroups) ToConsul(datacenter string) api.ConfigEntry { - //consulConfig := in.convertConfig() +func (in *SamenessGroup) ToConsul(datacenter string) api.ConfigEntry { return &capi.SamenessGroupConfigEntry{ Kind: in.ConsulKind(), Name: in.ConsulName(), @@ -159,7 +158,7 @@ func (in *SamenessGroups) ToConsul(datacenter string) api.ConfigEntry { } } -func (in *SamenessGroups) MatchesConsul(candidate api.ConfigEntry) bool { +func (in *SamenessGroup) MatchesConsul(candidate api.ConfigEntry) bool { configEntry, ok := candidate.(*capi.SamenessGroupConfigEntry) if !ok { return false @@ -168,7 +167,7 @@ func (in *SamenessGroups) MatchesConsul(candidate api.ConfigEntry) bool { cmp.Comparer(transparentProxyConfigComparer)) } -func (in *SamenessGroups) Validate(consulMeta common.ConsulMeta) error { +func (in *SamenessGroup) Validate(consulMeta common.ConsulMeta) error { var allErrs field.ErrorList path := field.NewPath("spec") @@ -213,7 +212,7 @@ func (in *SamenessGroups) Validate(consulMeta common.ConsulMeta) error { if len(allErrs) > 0 { return apierrors.NewInvalid( - schema.GroupKind{Group: ConsulHashicorpGroup, Kind: SamenessGroupsKubeKind}, + schema.GroupKind{Group: ConsulHashicorpGroup, Kind: SamenessGroupKubeKind}, in.KubernetesName(), allErrs) } @@ -221,7 +220,7 @@ func (in *SamenessGroups) Validate(consulMeta common.ConsulMeta) error { } // DefaultNamespaceFields has no behaviour here as sameness-groups have no namespace specific fields. -func (in *SamenessGroups) DefaultNamespaceFields(_ common.ConsulMeta) { +func (in *SamenessGroup) DefaultNamespaceFields(_ common.ConsulMeta) { } type SamenessGroupMembers []SamenessGroupMember diff --git a/control-plane/api/v1alpha1/samenessgroups_types_test.go b/control-plane/api/v1alpha1/samenessgroup_types_test.go similarity index 85% rename from control-plane/api/v1alpha1/samenessgroups_types_test.go rename to control-plane/api/v1alpha1/samenessgroup_types_test.go index 70e8ff9426..bcd359293b 100644 --- a/control-plane/api/v1alpha1/samenessgroups_types_test.go +++ b/control-plane/api/v1alpha1/samenessgroup_types_test.go @@ -15,15 +15,15 @@ import ( func TestSamenessGroups_ToConsul(t *testing.T) { cases := map[string]struct { - input *SamenessGroups + input *SamenessGroup expected *capi.SamenessGroupConfigEntry }{ "empty fields": { - &SamenessGroups{ + &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", }, - Spec: SamenessGroupsSpec{}, + Spec: SamenessGroupSpec{}, }, &capi.SamenessGroupConfigEntry{ Name: "foo", @@ -35,11 +35,11 @@ func TestSamenessGroups_ToConsul(t *testing.T) { }, }, "every field set": { - &SamenessGroups{ + &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", }, - Spec: SamenessGroupsSpec{ + Spec: SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []SamenessGroupMember{ @@ -82,16 +82,16 @@ func TestSamenessGroups_ToConsul(t *testing.T) { func TestSamenessGroups_MatchesConsul(t *testing.T) { cases := map[string]struct { - internal *SamenessGroups + internal *SamenessGroup consul capi.ConfigEntry matches bool }{ "empty fields matches": { - &SamenessGroups{ + &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "my-test-sameness-group", }, - Spec: SamenessGroupsSpec{}, + Spec: SamenessGroupSpec{}, }, &capi.SamenessGroupConfigEntry{ Kind: capi.SamenessGroup, @@ -106,11 +106,11 @@ func TestSamenessGroups_MatchesConsul(t *testing.T) { true, }, "all fields populated matches": { - &SamenessGroups{ + &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "my-test-sameness-group", }, - Spec: SamenessGroupsSpec{ + Spec: SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []SamenessGroupMember{ @@ -154,16 +154,16 @@ func TestSamenessGroups_MatchesConsul(t *testing.T) { func TestSamenessGroups_Validate(t *testing.T) { cases := map[string]struct { - input *SamenessGroups + input *SamenessGroup partitionsEnabled bool expectedErrMsg string }{ "valid": { - input: &SamenessGroups{ + input: &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "my-sameness-group", }, - Spec: SamenessGroupsSpec{ + Spec: SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []SamenessGroupMember{ @@ -182,11 +182,11 @@ func TestSamenessGroups_Validate(t *testing.T) { expectedErrMsg: "", }, "invalid - with peer and partition both": { - input: &SamenessGroups{ + input: &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "my-sameness-group", }, - Spec: SamenessGroupsSpec{ + Spec: SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []SamenessGroupMember{ @@ -201,9 +201,9 @@ func TestSamenessGroups_Validate(t *testing.T) { expectedErrMsg: "sameness group members cannot specify both partition and peer in the same entry", }, "invalid - no name": { - input: &SamenessGroups{ + input: &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{}, - Spec: SamenessGroupsSpec{ + Spec: SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []SamenessGroupMember{ @@ -220,11 +220,11 @@ func TestSamenessGroups_Validate(t *testing.T) { expectedErrMsg: "sameness groups must have a name defined", }, "invalid - empty members": { - input: &SamenessGroups{ + input: &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "my-sameness-group", }, - Spec: SamenessGroupsSpec{ + Spec: SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []SamenessGroupMember{}, @@ -234,11 +234,11 @@ func TestSamenessGroups_Validate(t *testing.T) { expectedErrMsg: "sameness groups must have at least one member", }, "invalid - not unique members": { - input: &SamenessGroups{ + input: &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "my-sameness-group", }, - Spec: SamenessGroupsSpec{ + Spec: SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []SamenessGroupMember{ @@ -255,12 +255,12 @@ func TestSamenessGroups_Validate(t *testing.T) { expectedErrMsg: "sameness group members must be unique", }, "invalid - not in default namespace": { - input: &SamenessGroups{ + input: &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "my-sameness-group", Namespace: "non-default", }, - Spec: SamenessGroupsSpec{ + Spec: SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []SamenessGroupMember{ @@ -291,20 +291,20 @@ func TestSamenessGroups_GetObjectMeta(t *testing.T) { meta := metav1.ObjectMeta{ Name: "name", } - samenessGroups := &SamenessGroups{ + samenessGroups := &SamenessGroup{ ObjectMeta: meta, } require.Equal(t, meta, samenessGroups.GetObjectMeta()) } func TestSamenessGroups_AddFinalizer(t *testing.T) { - samenessGroups := &SamenessGroups{} + samenessGroups := &SamenessGroup{} samenessGroups.AddFinalizer("finalizer") require.Equal(t, []string{"finalizer"}, samenessGroups.ObjectMeta.Finalizers) } func TestSamenessGroups_RemoveFinalizer(t *testing.T) { - samenessGroups := &SamenessGroups{ + samenessGroups := &SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Finalizers: []string{"f1", "f2"}, }, @@ -314,11 +314,11 @@ func TestSamenessGroups_RemoveFinalizer(t *testing.T) { } func TestSamenessGroups_ConsulKind(t *testing.T) { - require.Equal(t, capi.SamenessGroup, (&SamenessGroups{}).ConsulKind()) + require.Equal(t, capi.SamenessGroup, (&SamenessGroup{}).ConsulKind()) } func TestSamenessGroups_ConsulGlobalResource(t *testing.T) { - require.False(t, (&SamenessGroups{}).ConsulGlobalResource()) + require.False(t, (&SamenessGroup{}).ConsulGlobalResource()) } func TestSamenessGroups_ConsulMirroringNS(t *testing.T) { @@ -326,19 +326,19 @@ func TestSamenessGroups_ConsulMirroringNS(t *testing.T) { } func TestSamenessGroups_KubeKind(t *testing.T) { - require.Equal(t, "samenessgroups", (&SamenessGroups{}).KubeKind()) + require.Equal(t, "samenessgroups", (&SamenessGroup{}).KubeKind()) } func TestSamenessGroups_ConsulName(t *testing.T) { - require.Equal(t, "foo", (&SamenessGroups{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) + require.Equal(t, "foo", (&SamenessGroup{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) } func TestSamenessGroups_KubernetesName(t *testing.T) { - require.Equal(t, "foo", (&SamenessGroups{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) + require.Equal(t, "foo", (&SamenessGroup{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) } func TestSamenessGroups_SetSyncedCondition(t *testing.T) { - samenessGroups := &SamenessGroups{} + samenessGroups := &SamenessGroup{} samenessGroups.SetSyncedCondition(corev1.ConditionTrue, "reason", "message") require.Equal(t, corev1.ConditionTrue, samenessGroups.Status.Conditions[0].Status) @@ -349,7 +349,7 @@ func TestSamenessGroups_SetSyncedCondition(t *testing.T) { } func TestSamenessGroups_SetLastSyncedTime(t *testing.T) { - samenessGroups := &SamenessGroups{} + samenessGroups := &SamenessGroup{} syncedTime := metav1.NewTime(time.Now()) samenessGroups.SetLastSyncedTime(&syncedTime) @@ -364,7 +364,7 @@ func TestSamenessGroups_GetSyncedConditionStatus(t *testing.T) { } for _, status := range cases { t.Run(string(status), func(t *testing.T) { - samenessGroups := &SamenessGroups{ + samenessGroups := &SamenessGroup{ Status: Status{ Conditions: []Condition{{ Type: ConditionSynced, @@ -379,11 +379,11 @@ func TestSamenessGroups_GetSyncedConditionStatus(t *testing.T) { } func TestSamenessGroups_SyncedConditionStatusWhenStatusNil(t *testing.T) { - require.Equal(t, corev1.ConditionUnknown, (&SamenessGroups{}).SyncedConditionStatus()) + require.Equal(t, corev1.ConditionUnknown, (&SamenessGroup{}).SyncedConditionStatus()) } func TestSamenessGroups_SyncedConditionWhenStatusNil(t *testing.T) { - status, reason, message := (&SamenessGroups{}).SyncedCondition() + status, reason, message := (&SamenessGroup{}).SyncedCondition() require.Equal(t, corev1.ConditionUnknown, status) require.Equal(t, "", reason) require.Equal(t, "", message) diff --git a/control-plane/api/v1alpha1/samenessgroups_webhook.go b/control-plane/api/v1alpha1/samenessgroup_webhook.go similarity index 76% rename from control-plane/api/v1alpha1/samenessgroups_webhook.go rename to control-plane/api/v1alpha1/samenessgroup_webhook.go index c7bbe9adf1..6c1da5cba2 100644 --- a/control-plane/api/v1alpha1/samenessgroups_webhook.go +++ b/control-plane/api/v1alpha1/samenessgroup_webhook.go @@ -15,7 +15,7 @@ import ( // +kubebuilder:object:generate=false -type SamenessGroupsWebhook struct { +type SamenessGroupWebhook struct { Logger logr.Logger // ConsulMeta contains metadata specific to the Consul installation. @@ -31,10 +31,10 @@ type SamenessGroupsWebhook struct { // // NOTE: The below line cannot be combined with any other comment. If it is it will break the code generation. // -// +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-samenessgroups,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=samenessgroups,versions=v1alpha1,name=mutate-samenessgroups.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 +// +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-samenessgroups,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=samenessgroups,versions=v1alpha1,name=mutate-samenessgroup.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 -func (v *SamenessGroupsWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { - var resource SamenessGroups +func (v *SamenessGroupWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { + var resource SamenessGroup err := v.decoder.Decode(req, &resource) if err != nil { return admission.Errored(http.StatusBadRequest, err) @@ -43,8 +43,8 @@ func (v *SamenessGroupsWebhook) Handle(ctx context.Context, req admission.Reques return common.ValidateConfigEntry(ctx, req, v.Logger, v, &resource, v.ConsulMeta) } -func (v *SamenessGroupsWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { - var resourceList SamenessGroupsList +func (v *SamenessGroupWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { + var resourceList SamenessGroupList if err := v.Client.List(ctx, &resourceList); err != nil { return nil, err } @@ -55,7 +55,7 @@ func (v *SamenessGroupsWebhook) List(ctx context.Context) ([]common.ConfigEntryR return entries, nil } -func (v *SamenessGroupsWebhook) InjectDecoder(d *admission.Decoder) error { +func (v *SamenessGroupWebhook) InjectDecoder(d *admission.Decoder) error { v.decoder = d return nil } diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index fdc82be6b3..f485b5c5f1 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -1340,7 +1340,7 @@ func (in *SamenessGroupMember) DeepCopy() *SamenessGroupMember { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SamenessGroups) DeepCopyInto(out *SamenessGroups) { +func (in *SamenessGroup) DeepCopyInto(out *SamenessGroup) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) @@ -1349,17 +1349,17 @@ func (in *SamenessGroups) DeepCopyInto(out *SamenessGroups) { } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroups. -func (in *SamenessGroups) DeepCopy() *SamenessGroups { +func (in *SamenessGroup) DeepCopy() *SamenessGroup { if in == nil { return nil } - out := new(SamenessGroups) + out := new(SamenessGroup) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SamenessGroups) DeepCopyObject() runtime.Object { +func (in *SamenessGroup) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1367,31 +1367,31 @@ func (in *SamenessGroups) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SamenessGroupsList) DeepCopyInto(out *SamenessGroupsList) { +func (in *SamenessGroupList) DeepCopyInto(out *SamenessGroupList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]SamenessGroups, len(*in)) + *out = make([]SamenessGroup, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupsList. -func (in *SamenessGroupsList) DeepCopy() *SamenessGroupsList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupList. +func (in *SamenessGroupList) DeepCopy() *SamenessGroupList { if in == nil { return nil } - out := new(SamenessGroupsList) + out := new(SamenessGroupList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *SamenessGroupsList) DeepCopyObject() runtime.Object { +func (in *SamenessGroupList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -1399,7 +1399,7 @@ func (in *SamenessGroupsList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SamenessGroupsSpec) DeepCopyInto(out *SamenessGroupsSpec) { +func (in *SamenessGroupSpec) DeepCopyInto(out *SamenessGroupSpec) { *out = *in if in.Members != nil { in, out := &in.Members, &out.Members @@ -1408,12 +1408,12 @@ func (in *SamenessGroupsSpec) DeepCopyInto(out *SamenessGroupsSpec) { } } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupsSpec. -func (in *SamenessGroupsSpec) DeepCopy() *SamenessGroupsSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SamenessGroupSpec. +func (in *SamenessGroupSpec) DeepCopy() *SamenessGroupSpec { if in == nil { return nil } - out := new(SamenessGroupsSpec) + out := new(SamenessGroupSpec) in.DeepCopyInto(out) return out } diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml index bd49205a98..84174cbcb3 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml @@ -8,16 +8,16 @@ metadata: annotations: controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null - name: samenessgroups.consul.hashicorp.com + name: samenessgroup.consul.hashicorp.com spec: group: consul.hashicorp.com names: - kind: SamenessGroups - listKind: SamenessGroupsList + kind: SamenessGroup + listKind: SamenessGroupList plural: samenessgroups shortNames: - - sameness-groups - singular: samenessgroups + - sameness-group + singular: samenessgroup scope: Namespaced versions: - additionalPrinterColumns: @@ -36,7 +36,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: SamenessGroups is the Schema for the samenessgroups API + description: SamenessGroup is the Schema for the samenessgroups API properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation @@ -51,7 +51,7 @@ spec: metadata: type: object spec: - description: SamenessGroupsSpec defines the desired state of SamenessGroups. + description: SamenessGroupSpec defines the desired state of SamenessGroup. properties: defaultForFailover: description: 'DefaultForFailover indicates that upstream requests to members of the given sameness group will implicitly failover between members of this sameness group.' diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml index 9a2711383d..56b5e72014 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml @@ -84,6 +84,8 @@ spec: to "sequential") and "order-by-locality". type: string regions: + description: The ordered list of the regions of the failover targets. + Valid values can be "us-west-1", "us-west-2", and so on. items: type: string type: array diff --git a/control-plane/config/webhook/manifests.yaml b/control-plane/config/webhook/manifests.yaml index b0787f4a43..f96d669544 100644 --- a/control-plane/config/webhook/manifests.yaml +++ b/control-plane/config/webhook/manifests.yaml @@ -138,9 +138,9 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-v1alpha1-samenessgroups + path: /mutate-v1alpha1-samenessgroup failurePolicy: Fail - name: mutate-samenessgroups.consul.hashicorp.com + name: mutate-samenessgroup.consul.hashicorp.com rules: - apiGroups: - consul.hashicorp.com diff --git a/control-plane/controllers/configentry_controller_ent_test.go b/control-plane/controllers/configentry_controller_ent_test.go index 10a0a93ef3..ef2aa6b7a4 100644 --- a/control-plane/controllers/configentry_controller_ent_test.go +++ b/control-plane/controllers/configentry_controller_ent_test.go @@ -49,14 +49,14 @@ func TestConfigEntryController_createsEntConfigEntry(t *testing.T) { compare func(t *testing.T, consul capi.ConfigEntry) }{ { - kubeKind: "SamenessGroups", + kubeKind: "SamenessGroup", consulKind: capi.SamenessGroup, - configEntryResource: &v1alpha1.SamenessGroups{ + configEntryResource: &v1alpha1.SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: kubeNS, }, - Spec: v1alpha1.SamenessGroupsSpec{ + Spec: v1alpha1.SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []v1alpha1.SamenessGroupMember{ @@ -68,7 +68,7 @@ func TestConfigEntryController_createsEntConfigEntry(t *testing.T) { }, }, reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &SamenessGroupsController{ + return &SamenessGroupController{ Client: client, Log: logger, ConfigEntryController: &ConfigEntryController{ @@ -149,14 +149,14 @@ func TestConfigEntryController_updatesEntConfigEntry(t *testing.T) { compare func(t *testing.T, consul capi.ConfigEntry) }{ { - kubeKind: "SamenessGroups", + kubeKind: "SamenessGroup", consulKind: capi.SamenessGroup, - configEntryResource: &v1alpha1.SamenessGroups{ + configEntryResource: &v1alpha1.SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: kubeNS, }, - Spec: v1alpha1.SamenessGroupsSpec{ + Spec: v1alpha1.SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []v1alpha1.SamenessGroupMember{ @@ -168,7 +168,7 @@ func TestConfigEntryController_updatesEntConfigEntry(t *testing.T) { }, }, reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &SamenessGroupsController{ + return &SamenessGroupController{ Client: client, Log: logger, ConfigEntryController: &ConfigEntryController{ @@ -179,7 +179,7 @@ func TestConfigEntryController_updatesEntConfigEntry(t *testing.T) { } }, updateF: func(resource common.ConfigEntryResource) { - sg := resource.(*v1alpha1.SamenessGroups) + sg := resource.(*v1alpha1.SamenessGroup) sg.Spec.IncludeLocal = false }, compare: func(t *testing.T, consulEntry capi.ConfigEntry) { @@ -264,16 +264,16 @@ func TestConfigEntryController_deletesEntConfigEntry(t *testing.T) { reconciler func(client.Client, *consul.Config, consul.ServerConnectionManager, logr.Logger) testReconciler }{ { - kubeKind: "SamenessGroups", + kubeKind: "SamenessGroup", consulKind: capi.SamenessGroup, - configEntryResourceWithDeletion: &v1alpha1.SamenessGroups{ + configEntryResourceWithDeletion: &v1alpha1.SamenessGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: kubeNS, DeletionTimestamp: &metav1.Time{Time: time.Now()}, Finalizers: []string{FinalizerName}, }, - Spec: v1alpha1.SamenessGroupsSpec{ + Spec: v1alpha1.SamenessGroupSpec{ DefaultForFailover: true, IncludeLocal: true, Members: []v1alpha1.SamenessGroupMember{ @@ -285,7 +285,7 @@ func TestConfigEntryController_deletesEntConfigEntry(t *testing.T) { }, }, reconciler: func(client client.Client, cfg *consul.Config, watcher consul.ServerConnectionManager, logger logr.Logger) testReconciler { - return &SamenessGroupsController{ + return &SamenessGroupController{ Client: client, Log: logger, ConfigEntryController: &ConfigEntryController{ diff --git a/control-plane/controllers/samenessgroups_controller.go b/control-plane/controllers/samenessgroups_controller.go index 97d4e5230c..afc243f267 100644 --- a/control-plane/controllers/samenessgroups_controller.go +++ b/control-plane/controllers/samenessgroups_controller.go @@ -12,8 +12,8 @@ import ( consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" ) -// SamenessGroupsController reconciles a SamenessGroups object. -type SamenessGroupsController struct { +// SamenessGroupController reconciles a SamenessGroups object. +type SamenessGroupController struct { client.Client Log logr.Logger Scheme *runtime.Scheme @@ -23,19 +23,19 @@ type SamenessGroupsController struct { //+kubebuilder:rbac:groups=consul.hashicorp.com,resources=samenessgroups,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=consul.hashicorp.com,resources=samenessgroups/status,verbs=get;update;patch -func (r *SamenessGroupsController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - return r.ConfigEntryController.ReconcileEntry(ctx, r, req, &consulv1alpha1.SamenessGroups{}) +func (r *SamenessGroupController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + return r.ConfigEntryController.ReconcileEntry(ctx, r, req, &consulv1alpha1.SamenessGroup{}) } -func (r *SamenessGroupsController) Logger(name types.NamespacedName) logr.Logger { +func (r *SamenessGroupController) Logger(name types.NamespacedName) logr.Logger { return r.Log.WithValues("request", name) } -func (r *SamenessGroupsController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { +func (r *SamenessGroupController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return r.Status().Update(ctx, obj, opts...) } // SetupWithManager sets up the controller with the Manager. -func (r *SamenessGroupsController) SetupWithManager(mgr ctrl.Manager) error { - return setupWithManager(mgr, &consulv1alpha1.SamenessGroups{}, r) +func (r *SamenessGroupController) SetupWithManager(mgr ctrl.Manager) error { + return setupWithManager(mgr, &consulv1alpha1.SamenessGroup{}, r) } diff --git a/control-plane/subcommand/inject-connect/command.go b/control-plane/subcommand/inject-connect/command.go index 6c12cacaea..05937dfe90 100644 --- a/control-plane/subcommand/inject-connect/command.go +++ b/control-plane/subcommand/inject-connect/command.go @@ -556,13 +556,13 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", apicommon.TerminatingGateway) return 1 } - if err = (&controllers.SamenessGroupsController{ + if err = (&controllers.SamenessGroupController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.SamenessGroups), + Log: ctrl.Log.WithName("controller").WithName(apicommon.SamenessGroup), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.SamenessGroups) + setupLog.Error(err, "unable to create controller", "controller", apicommon.SamenessGroup) return 1 } @@ -715,10 +715,10 @@ func (c *Command) Run(args []string) int { Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.TerminatingGateway), ConsulMeta: consulMeta, }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-samenessgroups", - &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.SamenessGroupsWebhook{ + mgr.GetWebhookServer().Register("/mutate-v1alpha1-samenessgroup", + &ctrlRuntimeWebhook.Admission{Handler: &v1alpha1.SamenessGroupWebhook{ Client: mgr.GetClient(), - Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.SamenessGroups), + Logger: ctrl.Log.WithName("webhooks").WithName(apicommon.SamenessGroup), ConsulMeta: consulMeta, }}) From 0b62dd2721d85f58d2c9aeacc980f35dcf1e9b84 Mon Sep 17 00:00:00 2001 From: Maliz Date: Tue, 18 Apr 2023 10:35:29 -0700 Subject: [PATCH 09/10] fix resource names --- charts/consul/templates/crd-samenessgroups.yaml | 2 +- .../config/crd/bases/consul.hashicorp.com_samenessgroups.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/consul/templates/crd-samenessgroups.yaml b/charts/consul/templates/crd-samenessgroups.yaml index df206f2a8c..e541539481 100644 --- a/charts/consul/templates/crd-samenessgroups.yaml +++ b/charts/consul/templates/crd-samenessgroups.yaml @@ -6,7 +6,7 @@ metadata: annotations: controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null - name: samenessgroup.consul.hashicorp.com + name: samenessgroups.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml index 84174cbcb3..5efda1ffa2 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_samenessgroups.yaml @@ -8,7 +8,7 @@ metadata: annotations: controller-gen.kubebuilder.io/version: v0.8.0 creationTimestamp: null - name: samenessgroup.consul.hashicorp.com + name: samenessgroups.consul.hashicorp.com spec: group: consul.hashicorp.com names: From b02c6889a1e8c3ae61d4e2e10c918d92e017681a Mon Sep 17 00:00:00 2001 From: Maliz Date: Tue, 18 Apr 2023 11:37:22 -0700 Subject: [PATCH 10/10] update failing unit test --- control-plane/api/v1alpha1/samenessgroup_types_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control-plane/api/v1alpha1/samenessgroup_types_test.go b/control-plane/api/v1alpha1/samenessgroup_types_test.go index bcd359293b..0f461701cc 100644 --- a/control-plane/api/v1alpha1/samenessgroup_types_test.go +++ b/control-plane/api/v1alpha1/samenessgroup_types_test.go @@ -326,7 +326,7 @@ func TestSamenessGroups_ConsulMirroringNS(t *testing.T) { } func TestSamenessGroups_KubeKind(t *testing.T) { - require.Equal(t, "samenessgroups", (&SamenessGroup{}).KubeKind()) + require.Equal(t, "samenessgroup", (&SamenessGroup{}).KubeKind()) } func TestSamenessGroups_ConsulName(t *testing.T) {