From d0531847a6d27bfeea768c536ee5ade4f9272a5d Mon Sep 17 00:00:00 2001 From: "R.B. Boyer" Date: Thu, 30 May 2024 15:40:18 -0500 Subject: [PATCH] remove the rest of the v2 plumbing --- acceptance/framework/consul/helm_cluster.go | 23 -- acceptance/framework/resource/helpers.go | 94 ----- acceptance/go.mod | 4 +- acceptance/go.sum | 7 - .../templates/connect-inject-clusterrole.yaml | 26 -- .../templates/crd-exportedservices.yaml | 108 ------ control-plane/api/common/common.go | 22 -- control-plane/api/common/consul_resource.go | 59 ---- .../api/common/consul_resource_webhook.go | 87 ----- .../common/consul_resource_webhook_test.go | 333 ------------------ .../v2/exported_services_types.go | 147 -------- .../v2/multicluster_groupversion_info.go | 27 -- .../api/multicluster/v2/shared_types.go | 14 - control-plane/api/multicluster/v2/status.go | 93 ----- .../multicluster/v2/zz_generated.deepcopy.go | 139 -------- ...consul.hashicorp.com_exportedservices.yaml | 103 ------ control-plane/config/rbac/role.yaml | 20 -- control-plane/connect-inject/common/common.go | 19 - .../connect-inject/common/common_test.go | 31 -- control-plane/consul/resource_client.go | 28 -- .../resources/consul_resource_controller.go | 327 ----------------- .../resources/exported_services_controller.go | 45 --- control-plane/go.mod | 4 +- control-plane/helper/test/test_util.go | 43 +-- .../subcommand/inject-connect/command.go | 5 - .../inject-connect/v1controllers.go | 28 -- 26 files changed, 12 insertions(+), 1824 deletions(-) delete mode 100644 acceptance/framework/resource/helpers.go delete mode 100644 charts/consul/templates/crd-exportedservices.yaml delete mode 100644 control-plane/api/common/consul_resource.go delete mode 100644 control-plane/api/common/consul_resource_webhook.go delete mode 100644 control-plane/api/common/consul_resource_webhook_test.go delete mode 100644 control-plane/api/multicluster/v2/exported_services_types.go delete mode 100644 control-plane/api/multicluster/v2/multicluster_groupversion_info.go delete mode 100644 control-plane/api/multicluster/v2/shared_types.go delete mode 100644 control-plane/api/multicluster/v2/status.go delete mode 100644 control-plane/api/multicluster/v2/zz_generated.deepcopy.go delete mode 100644 control-plane/config/crd/bases/multicluster.consul.hashicorp.com_exportedservices.yaml delete mode 100644 control-plane/consul/resource_client.go delete mode 100644 control-plane/controllers/resources/consul_resource_controller.go delete mode 100644 control-plane/controllers/resources/exported_services_controller.go diff --git a/acceptance/framework/consul/helm_cluster.go b/acceptance/framework/consul/helm_cluster.go index e12456876e..3471478bb5 100644 --- a/acceptance/framework/consul/helm_cluster.go +++ b/acceptance/framework/consul/helm_cluster.go @@ -13,8 +13,6 @@ import ( "github.com/gruntwork-io/terratest/modules/helm" terratestLogger "github.com/gruntwork-io/terratest/modules/logger" "github.com/stretchr/testify/require" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" corev1 "k8s.io/api/core/v1" policyv1beta "k8s.io/api/policy/v1beta1" rbacv1 "k8s.io/api/rbac/v1" @@ -28,7 +26,6 @@ import ( "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/consul-k8s/acceptance/framework/config" @@ -487,26 +484,6 @@ func (h *HelmCluster) CreatePortForwardTunnel(t *testing.T, remotePort int, rele return portforward.CreateTunnelToResourcePort(t, serverPod, remotePort, h.helmOptions.KubectlOptions, h.logger) } -// ResourceClient returns a resource service grpc client for the given helm release. -func (h *HelmCluster) ResourceClient(t *testing.T, secure bool, release ...string) (client pbresource.ResourceServiceClient) { - if secure { - panic("TODO: add support for secure resource client") - } - releaseName := h.releaseName - if len(release) > 0 { - releaseName = release[0] - } - - // TODO: get grpc port from somewhere - localTunnelAddr := h.CreatePortForwardTunnel(t, 8502, releaseName) - - // Create a grpc connection to the server pod. - grpcConn, err := grpc.Dial(localTunnelAddr, grpc.WithTransportCredentials(insecure.NewCredentials())) - require.NoError(t, err) - resourceClient := pbresource.NewResourceServiceClient(grpcConn) - return resourceClient -} - func (h *HelmCluster) SetupConsulClient(t *testing.T, secure bool, release ...string) (client *api.Client, configAddress string) { t.Helper() diff --git a/acceptance/framework/resource/helpers.go b/acceptance/framework/resource/helpers.go deleted file mode 100644 index 4e94f73faf..0000000000 --- a/acceptance/framework/resource/helpers.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package resource - -import ( - "context" - "time" - - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" - - "github.com/hashicorp/consul/proto-public/pbresource" - "github.com/hashicorp/consul/sdk/testutil" - "github.com/hashicorp/consul/sdk/testutil/retry" -) - -// ResourceTester is a helper for making assertions about resources. -type ResourceTester struct { - // resourceClient is the client to use for resource operations. - resourceClient pbresource.ResourceServiceClient - // timeout is the total time across which to apply retries. - timeout time.Duration - // wait is the wait time between retries. - wait time.Duration - // token is the token to use for requests when ACLs are enabled. - token string -} - -func NewResourceTester(resourceClient pbresource.ResourceServiceClient) *ResourceTester { - return &ResourceTester{ - resourceClient: resourceClient, - timeout: 7 * time.Second, - wait: 25 * time.Millisecond, - } -} - -func (rt *ResourceTester) retry(t testutil.TestingTB, fn func(r *retry.R)) { - t.Helper() - retryer := &retry.Timer{Timeout: rt.timeout, Wait: rt.wait} - retry.RunWith(retryer, t, fn) -} - -func (rt *ResourceTester) Context(t testutil.TestingTB) context.Context { - ctx := testutil.TestContext(t) - - if rt.token != "" { - md := metadata.New(map[string]string{ - "x-consul-token": rt.token, - }) - ctx = metadata.NewOutgoingContext(ctx, md) - } - - return ctx -} - -func (rt *ResourceTester) RequireResourceExists(t testutil.TestingTB, id *pbresource.ID) *pbresource.Resource { - t.Helper() - - rsp, err := rt.resourceClient.Read(rt.Context(t), &pbresource.ReadRequest{Id: id}) - require.NoError(t, err, "error reading %s with type %v", id.Name, id.Type) - require.NotNil(t, rsp) - return rsp.Resource -} - -func (rt *ResourceTester) RequireResourceNotFound(t testutil.TestingTB, id *pbresource.ID) { - t.Helper() - - rsp, err := rt.resourceClient.Read(rt.Context(t), &pbresource.ReadRequest{Id: id}) - require.Error(t, err) - require.Equal(t, codes.NotFound, status.Code(err)) - require.Nil(t, rsp) -} - -func (rt *ResourceTester) WaitForResourceExists(t testutil.TestingTB, id *pbresource.ID) *pbresource.Resource { - t.Helper() - - var res *pbresource.Resource - rt.retry(t, func(r *retry.R) { - res = rt.RequireResourceExists(r, id) - }) - - return res -} - -func (rt *ResourceTester) WaitForResourceNotFound(t testutil.TestingTB, id *pbresource.ID) { - t.Helper() - - rt.retry(t, func(r *retry.R) { - rt.RequireResourceNotFound(r, id) - }) -} diff --git a/acceptance/go.mod b/acceptance/go.mod index d23f2287f4..b63e717d85 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -9,7 +9,6 @@ require ( github.com/gruntwork-io/terratest v0.46.7 github.com/hashicorp/consul-k8s/control-plane v0.0.0-20240226161840-f3842c41cb2b github.com/hashicorp/consul/api v1.29.1 - github.com/hashicorp/consul/proto-public v0.6.1 github.com/hashicorp/consul/sdk v0.16.1 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-uuid v1.0.3 @@ -19,7 +18,6 @@ require ( github.com/hashicorp/vault/api v1.12.2 github.com/stretchr/testify v1.8.4 go.opentelemetry.io/proto/otlp v1.0.0 - google.golang.org/grpc v1.58.3 google.golang.org/protobuf v1.33.0 gopkg.in/yaml.v2 v2.4.0 k8s.io/api v0.28.9 @@ -70,6 +68,7 @@ require ( github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/gruntwork-io/go-commons v0.8.0 // indirect + github.com/hashicorp/consul/proto-public v0.6.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-bexpr v0.1.11 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -135,6 +134,7 @@ require ( google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + google.golang.org/grpc v1.58.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.100.1 // indirect diff --git a/acceptance/go.sum b/acceptance/go.sum index e2ebe425ee..79fc20f17f 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -27,11 +27,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -188,8 +185,6 @@ github.com/gruntwork-io/terratest v0.46.7 h1:oqGPBBO87SEsvBYaA0R5xOq+Lm2Xc5dmFVf github.com/gruntwork-io/terratest v0.46.7/go.mod h1:6gI5MlLeyF+SLwqocA5GBzcTix+XiuxCy1BPwKuT+WM= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20240226161840-f3842c41cb2b h1:AdeWjUb+rxrRryC5ZHaL32oOZuxubOzV2q6oJ97UMT0= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20240226161840-f3842c41cb2b/go.mod h1:TVaSJM7vYM/mtKGpVc/Lch53lrqLI9XAXJgy/gY8v4A= -github.com/hashicorp/consul-server-connection-manager v0.1.6 h1:ktj8Fi+dRXn9hhM+FXsfEJayhzzgTqfH08Ne5M6Fmug= -github.com/hashicorp/consul-server-connection-manager v0.1.6/go.mod h1:HngMIv57MT+pqCVeRQMa1eTB5dqnyMm8uxjyv+Hn8cs= github.com/hashicorp/consul/api v1.29.1 h1:UEwOjYJrd3lG1x5w7HxDRMGiAUPrb3f103EoeKuuEcc= github.com/hashicorp/consul/api v1.29.1/go.mod h1:lumfRkY/coLuqMICkI7Fh3ylMG31mQSRZyef2c5YvJI= github.com/hashicorp/consul/proto-public v0.6.1 h1:+uzH3olCrksXYWAYHKqK782CtK9scfqH+Unlw3UHhCg= @@ -218,8 +213,6 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-netaddrs v0.1.0 h1:TnlYvODD4C/wO+j7cX1z69kV5gOzI87u3OcUinANaW8= -github.com/hashicorp/go-netaddrs v0.1.0/go.mod h1:33+a/emi5R5dqRspOuZKO0E+Tuz5WV1F84eRWALkedA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= diff --git a/charts/consul/templates/connect-inject-clusterrole.yaml b/charts/consul/templates/connect-inject-clusterrole.yaml index 89dc56326d..c8d6d71794 100644 --- a/charts/consul/templates/connect-inject-clusterrole.yaml +++ b/charts/consul/templates/connect-inject-clusterrole.yaml @@ -74,32 +74,6 @@ rules: - get - patch - update -{{- if (false) }} -- apiGroups: - - multicluster.consul.hashicorp.com - resources: - - exportedservices - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - multicluster.consul.hashicorp.com - resources: - - exportedservices/status - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -{{- end }} - apiGroups: [ "" ] resources: [ "secrets", "serviceaccounts", "endpoints", "services", "namespaces", "nodes" ] verbs: diff --git a/charts/consul/templates/crd-exportedservices.yaml b/charts/consul/templates/crd-exportedservices.yaml deleted file mode 100644 index 6613e3da7e..0000000000 --- a/charts/consul/templates/crd-exportedservices.yaml +++ /dev/null @@ -1,108 +0,0 @@ -{{- if .Values.connectInject.enabled }} -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.12.1 - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: crd - name: exportedservices.multicluster.consul.hashicorp.com -spec: - group: multicluster.consul.hashicorp.com - names: - kind: ExportedServices - listKind: ExportedServicesList - plural: exportedservices - singular: exportedservices - 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: v2 - schema: - openAPIV3Schema: - description: ExportedServices is the Schema for the Exported Services 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: - properties: - consumers: - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - services: - items: - type: string - 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: {} -{{- end }} diff --git a/control-plane/api/common/common.go b/control-plane/api/common/common.go index 4697f5e853..d40755f5ba 100644 --- a/control-plane/api/common/common.go +++ b/control-plane/api/common/common.go @@ -47,28 +47,6 @@ const ( DefaultPeerName = "local" ) -// ConsulTenancyConfig manages settings related to Consul namespaces and partitions. -type ConsulTenancyConfig struct { - // EnableConsulPartitions indicates that a user is running Consul Enterprise. - EnableConsulPartitions bool - // ConsulPartition is the Consul Partition to which this controller belongs. - ConsulPartition string - // EnableConsulNamespaces indicates that a user is running Consul Enterprise. - EnableConsulNamespaces bool - // ConsulDestinationNamespace is the name of the Consul namespace to create - // all resources in. If EnableNSMirroring is true this is ignored. - ConsulDestinationNamespace string - // EnableNSMirroring causes Consul namespaces to be created to match the - // k8s namespace of any config entry custom resource. Resources will - // be created in the matching Consul namespace. - EnableNSMirroring bool - // NSMirroringPrefix is an optional prefix that can be added to the Consul - // namespaces created while mirroring. For example, if it is set to "k8s-", - // then the k8s `default` namespace will be mirrored in Consul's - // `k8s-default` namespace. - NSMirroringPrefix string -} - // K8sNamespaceConfig manages allow/deny Kubernetes namespaces. type K8sNamespaceConfig struct { // Only endpoints in the AllowK8sNamespacesSet are reconciled. diff --git a/control-plane/api/common/consul_resource.go b/control-plane/api/common/consul_resource.go deleted file mode 100644 index b957d0fb79..0000000000 --- a/control-plane/api/common/consul_resource.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "github.com/hashicorp/consul/proto-public/pbresource" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" -) - -type ConsulResource interface { - ResourceID(namespace, partition string) *pbresource.ID - Resource(namespace, partition string) *pbresource.Resource - - // GetObjectKind should be implemented by the generated code. - GetObjectKind() schema.ObjectKind - // DeepCopyObject should be implemented by the generated code. - DeepCopyObject() runtime.Object - - // AddFinalizer adds a finalizer to the list of finalizers. - AddFinalizer(name string) - // RemoveFinalizer removes this finalizer from the list. - RemoveFinalizer(name string) - // Finalizers returns the list of finalizers for this object. - Finalizers() []string - - // MatchesConsul returns true if the resource has the same fields as the Consul - // config entry. - MatchesConsul(candidate *pbresource.Resource, namespace, partition string) bool - - // KubeKind returns the Kube config entry kind, i.e. servicedefaults, not - // service-defaults. - KubeKind() string - // KubernetesName returns the name of the Kubernetes resource. - KubernetesName() string - - // SetSyncedCondition updates the synced condition. - SetSyncedCondition(status corev1.ConditionStatus, reason, message string) - // SetLastSyncedTime updates the last synced time. - SetLastSyncedTime(time *metav1.Time) - // SyncedCondition gets the synced condition. - SyncedCondition() (status corev1.ConditionStatus, reason, message string) - // SyncedConditionStatus returns the status of the synced condition. - SyncedConditionStatus() corev1.ConditionStatus - - // Validate returns an error if the resource is invalid. - Validate(tenancy ConsulTenancyConfig) error - - // DefaultNamespaceFields sets Consul namespace fields on the resource - // spec to their default values if namespaces are enabled. - DefaultNamespaceFields(tenancy ConsulTenancyConfig) - - // Object is required so that MeshConfig implements metav1.Object, which is - // the interface supported by controller-runtime reconcile-able resources. - metav1.Object -} diff --git a/control-plane/api/common/consul_resource_webhook.go b/control-plane/api/common/consul_resource_webhook.go deleted file mode 100644 index afda672873..0000000000 --- a/control-plane/api/common/consul_resource_webhook.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - - "github.com/go-logr/logr" - "gomodules.xyz/jsonpatch/v2" - admissionv1 "k8s.io/api/admission/v1" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -// ConsulResourceLister is implemented by CRD-specific webhooks. -type ConsulResourceLister interface { - // List returns all resources of this type across all namespaces in a - // Kubernetes cluster. - List(ctx context.Context) ([]ConsulResource, error) -} - -// ValidateConsulResource validates a Consul Resource. It is a generic method that -// can be used by all CRD-specific validators. -// Callers should pass themselves as validator and kind should be the custom -// resource name, e.g. "TrafficPermissions". -func ValidateConsulResource( - ctx context.Context, - req admission.Request, - logger logr.Logger, - resourceLister ConsulResourceLister, - resource ConsulResource, - tenancy ConsulTenancyConfig) admission.Response { - - defaultingPatches, err := ConsulResourceDefaultingPatches(resource, tenancy) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - // On create we need to validate that there isn't already a resource with - // the same name in a different namespace if we're mapping all Kube - // resources to a single Consul namespace. The only case where we're not - // mapping all kube resources to a single Consul namespace is when we - // are running Consul enterprise with namespace mirroring. - singleConsulDestNS := !(tenancy.EnableConsulNamespaces && tenancy.EnableNSMirroring) - if req.Operation == admissionv1.Create && singleConsulDestNS { - logger.Info("validate create", "name", resource.KubernetesName()) - - list, err := resourceLister.List(ctx) - if err != nil { - return admission.Errored(http.StatusInternalServerError, err) - } - for _, item := range list { - if item.KubernetesName() == resource.KubernetesName() { - return admission.Errored(http.StatusBadRequest, - fmt.Errorf("%s resource with name %q is already defined – all %s resources must have unique names across namespaces", - resource.KubeKind(), - resource.KubernetesName(), - resource.KubeKind())) - } - } - } - if err := resource.Validate(tenancy); err != nil { - return admission.Errored(http.StatusBadRequest, err) - } - return admission.Patched(fmt.Sprintf("valid %s request", resource.KubeKind()), defaultingPatches...) -} - -// ConsulResourceDefaultingPatches returns the patches needed to set fields to their defaults. -func ConsulResourceDefaultingPatches(resource ConsulResource, tenancy ConsulTenancyConfig) ([]jsonpatch.Operation, error) { - beforeDefaulting, err := json.Marshal(resource) - if err != nil { - return nil, fmt.Errorf("marshalling input: %s", err) - } - resource.DefaultNamespaceFields(tenancy) - afterDefaulting, err := json.Marshal(resource) - if err != nil { - return nil, fmt.Errorf("marshalling after defaulting: %s", err) - } - - defaultingPatches, err := jsonpatch.CreatePatch(beforeDefaulting, afterDefaulting) - if err != nil { - return nil, fmt.Errorf("creating patches: %s", err) - } - return defaultingPatches, nil -} diff --git a/control-plane/api/common/consul_resource_webhook_test.go b/control-plane/api/common/consul_resource_webhook_test.go deleted file mode 100644 index 63bbf9a6e0..0000000000 --- a/control-plane/api/common/consul_resource_webhook_test.go +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package common - -import ( - "context" - "encoding/json" - "errors" - "testing" - - logrtest "github.com/go-logr/logr/testr" - "github.com/hashicorp/consul/proto-public/pbresource" - "github.com/stretchr/testify/require" - "gomodules.xyz/jsonpatch/v2" - admissionv1 "k8s.io/api/admission/v1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/webhook/admission" -) - -func TestValidateConsulResource(t *testing.T) { - otherNS := "other" - - cases := map[string]struct { - existingResources []ConsulResource - newResource ConsulResource - enableNamespaces bool - nsMirroring bool - consulDestinationNS string - nsMirroringPrefix string - expAllow bool - expErrMessage string - }{ - "no duplicates, valid": { - existingResources: nil, - newResource: &mockConsulResource{ - MockName: "foo", - MockNamespace: otherNS, - Valid: true, - }, - expAllow: true, - }, - "no duplicates, invalid": { - existingResources: nil, - newResource: &mockConsulResource{ - MockName: "foo", - MockNamespace: otherNS, - Valid: false, - }, - expAllow: false, - expErrMessage: "invalid", - }, - "duplicate name": { - existingResources: []ConsulResource{&mockConsulResource{ - MockName: "foo", - MockNamespace: "default", - }}, - newResource: &mockConsulResource{ - MockName: "foo", - MockNamespace: otherNS, - Valid: true, - }, - expAllow: false, - expErrMessage: "mockkind resource with name \"foo\" is already defined – all mockkind resources must have unique names across namespaces", - }, - "duplicate name, namespaces enabled": { - existingResources: []ConsulResource{&mockConsulResource{ - MockName: "foo", - MockNamespace: "default", - }}, - newResource: &mockConsulResource{ - MockName: "foo", - MockNamespace: otherNS, - Valid: true, - }, - enableNamespaces: true, - expAllow: false, - expErrMessage: "mockkind resource with name \"foo\" is already defined – all mockkind resources must have unique names across namespaces", - }, - "duplicate name, namespaces enabled, mirroring enabled": { - existingResources: []ConsulResource{&mockConsulResource{ - MockName: "foo", - MockNamespace: "default", - }}, - newResource: &mockConsulResource{ - MockName: "foo", - MockNamespace: otherNS, - Valid: true, - }, - enableNamespaces: true, - nsMirroring: true, - expAllow: true, - }, - } - for name, c := range cases { - t.Run(name, func(t *testing.T) { - ctx := context.Background() - marshalledRequestObject, err := json.Marshal(c.newResource) - require.NoError(t, err) - - lister := &mockConsulResourceLister{ - Resources: c.existingResources, - } - response := ValidateConsulResource(ctx, admission.Request{ - AdmissionRequest: admissionv1.AdmissionRequest{ - Name: c.newResource.KubernetesName(), - Namespace: otherNS, - Operation: admissionv1.Create, - Object: runtime.RawExtension{ - Raw: marshalledRequestObject, - }, - }, - }, - logrtest.New(t), - lister, - c.newResource, - ConsulTenancyConfig{ - EnableConsulNamespaces: c.enableNamespaces, - ConsulDestinationNamespace: c.consulDestinationNS, - EnableNSMirroring: c.nsMirroring, - NSMirroringPrefix: c.nsMirroringPrefix, - }) - require.Equal(t, c.expAllow, response.Allowed) - if c.expErrMessage != "" { - require.Equal(t, c.expErrMessage, response.AdmissionResponse.Result.Message) - } - }) - } -} - -func TestConsulResourceDefaultingPatches(t *testing.T) { - meshConfig := &mockConsulResource{ - MockName: "test", - Valid: true, - } - - // This test validates that DefaultingPatches invokes DefaultNamespaceFields on the Config Entry. - patches, err := ConsulResourceDefaultingPatches(meshConfig, ConsulTenancyConfig{}) - require.NoError(t, err) - - require.Equal(t, []jsonpatch.Operation{ - { - Operation: "replace", - Path: "/MockNamespace", - Value: "bar", - }, - }, patches) -} - -type mockConsulResourceLister struct { - Resources []ConsulResource -} - -var _ ConsulResourceLister = &mockConsulResourceLister{} - -func (in *mockConsulResourceLister) List(_ context.Context) ([]ConsulResource, error) { - return in.Resources, nil -} - -type mockConsulResource struct { - MockName string - MockNamespace string - Valid bool -} - -var _ ConsulResource = &mockConsulResource{} - -func (in *mockConsulResource) ResourceID(_, _ string) *pbresource.ID { - return nil -} - -func (in *mockConsulResource) Resource(_, _ string) *pbresource.Resource { - return nil -} - -func (in *mockConsulResource) GetNamespace() string { - return in.MockNamespace -} - -func (in *mockConsulResource) SetNamespace(namespace string) { - in.MockNamespace = namespace -} - -func (in *mockConsulResource) GetName() string { - return in.MockName -} - -func (in *mockConsulResource) SetName(name string) { - in.MockName = name -} - -func (in *mockConsulResource) GetGenerateName() string { - return "" -} - -func (in *mockConsulResource) SetGenerateName(_ string) {} - -func (in *mockConsulResource) GetUID() types.UID { - return "" -} - -func (in *mockConsulResource) SetUID(_ types.UID) {} - -func (in *mockConsulResource) GetResourceVersion() string { - return "" -} - -func (in *mockConsulResource) SetResourceVersion(_ string) {} - -func (in *mockConsulResource) GetGeneration() int64 { - return 0 -} - -func (in *mockConsulResource) SetGeneration(_ int64) {} - -func (in *mockConsulResource) GetSelfLink() string { - return "" -} - -func (in *mockConsulResource) SetSelfLink(_ string) {} - -func (in *mockConsulResource) GetCreationTimestamp() metav1.Time { - return metav1.Time{} -} - -func (in *mockConsulResource) SetCreationTimestamp(_ metav1.Time) {} - -func (in *mockConsulResource) GetDeletionTimestamp() *metav1.Time { - return nil -} - -func (in *mockConsulResource) SetDeletionTimestamp(_ *metav1.Time) {} - -func (in *mockConsulResource) GetDeletionGracePeriodSeconds() *int64 { - return nil -} - -func (in *mockConsulResource) SetDeletionGracePeriodSeconds(_ *int64) {} - -func (in *mockConsulResource) GetLabels() map[string]string { - return nil -} - -func (in *mockConsulResource) SetLabels(_ map[string]string) {} - -func (in *mockConsulResource) GetAnnotations() map[string]string { - return nil -} - -func (in *mockConsulResource) SetAnnotations(_ map[string]string) {} - -func (in *mockConsulResource) GetFinalizers() []string { - return nil -} - -func (in *mockConsulResource) SetFinalizers(_ []string) {} - -func (in *mockConsulResource) GetOwnerReferences() []metav1.OwnerReference { - return nil -} - -func (in *mockConsulResource) SetOwnerReferences(_ []metav1.OwnerReference) {} - -func (in *mockConsulResource) GetClusterName() string { - return "" -} - -func (in *mockConsulResource) SetClusterName(_ string) {} - -func (in *mockConsulResource) GetManagedFields() []metav1.ManagedFieldsEntry { - return nil -} - -func (in *mockConsulResource) SetManagedFields(_ []metav1.ManagedFieldsEntry) {} - -func (in *mockConsulResource) KubernetesName() string { - return in.MockName -} - -func (in *mockConsulResource) GetObjectMeta() metav1.ObjectMeta { - return metav1.ObjectMeta{} -} - -func (in *mockConsulResource) GetObjectKind() schema.ObjectKind { - return schema.EmptyObjectKind -} - -func (in *mockConsulResource) DeepCopyObject() runtime.Object { - return in -} - -func (in *mockConsulResource) AddFinalizer(_ string) {} - -func (in *mockConsulResource) RemoveFinalizer(_ string) {} - -func (in *mockConsulResource) Finalizers() []string { - return nil -} - -func (in *mockConsulResource) KubeKind() string { - return "mockkind" -} - -func (in *mockConsulResource) SetSyncedCondition(_ corev1.ConditionStatus, _ string, _ string) {} - -func (in *mockConsulResource) SetLastSyncedTime(_ *metav1.Time) {} - -func (in *mockConsulResource) SyncedCondition() (status corev1.ConditionStatus, reason string, message string) { - return corev1.ConditionTrue, "", "" -} - -func (in *mockConsulResource) SyncedConditionStatus() corev1.ConditionStatus { - return corev1.ConditionTrue -} - -func (in *mockConsulResource) Validate(_ ConsulTenancyConfig) error { - if !in.Valid { - return errors.New("invalid") - } - return nil -} - -func (in *mockConsulResource) DefaultNamespaceFields(_ ConsulTenancyConfig) { - in.MockNamespace = "bar" -} - -func (in *mockConsulResource) MatchesConsul(_ *pbresource.Resource, _, _ string) bool { - return false -} diff --git a/control-plane/api/multicluster/v2/exported_services_types.go b/control-plane/api/multicluster/v2/exported_services_types.go deleted file mode 100644 index 7950af4c70..0000000000 --- a/control-plane/api/multicluster/v2/exported_services_types.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 -package v2 - -import ( - "fmt" - - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2" - "github.com/hashicorp/consul/proto-public/pbresource" - "google.golang.org/protobuf/testing/protocmp" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/hashicorp/consul-k8s/control-plane/api/common" - inject "github.com/hashicorp/consul-k8s/control-plane/connect-inject/common" -) - -const ( - exportedServicesKubeKind = "exportedservices" -) - -func init() { - MultiClusterSchemeBuilder.Register(&ExportedServices{}, &ExportedServicesList{}) -} - -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status - -// ExportedServices is the Schema for the Exported Services 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:scope="Namespaced" -type ExportedServices struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec *pbmulticluster.ExportedServices `json:"spec,omitempty"` - Status `json:"status,omitempty"` -} - -// +kubebuilder:object:root=true - -// ExportedServicesList contains a list of ExportedServices. -type ExportedServicesList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []*ExportedServices `json:"items"` -} - -func (in *ExportedServices) ResourceID(_, partition string) *pbresource.ID { - return &pbresource.ID{ - Name: in.Name, - Type: pbmulticluster.ExportedServicesType, - Tenancy: &pbresource.Tenancy{ - Partition: partition, - Namespace: "", // Namespace is always unset because ExportedServices is partition-scoped - }, - } -} - -func (in *ExportedServices) Resource(namespace, partition string) *pbresource.Resource { - return &pbresource.Resource{ - Id: in.ResourceID(namespace, partition), - Data: inject.ToProtoAny(in.Spec), - Metadata: multiClusterConfigMeta(), - } -} - -func (in *ExportedServices) AddFinalizer(f string) { - in.ObjectMeta.Finalizers = append(in.Finalizers(), f) -} - -func (in *ExportedServices) RemoveFinalizer(f string) { - var newFinalizers []string - for _, oldF := range in.Finalizers() { - if oldF != f { - newFinalizers = append(newFinalizers, oldF) - } - } - in.ObjectMeta.Finalizers = newFinalizers -} - -func (in *ExportedServices) Finalizers() []string { - return in.ObjectMeta.Finalizers -} - -func (in *ExportedServices) MatchesConsul(candidate *pbresource.Resource, namespace, partition string) bool { - return cmp.Equal( - in.Resource(namespace, partition), - candidate, - protocmp.IgnoreFields(&pbresource.Resource{}, "status", "generation", "version"), - protocmp.IgnoreFields(&pbresource.ID{}, "uid"), - protocmp.Transform(), - cmpopts.SortSlices(func(a, b any) bool { return fmt.Sprintf("%v", a) < fmt.Sprintf("%v", b) }), - ) -} - -func (in *ExportedServices) KubeKind() string { - return exportedServicesKubeKind -} - -func (in *ExportedServices) KubernetesName() string { - return in.ObjectMeta.Name -} - -func (in *ExportedServices) SetSyncedCondition(status corev1.ConditionStatus, reason, message string) { - in.Status.Conditions = Conditions{ - { - Type: ConditionSynced, - Status: status, - LastTransitionTime: metav1.Now(), - Reason: reason, - Message: message, - }, - } -} - -func (in *ExportedServices) SetLastSyncedTime(time *metav1.Time) { - in.Status.LastSyncedTime = time -} - -func (in *ExportedServices) 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 *ExportedServices) SyncedConditionStatus() corev1.ConditionStatus { - condition := in.Status.GetCondition(ConditionSynced) - if condition == nil { - return corev1.ConditionUnknown - } - return condition.Status -} - -func (in *ExportedServices) Validate(tenancy common.ConsulTenancyConfig) error { - // TODO add validation logic that ensures we only ever write this to the default namespace. - return nil -} - -// DefaultNamespaceFields is required as part of the common.MeshConfig interface. -func (in *ExportedServices) DefaultNamespaceFields(tenancy common.ConsulTenancyConfig) {} diff --git a/control-plane/api/multicluster/v2/multicluster_groupversion_info.go b/control-plane/api/multicluster/v2/multicluster_groupversion_info.go deleted file mode 100644 index 7b8f92f4ac..0000000000 --- a/control-plane/api/multicluster/v2/multicluster_groupversion_info.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -// Package v2 contains API Schema definitions for the consul.hashicorp.com v2 API group -// +kubebuilder:object:generate=true -// +groupName=multicluster.consul.hashicorp.com -package v2 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -var ( - - // MultiClusterGroup is a collection of multi-cluster resources. - MultiClusterGroup = "multicluster.consul.hashicorp.com" - - // MultiClusterGroupVersion is group version used to register these objects. - MultiClusterGroupVersion = schema.GroupVersion{Group: MultiClusterGroup, Version: "v2"} - - // MultiClusterSchemeBuilder is used to add go types to the GroupVersionKind scheme. - MultiClusterSchemeBuilder = &scheme.Builder{GroupVersion: MultiClusterGroupVersion} - - // AddMultiClusterToScheme adds the types in this group-version to the given scheme. - AddMultiClusterToScheme = MultiClusterSchemeBuilder.AddToScheme -) diff --git a/control-plane/api/multicluster/v2/shared_types.go b/control-plane/api/multicluster/v2/shared_types.go deleted file mode 100644 index 04f9fcefa4..0000000000 --- a/control-plane/api/multicluster/v2/shared_types.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v2 - -import ( - "github.com/hashicorp/consul-k8s/control-plane/api/common" -) - -func multiClusterConfigMeta() map[string]string { - return map[string]string{ - common.SourceKey: common.SourceValue, - } -} diff --git a/control-plane/api/multicluster/v2/status.go b/control-plane/api/multicluster/v2/status.go deleted file mode 100644 index 070c57a7d9..0000000000 --- a/control-plane/api/multicluster/v2/status.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package v2 - -import ( - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// Conditions is the schema for the conditions portion of the payload. -type Conditions []Condition - -// ConditionType is a camel-cased condition type. -type ConditionType string - -const ( - // ConditionSynced specifies that the resource has been synced with Consul. - ConditionSynced ConditionType = "Synced" -) - -// 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 -// +k8s:deepcopy-gen=true -// +k8s:openapi-gen=true -type Condition struct { - // Type of condition. - // +required - Type ConditionType `json:"type" description:"type of status condition"` - - // Status of the condition, one of True, False, Unknown. - // +required - Status corev1.ConditionStatus `json:"status" description:"status of the condition, one of True, False, Unknown"` - - // LastTransitionTime is the last time the condition transitioned from one status to another. - // +optional - LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty" description:"last time the condition transitioned from one status to another"` - - // The reason for the condition's last transition. - // +optional - Reason string `json:"reason,omitempty" description:"one-word CamelCase reason for the condition's last transition"` - - // A human readable message indicating details about the transition. - // +optional - Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"` -} - -// IsTrue is true if the condition is True. -func (c *Condition) IsTrue() bool { - if c == nil { - return false - } - return c.Status == corev1.ConditionTrue -} - -// IsFalse is true if the condition is False. -func (c *Condition) IsFalse() bool { - if c == nil { - return false - } - return c.Status == corev1.ConditionFalse -} - -// IsUnknown is true if the condition is Unknown. -func (c *Condition) IsUnknown() bool { - if c == nil { - return true - } - return c.Status == corev1.ConditionUnknown -} - -// +k8s:deepcopy-gen=true -// +k8s:openapi-gen=true -type Status struct { - // Conditions indicate the latest available observations of a resource's current state. - // +optional - // +patchMergeKey=type - // +patchStrategy=merge - Conditions Conditions `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` - - // LastSyncedTime is the last time the resource successfully synced with Consul. - // +optional - LastSyncedTime *metav1.Time `json:"lastSyncedTime,omitempty" description:"last time the condition transitioned from one status to another"` -} - -func (s *Status) GetCondition(t ConditionType) *Condition { - for _, cond := range s.Conditions { - if cond.Type == t { - return &cond - } - } - return nil -} diff --git a/control-plane/api/multicluster/v2/zz_generated.deepcopy.go b/control-plane/api/multicluster/v2/zz_generated.deepcopy.go deleted file mode 100644 index a7d79990bb..0000000000 --- a/control-plane/api/multicluster/v2/zz_generated.deepcopy.go +++ /dev/null @@ -1,139 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -// Code generated by controller-gen. DO NOT EDIT. - -package v2 - -import ( - runtime "k8s.io/apimachinery/pkg/runtime" -) - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Condition) DeepCopyInto(out *Condition) { - *out = *in - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition. -func (in *Condition) DeepCopy() *Condition { - if in == nil { - return nil - } - out := new(Condition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in Conditions) DeepCopyInto(out *Conditions) { - { - in := &in - *out = make(Conditions, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Conditions. -func (in Conditions) DeepCopy() Conditions { - if in == nil { - return nil - } - out := new(Conditions) - in.DeepCopyInto(out) - return *out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ExportedServices) DeepCopyInto(out *ExportedServices) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.Spec != nil { - in, out := &in.Spec, &out.Spec - *out = (*in).DeepCopy() - } - in.Status.DeepCopyInto(&out.Status) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExportedServices. -func (in *ExportedServices) DeepCopy() *ExportedServices { - if in == nil { - return nil - } - out := new(ExportedServices) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ExportedServices) 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 *ExportedServicesList) DeepCopyInto(out *ExportedServicesList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]*ExportedServices, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(ExportedServices) - (*in).DeepCopyInto(*out) - } - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExportedServicesList. -func (in *ExportedServicesList) DeepCopy() *ExportedServicesList { - if in == nil { - return nil - } - out := new(ExportedServicesList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *ExportedServicesList) 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 *Status) DeepCopyInto(out *Status) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make(Conditions, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.LastSyncedTime != nil { - in, out := &in.LastSyncedTime, &out.LastSyncedTime - *out = (*in).DeepCopy() - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Status. -func (in *Status) DeepCopy() *Status { - if in == nil { - return nil - } - out := new(Status) - in.DeepCopyInto(out) - return out -} diff --git a/control-plane/config/crd/bases/multicluster.consul.hashicorp.com_exportedservices.yaml b/control-plane/config/crd/bases/multicluster.consul.hashicorp.com_exportedservices.yaml deleted file mode 100644 index 36020e3639..0000000000 --- a/control-plane/config/crd/bases/multicluster.consul.hashicorp.com_exportedservices.yaml +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.12.1 - name: exportedservices.multicluster.consul.hashicorp.com -spec: - group: multicluster.consul.hashicorp.com - names: - kind: ExportedServices - listKind: ExportedServicesList - plural: exportedservices - singular: exportedservices - 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: v2 - schema: - openAPIV3Schema: - description: ExportedServices is the Schema for the Exported Services 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: - properties: - consumers: - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - services: - items: - type: string - 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: {} diff --git a/control-plane/config/rbac/role.yaml b/control-plane/config/rbac/role.yaml index df46bea195..4fac4ac9b8 100644 --- a/control-plane/config/rbac/role.yaml +++ b/control-plane/config/rbac/role.yaml @@ -325,23 +325,3 @@ rules: - get - patch - update -- apiGroups: - - multicluster.consul.hashicorp.com - resources: - - exportedservices - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - multicluster.consul.hashicorp.com - resources: - - exportedservices/status - verbs: - - get - - patch - - update diff --git a/control-plane/connect-inject/common/common.go b/control-plane/connect-inject/common/common.go index 55a878d47c..63d0e4314a 100644 --- a/control-plane/connect-inject/common/common.go +++ b/control-plane/connect-inject/common/common.go @@ -11,8 +11,6 @@ import ( mapset "github.com/deckarep/golang-set" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/types/known/anypb" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -121,23 +119,6 @@ func ConsulNodeNameFromK8sNode(nodeName string) string { return fmt.Sprintf("%s-virtual", nodeName) } -// ToProtoAny is a convenience function for converting proto.Message values to anypb.Any without error handling. -// This should _only_ be used in cases where a nil or valid proto.Message value is _guaranteed_, else it will panic. -// If the type of m is *anypb.Any, that value will be returned unmodified. -func ToProtoAny(m proto.Message) *anypb.Any { - switch v := m.(type) { - case nil: - return nil - case *anypb.Any: - return v - } - a, err := anypb.New(m) - if err != nil { - panic(fmt.Errorf("unexpected error: failed to convert proto message to anypb.Any: %w", err)) - } - return a -} - // ConsulNamespaceIsNotFound checks the gRPC error code and message to determine // if a namespace does not exist. If the namespace exists this function returns false, true otherwise. func ConsulNamespaceIsNotFound(err error) bool { diff --git a/control-plane/connect-inject/common/common_test.go b/control-plane/connect-inject/common/common_test.go index 5da5ed287a..4cd58fea81 100644 --- a/control-plane/connect-inject/common/common_test.go +++ b/control-plane/connect-inject/common/common_test.go @@ -8,17 +8,12 @@ import ( "testing" mapset "github.com/deckarep/golang-set" - "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "google.golang.org/protobuf/testing/protocmp" - "google.golang.org/protobuf/types/known/anypb" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/hashicorp/consul/proto-public/pbresource" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" "github.com/hashicorp/consul-k8s/control-plane/namespaces" ) @@ -323,32 +318,6 @@ func TestShouldIgnore(t *testing.T) { } } -func TestToProtoAny(t *testing.T) { - t.Parallel() - - t.Run("nil gets nil", func(t *testing.T) { - require.Nil(t, ToProtoAny(nil)) - }) - - t.Run("anypb.Any gets same value", func(t *testing.T) { - testMsg := &pbresource.Resource{Id: &pbresource.ID{Name: "foo"}} - testAny, err := anypb.New(testMsg) - require.NoError(t, err) - - require.Equal(t, testAny, ToProtoAny(testAny)) - }) - - t.Run("valid proto is successfully serialized", func(t *testing.T) { - testMsg := &pbresource.Resource{Id: &pbresource.ID{Name: "foo"}} - testAny, err := anypb.New(testMsg) - require.NoError(t, err) - - if diff := cmp.Diff(testAny, ToProtoAny(testMsg), protocmp.Transform()); diff != "" { - t.Errorf("unexpected difference:\n%v", diff) - } - }) -} - func Test_ConsulNamespaceIsNotFound(t *testing.T) { t.Parallel() diff --git a/control-plane/consul/resource_client.go b/control-plane/consul/resource_client.go deleted file mode 100644 index 82c24af34f..0000000000 --- a/control-plane/consul/resource_client.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package consul - -import ( - "fmt" - - "github.com/hashicorp/consul/proto-public/pbresource" -) - -// NewResourceServiceClient creates a pbresource.ResourceServiceClient for creating V2 Consul resources. -// It is initialized with a consul-server-connection-manager Watcher to continuously find Consul -// server addresses. -func NewResourceServiceClient(watcher ServerConnectionManager) (pbresource.ResourceServiceClient, error) { - - // We recycle the GRPC connection from the discovery client because it - // should have all the necessary dial options, including the resolver that - // continuously updates Consul server addresses. Otherwise, a lot of code from consul-server-connection-manager - // would need to be duplicated - state, err := watcher.State() - if err != nil { - return nil, fmt.Errorf("unable to get connection manager state: %w", err) - } - resourceClient := pbresource.NewResourceServiceClient(state.GRPCConn) - - return resourceClient, nil -} diff --git a/control-plane/controllers/resources/consul_resource_controller.go b/control-plane/controllers/resources/consul_resource_controller.go deleted file mode 100644 index 95c5cbcac6..0000000000 --- a/control-plane/controllers/resources/consul_resource_controller.go +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package resources - -import ( - "context" - "fmt" - "time" - - "github.com/go-logr/logr" - "github.com/hashicorp/consul/proto-public/pbresource" - "golang.org/x/time/rate" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" - corev1 "k8s.io/api/core/v1" - k8serr "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/workqueue" - "k8s.io/utils/strings/slices" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/hashicorp/consul-k8s/control-plane/api/common" - tenancy "github.com/hashicorp/consul-k8s/control-plane/connect-inject/common" - "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/namespaces" -) - -const ( - FinalizerName = "finalizers.consul.hashicorp.com" - ConsulAgentError = "ConsulAgentError" - ExternallyManagedConfigError = "ExternallyManagedConfigError" -) - -// ResourceController is implemented by resources syncing Consul Resources from their CRD counterparts. -// It is used by ConsulResourceController to abstract CRD-specific Consul Resources. -type ResourceController interface { - // Update updates the state of the whole object. - Update(context.Context, client.Object, ...client.UpdateOption) error - // UpdateStatus updates the state of just the object's status. - UpdateStatus(context.Context, client.Object, ...client.SubResourceUpdateOption) error - // Get retrieves an object for the given object key from the Kubernetes Cluster. - // obj must be a struct pointer so that obj can be updated with the response - // returned by the Server. - Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error - // Logger returns a logger with values added for the specific controller - // and request name. - Logger(types.NamespacedName) logr.Logger -} - -// ConsulResourceController is a generic controller that is used to reconcile -// all Consul Resource types, e.g. TrafficPermissions, ProxyConfiguration, etc., since -// they share the same reconcile behaviour. -type ConsulResourceController struct { - // ConsulClientConfig is the config for the Consul API client. - ConsulClientConfig *consul.Config - - // ConsulServerConnMgr is the watcher for the Consul server addresses. - ConsulServerConnMgr consul.ServerConnectionManager - - common.ConsulTenancyConfig -} - -// ReconcileResource reconciles an update to a resource. CRD-specific controller's -// call this function because it handles reconciliation of config entries -// generically. -// CRD-specific controller should pass themselves in as updater since we -// need to call back into their own update methods to ensure they update their -// internal state. -func (r *ConsulResourceController) ReconcileResource(ctx context.Context, crdCtrl ResourceController, req ctrl.Request, resource common.ConsulResource) (ctrl.Result, error) { - logger := crdCtrl.Logger(req.NamespacedName) - err := crdCtrl.Get(ctx, req.NamespacedName, resource) - if k8serr.IsNotFound(err) { - return ctrl.Result{}, client.IgnoreNotFound(err) - } else if err != nil { - logger.Error(err, "retrieving resource") - return ctrl.Result{}, err - } - - // Create Consul resource service client for this reconcile. - resourceClient, err := consul.NewResourceServiceClient(r.ConsulServerConnMgr) - if err != nil { - logger.Error(err, "failed to create Consul resource client", "name", req.Name, "ns", req.Namespace) - return ctrl.Result{}, err - } - - state, err := r.ConsulServerConnMgr.State() - if err != nil { - logger.Error(err, "failed to query Consul client state", "name", req.Name, "ns", req.Namespace) - return ctrl.Result{}, err - } - if state.Token != "" { - ctx = metadata.AppendToOutgoingContext(ctx, "x-consul-token", state.Token) - } - - if resource.GetDeletionTimestamp().IsZero() { - // The object is not being deleted, so if it does not have our finalizer, - // then let's add the finalizer and update the object. This is equivalent - // registering our finalizer. - if !slices.Contains(resource.GetFinalizers(), FinalizerName) { - resource.AddFinalizer(FinalizerName) - if err := r.syncUnknown(ctx, crdCtrl, resource); err != nil { - return ctrl.Result{}, err - } - } - } - - if !resource.GetDeletionTimestamp().IsZero() { - if slices.Contains(resource.GetFinalizers(), FinalizerName) { - // The object is being deleted - logger.Info("deletion event") - // Check to see if consul has config entry with the same name - res, err := resourceClient.Read(ctx, &pbresource.ReadRequest{Id: resource.ResourceID(r.consulNamespace(req.Namespace), r.getConsulPartition())}) - - // Ignore the error where the resource isn't found in Consul. - // It is indicative of desired state. - if err != nil && !isNotFoundErr(err) { - return ctrl.Result{}, fmt.Errorf("getting resource from Consul: %w", err) - } - - // In the case this resource was created outside of consul, skip the deletion process and continue - if !managedByConsulResourceController(res.GetResource()) { - logger.Info("resource in Consul was created outside of Kubernetes - skipping delete from Consul") - } - - if err == nil && managedByConsulResourceController(res.GetResource()) { - _, err := resourceClient.Delete(ctx, &pbresource.DeleteRequest{Id: resource.ResourceID(r.consulNamespace(req.Namespace), r.getConsulPartition())}) - if err != nil { - return r.syncFailed(ctx, logger, crdCtrl, resource, ConsulAgentError, - fmt.Errorf("deleting resource from Consul: %w", err)) - } - logger.Info("deletion from Consul successful") - } - // remove our finalizer from the list and update it. - resource.RemoveFinalizer(FinalizerName) - if err := crdCtrl.Update(ctx, resource); err != nil { - return ctrl.Result{}, err - } - logger.Info("finalizer removed") - } - - // Stop reconciliation as the item is being deleted - return ctrl.Result{}, nil - } - - // Check to see if consul has config entry with the same name - res, err := resourceClient.Read(ctx, &pbresource.ReadRequest{Id: resource.ResourceID(r.consulNamespace(req.Namespace), r.getConsulPartition())}) - - // In the case the namespace doesn't exist in Consul yet, assume we are racing with the namespace controller - // and requeue. - if tenancy.ConsulNamespaceIsNotFound(err) { - logger.Info("Consul namespace not found; re-queueing request", - "name", req.Name, "ns", req.Namespace, "consul-ns", - r.consulNamespace(req.Namespace), "err", err.Error()) - return ctrl.Result{Requeue: true}, nil - } - - // If resource with this name does not exist - if isNotFoundErr(err) { - logger.Info("resource not found in Consul") - - // Create the config entry - _, err := resourceClient.Write(ctx, &pbresource.WriteRequest{Resource: resource.Resource(r.consulNamespace(req.Namespace), r.getConsulPartition())}) - if err != nil { - return r.syncFailed(ctx, logger, crdCtrl, resource, ConsulAgentError, - fmt.Errorf("writing resource to Consul: %w", err)) - } - - logger.Info("resource created") - return r.syncSuccessful(ctx, crdCtrl, resource) - } - - // If there is an error when trying to get the resource from the api server, - // fail the reconcile. - if err != nil { - return r.syncFailed(ctx, logger, crdCtrl, resource, ConsulAgentError, err) - } - - // TODO: consider the case where we want to migrate a resource existing into Consul to a CRD with an annotation - if !managedByConsulResourceController(res.Resource) { - return r.syncFailed(ctx, logger, crdCtrl, resource, ExternallyManagedConfigError, - fmt.Errorf("resource already exists in Consul")) - } - - if !resource.MatchesConsul(res.Resource, r.consulNamespace(req.Namespace), r.getConsulPartition()) { - logger.Info("resource does not match Consul") - _, err := resourceClient.Write(ctx, &pbresource.WriteRequest{Resource: resource.Resource(r.consulNamespace(req.Namespace), r.getConsulPartition())}) - if err != nil { - return r.syncUnknownWithError(ctx, logger, crdCtrl, resource, ConsulAgentError, - fmt.Errorf("updating resource in Consul: %w", err)) - } - logger.Info("resource updated") - return r.syncSuccessful(ctx, crdCtrl, resource) - } else if resource.SyncedConditionStatus() != corev1.ConditionTrue { - return r.syncSuccessful(ctx, crdCtrl, resource) - } - - return ctrl.Result{}, nil -} - -// setupWithManager sets up the controller manager for the given resource -// with our default options. -func setupWithManager(mgr ctrl.Manager, resource client.Object, reconciler reconcile.Reconciler) error { - options := controller.Options{ - // Taken from https://github.com/kubernetes/client-go/blob/master/util/workqueue/default_rate_limiters.go#L39 - // and modified from a starting backoff of 5ms and max of 1000s to a - // starting backoff of 200ms and a max of 5s to better fit our most - // common error cases and performance characteristics. - // - // One common error case is that a resource is applied that requires - // a protocol like http or grpc. Often the user will apply a new resource - // to set the protocol in a minute or two. During this time, the - // default backoff could then be set up to 5m or more which means the - // original resource takes a long time to re-sync. - // - // In terms of performance, Consul servers can handle tens of thousands - // of writes per second, so retrying at max every 5s isn't an issue and - // provides a better UX. - RateLimiter: workqueue.NewMaxOfRateLimiter( - workqueue.NewItemExponentialFailureRateLimiter(200*time.Millisecond, 5*time.Second), - // 10 qps, 100 bucket size. This is only for retry speed, and it's only the overall factor (not per item) - &workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)}, - ), - } - - return ctrl.NewControllerManagedBy(mgr). - For(resource). - WithOptions(options). - Complete(reconciler) -} - -func (r *ConsulResourceController) syncFailed(ctx context.Context, logger logr.Logger, updater ResourceController, resource common.ConsulResource, errType string, err error) (ctrl.Result, error) { - resource.SetSyncedCondition(corev1.ConditionFalse, errType, err.Error()) - if updateErr := updater.UpdateStatus(ctx, resource); updateErr != nil { - // Log the original error here because we are returning the updateErr. - // Otherwise, the original error would be lost. - logger.Error(err, "sync failed") - return ctrl.Result{}, updateErr - } - return ctrl.Result{}, err -} - -func (r *ConsulResourceController) syncSuccessful(ctx context.Context, updater ResourceController, resource common.ConsulResource) (ctrl.Result, error) { - resource.SetSyncedCondition(corev1.ConditionTrue, "", "") - timeNow := metav1.NewTime(time.Now()) - resource.SetLastSyncedTime(&timeNow) - return ctrl.Result{}, updater.UpdateStatus(ctx, resource) -} - -func (r *ConsulResourceController) syncUnknown(ctx context.Context, updater ResourceController, resource common.ConsulResource) error { - resource.SetSyncedCondition(corev1.ConditionUnknown, "", "") - return updater.Update(ctx, resource) -} - -func (r *ConsulResourceController) syncUnknownWithError(ctx context.Context, - logger logr.Logger, - updater ResourceController, - resource common.ConsulResource, - errType string, - err error, -) (ctrl.Result, error) { - resource.SetSyncedCondition(corev1.ConditionUnknown, errType, err.Error()) - if updateErr := updater.UpdateStatus(ctx, resource); updateErr != nil { - // Log the original error here because we are returning the updateErr. - // Otherwise, the original error would be lost. - logger.Error(err, "sync status unknown") - return ctrl.Result{}, updateErr - } - return ctrl.Result{}, err -} - -// isNotFoundErr checks the grpc response code for "NotFound". -func isNotFoundErr(err error) bool { - if err == nil { - return false - } - s, ok := status.FromError(err) - if !ok { - return false - } - return codes.NotFound == s.Code() -} - -func (r *ConsulResourceController) consulNamespace(namespace string) string { - ns := namespaces.ConsulNamespace( - namespace, - r.EnableConsulNamespaces, - r.ConsulDestinationNamespace, - r.EnableNSMirroring, - r.NSMirroringPrefix, - ) - - // TODO: remove this if and when the default namespace of resources is no longer required to be set explicitly. - if ns == "" { - ns = constants.DefaultConsulNS - } - return ns -} - -func (r *ConsulResourceController) getConsulPartition() string { - if !r.EnableConsulPartitions || r.ConsulPartition == "" { - return constants.DefaultConsulPartition - } - return r.ConsulPartition -} - -func managedByConsulResourceController(resource *pbresource.Resource) bool { - if resource == nil { - return false - } - - consulMeta := resource.GetMetadata() - if consulMeta == nil { - return false - } - - if val, ok := consulMeta[common.SourceKey]; ok && val == common.SourceValue { - return true - } - return false -} diff --git a/control-plane/controllers/resources/exported_services_controller.go b/control-plane/controllers/resources/exported_services_controller.go deleted file mode 100644 index 8ee7a172a6..0000000000 --- a/control-plane/controllers/resources/exported_services_controller.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package resources - -import ( - "context" - - "github.com/go-logr/logr" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/types" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - - multiclusterv2 "github.com/hashicorp/consul-k8s/control-plane/api/multicluster/v2" -) - -// ExportedServicesController reconciles a MeshGateway object. -// -// NOTE: retaining this resource -type ExportedServicesController struct { - client.Client - Log logr.Logger - Scheme *runtime.Scheme - Controller *ConsulResourceController -} - -// +kubebuilder:rbac:groups=multicluster.consul.hashicorp.com,resources=exportedservices,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=multicluster.consul.hashicorp.com,resources=exportedservices/status,verbs=get;update;patch - -func (r *ExportedServicesController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - return r.Controller.ReconcileResource(ctx, r, req, &multiclusterv2.ExportedServices{}) -} - -func (r *ExportedServicesController) Logger(name types.NamespacedName) logr.Logger { - return r.Log.WithValues("request", name) -} - -func (r *ExportedServicesController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.SubResourceUpdateOption) error { - return r.Status().Update(ctx, obj, opts...) -} - -func (r *ExportedServicesController) SetupWithManager(mgr ctrl.Manager) error { - return setupWithManager(mgr, &multiclusterv2.ExportedServices{}, r) -} diff --git a/control-plane/go.mod b/control-plane/go.mod index db29e90540..0faf72cc2e 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -13,7 +13,6 @@ require ( github.com/hashicorp/consul-k8s/control-plane/cni v0.0.0-20240226161840-f3842c41cb2b github.com/hashicorp/consul-server-connection-manager v0.1.6 github.com/hashicorp/consul/api v1.29.1 - github.com/hashicorp/consul/proto-public v0.6.1 github.com/hashicorp/consul/sdk v0.16.1 github.com/hashicorp/go-bexpr v0.1.11 github.com/hashicorp/go-discover v0.0.0-20230519164032-214571b6a530 @@ -46,7 +45,6 @@ require ( k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 sigs.k8s.io/controller-runtime v0.16.5 sigs.k8s.io/gateway-api v0.7.1 - sigs.k8s.io/yaml v1.3.0 ) require ( @@ -95,6 +93,7 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect github.com/googleapis/gax-go/v2 v2.11.0 // indirect github.com/gophercloud/gophercloud v0.1.0 // indirect + github.com/hashicorp/consul/proto-public v0.6.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect @@ -159,6 +158,7 @@ require ( k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect + sigs.k8s.io/yaml v1.3.0 // indirect ) go 1.20 diff --git a/control-plane/helper/test/test_util.go b/control-plane/helper/test/test_util.go index 0cf96619d3..542700c34f 100644 --- a/control-plane/helper/test/test_util.go +++ b/control-plane/helper/test/test_util.go @@ -18,7 +18,6 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/hashicorp/consul-server-connection-manager/discovery" "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/consul/sdk/testutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -38,11 +37,10 @@ const ( ) type TestServerClient struct { - TestServer *testutil.TestServer - APIClient *api.Client - Cfg *consul.Config - Watcher consul.ServerConnectionManager - ResourceClient pbresource.ResourceServiceClient + TestServer *testutil.TestServer + APIClient *api.Client + Cfg *consul.Config + Watcher consul.ServerConnectionManager } func TestServerWithMockConnMgrWatcher(t *testing.T, callback testutil.ServerConfigCallback) *TestServerClient { @@ -74,17 +72,13 @@ func TestServerWithMockConnMgrWatcher(t *testing.T, callback testutil.ServerConf requireACLBootstrapped(t, cfg, client) watcher := MockConnMgrForIPAndPort(t, "127.0.0.1", cfg.Ports.GRPC, true) - resourceClient, err := consul.NewResourceServiceClient(watcher) - require.NoError(t, err) - requireTenancyBuiltins(t, cfg, client) return &TestServerClient{ - TestServer: consulServer, - APIClient: client, - Cfg: consulConfig, - Watcher: watcher, - ResourceClient: resourceClient, + TestServer: consulServer, + APIClient: client, + Cfg: consulConfig, + Watcher: watcher, } } @@ -314,27 +308,6 @@ func SetupK8sAuthMethodWithNamespaces(t *testing.T, consulClient *api.Client, se require.NoError(t, err) } -// ResourceHasPersisted checks that a recently written resource exists in the Consul -// state store with a valid version. This must be true before a resource is overwritten -// or deleted. -func ResourceHasPersisted(t *testing.T, ctx context.Context, client pbresource.ResourceServiceClient, id *pbresource.ID) { - req := &pbresource.ReadRequest{Id: id} - - require.Eventually(t, func() bool { - res, err := client.Read(ctx, req) - if err != nil { - return false - } - - if res.GetResource().GetVersion() == "" { - return false - } - - return true - }, 5*time.Second, - time.Second) -} - func TokenReviewsResponse(name, ns string) string { return fmt.Sprintf(`{ "kind": "TokenReview", diff --git a/control-plane/subcommand/inject-connect/command.go b/control-plane/subcommand/inject-connect/command.go index 138d1c5e83..fb43c034dc 100644 --- a/control-plane/subcommand/inject-connect/command.go +++ b/control-plane/subcommand/inject-connect/command.go @@ -32,7 +32,6 @@ import ( gwv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" gwv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" - multiclusterv2 "github.com/hashicorp/consul-k8s/control-plane/api/multicluster/v2" "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" "github.com/hashicorp/consul-k8s/control-plane/connect-inject/constants" "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" @@ -169,10 +168,6 @@ func init() { utilruntime.Must(gwv1beta1.AddToScheme(scheme)) utilruntime.Must(gwv1alpha2.AddToScheme(scheme)) - // V2 resources - utilruntime.Must(multiclusterv2.AddMultiClusterToScheme(scheme)) - - // +kubebuilder:scaffold:scheme } func (c *Command) init() { diff --git a/control-plane/subcommand/inject-connect/v1controllers.go b/control-plane/subcommand/inject-connect/v1controllers.go index 08d1a1522e..033b911cad 100644 --- a/control-plane/subcommand/inject-connect/v1controllers.go +++ b/control-plane/subcommand/inject-connect/v1controllers.go @@ -14,7 +14,6 @@ import ( gatewaycommon "github.com/hashicorp/consul-k8s/control-plane/api-gateway/common" gatewaycontrollers "github.com/hashicorp/consul-k8s/control-plane/api-gateway/controllers" - "github.com/hashicorp/consul-k8s/control-plane/api/common" apicommon "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/catalog/registration" @@ -24,7 +23,6 @@ import ( "github.com/hashicorp/consul-k8s/control-plane/connect-inject/metrics" "github.com/hashicorp/consul-k8s/control-plane/connect-inject/webhook" controllers "github.com/hashicorp/consul-k8s/control-plane/controllers/configentries" - resourceControllers "github.com/hashicorp/consul-k8s/control-plane/controllers/resources" webhookconfiguration "github.com/hashicorp/consul-k8s/control-plane/helper/webhook-configuration" "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" ) @@ -215,32 +213,6 @@ func (c *Command) configureControllers(ctx context.Context, mgr manager.Manager, setupLog.Error(err, "unable to create controller", "controller", apicommon.ExportedServices) return err } - - if false { - // TODO: revisit if this is even necessary here; it was not activated in v1 mode at all previously - consulTenancyConfig := common.ConsulTenancyConfig{ - EnableConsulPartitions: c.flagEnablePartitions, - EnableConsulNamespaces: c.flagEnableNamespaces, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - EnableNSMirroring: c.flagEnableK8SNSMirroring, - NSMirroringPrefix: c.flagK8SNSMirroringPrefix, - ConsulPartition: c.consul.Partition, - } - consulResourceController := &resourceControllers.ConsulResourceController{ - ConsulClientConfig: consulConfig, - ConsulServerConnMgr: watcher, - ConsulTenancyConfig: consulTenancyConfig, - } - // IF retained, the name should change to avoid conflict. - if err := (&resourceControllers.ExportedServicesController{ - Controller: consulResourceController, - Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(apicommon.ExportedServices), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", apicommon.ExportedServices) - return err - } - } if err := (&controllers.ServiceRouterController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(),