From 1237f2824080aaca2b06133d694bd73a786f37f3 Mon Sep 17 00:00:00 2001 From: Saad Date: Wed, 18 Aug 2021 15:46:23 -0700 Subject: [PATCH 001/418] Combined .gitignore for merge-repos and ignore the .idea from JetBrains IDEs. --- .gitignore | 3 +++ control-plane/.gitignore | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 control-plane/.gitignore diff --git a/.gitignore b/.gitignore index f7de6f7f94..15208bcff3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ terraform.tfstate* terraform.tfvars values.dev.yaml +bin/ +pkg/ +.idea/ \ No newline at end of file diff --git a/control-plane/.gitignore b/control-plane/.gitignore deleted file mode 100644 index 14f1aa298b..0000000000 --- a/control-plane/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.DS_Store -/bin -/pkg From fa9ed1bcdfcc99209be02dad9ceefb616e6dcb62 Mon Sep 17 00:00:00 2001 From: Saad Date: Wed, 18 Aug 2021 15:50:30 -0700 Subject: [PATCH 002/418] Files should end in new-lines. --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 15208bcff3..33b40aed54 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ terraform.tfvars values.dev.yaml bin/ pkg/ -.idea/ \ No newline at end of file +.idea/ From a1a3586d59a83aa60fe25afc25d014be9a71f32e Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 31 Aug 2021 12:32:43 -0600 Subject: [PATCH 003/418] Add startup probe to connect inject deployment. (#701) We did so in https://github.com/hashicorp/consul-helm/pull/885, but it never got released. This adds the same probe now that we have a health endpoint in the webhook. This also changes the periodSeconds for the liveness and readiness probes to use the default of 10s instead of 2s we used previously. That is because now with the startup probe in place, we don't need to check for certs being present that frequently. --- CHANGELOG.md | 2 +- charts/consul/templates/connect-inject-deployment.yaml | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7db21a5eb9..e57f00259a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ IMPROVEMENTS: * Helm Chart * Add ability to specify port for ui service. [[GH-604](https://github.com/hashicorp/consul-k8s/pull/604)] * Use `policy/v1` for Consul server `PodDisruptionBudget` if supported. [[GH-606](https://github.com/hashicorp/consul-k8s/pull/606)] - * Added readiness and liveness checks to the connect inject deployment. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)] + * Added readiness, liveness and startup probes to the connect inject deployment. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)][[GH-701](https://github.com/hashicorp/consul-k8s/pull/701)] * Add support for setting container security contexts on client and server Pods. [[GH-620](https://github.com/hashicorp/consul-k8s/pull/620)] * Control Plane * Added health endpoint to the connect inject webhook that will be healthy when webhook certs are present and not empty. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)] diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index 8fa83948b4..8e00c7f250 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -193,6 +193,14 @@ spec: -consul-sidecar-cpu-request={{ $consulSidecarResources.requests.cpu }} \ {{- end }} {{- end }} + startupProbe: + httpGet: + path: /readyz/ready + port: 9445 + scheme: HTTP + failureThreshold: 15 + periodSeconds: 2 + timeoutSeconds: 5 livenessProbe: httpGet: path: /readyz/ready @@ -200,7 +208,6 @@ spec: scheme: HTTP failureThreshold: 2 initialDelaySeconds: 1 - periodSeconds: 2 successThreshold: 1 timeoutSeconds: 5 readinessProbe: @@ -210,7 +217,6 @@ spec: scheme: HTTP failureThreshold: 2 initialDelaySeconds: 2 - periodSeconds: 2 successThreshold: 1 timeoutSeconds: 5 volumeMounts: From a81d9a1c1bfad140877fba73a285d60e04298219 Mon Sep 17 00:00:00 2001 From: David Yu Date: Tue, 31 Aug 2021 15:16:25 -0700 Subject: [PATCH 004/418] values.yaml: Make it more clear how to utilize connectInject.namespaceSelector (#703) * values.yaml: Make it more clear how to utilize connectInject.namespaceSelector Describe that `connectInject.default` should be used if trying to enable/disable `connectInject` by default. Addresses: https://github.com/hashicorp/consul-k8s/issues/698 --- charts/consul/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 946c052b09..72d04f9c70 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -1556,8 +1556,8 @@ connectInject: # This setting can be safely disabled by setting to "Ignore". failurePolicy: "Fail" - # Selector for restricting the webhook to only - # specific namespaces. This should be set to a multiline string. + # Selector for restricting the webhook to only specific namespaces. + # Use with `connectInject.default: true` to automatically inject all pods in namespaces that match the selector. This should be set to a multiline string. # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-namespaceselector # for more details. # From b5d2de83eb5c6c98a216e5fb9d28a9a454ae1a97 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 31 Aug 2021 20:08:24 -0400 Subject: [PATCH 005/418] Use command struct ctx in server-acl-init (#707) * Change to single ctx in connect_inject_test * Use ctx from command struct --- control-plane/subcommand/server-acl-init/command.go | 10 +++++----- .../subcommand/server-acl-init/command_test.go | 4 ++-- .../subcommand/server-acl-init/connect_inject.go | 5 ++--- .../subcommand/server-acl-init/connect_inject_test.go | 9 +++++---- .../subcommand/server-acl-init/create_or_update.go | 5 ++--- control-plane/subcommand/server-acl-init/servers.go | 3 +-- 6 files changed, 17 insertions(+), 19 deletions(-) diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index 0625b056b9..f5737632c0 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -91,8 +91,8 @@ type Command struct { clientset kubernetes.Interface - // cmdTimeout is cancelled when the command timeout is reached. - cmdTimeout context.Context + // ctx is cancelled when the command timeout is reached. + ctx context.Context retryDuration time.Duration // log @@ -276,7 +276,7 @@ func (c *Command) Run(args []string) int { } var cancel context.CancelFunc - c.cmdTimeout, cancel = context.WithTimeout(context.Background(), c.flagTimeout) + c.ctx, cancel = context.WithTimeout(context.Background(), c.flagTimeout) // The context will only ever be intentionally ended by the timeout. defer cancel() @@ -687,7 +687,7 @@ func (c *Command) Run(args []string) int { // reading the Kubernetes Secret with name secretName. // If there is no bootstrap token yet, then it returns an empty string (not an error). func (c *Command) getBootstrapToken(secretName string) (string, error) { - secret, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Get(context.TODO(), secretName, metav1.GetOptions{}) + secret, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Get(c.ctx, secretName, metav1.GetOptions{}) if err != nil { if k8serrors.IsNotFound(err) { return "", nil @@ -729,7 +729,7 @@ func (c *Command) untilSucceeds(opName string, op func() error) error { select { case <-time.After(c.retryDuration): continue - case <-c.cmdTimeout.Done(): + case <-c.ctx.Done(): return errors.New("reached command timeout") } } diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index 037731de62..1a3d81ab2d 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -1448,8 +1448,8 @@ func TestConsulDatacenterList(t *testing.T) { require.NoError(t, err) command := Command{ - log: hclog.New(hclog.DefaultOptions), - cmdTimeout: context.Background(), + log: hclog.New(hclog.DefaultOptions), + ctx: context.Background(), } actDC, actPrimaryDC, err := command.consulDatacenterList(consulClient) if c.expErr != "" { diff --git a/control-plane/subcommand/server-acl-init/connect_inject.go b/control-plane/subcommand/server-acl-init/connect_inject.go index 6389b6d3c8..4764517ea6 100644 --- a/control-plane/subcommand/server-acl-init/connect_inject.go +++ b/control-plane/subcommand/server-acl-init/connect_inject.go @@ -1,7 +1,6 @@ package serveraclinit import ( - "context" "errors" "fmt" @@ -144,7 +143,7 @@ func (c *Command) createAuthMethodTmpl(authMethodName string) (api.ACLAuthMethod err := c.untilSucceeds(fmt.Sprintf("getting %s ServiceAccount", saName), func() error { var err error - authMethodServiceAccount, err = c.clientset.CoreV1().ServiceAccounts(c.flagK8sNamespace).Get(context.TODO(), saName, metav1.GetOptions{}) + authMethodServiceAccount, err = c.clientset.CoreV1().ServiceAccounts(c.flagK8sNamespace).Get(c.ctx, saName, metav1.GetOptions{}) return err }) if err != nil { @@ -161,7 +160,7 @@ func (c *Command) createAuthMethodTmpl(authMethodName string) (api.ACLAuthMethod err = c.untilSucceeds(fmt.Sprintf("getting %s Secret", secretRef.Name), func() error { var err error - secret, err = c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Get(context.TODO(), secretRef.Name, metav1.GetOptions{}) + secret, err = c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Get(c.ctx, secretRef.Name, metav1.GetOptions{}) return err }) if secret != nil && secret.Type == apiv1.SecretTypeServiceAccountToken { diff --git a/control-plane/subcommand/server-acl-init/connect_inject_test.go b/control-plane/subcommand/server-acl-init/connect_inject_test.go index cad81d8b3c..556148acc4 100644 --- a/control-plane/subcommand/server-acl-init/connect_inject_test.go +++ b/control-plane/subcommand/server-acl-init/connect_inject_test.go @@ -19,23 +19,24 @@ import ( // Also note that the remainder of this function is tested in the command_test.go. func TestCommand_createAuthMethodTmpl_SecretNotFound(t *testing.T) { k8s := fake.NewSimpleClientset() + ctx := context.Background() cmd := &Command{ flagK8sNamespace: ns, flagResourcePrefix: resourcePrefix, clientset: k8s, log: hclog.New(nil), - cmdTimeout: context.TODO(), + ctx: ctx, } serviceAccountName := resourcePrefix + "-connect-injector-authmethod-svc-account" secretName := resourcePrefix + "-connect-injector-authmethod-svc-account" // Create a service account referencing secretName - sa, _ := k8s.CoreV1().ServiceAccounts(ns).Get(context.Background(), serviceAccountName, metav1.GetOptions{}) + sa, _ := k8s.CoreV1().ServiceAccounts(ns).Get(ctx, serviceAccountName, metav1.GetOptions{}) if sa == nil { _, err := k8s.CoreV1().ServiceAccounts(ns).Create( - context.Background(), + ctx, &v1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: serviceAccountName, @@ -58,7 +59,7 @@ func TestCommand_createAuthMethodTmpl_SecretNotFound(t *testing.T) { Data: map[string][]byte{}, Type: v1.SecretTypeOpaque, } - _, err := k8s.CoreV1().Secrets(ns).Create(context.TODO(), secret, metav1.CreateOptions{}) + _, err := k8s.CoreV1().Secrets(ns).Create(ctx, secret, metav1.CreateOptions{}) require.NoError(t, err) _, err = cmd.createAuthMethodTmpl("test") diff --git a/control-plane/subcommand/server-acl-init/create_or_update.go b/control-plane/subcommand/server-acl-init/create_or_update.go index 4710258c84..404426ebfa 100644 --- a/control-plane/subcommand/server-acl-init/create_or_update.go +++ b/control-plane/subcommand/server-acl-init/create_or_update.go @@ -1,7 +1,6 @@ package serveraclinit import ( - "context" "fmt" "strings" @@ -57,7 +56,7 @@ func (c *Command) createACL(name, rules string, localToken bool, dc string, isPr // Check if the secret already exists, if so, we assume the ACL has already been // created and return. secretName := c.withPrefix(name + "-acl-token") - _, err = c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Get(context.TODO(), secretName, metav1.GetOptions{}) + _, err = c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Get(c.ctx, secretName, metav1.GetOptions{}) if err == nil { c.log.Info(fmt.Sprintf("Secret %q already exists", secretName)) return nil @@ -93,7 +92,7 @@ func (c *Command) createACL(name, rules string, localToken bool, dc string, isPr common.ACLTokenSecretKey: []byte(token), }, } - _, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Create(context.TODO(), secret, metav1.CreateOptions{}) + _, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Create(c.ctx, secret, metav1.CreateOptions{}) return err }) } diff --git a/control-plane/subcommand/server-acl-init/servers.go b/control-plane/subcommand/server-acl-init/servers.go index 8e4b782481..09f1c6e789 100644 --- a/control-plane/subcommand/server-acl-init/servers.go +++ b/control-plane/subcommand/server-acl-init/servers.go @@ -1,7 +1,6 @@ package serveraclinit import ( - "context" "errors" "fmt" "strings" @@ -73,7 +72,7 @@ func (c *Command) bootstrapServers(serverAddresses []string, bootTokenSecretName common.ACLTokenSecretKey: bootstrapToken, }, } - _, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Create(context.TODO(), secret, metav1.CreateOptions{}) + _, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Create(c.ctx, secret, metav1.CreateOptions{}) return err }) if err != nil { From b7ef83cc25b403ffd6a05f353b9d93776ea88522 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 31 Aug 2021 18:23:00 -0600 Subject: [PATCH 006/418] Update AKS version in tests (#702) --- charts/consul/test/terraform/aks/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/consul/test/terraform/aks/main.tf b/charts/consul/test/terraform/aks/main.tf index 77df4bcd05..0406afd0b2 100644 --- a/charts/consul/test/terraform/aks/main.tf +++ b/charts/consul/test/terraform/aks/main.tf @@ -24,7 +24,7 @@ resource "azurerm_kubernetes_cluster" "default" { location = azurerm_resource_group.default[count.index].location resource_group_name = azurerm_resource_group.default[count.index].name dns_prefix = "consul-k8s-${random_id.suffix[count.index].dec}" - kubernetes_version = "1.19.9" + kubernetes_version = "1.19.13" default_node_pool { name = "default" From edb12863a5a6bab0235b29e7036628a8ed0a5e9a Mon Sep 17 00:00:00 2001 From: NicoletaPopoviciu <87660255+NicoletaPopoviciu@users.noreply.github.com> Date: Wed, 1 Sep 2021 12:07:14 -0400 Subject: [PATCH 007/418] Allow registering the same service in multiple namespaces. (#697) * Allow registering the same service in multiple namespaces. * Added changelog entry --- CHANGELOG.md | 2 +- .../connect-inject/endpoints_controller.go | 21 ----- .../endpoints_controller_test.go | 78 ------------------- 3 files changed, 1 insertion(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e57f00259a..210c72fc7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ IMPROVEMENTS: * Control Plane * Added health endpoint to the connect inject webhook that will be healthy when webhook certs are present and not empty. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)] * Catalog Sync: Fix issue registering NodePort services with wrong IPs when a node has multiple IP addresses. [[GH-619](https://github.com/hashicorp/consul-k8s/pull/619)] - + * Allow registering the same service in multiple namespaces. [[GH-697](https://github.com/hashicorp/consul-k8s/pull/697)] ## 0.33.0 (August 12, 2021) diff --git a/control-plane/connect-inject/endpoints_controller.go b/control-plane/connect-inject/endpoints_controller.go index 104c6cb1c1..247bcbd55c 100644 --- a/control-plane/connect-inject/endpoints_controller.go +++ b/control-plane/connect-inject/endpoints_controller.go @@ -232,27 +232,6 @@ func (r *EndpointsController) registerServicesAndHealthCheck(ctx context.Context return err } - // When Consul namespaces are not enabled, we check that the service with the same name but in a different namespace - // is already registered with Consul, and if it is, we skip the registration to avoid service name collisions. - if !r.EnableConsulNamespaces { - services, _, err := client.Catalog().Service(serviceRegistration.Name, "", nil) - if err != nil { - r.Log.Error(err, "failed to get service from the Consul catalog", "name", serviceRegistration.Name) - return err - } - for _, service := range services { - if existingNS, ok := service.ServiceMeta[MetaKeyKubeNS]; ok && existingNS != serviceEndpoints.Namespace { - // Log but don't return an error because we don't want to reconcile this endpoints object again. - r.Log.Info("Skipping service registration because a service with the same name "+ - "but a different Kubernetes namespace is already registered with Consul", - "name", serviceRegistration.Name, - MetaKeyKubeNS, serviceEndpoints.Namespace, - "existing-k8s-namespace", existingNS) - return nil - } - } - } - // Register the service instance with the local agent. // Note: the order of how we register services is important, // and the connect-proxy service should come after the "main" service diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index 049864099b..ec3898c8f3 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -4658,84 +4658,6 @@ func TestCreateServiceRegistrations_withTransparentProxy(t *testing.T) { } } -func TestRegisterServicesAndHealthCheck_skipsWhenDuplicateServiceFound(t *testing.T) { - t.Parallel() - - nodeName := "test-node" - consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { - c.NodeName = nodeName - }) - require.NoError(t, err) - defer consul.Stop() - - consul.WaitForServiceIntentions(t) - httpAddr := consul.HTTPAddr - clientConfig := &api.Config{ - Address: httpAddr, - } - consulClient, err := api.NewClient(clientConfig) - require.NoError(t, err) - addr := strings.Split(httpAddr, ":") - consulPort := addr[1] - - existingService := &api.AgentServiceRegistration{ - ID: "test-service", - Name: "test-service", - Port: 1234, - Address: "1.2.3.4", - Meta: map[string]string{MetaKeyKubeNS: "some-other-ns"}, - } - err = consulClient.Agent().ServiceRegister(existingService) - require.NoError(t, err) - pod := createPod("test-pod", "1.1.1.1", true, true) - - endpointsAddress := corev1.EndpointAddress{ - IP: "1.2.3.4", - NodeName: &nodeName, - TargetRef: &corev1.ObjectReference{ - Kind: "Pod", - Name: pod.Name, - Namespace: pod.Namespace, - }, - } - endpoints := &corev1.Endpoints{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-service", - Namespace: "default", - }, - Subsets: []corev1.EndpointSubset{ - { - Addresses: []corev1.EndpointAddress{endpointsAddress}, - }, - }, - } - ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}} - fakeClient := fake.NewClientBuilder().WithRuntimeObjects(ns, pod, endpoints).Build() - - ep := &EndpointsController{ - Log: logrtest.TestLogger{T: t}, - ConsulClient: consulClient, - ConsulPort: consulPort, - ConsulScheme: "http", - ConsulClientCfg: clientConfig, - AllowK8sNamespacesSet: mapset.NewSetWith("*"), - DenyK8sNamespacesSet: mapset.NewSetWith(), - Client: fakeClient, - } - - err = ep.registerServicesAndHealthCheck(context.Background(), *endpoints, endpointsAddress, api.HealthPassing, make(map[string]bool)) - require.NoError(t, err) - - // Check that the service is not registered with Consul. - _, _, err = consulClient.Agent().Service("test-pod-test-service", nil) - require.Error(t, err) - require.Contains(t, err.Error(), "Unexpected response code: 404 (unknown service ID") - - _, _, err = consulClient.Agent().Service("test-pod-test-service-sidecar-proxy", nil) - require.Error(t, err) - require.Contains(t, err.Error(), "Unexpected response code: 404 (unknown service ID") -} - func TestGetTokenMetaFromDescription(t *testing.T) { t.Parallel() cases := map[string]struct { From 1f7b1bded9b0b5a9b1a26e9b3f50d8d3808c93dc Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 1 Sep 2021 14:43:41 -0400 Subject: [PATCH 008/418] Change tense of current changelog and add Envoy update entry (#709) * Change tense of current CHANGELOG entries * Add Envoy update to CHANGELOG --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 210c72fc7b..41bb6ec661 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,11 @@ IMPROVEMENTS: * Helm Chart * Add ability to specify port for ui service. [[GH-604](https://github.com/hashicorp/consul-k8s/pull/604)] * Use `policy/v1` for Consul server `PodDisruptionBudget` if supported. [[GH-606](https://github.com/hashicorp/consul-k8s/pull/606)] - * Added readiness, liveness and startup probes to the connect inject deployment. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)][[GH-701](https://github.com/hashicorp/consul-k8s/pull/701)] + * Add readiness, liveness and startup probes to the connect inject deployment. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)][[GH-701](https://github.com/hashicorp/consul-k8s/pull/701)] * Add support for setting container security contexts on client and server Pods. [[GH-620](https://github.com/hashicorp/consul-k8s/pull/620)] + * Update Envoy image to 1.18.4 [[GH-699](https://github.com/hashicorp/consul-k8s/pull/699)] * Control Plane - * Added health endpoint to the connect inject webhook that will be healthy when webhook certs are present and not empty. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)] + * Add health endpoint to the connect inject webhook that will be healthy when webhook certs are present and not empty. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)] * Catalog Sync: Fix issue registering NodePort services with wrong IPs when a node has multiple IP addresses. [[GH-619](https://github.com/hashicorp/consul-k8s/pull/619)] * Allow registering the same service in multiple namespaces. [[GH-697](https://github.com/hashicorp/consul-k8s/pull/697)] From 1b15f633c683fdae62e6770d64f4681a68ec73f6 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 1 Sep 2021 15:35:20 -0400 Subject: [PATCH 009/418] Add present tense note to PR template (#708) * Add present tense note to PR template * Update .github/pull_request_template.md Co-authored-by: Iryna Shustava Co-authored-by: Iryna Shustava --- .github/pull_request_template.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 0fe76eff6e..b615e69dd1 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -9,5 +9,7 @@ How I expect reviewers to test this PR: Checklist: - [ ] Tests added -- [ ] CHANGELOG entry added (*HashiCorp engineers only, community PRs should not add a changelog entry*) +- [ ] CHANGELOG entry added + > HashiCorp engineers only, community PRs should not add a changelog entry. + > Entries should use present tense (e.g. Add support for...) From 4e510e6c8515b01748d85417fc8413ae4f4b3601 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Wed, 1 Sep 2021 17:39:27 -0600 Subject: [PATCH 010/418] Disable openshift tests until we can use UBI images (#704) --- .circleci/config.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8e83d51017..5a9b4d80ff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -946,9 +946,10 @@ workflows: - cleanup-gcp-resources - cleanup-azure-resources - cleanup-eks-resources - - acceptance-openshift: - requires: - - cleanup-azure-resources +# Disable until we can use UBI images. +# - acceptance-openshift: +# requires: +# - cleanup-azure-resources - acceptance-gke-1-17: requires: - cleanup-gcp-resources From 306fde7c28be72c9c0c49619e66e84920f8b60b9 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 2 Sep 2021 11:35:56 -0400 Subject: [PATCH 011/418] Use root context in sync-catalog to-k8s (#710) * Use root context in sync-catalog to-k8s * Grammatical fixes --- control-plane/catalog/to-k8s/sink.go | 15 +++++++++------ control-plane/catalog/to-k8s/sink_test.go | 1 + control-plane/subcommand/sync-catalog/command.go | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/control-plane/catalog/to-k8s/sink.go b/control-plane/catalog/to-k8s/sink.go index a823842fb3..e3bfed7789 100644 --- a/control-plane/catalog/to-k8s/sink.go +++ b/control-plane/catalog/to-k8s/sink.go @@ -51,6 +51,9 @@ type K8SSink struct { // done if there are no changes. SyncPeriod time.Duration + // Ctx is used to cancel the Sink. + Ctx context.Context + // lock gates concurrent access to all the maps. lock sync.Mutex @@ -105,11 +108,11 @@ func (s *K8SSink) Informer() cache.SharedIndexInformer { return cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { - return s.Client.CoreV1().Services(s.namespace()).List(context.TODO(), options) + return s.Client.CoreV1().Services(s.namespace()).List(s.Ctx, options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return s.Client.CoreV1().Services(s.namespace()).Watch(context.TODO(), options) + return s.Client.CoreV1().Services(s.namespace()).Watch(s.Ctx, options) }, }, &apiv1.Service{}, @@ -207,7 +210,7 @@ func (s *K8SSink) Run(ch <-chan struct{}) { return case <-triggerCh: // Coalesce to prevent lots of API calls during churn periods. - coalesce.Coalesce(context.TODO(), + coalesce.Coalesce(s.Ctx, K8SQuietPeriod, K8SMaxPeriod, func(ctx context.Context) { select { @@ -224,20 +227,20 @@ func (s *K8SSink) Run(ch <-chan struct{}) { svcClient := s.Client.CoreV1().Services(s.namespace()) for _, name := range delete { - if err := svcClient.Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil { + if err := svcClient.Delete(s.Ctx, name, metav1.DeleteOptions{}); err != nil { s.Log.Warn("error deleting service", "name", name, "error", err) } } for _, svc := range update { - _, err := svcClient.Update(context.TODO(), svc, metav1.UpdateOptions{}) + _, err := svcClient.Update(s.Ctx, svc, metav1.UpdateOptions{}) if err != nil { s.Log.Warn("error updating service", "name", svc.Name, "error", err) } } for _, svc := range create { - _, err := svcClient.Create(context.TODO(), svc, metav1.CreateOptions{}) + _, err := svcClient.Create(s.Ctx, svc, metav1.CreateOptions{}) if err != nil { s.Log.Warn("error creating service", "name", svc.Name, "error", err) } diff --git a/control-plane/catalog/to-k8s/sink_test.go b/control-plane/catalog/to-k8s/sink_test.go index d66102cde2..3d5270af39 100644 --- a/control-plane/catalog/to-k8s/sink_test.go +++ b/control-plane/catalog/to-k8s/sink_test.go @@ -398,6 +398,7 @@ func testSink(t *testing.T, client kubernetes.Interface) (*K8SSink, func()) { sink := &K8SSink{ Client: client, Log: hclog.Default(), + Ctx: context.Background(), } closer := controller.TestControllerRun(sink) diff --git a/control-plane/subcommand/sync-catalog/command.go b/control-plane/subcommand/sync-catalog/command.go index be893f0a54..85c1f8519a 100644 --- a/control-plane/subcommand/sync-catalog/command.go +++ b/control-plane/subcommand/sync-catalog/command.go @@ -293,6 +293,7 @@ func (c *Command) Run(args []string) int { Client: c.clientset, Namespace: c.flagK8SWriteNamespace, Log: c.logger.Named("to-k8s/sink"), + Ctx: ctx, } source := &catalogtok8s.Source{ From 7423b106e50d420e08751e4c1e9de809983d336f Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 7 Sep 2021 16:55:15 -0400 Subject: [PATCH 012/418] Move Contexts to Command structs (#711) * Use root context in sync-catalog to-k8s * Grammatical fixes * Use context in ServiceResource * Move ctx setting to within Command struct * Move set context on create-federation-secret command * Use ctx on delete-completed-job Command * Use ctx on create-federation-secret Command * Use ctx on service-address Command struct * Move context initialization up in Run * Remove setting the `ctx` explicitly in act-init/command_test --- control-plane/catalog/to-consul/resource.go | 18 +++++++++++------- .../catalog/to-consul/resource_test.go | 1 + control-plane/subcommand/acl-init/command.go | 8 +++++++- .../create-federation-secret/command.go | 11 ++++++++--- .../subcommand/delete-completed-job/command.go | 18 ++++++++++++------ .../subcommand/service-address/command.go | 8 +++++++- .../subcommand/sync-catalog/command.go | 1 + 7 files changed, 47 insertions(+), 18 deletions(-) diff --git a/control-plane/catalog/to-consul/resource.go b/control-plane/catalog/to-consul/resource.go index 9fd0b5cfc0..dd170e4990 100644 --- a/control-plane/catalog/to-consul/resource.go +++ b/control-plane/catalog/to-consul/resource.go @@ -53,6 +53,9 @@ type ServiceResource struct { Client kubernetes.Interface Syncer Syncer + // Ctx is used to cancel processes kicked off by ServiceResource. + Ctx context.Context + // AllowK8sNamespacesSet is a set of k8s namespaces to explicitly allow for // syncing. It supports the special character `*` which indicates that // all k8s namespaces are eligible unless explicitly denied. This filter @@ -143,11 +146,11 @@ func (t *ServiceResource) Informer() cache.SharedIndexInformer { return cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { - return t.Client.CoreV1().Services(metav1.NamespaceAll).List(context.TODO(), options) + return t.Client.CoreV1().Services(metav1.NamespaceAll).List(t.Ctx, options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return t.Client.CoreV1().Services(metav1.NamespaceAll).Watch(context.TODO(), options) + return t.Client.CoreV1().Services(metav1.NamespaceAll).Watch(t.Ctx, options) }, }, &apiv1.Service{}, @@ -191,7 +194,7 @@ func (t *ServiceResource) Upsert(key string, raw interface{}) error { if t.shouldTrackEndpoints(key) { endpoints, err := t.Client.CoreV1(). Endpoints(service.Namespace). - Get(context.TODO(), service.Name, metav1.GetOptions{}) + Get(t.Ctx, service.Name, metav1.GetOptions{}) if err != nil { t.Log.Warn("error loading initial endpoints", "key", key, @@ -242,7 +245,7 @@ func (t *ServiceResource) Run(ch <-chan struct{}) { t.Log.Info("starting runner for endpoints") (&controller.Controller{ Log: t.Log.Named("controller/endpoints"), - Resource: &serviceEndpointsResource{Service: t}, + Resource: &serviceEndpointsResource{Service: t, Ctx: t.Ctx}, }).Run(ch) } @@ -526,7 +529,7 @@ func (t *ServiceResource) generateRegistrations(key string) { } // Look up the node's ip address by getting node info - node, err := t.Client.CoreV1().Nodes().Get(context.TODO(), *subsetAddr.NodeName, metav1.GetOptions{}) + node, err := t.Client.CoreV1().Nodes().Get(t.Ctx, *subsetAddr.NodeName, metav1.GetOptions{}) if err != nil { t.Log.Warn("error getting node info", "error", err) continue @@ -683,6 +686,7 @@ func (t *ServiceResource) sync() { // to keep track of changing endpoints for registered services. type serviceEndpointsResource struct { Service *ServiceResource + Ctx context.Context } func (t *serviceEndpointsResource) Informer() cache.SharedIndexInformer { @@ -695,13 +699,13 @@ func (t *serviceEndpointsResource) Informer() cache.SharedIndexInformer { ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { return t.Service.Client.CoreV1(). Endpoints(metav1.NamespaceAll). - List(context.TODO(), options) + List(t.Ctx, options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { return t.Service.Client.CoreV1(). Endpoints(metav1.NamespaceAll). - Watch(context.TODO(), options) + Watch(t.Ctx, options) }, }, &apiv1.Endpoints{}, diff --git a/control-plane/catalog/to-consul/resource_test.go b/control-plane/catalog/to-consul/resource_test.go index 5dc0f5e04a..461f87bd0c 100644 --- a/control-plane/catalog/to-consul/resource_test.go +++ b/control-plane/catalog/to-consul/resource_test.go @@ -1597,6 +1597,7 @@ func defaultServiceResource(client kubernetes.Interface, syncer Syncer) ServiceR Log: hclog.Default(), Client: client, Syncer: syncer, + Ctx: context.Background(), AllowK8sNamespacesSet: mapset.NewSet("*"), DenyK8sNamespacesSet: mapset.NewSet(), ConsulNodeName: ConsulSyncNodeName, diff --git a/control-plane/subcommand/acl-init/command.go b/control-plane/subcommand/acl-init/command.go index 8bb7aee4b2..6017137bbf 100644 --- a/control-plane/subcommand/acl-init/command.go +++ b/control-plane/subcommand/acl-init/command.go @@ -34,6 +34,8 @@ type Command struct { once sync.Once help string + + ctx context.Context } func (c *Command) init() { @@ -64,6 +66,10 @@ func (c *Command) Run(args []string) int { return 1 } + if c.ctx == nil { + c.ctx = context.Background() + } + // Create the Kubernetes clientset if c.k8sClient == nil { config, err := subcommand.K8SConfig(c.k8s.KubeConfig()) @@ -128,7 +134,7 @@ func (c *Command) Run(args []string) int { } func (c *Command) getSecret(secretName string) (string, error) { - secret, err := c.k8sClient.CoreV1().Secrets(c.flagNamespace).Get(context.TODO(), secretName, metav1.GetOptions{}) + secret, err := c.k8sClient.CoreV1().Secrets(c.flagNamespace).Get(c.ctx, secretName, metav1.GetOptions{}) if err != nil { return "", err } diff --git a/control-plane/subcommand/create-federation-secret/command.go b/control-plane/subcommand/create-federation-secret/command.go index 794dbb2804..860c5386b7 100644 --- a/control-plane/subcommand/create-federation-secret/command.go +++ b/control-plane/subcommand/create-federation-secret/command.go @@ -67,6 +67,7 @@ type Command struct { once sync.Once help string + ctx context.Context } func (c *Command) init() { @@ -117,6 +118,10 @@ func (c *Command) Run(args []string) int { return 1 } + if c.ctx == nil { + c.ctx = context.Background() + } + // The initial secret struct. We will be filling in its data map // as we continue. federationSecret := &corev1.Secret{ @@ -239,10 +244,10 @@ func (c *Command) Run(args []string) int { // Now create the Kubernetes secret. logger.Info("Creating/updating Kubernetes secret", "name", federationSecret.ObjectMeta.Name, "ns", c.flagK8sNamespace) - _, err = c.k8sClient.CoreV1().Secrets(c.flagK8sNamespace).Create(context.TODO(), federationSecret, metav1.CreateOptions{}) + _, err = c.k8sClient.CoreV1().Secrets(c.flagK8sNamespace).Create(c.ctx, federationSecret, metav1.CreateOptions{}) if k8serrors.IsAlreadyExists(err) { logger.Info("Secret already exists, updating instead") - _, err = c.k8sClient.CoreV1().Secrets(c.flagK8sNamespace).Update(context.TODO(), federationSecret, metav1.UpdateOptions{}) + _, err = c.k8sClient.CoreV1().Secrets(c.flagK8sNamespace).Update(c.ctx, federationSecret, metav1.UpdateOptions{}) } if err != nil { @@ -296,7 +301,7 @@ func (c *Command) replicationToken(logger hclog.Logger) ([]byte, error) { // This will run forever but it's running as a Helm hook so Helm will timeout // after a configurable time period. err := backoff.Retry(func() error { - secret, err := c.k8sClient.CoreV1().Secrets(c.flagK8sNamespace).Get(context.TODO(), secretName, metav1.GetOptions{}) + secret, err := c.k8sClient.CoreV1().Secrets(c.flagK8sNamespace).Get(c.ctx, secretName, metav1.GetOptions{}) if k8serrors.IsNotFound(err) { logger.Warn("secret not yet created, retrying", "secret", secretName, "ns", c.flagK8sNamespace) return errors.New("") diff --git a/control-plane/subcommand/delete-completed-job/command.go b/control-plane/subcommand/delete-completed-job/command.go index 23f8c22776..273e621a2a 100644 --- a/control-plane/subcommand/delete-completed-job/command.go +++ b/control-plane/subcommand/delete-completed-job/command.go @@ -35,6 +35,8 @@ type Command struct { // retryDuration is how often we'll retry deletion. retryDuration time.Duration + + ctx context.Context } func (c *Command) init() { @@ -82,9 +84,13 @@ func (c *Command) Run(args []string) int { c.UI.Error(fmt.Sprintf("%q is not a valid timeout: %s", c.flagTimeout, err)) return 1 } - ctx, cancel := context.WithTimeout(context.Background(), timeout) - // The context will only ever be intentionally ended by the timeout. - defer cancel() + + if c.ctx == nil { + var cancel context.CancelFunc + c.ctx, cancel = context.WithTimeout(context.Background(), timeout) + // The context will only ever be intentionally ended by the timeout. + defer cancel() + } // c.k8sclient might already be set in a test. if c.k8sClient == nil { @@ -110,7 +116,7 @@ func (c *Command) Run(args []string) int { // Wait for job to complete. logger.Info(fmt.Sprintf("waiting for job %q to complete successfully", jobName)) for { - job, err := c.k8sClient.BatchV1().Jobs(c.flagNamespace).Get(context.TODO(), jobName, metav1.GetOptions{}) + job, err := c.k8sClient.BatchV1().Jobs(c.flagNamespace).Get(c.ctx, jobName, metav1.GetOptions{}) if k8serrors.IsNotFound(err) { logger.Info(fmt.Sprintf("job %q does not exist, no need to delete", jobName)) return 0 @@ -139,7 +145,7 @@ func (c *Command) Run(args []string) int { select { case <-time.After(c.retryDuration): continue - case <-ctx.Done(): + case <-c.ctx.Done(): logger.Warn(fmt.Sprintf("timeout %q has been reached, exiting without deleting job", timeout)) return 1 } @@ -149,7 +155,7 @@ func (c *Command) Run(args []string) int { // ourselves. logger.Info(fmt.Sprintf("job %q has succeeded, deleting", jobName)) propagationPolicy := metav1.DeletePropagationForeground - err = c.k8sClient.BatchV1().Jobs(c.flagNamespace).Delete(context.TODO(), jobName, metav1.DeleteOptions{ + err = c.k8sClient.BatchV1().Jobs(c.flagNamespace).Delete(c.ctx, jobName, metav1.DeleteOptions{ // Needed so that the underlying pods are also deleted. PropagationPolicy: &propagationPolicy, }) diff --git a/control-plane/subcommand/service-address/command.go b/control-plane/subcommand/service-address/command.go index 80e41ecf3a..d775b65ba1 100644 --- a/control-plane/subcommand/service-address/command.go +++ b/control-plane/subcommand/service-address/command.go @@ -39,6 +39,8 @@ type Command struct { k8sClient kubernetes.Interface once sync.Once help string + + ctx context.Context } func (c *Command) init() { @@ -92,11 +94,15 @@ func (c *Command) Run(args []string) int { return 1 } + if c.ctx == nil { + c.ctx = context.Background() + } + // Run until we get an address from the service. var address string var unretryableErr error err = backoff.Retry(withErrLogger(logger, func() error { - svc, err := c.k8sClient.CoreV1().Services(c.flagNamespace).Get(context.TODO(), c.flagServiceName, metav1.GetOptions{}) + svc, err := c.k8sClient.CoreV1().Services(c.flagNamespace).Get(c.ctx, c.flagServiceName, metav1.GetOptions{}) if err != nil { return fmt.Errorf("getting service %s: %s", c.flagServiceName, err) } diff --git a/control-plane/subcommand/sync-catalog/command.go b/control-plane/subcommand/sync-catalog/command.go index 85c1f8519a..fa478412c2 100644 --- a/control-plane/subcommand/sync-catalog/command.go +++ b/control-plane/subcommand/sync-catalog/command.go @@ -262,6 +262,7 @@ func (c *Command) Run(args []string) int { Log: c.logger.Named("to-consul/source"), Client: c.clientset, Syncer: syncer, + Ctx: ctx, AllowK8sNamespacesSet: allowSet, DenyK8sNamespacesSet: denySet, ExplicitEnable: !c.flagK8SDefault, From d12d9887a6f9b39b061f520d9dba146cdaf7dde2 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 9 Sep 2021 17:23:57 -0400 Subject: [PATCH 013/418] Add config for `webhook-cert-manager` tolerations (#712) * Add webhookCertManager.tolerations setting * Add tolerations to webhook cert template * Add bats test for setting tolerations * Update CHANGELOG * Set PR number in CHANGELOG * Add short desc to webhookCertManager * Update charts/consul/values.yaml Co-authored-by: Kyle Schochenmaier Co-authored-by: Kyle Schochenmaier --- CHANGELOG.md | 1 + .../webhook-cert-manager-deployment.yaml | 5 ++++ .../unit/webhook-cert-manager-deployment.bats | 23 +++++++++++++++++++ charts/consul/values.yaml | 10 ++++++++ 4 files changed, 39 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41bb6ec661..52b91008b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ IMPROVEMENTS: * Add readiness, liveness and startup probes to the connect inject deployment. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)][[GH-701](https://github.com/hashicorp/consul-k8s/pull/701)] * Add support for setting container security contexts on client and server Pods. [[GH-620](https://github.com/hashicorp/consul-k8s/pull/620)] * Update Envoy image to 1.18.4 [[GH-699](https://github.com/hashicorp/consul-k8s/pull/699)] + * Add configuration for webhook-cert-manager tolerations [[GH-712](https://github.com/hashicorp/consul-k8s/pull/712)] * Control Plane * Add health endpoint to the connect inject webhook that will be healthy when webhook certs are present and not empty. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)] * Catalog Sync: Fix issue registering NodePort services with wrong IPs when a node has multiple IP addresses. [[GH-619](https://github.com/hashicorp/consul-k8s/pull/619)] diff --git a/charts/consul/templates/webhook-cert-manager-deployment.yaml b/charts/consul/templates/webhook-cert-manager-deployment.yaml index 1d27a2a5f3..9974c4c1cd 100644 --- a/charts/consul/templates/webhook-cert-manager-deployment.yaml +++ b/charts/consul/templates/webhook-cert-manager-deployment.yaml @@ -60,4 +60,9 @@ spec: - name: config configMap: name: {{ template "consul.fullname" . }}-webhook-cert-manager-config + {{- if .Values.webhookCertManager.tolerations }} + tolerations: + {{ tpl .Values.webhookCertManager.tolerations . | indent 8 | trim }} + {{- end}} + {{- end }} diff --git a/charts/consul/test/unit/webhook-cert-manager-deployment.bats b/charts/consul/test/unit/webhook-cert-manager-deployment.bats index d51947aff5..f3118206bd 100644 --- a/charts/consul/test/unit/webhook-cert-manager-deployment.bats +++ b/charts/consul/test/unit/webhook-cert-manager-deployment.bats @@ -39,3 +39,26 @@ load _helpers yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] } + +@test "webhookCertManager/Deployment: no tolerations by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/webhook-cert-manager-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.tolerations' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + +@test "webhookCertManager/Deployment: tolerations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/webhook-cert-manager-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'webhookCertManager.tolerations=- key: value' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.tolerations[0].key' | tee /dev/stderr) + [ "${actual}" = "value" ] +} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 72d04f9c70..1fedc2f568 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2245,6 +2245,16 @@ terminatingGateways: gateways: - name: terminating-gateway +# Configuration settings for the webhook-cert-manager +# `webhook-cert-manager` ensures that cert bundles are up to date for the mutating webhook. +webhookCertManager: + + # Toleration Settings + # This should be a multi-line string matching the Toleration array + # in a PodSpec. + # @type: string + tolerations: null + # Configures a demo Prometheus installation. prometheus: # When true, the Helm chart will install a demo Prometheus server instance From 6b5b5deae242967accdad64d66c8afd5e5888efd Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Mon, 13 Sep 2021 09:27:29 -0700 Subject: [PATCH 014/418] Retry every 5s for deleting VPC (#720) https://app.circleci.com/pipelines/github/hashicorp/consul-k8s/2549/workflows/e3f5e78a-3e2e-4203-b7af-32be048a4626/jobs/15798 failed so thinking maybe it just takes longer sometimes to resolve the issue. --- charts/consul/hack/aws-acceptance-test-cleanup/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/consul/hack/aws-acceptance-test-cleanup/main.go b/charts/consul/hack/aws-acceptance-test-cleanup/main.go index 49b6c21301..fb998a5fd0 100644 --- a/charts/consul/hack/aws-acceptance-test-cleanup/main.go +++ b/charts/consul/hack/aws-acceptance-test-cleanup/main.go @@ -290,7 +290,7 @@ func realMain(ctx context.Context) error { break } fmt.Printf("VPC: Destroy error... [id=%s,err=%q,retry=%d]\n", *vpcID, err, retryCount) - time.Sleep(1 * time.Second) + time.Sleep(5 * time.Second) } if retryCount == 10 { return errors.New("reached max retry count deleting VPC") From 1e59741c0dc4a34a812112930d8740e67561ba82 Mon Sep 17 00:00:00 2001 From: Jean Morais Date: Tue, 14 Sep 2021 02:47:06 -0300 Subject: [PATCH 015/418] README: Fix broken link to helm chart and wrong binary name (#723) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3934202546..34c00c052a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ## Overview -The `consul-k8s` binary includes first-class integrations between Consul and +The `consul-k8s-control-plane` binary includes first-class integrations between Consul and Kubernetes. The project encapsulates multiple use cases such as syncing services, injecting Connect sidecars, and more. The Kubernetes integrations with Consul are @@ -41,7 +41,7 @@ by contacting us at [security@hashicorp.com](mailto:security@hashicorp.com). `consul-k8s` is distributed in multiple forms: * The recommended installation method is the official - [Consul Helm chart](https://github.com/hashicorp/consul-k8s/tree/merge-repos/charts/consul). This will + [Consul Helm chart](https://github.com/hashicorp/consul-k8s/tree/main/charts/consul). This will automatically configure the Consul and Kubernetes integration to run within an existing Kubernetes cluster. From 10328ec024af0f667afb5263c2ba093f487b03b5 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 14 Sep 2021 13:17:01 -0700 Subject: [PATCH 016/418] Bump default Consul version to 1.10.2 (#718) - fix tests that were failing due to a change in how the DestinationUpstream field is set in Consul OSS vs Enterprise. - set use_streaming_backend to false for Consul clients because streaming is not currently supported with mesh gateway federation --- .circleci/config.yml | 4 ++-- CHANGELOG.md | 13 +++++++++++++ charts/consul/Chart.yaml | 4 ++-- charts/consul/README.md | 2 +- .../consul/templates/client-config-configmap.yaml | 3 ++- charts/consul/test/unit/client-daemonset.bats | 8 ++++---- charts/consul/values.yaml | 2 +- .../connect-inject/endpoints_controller_test.go | 13 ++++++++++++- 8 files changed, 37 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5a9b4d80ff..7c713ae68d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,8 +9,8 @@ executors: - image: docker.mirror.hashicorp.services/circleci/golang:1.16 environment: TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.10.0 # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.10.0+ent # Consul's enterprise version to use in tests + CONSUL_VERSION: 1.10.2 # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.10.2+ent # Consul's enterprise version to use in tests control-plane-path : &control-plane-path control-plane acceptance-test-path: &acceptance-test-path charts/consul/test/acceptance diff --git a/CHANGELOG.md b/CHANGELOG.md index 52b91008b6..4e288ffc87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,24 @@ IMPROVEMENTS: * Add support for setting container security contexts on client and server Pods. [[GH-620](https://github.com/hashicorp/consul-k8s/pull/620)] * Update Envoy image to 1.18.4 [[GH-699](https://github.com/hashicorp/consul-k8s/pull/699)] * Add configuration for webhook-cert-manager tolerations [[GH-712](https://github.com/hashicorp/consul-k8s/pull/712)] + * Update default Consul version to 1.10.2 [[GH-718](https://github.com/hashicorp/consul-k8s/pull/718)] * Control Plane * Add health endpoint to the connect inject webhook that will be healthy when webhook certs are present and not empty. [[GH-626](https://github.com/hashicorp/consul-k8s/pull/626)] * Catalog Sync: Fix issue registering NodePort services with wrong IPs when a node has multiple IP addresses. [[GH-619](https://github.com/hashicorp/consul-k8s/pull/619)] * Allow registering the same service in multiple namespaces. [[GH-697](https://github.com/hashicorp/consul-k8s/pull/697)] +BUG FIXES: +* Helm Chart + * Disable [streaming](https://www.consul.io/docs/agent/options#use_streaming_backend) on Consul clients because it is currently not supported when + doing mesh gateway federation. If you wish to enable it, override the setting using `client.extraConfig`: + + ```yaml + client: + extraConfig: | + {"use_streaming_backend": true} + ``` + [[GH-718](https://github.com/hashicorp/consul-k8s/pull/718)] + ## 0.33.0 (August 12, 2021) BREAKING CHANGES: diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index 0fe255fa76..ebfb71a532 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: consul version: 0.33.0 -appVersion: 1.10.0 +appVersion: 1.10.2 kubeVersion: ">=1.17.0-0" description: Official HashiCorp Consul Chart home: https://www.consul.io @@ -13,7 +13,7 @@ annotations: artifacthub.io/prerelease: false artifacthub.io/images: | - name: consul - image: hashicorp/consul:1.10.0 + image: hashicorp/consul:1.10.2 - name: consul-k8s-control-plane image: hashicorp/consul-k8s-control-plane:0.33.0 - name: envoy diff --git a/charts/consul/README.md b/charts/consul/README.md index 0689880348..12e8aff1fb 100644 --- a/charts/consul/README.md +++ b/charts/consul/README.md @@ -44,7 +44,7 @@ Detailed installation instructions for Consul on Kubernetes are found [here](htt $ helm search repo hashicorp/consul NAME CHART VERSION APP VERSION DESCRIPTION - hashicorp/consul 0.33.0 1.10.0 Official HashiCorp Consul Chart + hashicorp/consul x.xx.x x.xx.x Official HashiCorp Consul Chart 3. Now you're ready to install Consul! To install Consul with the default configuration using Helm 3 run: diff --git a/charts/consul/templates/client-config-configmap.yaml b/charts/consul/templates/client-config-configmap.yaml index bfdeacc962..f4e5ade095 100644 --- a/charts/consul/templates/client-config-configmap.yaml +++ b/charts/consul/templates/client-config-configmap.yaml @@ -24,7 +24,8 @@ data: in the UI. */}} config.json: |- { - "check_update_interval": "0s" + "check_update_interval": "0s", + "use_streaming_backend": false } {{- end }} {{- end }} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index d1a0e0614c..0f79a4fa92 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -543,7 +543,7 @@ load _helpers #-------------------------------------------------------------------- # config-configmap -@test "client/DaemonSet: adds config-checksum annotation when extraConfig is blank" { +@test "client/DaemonSet: config-checksum annotation when extraConfig is blank" { cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ @@ -552,7 +552,7 @@ load _helpers [ "${actual}" = 779a0e24c2ed561c727730698a75b1c552f562c100f0c3315ff2cb925f5e296b ] } -@test "client/DaemonSet: adds config-checksum annotation when extraConfig is provided" { +@test "client/DaemonSet: config-checksum annotation changes when extraConfig is provided" { cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ @@ -562,14 +562,14 @@ load _helpers [ "${actual}" = ba1ceb79d2d18e136d3cc40a9dfddcf2a252aa19ca1703bee3219ca28f1ee187 ] } -@test "client/DaemonSet: adds config-checksum annotation when client config is updated" { +@test "client/DaemonSet: config-checksum annotation changes when connectInject.enabled=true" { cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 8496f6bcdec460eac8a5c890e7899f5757111e13e54808af533aaf205ef18bd0 ] + [ "${actual}" = b45de202f61d7d3b6118c1f47c351d357c2a83af09675f269d3617ae4a65a01c ] } #-------------------------------------------------------------------- diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 1fedc2f568..5058f7bd6a 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -42,7 +42,7 @@ global: # image: "hashicorp/consul-enterprise:1.10.0-ent" # ``` # @default: hashicorp/consul: - image: "hashicorp/consul:1.10.0" + image: "hashicorp/consul:1.10.2" # Array of objects containing image pull secret names that will be applied to each service account. # This can be used to reference image pull secrets if using a custom consul or consul-k8s-control-plane Docker image. diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index ec3898c8f3..a073af12ec 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -998,9 +998,20 @@ func TestReconcileCreateEndpoint(t *testing.T) { require.Equal(t, tt.expectedProxySvcInstances[i].ServiceName, instance.ServiceName) require.Equal(t, tt.expectedProxySvcInstances[i].ServiceAddress, instance.ServiceAddress) require.Equal(t, tt.expectedProxySvcInstances[i].ServicePort, instance.ServicePort) - require.Equal(t, tt.expectedProxySvcInstances[i].ServiceProxy, instance.ServiceProxy) require.Equal(t, tt.expectedProxySvcInstances[i].ServiceMeta, instance.ServiceMeta) require.Equal(t, tt.expectedProxySvcInstances[i].ServiceTags, instance.ServiceTags) + + // When comparing the ServiceProxy field we ignore the DestinationNamespace + // field within that struct because on Consul OSS it's set to "" but on Consul Enterprise + // it's set to "default" and we want to re-use this test for both OSS and Ent. + // This does mean that we don't test that field but that's okay because + // it's not getting set specifically in this test. + // To do the comparison that ignores that field we use go-cmp instead + // of the regular require.Equal call since it supports ignoring certain + // fields. + diff := cmp.Diff(tt.expectedProxySvcInstances[i].ServiceProxy, instance.ServiceProxy, + cmpopts.IgnoreFields(api.Upstream{}, "DestinationNamespace")) + require.Empty(t, diff, "expected objects to be equal") } _, checkInfos, err := consulClient.Agent().AgentHealthServiceByName(fmt.Sprintf("%s-sidecar-proxy", tt.consulSvcName)) From c79730ba4f0e25b8330950d7ab575e4e3cfc1ef0 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 14 Sep 2021 14:51:50 -0700 Subject: [PATCH 017/418] Move hack scripts to top-level (#691) * Move hack scripts to top-level * Also add Makefile to top-level for the targets that moved * Add target for aws acceptance tests * Delete unused circleci config in charts/consul * Update helm gen script for new directory of chart * Move crds-to-consul-helm script into top-level Also rename to copy-crds-to-chart --- .circleci/config.yml | 6 +- Makefile | 13 + charts/consul/.circleci/config.yml | 749 ------------------ charts/consul/Makefile | 5 - control-plane/Makefile | 5 - .../aws-acceptance-test-cleanup/go.mod | 0 .../aws-acceptance-test-cleanup/go.sum | 0 .../aws-acceptance-test-cleanup/main.go | 0 hack/copy-crds-to-chart/go.mod | 3 + .../copy-crds-to-chart}/main.go | 29 +- .../helm-reference-gen/doc_node.go | 0 .../fixtures/full-values.golden | 0 .../fixtures/full-values.yaml | 0 .../hack => hack}/helm-reference-gen/go.mod | 2 +- .../hack => hack}/helm-reference-gen/go.sum | 0 .../hack => hack}/helm-reference-gen/main.go | 2 +- .../helm-reference-gen/main_test.go | 0 .../helm-reference-gen/parse_error.go | 0 18 files changed, 28 insertions(+), 786 deletions(-) create mode 100644 Makefile delete mode 100644 charts/consul/.circleci/config.yml rename {charts/consul/hack => hack}/aws-acceptance-test-cleanup/go.mod (100%) rename {charts/consul/hack => hack}/aws-acceptance-test-cleanup/go.sum (100%) rename {charts/consul/hack => hack}/aws-acceptance-test-cleanup/main.go (100%) create mode 100644 hack/copy-crds-to-chart/go.mod rename {control-plane/hack/crds-to-consul-helm => hack/copy-crds-to-chart}/main.go (64%) rename {charts/consul/hack => hack}/helm-reference-gen/doc_node.go (100%) rename {charts/consul/hack => hack}/helm-reference-gen/fixtures/full-values.golden (100%) rename {charts/consul/hack => hack}/helm-reference-gen/fixtures/full-values.yaml (100%) rename {charts/consul/hack => hack}/helm-reference-gen/go.mod (63%) rename {charts/consul/hack => hack}/helm-reference-gen/go.sum (100%) rename {charts/consul/hack => hack}/helm-reference-gen/main.go (99%) rename {charts/consul/hack => hack}/helm-reference-gen/main_test.go (100%) rename {charts/consul/hack => hack}/helm-reference-gen/parse_error.go (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7c713ae68d..e7435d7449 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,7 +16,7 @@ control-plane-path : &control-plane-path control-plane acceptance-test-path: &acceptance-test-path charts/consul/test/acceptance acceptance-framework-path: &acceptance-framework-path charts/consul/test/acceptance/framework charts-consul-path: &charts-consul-path charts/consul -helm-gen-path: &helm-gen-path charts/consul/hack/helm-reference-gen +helm-gen-path: &helm-gen-path hack/helm-reference-gen gke-terraform-path: &gke-terraform-path charts/consul/test/terraform/gke eks-terraform-path: &eks-terraform-path charts/consul/test/terraform/eks aks-terraform-path: &aks-terraform-path charts/consul/test/terraform/aks @@ -547,7 +547,6 @@ jobs: - checkout - run: name: cleanup eks resources - working_directory: *charts-consul-path command: | # Assume the role and set environment variables. aws sts assume-role --role-arn "$AWS_ROLE_ARN" --role-session-name "consul-helm-$CIRCLE_BUILD_NUM" --duration-seconds 10800 > assume-role.json @@ -555,8 +554,7 @@ jobs: export AWS_SECRET_ACCESS_KEY="$(jq -r .Credentials.SecretAccessKey assume-role.json)" export AWS_SESSION_TOKEN="$(jq -r .Credentials.SessionToken assume-role.json)" - cd hack/aws-acceptance-test-cleanup - go run ./... -auto-approve + make ci.aws-acceptance-test-cleanup - slack/status: fail_only: true failure_message: "EKS cleanup failed" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000000..481a58a142 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +# Generate Helm reference docs from values.yaml and update Consul website. +# Usage: make gen-docs consul= +gen-docs: + @cd hack/helm-reference-gen; go run ./... $(consul) + +# Copy generated CRD YAML into charts/consul. +# Usage: make copy-crds-to-chart +copy-crds-to-chart: + @cd hack/copy-crds-to-chart; go run ./... + +# Deletes AWS resources left behind after failed acceptance tests. +ci.aws-acceptance-test-cleanup: + @cd hack/aws-acceptance-test-cleanup; go run ./... -auto-approve diff --git a/charts/consul/.circleci/config.yml b/charts/consul/.circleci/config.yml deleted file mode 100644 index b3fe72881b..0000000000 --- a/charts/consul/.circleci/config.yml +++ /dev/null @@ -1,749 +0,0 @@ -# Originally from consul-helm -version: 2.1 -orbs: - slack: circleci/slack@3.4.2 -executors: - go: - docker: - - image: docker.mirror.hashicorp.services/circleci/golang:1.16 - environment: - - TEST_RESULTS: /tmp/test-results - -commands: - install-prereqs: - steps: - - run: - name: Install gotestsum, kind, kubectl, and helm - command: | - wget https://golang.org/dl/go1.16.5.linux-amd64.tar.gz - sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.16.5.linux-amd64.tar.gz - rm go1.16.5.linux-amd64.tar.gz - echo 'export PATH=$PATH:/usr/local/go/bin' >> $BASH_ENV - - wget https://github.com/gotestyourself/gotestsum/releases/download/v1.6.4/gotestsum_1.6.4_linux_amd64.tar.gz - sudo tar -C /usr/local/bin -xzf gotestsum_1.6.4_linux_amd64.tar.gz - rm gotestsum_1.6.4_linux_amd64.tar.gz - - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.0/kind-linux-amd64 - chmod +x ./kind - sudo mv ./kind /usr/local/bin/kind - - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x ./kubectl - sudo mv ./kubectl /usr/local/bin/kubectl - - curl https://baltocdn.com/helm/signing.asc | sudo apt-key add - - sudo apt-get install apt-transport-https --yes - echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list - sudo apt-get update - sudo apt-get install helm - create-kind-clusters: - parameters: - version: - type: string - steps: - - run: - name: Create kind clusters - command: | - kind create cluster --name dc1 --image kindest/node:<< parameters.version >> - kind create cluster --name dc2 --image kindest/node:<< parameters.version >> - run-acceptance-tests: - parameters: - failfast: - type: boolean - default: false - additional-flags: - type: string - consul-k8s-image: - type: string - default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s:latest" - steps: - - when: - condition: << parameters.failfast >> - steps: - - run: - name: Run acceptance tests - working_directory: test/acceptance/tests - no_output_timeout: 2h - command: | - # Enterprise tests can't run on fork PRs because they require - # a secret. - if [ -z "$CIRCLE_PR_NUMBER" ]; then - ENABLE_ENTERPRISE=true - fi - - # We have to run the tests for each package separately so that we can - # exit early if any test fails (-failfast only works within a single - # package). - exit_code=0 - pkgs=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname) - echo "Running $(echo $pkgs | wc -w) packages:" - echo $pkgs - for pkg in $pkgs - do - if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ - << parameters.additional-flags >> \ - ${ENABLE_ENTERPRISE:+-enable-enterprise} \ - -enable-multi-cluster \ - -debug-directory="$TEST_RESULTS/debug" \ - -consul-k8s-image=<< parameters.consul-k8s-image >> - then - echo "Tests in ${pkg} failed, aborting early" - exit_code=1 - break - fi - done - gotestsum --raw-command --junitfile "$TEST_RESULTS/gotestsum-report.xml" -- cat jsonfile* - exit $exit_code - - - unless: - condition: << parameters.failfast >> - steps: - - run: - name: Run acceptance tests - working_directory: test/acceptance/tests - no_output_timeout: 2h - command: | - # Enterprise tests can't run on fork PRs because they require - # a secret. - if [ -z "$CIRCLE_PR_NUMBER" ]; then - ENABLE_ENTERPRISE=true - fi - - pkgs=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname) - echo "Running $pkgs" - gotestsum --junitfile "$TEST_RESULTS/gotestsum-report.xml" -- $pkgs -p 1 -timeout 2h -failfast \ - << parameters.additional-flags >> \ - -enable-multi-cluster \ - ${ENABLE_ENTERPRISE:+-enable-enterprise} \ - -debug-directory="$TEST_RESULTS/debug" \ - -consul-k8s-image=<< parameters.consul-k8s-image >> -jobs: - unit-helm: - docker: - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - - steps: - - checkout - - - run: - name: Run Unit Tests - command: bats --jobs 4 ./test/unit - - go-fmt-and-vet-acceptance: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "test/acceptance/go.mod" }} - - - run: - name: go mod download - working_directory: test/acceptance - command: go mod download - - # Save go module cache if the go.mod file has changed - - save_cache: - key: consul-helm-acceptance-modcache-v1-{{ checksum "test/acceptance/go.mod" }} - paths: - - "/go/pkg/mod" - - # check go fmt output because it does not report non-zero when there are fmt changes - - run: - name: check go fmt - working_directory: test/acceptance - command: | - files=$(go fmt ./...) - if [ -n "$files" ]; then - echo "The following file(s) do not conform to go fmt:" - echo "$files" - exit 1 - fi - - - run: - name: go vet - working_directory: test/acceptance - command: go vet ./... - - unit-acceptance-framework: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "test/acceptance/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run: - name: Run tests - working_directory: test/acceptance/framework - command: | - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - acceptance: - environment: - - TEST_RESULTS: /tmp/test-results - machine: - image: ubuntu-2004:202010-01 - resource_class: xlarge - parallelism: 6 - steps: - - checkout - - install-prereqs - - create-kind-clusters: - version: "v1.20.7" - - restore_cache: - keys: - - consul-helm-modcache-v2-{{ checksum "test/acceptance/go.mod" }} - - run: - name: go mod download - working_directory: test/acceptance - command: go mod download - - save_cache: - key: consul-helm-modcache-v2-{{ checksum "test/acceptance/go.mod" }} - paths: - - ~/.go_workspace/pkg/mod - - run: mkdir -p $TEST_RESULTS - - run-acceptance-tests: - failfast: true - additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - acceptance-tproxy: - environment: - - TEST_RESULTS: /tmp/test-results - machine: - image: ubuntu-2004:202010-01 - resource_class: xlarge - parallelism: 6 - steps: - - checkout - - install-prereqs - - create-kind-clusters: - version: "v1.20.7" - - restore_cache: - keys: - - consul-helm-modcache-v2-{{ checksum "test/acceptance/go.mod" }} - - run: - name: go mod download - working_directory: test/acceptance - command: go mod download - - save_cache: - key: consul-helm-modcache-v2-{{ checksum "test/acceptance/go.mod" }} - paths: - - ~/.go_workspace/pkg/mod - - run: mkdir -p $TEST_RESULTS - - run-acceptance-tests: - failfast: true - additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" -enable-transparent-proxy - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - acceptance-gke-1-17: - environment: - - TEST_RESULTS: /tmp/test-results - docker: - # This image is built from test/docker/Test.dockerfile - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - - steps: - - run: - name: Exit if forked PR - command: | - if [ -n "$CIRCLE_PR_NUMBER" ]; then - echo "Skipping acceptance tests for forked PRs; marking step successful." - circleci step halt - fi - - - checkout - - - run: - name: terraform init & apply - working_directory: test/terraform/gke - command: | - terraform init - echo "${GOOGLE_CREDENTIALS}" | gcloud auth activate-service-account --key-file=- - - # On GKE, we're setting the build number instead of build URL because label values - # cannot contain '/'. - terraform apply \ - -var project=${CLOUDSDK_CORE_PROJECT} \ - -var init_cli=true \ - -var cluster_count=2 \ - -var labels="{\"build_number\": \"$CIRCLE_BUILD_NUM\"}" \ - -auto-approve - - primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) - secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) - - echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV - echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "test/acceptance/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run-acceptance-tests: - additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-pod-security-policies -enable-transparent-proxy - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - - run: - name: terraform destroy - working_directory: test/terraform/gke - command: | - terraform destroy -var project=${CLOUDSDK_CORE_PROJECT} -auto-approve - when: always - - - slack/status: - fail_only: true - failure_message: "GKE acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - - acceptance-aks-1-19: - environment: - - TEST_RESULTS: /tmp/test-results - docker: - # This image is built from test/docker/Test.dockerfile - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - - steps: - - checkout - - - run: - name: terraform init & apply - working_directory: test/terraform/aks - command: | - terraform init - - terraform apply \ - -var client_id="$ARM_CLIENT_ID" \ - -var client_secret="$ARM_CLIENT_SECRET" \ - -var cluster_count=2 \ - -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" \ - -auto-approve - - primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) - secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) - - echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV - echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "test/acceptance/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run-acceptance-tests: - additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-transparent-proxy - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - - run: - name: terraform destroy - working_directory: test/terraform/aks - command: | - terraform destroy -auto-approve - when: always - - - slack/status: - fail_only: true - failure_message: "AKS acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - - acceptance-eks-1-18: - environment: - - TEST_RESULTS: /tmp/test-results - docker: - # This image is built from test/docker/Test.dockerfile - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - - steps: - - checkout - - - run: - name: configure aws - command: | - aws configure --profile helm_user set aws_access_key_id "$AWS_ACCESS_KEY_ID" - aws configure --profile helm_user set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" - aws configure set role_arn "$AWS_ROLE_ARN" - aws configure set source_profile helm_user - - echo "unset AWS_ACCESS_KEY_ID" >> $BASH_ENV - echo "unset AWS_SECRET_ACCESS_KEY" >> $BASH_ENV - - - run: - name: terraform init & apply - working_directory: test/terraform/eks - command: | - terraform init - - terraform apply -var cluster_count=2 -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" -auto-approve - - primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) - secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) - - echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV - echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV - - # Change file permissions of the kubecofig files to avoid warnings by helm. - # TODO: remove when https://github.com/terraform-aws-modules/terraform-aws-eks/pull/1114 is merged. - chmod 600 "$primary_kubeconfig" - chmod 600 "$secondary_kubeconfig" - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "test/acceptance/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run-acceptance-tests: - additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-transparent-proxy - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - - run: - name: terraform destroy - working_directory: test/terraform/eks - command: | - terraform destroy -auto-approve - when: always - - - slack/status: - fail_only: true - failure_message: "EKS acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - - acceptance-openshift: - environment: - TEST_RESULTS: /tmp/test-results - parallelism: 3 - docker: - # This image is built from test/docker/Test.dockerfile - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - - steps: - - checkout - - run: - name: terraform init & apply - working_directory: test/terraform/openshift - command: | - terraform init - - az login --service-principal -u "$ARM_CLIENT_ID" -p "$ARM_CLIENT_SECRET" --tenant "$ARM_TENANT_ID" > /dev/null - terraform apply \ - -var cluster_count=2 \ - -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" \ - -auto-approve - - primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) - secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) - - echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV - echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "test/acceptance/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run-acceptance-tests: - additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-openshift -enable-transparent-proxy - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - run: - name: terraform destroy - working_directory: test/terraform/openshift - command: | - terraform destroy -auto-approve - when: always - - slack/status: - fail_only: true - failure_message: "OpenShift acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - - acceptance-kind-1-21: - environment: - - TEST_RESULTS: /tmp/test-results - machine: - image: ubuntu-2004:202010-01 - resource_class: xlarge - steps: - - checkout - - install-prereqs - - create-kind-clusters: - version: "v1.21.1" - - restore_cache: - keys: - - consul-helm-modcache-v2-{{ checksum "test/acceptance/go.mod" }} - - run: - name: go mod download - working_directory: test/acceptance - command: go mod download - - save_cache: - key: consul-helm-modcache-v2-{{ checksum "test/acceptance/go.mod" }} - paths: - - ~/.go_workspace/pkg/mod - - run: mkdir -p $TEST_RESULTS - - run-acceptance-tests: - additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" -enable-transparent-proxy - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - slack/status: - fail_only: true - failure_message: "Acceptance tests against Kind with Kubernetes v1.21 failed. Check the logs at: ${CIRCLE_BUILD_URL}" - - go-fmt-and-vet-helm-gen: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-helm-gen-modcache-v1-{{ checksum "hack/helm-reference-gen/go.mod" }} - - - run: - name: go mod download - working_directory: hack/helm-reference-gen - command: go mod download - - # Save go module cache if the go.mod file has changed - - save_cache: - key: consul-helm-helm-gen-modcache-v1-{{ checksum "hack/helm-reference-gen/go.mod" }} - paths: - - "/go/pkg/mod" - - # check go fmt output because it does not report non-zero when there are fmt changes - - run: - name: check go fmt - working_directory: hack/helm-reference-gen - command: | - files=$(go fmt ./...) - if [ -n "$files" ]; then - echo "The following file(s) do not conform to go fmt:" - echo "$files" - exit 1 - fi - - - run: - name: go vet - working_directory: hack/helm-reference-gen - command: go vet ./... - - unit-helm-gen: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-helm-gen-modcache-v1-{{ checksum "hack/helm-reference-gen/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run: - name: Run tests - working_directory: hack/helm-reference-gen - command: | - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - test-helm-gen: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-helm-gen-modcache-v1-{{ checksum "hack/helm-reference-gen/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run: - name: Run tests - working_directory: hack/helm-reference-gen - command: | - go run ./... -validate - - update-helm-charts-index: - docker: - - image: docker.mirror.hashicorp.services/circleci/golang:latest - steps: - - checkout - - run: - name: verify Chart version matches tag version - command: | - GO111MODULE=on go get github.com/mikefarah/yq/v2 - git_tag=$(echo "${CIRCLE_TAG#v}") - chart_tag=$(yq r Chart.yaml version) - if [ "${git_tag}" != "${chart_tag}" ]; then - echo "chart version (${chart_tag}) did not match git version (${git_tag})" - exit 1 - fi - - run: - name: update helm-charts index - command: | - curl --show-error --silent --fail --user "${CIRCLE_TOKEN}:" \ - -X POST \ - -H 'Content-Type: application/json' \ - -H 'Accept: application/json' \ - -d "{\"branch\": \"master\",\"parameters\":{\"SOURCE_REPO\": \"${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}\",\"SOURCE_TAG\": \"${CIRCLE_TAG}\"}}" \ - "${CIRCLE_ENDPOINT}/${CIRCLE_PROJECT}/pipeline" - - slack/status: - fail_only: true - failure_message: "Failed to trigger an update to the helm charts index. Check the logs at: ${CIRCLE_BUILD_URL}" - - cleanup-azure-resources: - docker: - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - steps: - - run: - name: cleanup leftover resources - command: | - az login --service-principal -u "$ARM_CLIENT_ID" -p "$ARM_CLIENT_SECRET" --tenant "$ARM_TENANT_ID" > /dev/null - resource_groups=$(az group list -o json | jq -r '.[] | select(.name | test("^consul-k8s-\\d+$")) | .name') - for group in $resource_groups; do - echo "Deleting $group resource group" - az group delete -n $group --yes - done - - - slack/status: - fail_only: true - failure_message: "AKS cleanup failed" - - cleanup-gcp-resources: - docker: - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - steps: - - run: - name: cleanup leftover resources - command: | - echo "${GOOGLE_CREDENTIALS}" | gcloud auth activate-service-account --key-file=- - clusters=$(gcloud container clusters list --zone us-central1-a --project ${CLOUDSDK_CORE_PROJECT} --format json | jq -r '.[] | select(.name | test("^consul-k8s-\\d+$")) | .name') - for cluster in $clusters; do - echo "Deleting $cluster GKE cluster" - gcloud container clusters delete $cluster --zone us-central1-a --project ${CLOUDSDK_CORE_PROJECT} --quiet - done - - - slack/status: - fail_only: true - failure_message: "GKE cleanup failed" - - cleanup-eks-resources: - docker: - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.9.0 - steps: - - checkout - - run: - name: cleanup eks resources - command: | - # Assume the role and set environment variables. - aws sts assume-role --role-arn "$AWS_ROLE_ARN" --role-session-name "consul-helm-$CIRCLE_BUILD_NUM" --duration-seconds 10800 > assume-role.json - export AWS_ACCESS_KEY_ID="$(jq -r .Credentials.AccessKeyId assume-role.json)" - export AWS_SECRET_ACCESS_KEY="$(jq -r .Credentials.SecretAccessKey assume-role.json)" - export AWS_SESSION_TOKEN="$(jq -r .Credentials.SessionToken assume-role.json)" - - cd hack/aws-acceptance-test-cleanup - go run ./... -auto-approve - - - slack/status: - fail_only: true - failure_message: "EKS cleanup failed" - -workflows: - version: 2 - test: - jobs: - - go-fmt-and-vet-acceptance - - go-fmt-and-vet-helm-gen - - unit-acceptance-framework: - requires: - - go-fmt-and-vet-acceptance - - unit-helm-gen: - requires: - - go-fmt-and-vet-helm-gen - - test-helm-gen - - unit-helm - - acceptance: - requires: - - unit-helm - - unit-acceptance-framework - - acceptance-tproxy: - requires: - - unit-helm - - unit-acceptance-framework - nightly-acceptance-tests: - triggers: - - schedule: - cron: "0 0 * * *" - filters: - branches: - only: - - master - jobs: - - cleanup-gcp-resources - - cleanup-azure-resources - - cleanup-eks-resources -# - acceptance-openshift: <-- Disabled until we can make them less flakey. -# requires: -# - cleanup-azure-resources - - acceptance-gke-1-17: - requires: - - cleanup-gcp-resources - - acceptance-eks-1-18: - requires: - - cleanup-eks-resources - - acceptance-aks-1-19: - requires: - - cleanup-azure-resources - - acceptance-kind-1-21 - update-helm-charts-index: - jobs: - - update-helm-charts-index: - context: helm-charts-trigger-consul - filters: - tags: - only: /^v.*/ - branches: - ignore: /.*/ diff --git a/charts/consul/Makefile b/charts/consul/Makefile index 43543821d8..ec8cd7505f 100644 --- a/charts/consul/Makefile +++ b/charts/consul/Makefile @@ -3,9 +3,4 @@ TEST_IMAGE?=consul-helm-test test-docker: @docker build --rm -t '$(TEST_IMAGE)' -f $(CURDIR)/test/docker/Test.dockerfile $(CURDIR) -# Generate Helm reference docs from values.yaml and update Consul website. -# Usage: make gen-docs consul= -gen-docs: - @cd hack/helm-reference-gen; go run ./... $(consul) - .PHONY: test-docker diff --git a/control-plane/Makefile b/control-plane/Makefile index 3560b22a55..473fae2dd0 100644 --- a/control-plane/Makefile +++ b/control-plane/Makefile @@ -63,11 +63,6 @@ ctrl-manifests: get-controller-gen ctrl-generate: get-controller-gen $(CONTROLLER_GEN) object:headerFile="build-support/controller/boilerplate.go.txt" paths="./..." -# Copy CRD YAML to consul-helm. -# Usage: make ctrl-crd-copy helm= -ctrl-crd-copy: - @cd hack/crds-to-consul-helm; go run ./... $(helm) - # find or download controller-gen # download controller-gen if necessary get-controller-gen: diff --git a/charts/consul/hack/aws-acceptance-test-cleanup/go.mod b/hack/aws-acceptance-test-cleanup/go.mod similarity index 100% rename from charts/consul/hack/aws-acceptance-test-cleanup/go.mod rename to hack/aws-acceptance-test-cleanup/go.mod diff --git a/charts/consul/hack/aws-acceptance-test-cleanup/go.sum b/hack/aws-acceptance-test-cleanup/go.sum similarity index 100% rename from charts/consul/hack/aws-acceptance-test-cleanup/go.sum rename to hack/aws-acceptance-test-cleanup/go.sum diff --git a/charts/consul/hack/aws-acceptance-test-cleanup/main.go b/hack/aws-acceptance-test-cleanup/main.go similarity index 100% rename from charts/consul/hack/aws-acceptance-test-cleanup/main.go rename to hack/aws-acceptance-test-cleanup/main.go diff --git a/hack/copy-crds-to-chart/go.mod b/hack/copy-crds-to-chart/go.mod new file mode 100644 index 0000000000..f88fccc7a9 --- /dev/null +++ b/hack/copy-crds-to-chart/go.mod @@ -0,0 +1,3 @@ +module github.com/hashicorp/consul-k8s/hack/copy-crds-to-chart + +go 1.16 diff --git a/control-plane/hack/crds-to-consul-helm/main.go b/hack/copy-crds-to-chart/main.go similarity index 64% rename from control-plane/hack/crds-to-consul-helm/main.go rename to hack/copy-crds-to-chart/main.go index a9ec363d6a..efdf2dbf9f 100644 --- a/control-plane/hack/crds-to-consul-helm/main.go +++ b/hack/copy-crds-to-chart/main.go @@ -1,5 +1,5 @@ -// Script to move generated CRD yaml into consul-helm and modify it to match -// the expected consul-helm format. +// Script to copy generated CRD yaml into chart directory and modify it to match +// the expected chart format (e.g. formatted YAML). package main import ( @@ -11,33 +11,20 @@ import ( ) func main() { - if len(os.Args) < 2 { - fmt.Println("Usage: go run ./... ") + if len(os.Args) != 1 { + fmt.Println("Usage: go run ./...") os.Exit(1) } - helmRepoPath := os.Args[1] - if !filepath.IsAbs(helmRepoPath) { - var err error - // NOTE: Must add ../.. to a relative path because this program is in - // hack/crds-to-consul-helm. - helmRepoPath, err = filepath.Abs(filepath.Join("../..", helmRepoPath)) - if err != nil { - fmt.Printf("Error: %s\n", err) - os.Exit(1) - } - } - fmt.Printf("Using consul-helm repo path: %s\n", helmRepoPath) - - if err := realMain(helmRepoPath); err != nil { + if err := realMain("../../charts/consul"); err != nil { fmt.Printf("Error: %s\n", err) os.Exit(1) } os.Exit(0) } -func realMain(helmPathAbs string) error { - return filepath.Walk("../../config/crd/bases", func(path string, info os.FileInfo, err error) error { +func realMain(helmPath string) error { + return filepath.Walk("../../control-plane/config/crd/bases", func(path string, info os.FileInfo, err error) error { if err != nil { return err } @@ -77,7 +64,7 @@ func realMain(helmPathAbs string) error { // Construct the destination filename. filenameSplit := strings.Split(info.Name(), "_") crdName := filenameSplit[1] - destinationPath := filepath.Join(helmPathAbs, "templates", fmt.Sprintf("crd-%s", crdName)) + destinationPath := filepath.Join(helmPath, "templates", fmt.Sprintf("crd-%s", crdName)) // Write it. printf("writing to %s", destinationPath) diff --git a/charts/consul/hack/helm-reference-gen/doc_node.go b/hack/helm-reference-gen/doc_node.go similarity index 100% rename from charts/consul/hack/helm-reference-gen/doc_node.go rename to hack/helm-reference-gen/doc_node.go diff --git a/charts/consul/hack/helm-reference-gen/fixtures/full-values.golden b/hack/helm-reference-gen/fixtures/full-values.golden similarity index 100% rename from charts/consul/hack/helm-reference-gen/fixtures/full-values.golden rename to hack/helm-reference-gen/fixtures/full-values.golden diff --git a/charts/consul/hack/helm-reference-gen/fixtures/full-values.yaml b/hack/helm-reference-gen/fixtures/full-values.yaml similarity index 100% rename from charts/consul/hack/helm-reference-gen/fixtures/full-values.yaml rename to hack/helm-reference-gen/fixtures/full-values.yaml diff --git a/charts/consul/hack/helm-reference-gen/go.mod b/hack/helm-reference-gen/go.mod similarity index 63% rename from charts/consul/hack/helm-reference-gen/go.mod rename to hack/helm-reference-gen/go.mod index a63889328b..138cc52e5a 100644 --- a/charts/consul/hack/helm-reference-gen/go.mod +++ b/hack/helm-reference-gen/go.mod @@ -1,4 +1,4 @@ -module github.com/hashicorp/consul-helm/hack/helm-reference-gen +module github.com/hashicorp/consul-k8s/hack/helm-reference-gen go 1.15 diff --git a/charts/consul/hack/helm-reference-gen/go.sum b/hack/helm-reference-gen/go.sum similarity index 100% rename from charts/consul/hack/helm-reference-gen/go.sum rename to hack/helm-reference-gen/go.sum diff --git a/charts/consul/hack/helm-reference-gen/main.go b/hack/helm-reference-gen/main.go similarity index 99% rename from charts/consul/hack/helm-reference-gen/main.go rename to hack/helm-reference-gen/main.go index ca9c8f8dd2..eac978fdbf 100644 --- a/charts/consul/hack/helm-reference-gen/main.go +++ b/hack/helm-reference-gen/main.go @@ -90,7 +90,7 @@ func main() { } // Parse the values.yaml file. - inputBytes, err := ioutil.ReadFile("../../values.yaml") + inputBytes, err := ioutil.ReadFile("../../charts/consul/values.yaml") if err != nil { fmt.Println(err.Error()) os.Exit(1) diff --git a/charts/consul/hack/helm-reference-gen/main_test.go b/hack/helm-reference-gen/main_test.go similarity index 100% rename from charts/consul/hack/helm-reference-gen/main_test.go rename to hack/helm-reference-gen/main_test.go diff --git a/charts/consul/hack/helm-reference-gen/parse_error.go b/hack/helm-reference-gen/parse_error.go similarity index 100% rename from charts/consul/hack/helm-reference-gen/parse_error.go rename to hack/helm-reference-gen/parse_error.go From 7f9d8e759d49dd15ba8cccc503c49b3f863f1543 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 14 Sep 2021 21:21:49 -0700 Subject: [PATCH 018/418] Fix logging in controller (#573) Previously this would always log: handler.connect received pod {"name": "", "ns": ""} --- control-plane/connect-inject/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control-plane/connect-inject/handler.go b/control-plane/connect-inject/handler.go index 4dc355bd21..39124a1718 100644 --- a/control-plane/connect-inject/handler.go +++ b/control-plane/connect-inject/handler.go @@ -184,7 +184,7 @@ func (h *Handler) Handle(ctx context.Context, req admission.Request) admission.R return admission.Allowed(fmt.Sprintf("%s %s does not require injection", pod.Kind, pod.Name)) } - h.Log.Info("received pod", "name", pod.Name, "ns", pod.Namespace) + h.Log.Info("received pod", "name", req.Name, "ns", req.Namespace) // Add our volume that will be shared by the init container and // the sidecar for passing data in the pod. From 05a27eaf73535cc9061e148f6ac7330a6dedd351 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Wed, 15 Sep 2021 18:42:00 -0700 Subject: [PATCH 019/418] cli: add install command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit consul-k8s install installs the latest Helm chart onto your Kubernetes cluster after performing a few verification steps. common/flag is copied from Waypoint’s internal/pkg/flag. It is a thin layer over the standard Go flag package that provides features such as aliasing and global flags. It was created specifically for mitchellh/cli. common/terminal package is adapted from the Waypoint Plugin SDK and excludes the Status interface and Step interface as described in doc.go. It allows us to have a consistent UI output with style. common/base.go describes a base command that can be embedded into all commands, and pass in common functionality like UI and ctx. This pattern was adapted from Waypoint. Co-authored-by: Saad Jamal --- cli/README.md | 71 + cli/cmd/common/base.go | 44 + cli/cmd/common/flag/doc.go | 5 + cli/cmd/common/flag/flag.go | 74 + cli/cmd/common/flag/flag_bool.go | 77 ++ cli/cmd/common/flag/flag_enum.go | 90 ++ cli/cmd/common/flag/flag_enum_single.go | 80 ++ cli/cmd/common/flag/flag_float.go | 72 + cli/cmd/common/flag/flag_int.go | 296 ++++ cli/cmd/common/flag/flag_string.go | 72 + cli/cmd/common/flag/flag_string_map.go | 83 ++ cli/cmd/common/flag/flag_string_slice.go | 75 ++ cli/cmd/common/flag/flag_string_slice_test.go | 38 + cli/cmd/common/flag/flag_time.go | 81 ++ cli/cmd/common/flag/flag_var.go | 81 ++ cli/cmd/common/flag/set.go | 175 +++ cli/cmd/common/flag/set_test.go | 35 + cli/cmd/common/terminal/basic.go | 141 ++ cli/cmd/common/terminal/doc.go | 10 + cli/cmd/common/terminal/table.go | 99 ++ cli/cmd/common/terminal/ui.go | 173 +++ cli/cmd/common/usage.go | 86 ++ cli/cmd/install/install.go | 500 +++++++ cli/cmd/install/install_test.go | 187 +++ cli/cmd/install/presets.go | 51 + cli/cmd/version/version.go | 50 + cli/commands.go | 28 + cli/go.mod | 27 + cli/go.sum | 1200 +++++++++++++++++ cli/main.go | 48 + 30 files changed, 4049 insertions(+) create mode 100644 cli/README.md create mode 100644 cli/cmd/common/base.go create mode 100644 cli/cmd/common/flag/doc.go create mode 100644 cli/cmd/common/flag/flag.go create mode 100644 cli/cmd/common/flag/flag_bool.go create mode 100644 cli/cmd/common/flag/flag_enum.go create mode 100644 cli/cmd/common/flag/flag_enum_single.go create mode 100644 cli/cmd/common/flag/flag_float.go create mode 100644 cli/cmd/common/flag/flag_int.go create mode 100644 cli/cmd/common/flag/flag_string.go create mode 100644 cli/cmd/common/flag/flag_string_map.go create mode 100644 cli/cmd/common/flag/flag_string_slice.go create mode 100644 cli/cmd/common/flag/flag_string_slice_test.go create mode 100644 cli/cmd/common/flag/flag_time.go create mode 100644 cli/cmd/common/flag/flag_var.go create mode 100644 cli/cmd/common/flag/set.go create mode 100644 cli/cmd/common/flag/set_test.go create mode 100644 cli/cmd/common/terminal/basic.go create mode 100644 cli/cmd/common/terminal/doc.go create mode 100644 cli/cmd/common/terminal/table.go create mode 100644 cli/cmd/common/terminal/ui.go create mode 100644 cli/cmd/common/usage.go create mode 100644 cli/cmd/install/install.go create mode 100644 cli/cmd/install/install_test.go create mode 100644 cli/cmd/install/presets.go create mode 100644 cli/cmd/version/version.go create mode 100644 cli/commands.go create mode 100644 cli/go.mod create mode 100644 cli/go.sum create mode 100644 cli/main.go diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 0000000000..5f6667b382 --- /dev/null +++ b/cli/README.md @@ -0,0 +1,71 @@ +# Consul Kubernetes CLI +This repository contains a CLI tool for installing and operating [Consul](https://www.consul.io/) on Kubernetes. +**Warning** this tool is currently experimental. Do not use it on Consul clusters you care about. + +## Installation & Setup +Currently the tool is not available on any releases page. Instead clone the repository and run `go build -o bin/consul-k8s` +and proceed to run the binary. + +## Commands +* [consul-k8s install](#consul-k8s-install) + +### consul-k8s install +This command installs Consul on a Kubernetes cluster. It allows `demo` and `secure` installations via preset configurations +using the `-preset` flag. The `demo` installation installs just a single replica server with sidecar injection enabled and +is useful to test out service mesh functionality. The `secure` installation is minimal like `demo` but also enables ACLs and TLS. + +Get started with: +```bash +consul-k8s install -preset=demo +``` + +Note that when configuring an installation, the precedence order is as follows from lowest to highest precedence: +1. `-preset` +2. `-f` +3. `-set` +4. `-set-string` +5. `-set-file` + +For example, `-set-file` will override a value provided via `-set`. Additionally, within each of these groups the +rightmost flag value has the highest precedence, i.e `-set foo=bar -set foo=baz` will result in `foo: baz` being set. + +``` +Usage: consul-k8s install [flags] + + Install Consul onto a Kubernetes cluster. + +Flags: + + + -auto-approve + Skip confirmation prompt. + + -dry-run + Run pre-install checks and display summary of installation. + + -config-file,-f= + Path to a file to customize the installation, such as Consul Helm chart values file. Can be specified multiple times. + + -namespace= + Namespace for the Consul installation. Defaults to “consul”. + + -preset= + Use an installation preset, one of demo, secure. Defaults to the default configuration of the Consul Helm chart. + + -set= + Set a value to customize. Can be specified multiple times. Supports Consul Helm chart values. + + -set-file= + Set a value to customize via a file. The contents of the file will be set as the value. Can be specified multiple times. Supports Consul Helm chart values. + + -set-string= + Set a string value to customize. Can be specified multiple times. Supports Consul Helm chart values. + + +Global Flags: +-context= + Kubernetes context to use + +-kubeconfig, -c= + Path to kubeconfig file +``` diff --git a/cli/cmd/common/base.go b/cli/cmd/common/base.go new file mode 100644 index 0000000000..60f0096850 --- /dev/null +++ b/cli/cmd/common/base.go @@ -0,0 +1,44 @@ +package common + +import ( + "context" + "io" + + "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + "github.com/hashicorp/go-hclog" +) + +// BaseCommand is embedded in all commands to provide common logic and data. +type BaseCommand struct { + // Ctx is the base context for the command. It is up to commands to + // utilize this context so that cancellation works in a timely manner. + Ctx context.Context + + // Log is the logger to use. + Log hclog.Logger + + // UI is used to write to the CLI. + UI terminal.UI +} + +// Close cleans up any resources that the command created. This should be +// defered by any CLI command that embeds baseCommand in the Run command. +func (c *BaseCommand) Close() error { + // Close our UI if it implements it. The glint-based UI does for example + // to finish up all the CLI output. + var err error + if closer, ok := c.UI.(io.Closer); ok && closer != nil { + err = closer.Close() + } + if err != nil { + return err + } + + return nil +} + +// Init should be called FIRST within the Run function implementation. +func (c *BaseCommand) Init() { + ui := terminal.NewBasicUI(c.Ctx) + c.UI = ui +} diff --git a/cli/cmd/common/flag/doc.go b/cli/cmd/common/flag/doc.go new file mode 100644 index 0000000000..1e40f0742c --- /dev/null +++ b/cli/cmd/common/flag/doc.go @@ -0,0 +1,5 @@ +// Package flag is a thin layer over the stdlib flag package that provides +// some minimal features such as aliasing, autocompletion handling, improved +// defaults, etc. It was created for mitchellh/cli but can work as a standalone +// package. Source: https://github.com/hashicorp/waypoint/tree/348d2c77fce199952618ccef6433c8844b22583b/internal/pkg/flag, or release tag 0.5.1. +package flag diff --git a/cli/cmd/common/flag/flag.go b/cli/cmd/common/flag/flag.go new file mode 100644 index 0000000000..c89869e322 --- /dev/null +++ b/cli/cmd/common/flag/flag.go @@ -0,0 +1,74 @@ +package flag + +import ( + "os" + "regexp" + "strconv" + "strings" + "time" + + "github.com/kr/text" +) + +// maxLineLength is the maximum width of any line. +const maxLineLength int = 78 + +// reRemoveWhitespace is a regular expression for stripping whitespace from +// a string. +var reRemoveWhitespace = regexp.MustCompile(`[\s]+`) + +// FlagExample is an interface which declares an example value. This is +// used in help generation to provide better help text. +type FlagExample interface { + Example() string +} + +// FlagVisibility is an interface which declares whether a flag should be +// hidden from help and completions. This is usually used for deprecations +// on "internal-only" flags. +type FlagVisibility interface { + Hidden() bool +} + +// helpers + +func envDefault(key, def string) string { + if v, exist := os.LookupEnv(key); exist { + return v + } + return def +} + +func envBoolDefault(key string, def bool) bool { + if v, exist := os.LookupEnv(key); exist { + b, err := strconv.ParseBool(v) + if err != nil { + panic(err) + } + return b + } + return def +} + +func envDurationDefault(key string, def time.Duration) time.Duration { + if v, exist := os.LookupEnv(key); exist { + d, err := time.ParseDuration(v) + if err != nil { + panic(err) + } + return d + } + return def +} + +// wrapAtLengthWithPadding wraps the given text at the maxLineLength, taking +// into account any provided left padding. +func wrapAtLengthWithPadding(s string, pad int) string { + wrapped := text.Wrap(s, maxLineLength-pad) + lines := strings.Split(wrapped, "\n") + for i, line := range lines { + lines[i] = strings.Repeat(" ", pad) + line + } + + return strings.Join(lines, "\n") +} diff --git a/cli/cmd/common/flag/flag_bool.go b/cli/cmd/common/flag/flag_bool.go new file mode 100644 index 0000000000..6240cf2a63 --- /dev/null +++ b/cli/cmd/common/flag/flag_bool.go @@ -0,0 +1,77 @@ +package flag + +import ( + "os" + "strconv" + + "github.com/posener/complete" +) + +// -- BoolVar and boolValue +type BoolVar struct { + Name string + Aliases []string + Usage string + Default bool + Hidden bool + EnvVar string + Target *bool + Completion complete.Predictor + SetHook func(val bool) +} + +func (f *Set) BoolVar(i *BoolVar) { + def := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + if b, err := strconv.ParseBool(v); err == nil { + def = b + } + } + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: i.Usage, + Default: strconv.FormatBool(i.Default), + EnvVar: i.EnvVar, + Value: newBoolValue(i, def, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type boolValue struct { + v *BoolVar + hidden bool + target *bool +} + +func newBoolValue(v *BoolVar, def bool, target *bool, hidden bool) *boolValue { + *target = def + + return &boolValue{ + v: v, + hidden: hidden, + target: target, + } +} + +func (b *boolValue) Set(s string) error { + v, err := strconv.ParseBool(s) + if err != nil { + return err + } + + *b.target = v + + if b.v.SetHook != nil { + b.v.SetHook(v) + } + + return nil +} + +func (b *boolValue) Get() interface{} { return *b.target } +func (b *boolValue) String() string { return strconv.FormatBool(*b.target) } +func (b *boolValue) Example() string { return "" } +func (b *boolValue) Hidden() bool { return b.hidden } +func (b *boolValue) IsBoolFlag() bool { return true } diff --git a/cli/cmd/common/flag/flag_enum.go b/cli/cmd/common/flag/flag_enum.go new file mode 100644 index 0000000000..90e33069fa --- /dev/null +++ b/cli/cmd/common/flag/flag_enum.go @@ -0,0 +1,90 @@ +package flag + +import ( + "fmt" + "os" + "strings" + + "github.com/posener/complete" +) + +// -- EnumVar and enumValue +type EnumVar struct { + Name string + Aliases []string + Usage string + Values []string + Default []string + Hidden bool + EnvVar string + Target *[]string + Completion complete.Predictor +} + +func (f *Set) EnumVar(i *EnumVar) { + initial := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + parts := strings.Split(v, ",") + for i := range parts { + parts[i] = strings.TrimSpace(parts[i]) + } + initial = parts + } + + def := "" + if i.Default != nil { + def = strings.Join(i.Default, ",") + } + + possible := strings.Join(i.Values, ", ") + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: strings.TrimRight(i.Usage, ". \t") + ". One possible value from: " + possible + ".", + Default: def, + EnvVar: i.EnvVar, + Value: newEnumValue(i, initial, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type enumValue struct { + ev *EnumVar + hidden bool + target *[]string +} + +func newEnumValue(ev *EnumVar, def []string, target *[]string, hidden bool) *enumValue { + *target = def + return &enumValue{ + ev: ev, + hidden: hidden, + target: target, + } +} + +func (s *enumValue) Set(vals string) error { + parts := strings.Split(vals, ",") + +parts: + for _, val := range parts { + val = strings.TrimSpace(val) + + for _, p := range s.ev.Values { + if p == val { + *s.target = append(*s.target, strings.TrimSpace(val)) + continue parts + } + } + + return fmt.Errorf("'%s' not valid. Must be one of: %s", val, strings.Join(s.ev.Values, ", ")) + } + + return nil +} + +func (s *enumValue) Get() interface{} { return *s.target } +func (s *enumValue) String() string { return strings.Join(*s.target, ",") } +func (s *enumValue) Example() string { return "string" } +func (s *enumValue) Hidden() bool { return s.hidden } diff --git a/cli/cmd/common/flag/flag_enum_single.go b/cli/cmd/common/flag/flag_enum_single.go new file mode 100644 index 0000000000..667f7707bd --- /dev/null +++ b/cli/cmd/common/flag/flag_enum_single.go @@ -0,0 +1,80 @@ +package flag + +import ( + "fmt" + "os" + "strings" + + "github.com/posener/complete" +) + +// -- EnumVar and enumValue +type EnumSingleVar struct { + Name string + Aliases []string + Usage string + Values []string + Default string + Hidden bool + EnvVar string + Target *string + SetHook func(val string) + Completion complete.Predictor +} + +func (f *Set) EnumSingleVar(i *EnumSingleVar) { + initial := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + initial = v + } + + def := i.Default + + possible := strings.Join(i.Values, ", ") + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: strings.TrimRight(i.Usage, ". \t") + ". One possible value from: " + possible + ".", + Default: def, + EnvVar: i.EnvVar, + Value: newEnumSingleValue(i, initial, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type enumSingleValue struct { + ev *EnumSingleVar + hidden bool + target *string +} + +func newEnumSingleValue(ev *EnumSingleVar, def string, target *string, hidden bool) *enumSingleValue { + *target = def + return &enumSingleValue{ + ev: ev, + hidden: hidden, + target: target, + } +} + +func (s *enumSingleValue) Set(val string) error { + for _, p := range s.ev.Values { + if p == val { + *s.target = val + + if s.ev.SetHook != nil { + s.ev.SetHook(val) + } + + return nil + } + } + + return fmt.Errorf("'%s' not valid. Must be one of: %s", val, strings.Join(s.ev.Values, ", ")) +} + +func (s *enumSingleValue) Get() interface{} { return *s.target } +func (s *enumSingleValue) String() string { return *s.target } +func (s *enumSingleValue) Example() string { return "string" } +func (s *enumSingleValue) Hidden() bool { return s.hidden } diff --git a/cli/cmd/common/flag/flag_float.go b/cli/cmd/common/flag/flag_float.go new file mode 100644 index 0000000000..0a2f5c994e --- /dev/null +++ b/cli/cmd/common/flag/flag_float.go @@ -0,0 +1,72 @@ +package flag + +import ( + "os" + "strconv" + + "github.com/posener/complete" +) + +// -- Float64Var and float64Value +type Float64Var struct { + Name string + Aliases []string + Usage string + Default float64 + Hidden bool + EnvVar string + Target *float64 + Completion complete.Predictor +} + +func (f *Set) Float64Var(i *Float64Var) { + initial := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + if i, err := strconv.ParseFloat(v, 64); err == nil { + initial = i + } + } + + def := "" + if i.Default != 0 { + def = strconv.FormatFloat(i.Default, 'e', -1, 64) + } + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: i.Usage, + Default: def, + EnvVar: i.EnvVar, + Value: newFloat64Value(initial, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type float64Value struct { + hidden bool + target *float64 +} + +func newFloat64Value(def float64, target *float64, hidden bool) *float64Value { + *target = def + return &float64Value{ + hidden: hidden, + target: target, + } +} + +func (f *float64Value) Set(s string) error { + v, err := strconv.ParseFloat(s, 64) + if err != nil { + return err + } + + *f.target = v + return nil +} + +func (f *float64Value) Get() interface{} { return float64(*f.target) } +func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f.target), 'g', -1, 64) } +func (f *float64Value) Example() string { return "float" } +func (f *float64Value) Hidden() bool { return f.hidden } diff --git a/cli/cmd/common/flag/flag_int.go b/cli/cmd/common/flag/flag_int.go new file mode 100644 index 0000000000..12e87bef9c --- /dev/null +++ b/cli/cmd/common/flag/flag_int.go @@ -0,0 +1,296 @@ +package flag + +import ( + "os" + "strconv" + + "github.com/posener/complete" +) + +// -- IntVar and intValue +type IntVar struct { + Name string + Aliases []string + Usage string + Default int + Hidden bool + EnvVar string + Target *int + Completion complete.Predictor + SetHook func(val int) +} + +func (f *Set) IntVar(i *IntVar) { + initial := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + if i, err := strconv.ParseInt(v, 0, 64); err == nil { + initial = int(i) + } + } + + def := "" + if i.Default != 0 { + def = strconv.FormatInt(int64(i.Default), 10) + } + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: i.Usage, + Default: def, + EnvVar: i.EnvVar, + Value: newIntValue(i, initial, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type intValue struct { + v *IntVar + hidden bool + target *int +} + +func newIntValue(v *IntVar, def int, target *int, hidden bool) *intValue { + *target = def + return &intValue{ + v: v, + hidden: hidden, + target: target, + } +} + +func (i *intValue) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + if err != nil { + return err + } + + *i.target = int(v) + + if i.v.SetHook != nil { + i.v.SetHook(int(v)) + } + + return nil +} + +func (i *intValue) Get() interface{} { return int(*i.target) } +func (i *intValue) String() string { return strconv.Itoa(int(*i.target)) } +func (i *intValue) Example() string { return "int" } +func (i *intValue) Hidden() bool { return i.hidden } + +// -- Int64Var and int64Value +type Int64Var struct { + Name string + Aliases []string + Usage string + Default int64 + Hidden bool + EnvVar string + Target *int64 + Completion complete.Predictor + SetHook func(val int64) +} + +func (f *Set) Int64Var(i *Int64Var) { + initial := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + if i, err := strconv.ParseInt(v, 0, 64); err == nil { + initial = i + } + } + + def := "" + if i.Default != 0 { + def = strconv.FormatInt(int64(i.Default), 10) + } + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: i.Usage, + Default: def, + EnvVar: i.EnvVar, + Value: newInt64Value(i, initial, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type int64Value struct { + v *Int64Var + hidden bool + target *int64 +} + +func newInt64Value(v *Int64Var, def int64, target *int64, hidden bool) *int64Value { + *target = def + return &int64Value{ + v: v, + hidden: hidden, + target: target, + } +} + +func (i *int64Value) Set(s string) error { + v, err := strconv.ParseInt(s, 0, 64) + if err != nil { + return err + } + + *i.target = v + + if i.v.SetHook != nil { + i.v.SetHook(v) + } + + return nil +} + +func (i *int64Value) Get() interface{} { return int64(*i.target) } +func (i *int64Value) String() string { return strconv.FormatInt(int64(*i.target), 10) } +func (i *int64Value) Example() string { return "int" } +func (i *int64Value) Hidden() bool { return i.hidden } + +// -- UintVar && uintValue +type UintVar struct { + Name string + Aliases []string + Usage string + Default uint + Hidden bool + EnvVar string + Target *uint + Completion complete.Predictor + SetHook func(val uint) +} + +func (f *Set) UintVar(i *UintVar) { + initial := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + if i, err := strconv.ParseUint(v, 0, 64); err == nil { + initial = uint(i) + } + } + + def := "" + if i.Default != 0 { + def = strconv.FormatUint(uint64(i.Default), 10) + } + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: i.Usage, + Default: def, + EnvVar: i.EnvVar, + Value: newUintValue(i, initial, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type uintValue struct { + v *UintVar + hidden bool + target *uint +} + +func newUintValue(v *UintVar, def uint, target *uint, hidden bool) *uintValue { + *target = def + return &uintValue{ + v: v, + hidden: hidden, + target: target, + } +} + +func (i *uintValue) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 64) + if err != nil { + return err + } + + *i.target = uint(v) + + if i.v.SetHook != nil { + i.v.SetHook(uint(v)) + } + + return nil +} + +func (i *uintValue) Get() interface{} { return uint(*i.target) } +func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i.target), 10) } +func (i *uintValue) Example() string { return "uint" } +func (i *uintValue) Hidden() bool { return i.hidden } + +// -- Uint64Var and uint64Value +type Uint64Var struct { + Name string + Aliases []string + Usage string + Default uint64 + Hidden bool + EnvVar string + Target *uint64 + Completion complete.Predictor + SetHook func(val uint64) +} + +func (f *Set) Uint64Var(i *Uint64Var) { + initial := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + if i, err := strconv.ParseUint(v, 0, 64); err == nil { + initial = i + } + } + + def := "" + if i.Default != 0 { + strconv.FormatUint(i.Default, 10) + } + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: i.Usage, + Default: def, + EnvVar: i.EnvVar, + Value: newUint64Value(i, initial, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type uint64Value struct { + v *Uint64Var + hidden bool + target *uint64 +} + +func newUint64Value(v *Uint64Var, def uint64, target *uint64, hidden bool) *uint64Value { + *target = def + return &uint64Value{ + v: v, + hidden: hidden, + target: target, + } +} + +func (i *uint64Value) Set(s string) error { + v, err := strconv.ParseUint(s, 0, 64) + if err != nil { + return err + } + + *i.target = v + + if i.v.SetHook != nil { + i.v.SetHook(v) + } + + return nil +} + +func (i *uint64Value) Get() interface{} { return uint64(*i.target) } +func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i.target), 10) } +func (i *uint64Value) Example() string { return "uint" } +func (i *uint64Value) Hidden() bool { return i.hidden } diff --git a/cli/cmd/common/flag/flag_string.go b/cli/cmd/common/flag/flag_string.go new file mode 100644 index 0000000000..ee17a2916d --- /dev/null +++ b/cli/cmd/common/flag/flag_string.go @@ -0,0 +1,72 @@ +package flag + +import ( + "os" + + "github.com/posener/complete" +) + +// -- StringVar and stringValue +type StringVar struct { + Name string + Aliases []string + Usage string + Default string + Hidden bool + EnvVar string + Target *string + Completion complete.Predictor + SetHook func(val string) +} + +func (f *Set) StringVar(i *StringVar) { + initial := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + initial = v + } + + def := "" + if i.Default != "" { + def = i.Default + } + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: i.Usage, + Default: def, + EnvVar: i.EnvVar, + Value: newStringValue(i, initial, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type stringValue struct { + v *StringVar + hidden bool + target *string +} + +func newStringValue(v *StringVar, def string, target *string, hidden bool) *stringValue { + *target = def + return &stringValue{ + v: v, + hidden: hidden, + target: target, + } +} + +func (s *stringValue) Set(val string) error { + *s.target = val + + if s.v.SetHook != nil { + s.v.SetHook(val) + } + + return nil +} + +func (s *stringValue) Get() interface{} { return *s.target } +func (s *stringValue) String() string { return *s.target } +func (s *stringValue) Example() string { return "string" } +func (s *stringValue) Hidden() bool { return s.hidden } diff --git a/cli/cmd/common/flag/flag_string_map.go b/cli/cmd/common/flag/flag_string_map.go new file mode 100644 index 0000000000..009b1d7761 --- /dev/null +++ b/cli/cmd/common/flag/flag_string_map.go @@ -0,0 +1,83 @@ +package flag + +import ( + "fmt" + "sort" + "strings" + + "github.com/posener/complete" +) + +// -- StringMapVar and stringMapValue +type StringMapVar struct { + Name string + Aliases []string + Usage string + Default map[string]string + Hidden bool + Target *map[string]string + Completion complete.Predictor +} + +func (f *Set) StringMapVar(i *StringMapVar) { + def := "" + if i.Default != nil { + def = mapToKV(i.Default) + } + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: i.Usage, + Default: def, + Value: newStringMapValue(i.Default, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type stringMapValue struct { + hidden bool + target *map[string]string +} + +func newStringMapValue(def map[string]string, target *map[string]string, hidden bool) *stringMapValue { + *target = def + return &stringMapValue{ + hidden: hidden, + target: target, + } +} + +func (s *stringMapValue) Set(val string) error { + idx := strings.Index(val, "=") + if idx == -1 { + return fmt.Errorf("missing = in KV pair: %q", val) + } + + if *s.target == nil { + *s.target = make(map[string]string) + } + + k, v := val[0:idx], val[idx+1:] + (*s.target)[k] = v + return nil +} + +func (s *stringMapValue) Get() interface{} { return *s.target } +func (s *stringMapValue) String() string { return mapToKV(*s.target) } +func (s *stringMapValue) Example() string { return "key=value" } +func (s *stringMapValue) Hidden() bool { return s.hidden } + +func mapToKV(m map[string]string) string { + list := make([]string, 0, len(m)) + for k := range m { + list = append(list, k) + } + sort.Strings(list) + + for i, k := range list { + list[i] = k + "=" + m[k] + } + + return strings.Join(list, ",") +} diff --git a/cli/cmd/common/flag/flag_string_slice.go b/cli/cmd/common/flag/flag_string_slice.go new file mode 100644 index 0000000000..7f27c245a4 --- /dev/null +++ b/cli/cmd/common/flag/flag_string_slice.go @@ -0,0 +1,75 @@ +package flag + +import ( + "os" + "strings" + + "github.com/posener/complete" +) + +// -- StringSliceVar and stringSliceValue +type StringSliceVar struct { + Name string + Aliases []string + Usage string + Default []string + Hidden bool + EnvVar string + Target *[]string + Completion complete.Predictor +} + +func (f *Set) StringSliceVar(i *StringSliceVar) { + initial := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + parts := strings.Split(v, ",") + for i := range parts { + parts[i] = strings.TrimSpace(parts[i]) + } + initial = parts + } + + def := "" + if i.Default != nil { + def = strings.Join(i.Default, ",") + } + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: i.Usage, + Default: def, + EnvVar: i.EnvVar, + Value: newStringSliceValue(initial, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type stringSliceValue struct { + hidden bool + target *[]string + set bool +} + +func newStringSliceValue(def []string, target *[]string, hidden bool) *stringSliceValue { + *target = def + return &stringSliceValue{ + hidden: hidden, + target: target, + } +} + +func (s *stringSliceValue) Set(val string) error { + if !s.set { + s.set = true + *s.target = nil + } + + *s.target = append(*s.target, strings.Split(strings.TrimSpace(val), ",")...) + return nil +} + +func (s *stringSliceValue) Get() interface{} { return *s.target } +func (s *stringSliceValue) String() string { return strings.Join(*s.target, ",") } +func (s *stringSliceValue) Example() string { return "string" } +func (s *stringSliceValue) Hidden() bool { return s.hidden } diff --git a/cli/cmd/common/flag/flag_string_slice_test.go b/cli/cmd/common/flag/flag_string_slice_test.go new file mode 100644 index 0000000000..5bea43386f --- /dev/null +++ b/cli/cmd/common/flag/flag_string_slice_test.go @@ -0,0 +1,38 @@ +package flag + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestStringSlice(t *testing.T) { + require := require.New(t) + + var valA, valB []string + sets := NewSets() + { + set := sets.NewSet("A") + set.StringSliceVar(&StringSliceVar{ + Name: "a", + Target: &valA, + }) + } + + { + set := sets.NewSet("B") + set.StringSliceVar(&StringSliceVar{ + Name: "b", + Target: &valB, + }) + } + + err := sets.Parse([]string{ + "-b", "somevalueB", + "-a", "somevalueA,somevalueB", + }) + require.NoError(err) + + require.Equal([]string{"somevalueB"}, valB) + require.Equal([]string{"somevalueA", "somevalueB"}, valA) +} diff --git a/cli/cmd/common/flag/flag_time.go b/cli/cmd/common/flag/flag_time.go new file mode 100644 index 0000000000..39562b765d --- /dev/null +++ b/cli/cmd/common/flag/flag_time.go @@ -0,0 +1,81 @@ +package flag + +import ( + "os" + "strings" + "time" + + "github.com/posener/complete" +) + +// -- DurationVar and durationValue +type DurationVar struct { + Name string + Aliases []string + Usage string + Default time.Duration + Hidden bool + EnvVar string + Target *time.Duration + Completion complete.Predictor +} + +func (f *Set) DurationVar(i *DurationVar) { + initial := i.Default + if v, exist := os.LookupEnv(i.EnvVar); exist { + if d, err := time.ParseDuration(appendDurationSuffix(v)); err == nil { + initial = d + } + } + + def := "" + if i.Default != 0 { + def = i.Default.String() + } + + f.VarFlag(&VarFlag{ + Name: i.Name, + Aliases: i.Aliases, + Usage: i.Usage, + Default: def, + EnvVar: i.EnvVar, + Value: newDurationValue(initial, i.Target, i.Hidden), + Completion: i.Completion, + }) +} + +type durationValue struct { + hidden bool + target *time.Duration +} + +func newDurationValue(def time.Duration, target *time.Duration, hidden bool) *durationValue { + *target = def + return &durationValue{ + hidden: hidden, + target: target, + } +} + +func (d *durationValue) Set(s string) error { + v, err := time.ParseDuration(appendDurationSuffix(s)) + if err != nil { + return err + } + *d.target = v + return nil +} + +func (d *durationValue) Get() interface{} { return time.Duration(*d.target) } +func (d *durationValue) String() string { return (*d.target).String() } +func (d *durationValue) Example() string { return "duration" } +func (d *durationValue) Hidden() bool { return d.hidden } + +// appendDurationSuffix is used as a backwards-compat tool for assuming users +// meant "seconds" when they do not provide a suffixed duration value. +func appendDurationSuffix(s string) string { + if strings.HasSuffix(s, "s") || strings.HasSuffix(s, "m") || strings.HasSuffix(s, "h") { + return s + } + return s + "s" +} diff --git a/cli/cmd/common/flag/flag_var.go b/cli/cmd/common/flag/flag_var.go new file mode 100644 index 0000000000..7546c517f4 --- /dev/null +++ b/cli/cmd/common/flag/flag_var.go @@ -0,0 +1,81 @@ +package flag + +import ( + "flag" + "fmt" + "strings" + + "github.com/posener/complete" +) + +// -- VarFlag +type VarFlag struct { + Name string + Aliases []string + Usage string + Default string + EnvVar string + Value flag.Value + Completion complete.Predictor +} + +func (f *Set) VarFlag(i *VarFlag) { + f.vars = append(f.vars, i) + + // If the flag is marked as hidden, just add it to the set and return to + // avoid unnecessary computations here. We do not want to add completions or + // generate help output for hidden flags. + if v, ok := i.Value.(FlagVisibility); ok && v.Hidden() { + f.Var(i.Value, i.Name, "") + return + } + + // Calculate the full usage + usage := i.Usage + + if len(i.Aliases) > 0 { + sentence := make([]string, len(i.Aliases)) + for i, a := range i.Aliases { + sentence[i] = fmt.Sprintf(`"-%s"`, a) + } + + aliases := "" + switch len(sentence) { + case 0: + // impossible... + case 1: + aliases = sentence[0] + case 2: + aliases = sentence[0] + " and " + sentence[1] + default: + sentence[len(sentence)-1] = "and " + sentence[len(sentence)-1] + aliases = strings.Join(sentence, ", ") + } + + usage += fmt.Sprintf(" This is aliased as %s.", aliases) + } + + if i.Default != "" { + usage += fmt.Sprintf(" The default is %s.", i.Default) + } + + if i.EnvVar != "" { + usage += fmt.Sprintf(" This can also be specified via the %s "+ + "environment variable.", i.EnvVar) + } + + // Add aliases to the main set + for _, a := range i.Aliases { + f.unionSet.Var(i.Value, a, "") + } + + f.Var(i.Value, i.Name, usage) + f.completions["-"+i.Name] = i.Completion +} + +// Var is a lower-level API for adding something to the flags. It should be used +// wtih caution, since it bypasses all validation. Consider VarFlag instead. +func (f *Set) Var(value flag.Value, name, usage string) { + f.unionSet.Var(value, name, usage) + f.flagSet.Var(value, name, usage) +} diff --git a/cli/cmd/common/flag/set.go b/cli/cmd/common/flag/set.go new file mode 100644 index 0000000000..df44e7031c --- /dev/null +++ b/cli/cmd/common/flag/set.go @@ -0,0 +1,175 @@ +package flag + +import ( + "bytes" + "flag" + "fmt" + "io" + "io/ioutil" + "strings" + + "github.com/posener/complete" +) + +// Sets is a group of flag sets. +type Sets struct { + // unionSet is the set that is the union of all other sets. This + // has ALL flags defined on it and is the set that is parsed. But + // we maintain the other list of sets so that we can generate proper help. + unionSet *flag.FlagSet + + // flagSets is the list of sets that we have. We don't parse these + // directly but use them for help generation and autocompletion. + flagSets []*Set + + // completions is our set of autocompletion handlers. This is also + // the union of all available flags similar to unionSet. + completions complete.Flags +} + +// NewSets creates a new flag sets. +func NewSets() *Sets { + unionSet := flag.NewFlagSet("", flag.ContinueOnError) + + // Errors and usage are expected to be controlled externally by + // checking on the result of Parse. + unionSet.Usage = func() {} + unionSet.SetOutput(ioutil.Discard) + + return &Sets{ + unionSet: unionSet, + completions: complete.Flags{}, + } +} + +// NewSet creates a new single flag set. A set should be created for +// any grouping of flags, for example "Common Options", "Auth Options", etc. +func (f *Sets) NewSet(name string) *Set { + flagSet := NewSet(name) + + // The union and completions are pointers to our own values + flagSet.unionSet = f.unionSet + flagSet.completions = f.completions + + // Keep track of it for help generation + f.flagSets = append(f.flagSets, flagSet) + return flagSet +} + +// Completions returns the completions for this flag set. +func (f *Sets) Completions() complete.Flags { + return f.completions +} + +// Parse parses the given flags, returning any errors. +func (f *Sets) Parse(args []string) error { + return f.unionSet.Parse(args) +} + +// Parsed reports whether the command-line flags have been parsed. +func (f *Sets) Parsed() bool { + return f.unionSet.Parsed() +} + +// Args returns the remaining args after parsing. +func (f *Sets) Args() []string { + return f.unionSet.Args() +} + +// Visit visits the flags in lexicographical order, calling fn for each. It +// visits only those flags that have been set. +func (f *Sets) Visit(fn func(*flag.Flag)) { + f.unionSet.Visit(fn) +} + +// Help builds custom help for this command, grouping by flag set. +func (fs *Sets) Help() string { + var out bytes.Buffer + + for _, set := range fs.flagSets { + printFlagTitle(&out, set.name+":") + set.VisitAll(func(f *flag.Flag) { + // Skip any hidden flags + if v, ok := f.Value.(FlagVisibility); ok && v.Hidden() { + return + } + printFlagDetail(&out, f) + }) + } + + return strings.TrimRight(out.String(), "\n") +} + +// Help builds custom help for this command, grouping by flag set. +func (fs *Sets) VisitSets(fn func(name string, set *Set)) { + for _, set := range fs.flagSets { + fn(set.name, set) + } +} + +// Set is a grouped wrapper around a real flag set and a grouped flag set. +type Set struct { + name string + flagSet *flag.FlagSet + unionSet *flag.FlagSet + completions complete.Flags + + vars []*VarFlag +} + +// NewSet creates a new flag set. +func NewSet(name string) *Set { + return &Set{ + name: name, + flagSet: flag.NewFlagSet(name, flag.ContinueOnError), + } +} + +// Name returns the name of this flag set. +func (f *Set) Name() string { + return f.name +} + +func (f *Set) Visit(fn func(*flag.Flag)) { + f.flagSet.Visit(fn) +} + +func (f *Set) VisitAll(fn func(*flag.Flag)) { + f.flagSet.VisitAll(fn) +} + +func (f *Set) VisitVars(fn func(*VarFlag)) { + for _, v := range f.vars { + fn(v) + } +} + +// printFlagTitle prints a consistently-formatted title to the given writer. +func printFlagTitle(w io.Writer, s string) { + fmt.Fprintf(w, "%s\n\n", s) +} + +// printFlagDetail prints a single flag to the given writer. +func printFlagDetail(w io.Writer, f *flag.Flag) { + // Check if the flag is hidden - do not print any flag detail or help output + // if it is hidden. + if h, ok := f.Value.(FlagVisibility); ok && h.Hidden() { + return + } + + // Check for a detailed example + example := "" + if t, ok := f.Value.(FlagExample); ok { + example = t.Example() + } + + if example != "" { + fmt.Fprintf(w, " -%s=<%s>\n", f.Name, example) + } else { + fmt.Fprintf(w, " -%s\n", f.Name) + } + + usage := reRemoveWhitespace.ReplaceAllString(f.Usage, " ") + indented := wrapAtLengthWithPadding(usage, 6) + fmt.Fprintf(w, "%s\n\n", indented) +} diff --git a/cli/cmd/common/flag/set_test.go b/cli/cmd/common/flag/set_test.go new file mode 100644 index 0000000000..9bb4ef4a7a --- /dev/null +++ b/cli/cmd/common/flag/set_test.go @@ -0,0 +1,35 @@ +package flag + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSets(t *testing.T) { + require := require.New(t) + + var valA, valB int + sets := NewSets() + { + set := sets.NewSet("A") + set.IntVar(&IntVar{ + Name: "a", + Target: &valA, + }) + } + + { + set := sets.NewSet("B") + set.IntVar(&IntVar{ + Name: "b", + Target: &valB, + }) + } + + err := sets.Parse([]string{"-b", "42", "-a", "21"}) + require.NoError(err) + + require.Equal(int(21), valA) + require.Equal(int(42), valB) +} diff --git a/cli/cmd/common/terminal/basic.go b/cli/cmd/common/terminal/basic.go new file mode 100644 index 0000000000..15006b876c --- /dev/null +++ b/cli/cmd/common/terminal/basic.go @@ -0,0 +1,141 @@ +package terminal + +import ( + "bufio" + "bytes" + "context" + "fmt" + "io" + "os" + "strings" + "text/tabwriter" + + "github.com/bgentry/speakeasy" + "github.com/fatih/color" + "github.com/mattn/go-isatty" +) + +// basicUI +type basicUI struct { + ctx context.Context +} + +func NewBasicUI(ctx context.Context) *basicUI { + return &basicUI{ + ctx: ctx, + } +} + +// Input implements UI +func (ui *basicUI) Input(input *Input) (string, error) { + var buf bytes.Buffer + + // Write the prompt, add a space. + ui.Output(input.Prompt, WithStyle(input.Style), WithWriter(&buf)) + fmt.Fprint(color.Output, strings.TrimRight(buf.String(), "\r\n")) + fmt.Fprint(color.Output, " ") + + // Ask for input in a go-routine so that we can ignore it. + errCh := make(chan error, 1) + lineCh := make(chan string, 1) + go func() { + var line string + var err error + if input.Secret && isatty.IsTerminal(os.Stdin.Fd()) { + line, err = speakeasy.Ask("") + } else { + r := bufio.NewReader(os.Stdin) + line, err = r.ReadString('\n') + } + if err != nil { + errCh <- err + return + } + + lineCh <- strings.TrimRight(line, "\r\n") + }() + + select { + case err := <-errCh: + return "", err + case line := <-lineCh: + return line, nil + case <-ui.ctx.Done(): + // Print newline so that any further output starts properly + fmt.Fprintln(color.Output) + return "", ui.ctx.Err() + } +} + +// Interactive implements UI +func (ui *basicUI) Interactive() bool { + return isatty.IsTerminal(os.Stdin.Fd()) +} + +// Output implements UI +func (ui *basicUI) Output(msg string, raw ...interface{}) { + msg, style, w := Interpret(msg, raw...) + + switch style { + case HeaderStyle: + msg = colorHeader.Sprintf("\n==> %s", msg) + case ErrorStyle: + msg = colorError.Sprintf(" ! %s", msg) + case ErrorBoldStyle: + msg = colorErrorBold.Sprintf(" ! %s", msg) + case WarningStyle: + msg = colorWarning.Sprintf(" * %s", msg) + case WarningBoldStyle: + msg = colorWarningBold.Sprintf(" * %s", msg) + case SuccessStyle: + msg = colorSuccess.Sprintf(" + %s", msg) + case SuccessBoldStyle: + msg = colorSuccessBold.Sprintf(" + %s", msg) + case InfoStyle: + lines := strings.Split(msg, "\n") + for i, line := range lines { + lines[i] = colorInfo.Sprintf(" %s", line) + } + + msg = strings.Join(lines, "\n") + } + + // Write it + fmt.Fprintln(w, msg) +} + +// NamedValues implements UI +func (ui *basicUI) NamedValues(rows []NamedValue, opts ...Option) { + cfg := &config{Writer: color.Output} + for _, opt := range opts { + opt(cfg) + } + + var buf bytes.Buffer + tr := tabwriter.NewWriter(&buf, 1, 8, 0, ' ', tabwriter.AlignRight) + for _, row := range rows { + switch v := row.Value.(type) { + case int, uint, int8, uint8, int16, uint16, int32, uint32, int64, uint64: + fmt.Fprintf(tr, " %s: \t%d\n", row.Name, row.Value) + case float32, float64: + fmt.Fprintf(tr, " %s: \t%f\n", row.Name, row.Value) + case bool: + fmt.Fprintf(tr, " %s: \t%v\n", row.Name, row.Value) + case string: + if v == "" { + continue + } + fmt.Fprintf(tr, " %s: \t%s\n", row.Name, row.Value) + default: + fmt.Fprintf(tr, " %s: \t%s\n", row.Name, row.Value) + } + } + + tr.Flush() + colorInfo.Fprintln(cfg.Writer, buf.String()) +} + +// OutputWriters implements UI +func (ui *basicUI) OutputWriters() (io.Writer, io.Writer, error) { + return os.Stdout, os.Stderr, nil +} diff --git a/cli/cmd/common/terminal/doc.go b/cli/cmd/common/terminal/doc.go new file mode 100644 index 0000000000..2935fa9db5 --- /dev/null +++ b/cli/cmd/common/terminal/doc.go @@ -0,0 +1,10 @@ +// Package terminal is a modified version of +// https://github.com/hashicorp/waypoint-plugin-sdk/tree/74d9328929293551499078da388b8d057f3b2341/terminal. +// +// This terminal package only contains the basic UI implementation and excludes the glint UI and noninteractive UI +// implementations as they do not yet have an Input implementation which we leverage in commands. +// +// This terminal package does not contain the Status, Step, and StepGroup interface and implementation from the original +// terminal package since using the spinner package does not allow streaming outputs of a given Step or Status. Instead, +// we only use the UI interface to standardize Input and Output formatting. +package terminal diff --git a/cli/cmd/common/terminal/table.go b/cli/cmd/common/terminal/table.go new file mode 100644 index 0000000000..4d55e0006e --- /dev/null +++ b/cli/cmd/common/terminal/table.go @@ -0,0 +1,99 @@ +package terminal + +import ( + "github.com/fatih/color" + "github.com/olekukonko/tablewriter" +) + +// Passed to UI.Table to provide a nicely formatted table. +type Table struct { + Headers []string + Rows [][]TableEntry +} + +// Table creates a new Table structure that can be used with UI.Table. +func NewTable(headers ...string) *Table { + return &Table{ + Headers: headers, + } +} + +// TableEntry is a single entry for a table. +type TableEntry struct { + Value string + Color string +} + +// Rich adds a row to the table. +func (t *Table) Rich(cols []string, colors []string) { + var row []TableEntry + + for i, col := range cols { + if i < len(colors) { + row = append(row, TableEntry{Value: col, Color: colors[i]}) + } else { + row = append(row, TableEntry{Value: col}) + } + } + + t.Rows = append(t.Rows, row) +} + +// Table implements UI +func (u *basicUI) Table(tbl *Table, opts ...Option) { + // Build our config and set our options + cfg := &config{Writer: color.Output} + for _, opt := range opts { + opt(cfg) + } + + table := tablewriter.NewWriter(cfg.Writer) + + table.SetHeader(tbl.Headers) + table.SetBorder(false) + table.SetAutoWrapText(false) + + if cfg.Style == "Simple" { + // Format the table without borders, simple output + + table.SetAutoFormatHeaders(true) + table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) + table.SetAlignment(tablewriter.ALIGN_LEFT) + table.SetCenterSeparator("") + table.SetColumnSeparator("") + table.SetRowSeparator("") + table.SetHeaderLine(false) + table.SetTablePadding("\t") // pad with tabs + table.SetNoWhiteSpace(true) + } + + for _, row := range tbl.Rows { + colors := make([]tablewriter.Colors, len(row)) + entries := make([]string, len(row)) + + for i, ent := range row { + entries[i] = ent.Value + + color, ok := colorMapping[ent.Color] + if ok { + colors[i] = tablewriter.Colors{color} + } + } + + table.Rich(entries, colors) + } + + table.Render() +} + +const ( + Yellow = "yellow" + Green = "green" + Red = "red" +) + +var colorMapping = map[string]int{ + Green: tablewriter.FgGreenColor, + Yellow: tablewriter.FgYellowColor, + Red: tablewriter.FgRedColor, +} diff --git a/cli/cmd/common/terminal/ui.go b/cli/cmd/common/terminal/ui.go new file mode 100644 index 0000000000..f4775cf5cd --- /dev/null +++ b/cli/cmd/common/terminal/ui.go @@ -0,0 +1,173 @@ +package terminal + +import ( + "errors" + "fmt" + "io" + + "github.com/fatih/color" +) + +// ErrNonInteractive is returned when Input is called on a non-Interactive UI. +var ErrNonInteractive = errors.New("noninteractive UI doesn't support this operation") + +// Passed to UI.NamedValues to provide a nicely formatted key: value output +type NamedValue struct { + Name string + Value interface{} +} + +// UI is the primary interface for interacting with a user via the CLI. +// +// Some of the methods on this interface return values that have a lifetime +// such as Status and StepGroup. While these are still active (haven't called +// the close or equivalent method on these values), no other method on the +// UI should be called. +type UI interface { + // Input asks the user for input. This will immediately return an error + // if the UI doesn't support interaction. You can test for interaction + // ahead of time with Interactive(). + Input(*Input) (string, error) + + // Interactive returns true if this prompt supports user interaction. + // If this is false, Input will always error. + Interactive() bool + + // Output outputs a message directly to the terminal. The remaining + // arguments should be interpolations for the format string. After the + // interpolations you may add Options. + Output(string, ...interface{}) + + // Output data as a table of data. Each entry is a row which will be output + // with the columns lined up nicely. + NamedValues([]NamedValue, ...Option) + + // OutputWriters returns stdout and stderr writers. These are usually + // but not always TTYs. This is useful for subprocesses, network requests, + // etc. Note that writing to these is not thread-safe by default so + // you must take care that there is only ever one writer. + OutputWriters() (stdout, stderr io.Writer, err error) + + // Table outputs the information formatted into a Table structure. + Table(*Table, ...Option) +} + +// Input is the configuration for an input. +type Input struct { + // Prompt is a single-line prompt to give the user such as "Continue?" + // The user will input their answer after this prompt. + Prompt string + + // Style is the style to apply to the input. If this is blank, + // the output won't be colorized in any way. + Style string + + // True if this input is a secret. The input will be masked. + Secret bool +} + +// Interpret decomposes the msg and arguments into the message, style, and writer +func Interpret(msg string, raw ...interface{}) (string, string, io.Writer) { + // Build our args and options + var args []interface{} + var opts []Option + for _, r := range raw { + if opt, ok := r.(Option); ok { + opts = append(opts, opt) + } else { + args = append(args, r) + } + } + + // Build our message + msg = fmt.Sprintf(msg, args...) + + // Build our config and set our options + cfg := &config{Writer: color.Output} + for _, opt := range opts { + opt(cfg) + } + + return msg, cfg.Style, cfg.Writer +} + +const ( + HeaderStyle = "header" + ErrorStyle = "error" + ErrorBoldStyle = "error-bold" + WarningStyle = "warning" + WarningBoldStyle = "warning-bold" + InfoStyle = "info" + SuccessStyle = "success" + SuccessBoldStyle = "success-bold" +) + +type config struct { + // Writer is where the message will be written to. + Writer io.Writer + + // The style the output should take on + Style string +} + +// Option controls output styling. +type Option func(*config) + +// WithHeaderStyle styles the output like a header denoting a new section +// of execution. This should only be used with single-line output. Multi-line +// output will not look correct. +func WithHeaderStyle() Option { + return func(c *config) { + c.Style = HeaderStyle + } +} + +// WithInfoStyle styles the output like it's formatted information. +func WithInfoStyle() Option { + return func(c *config) { + c.Style = InfoStyle + } +} + +// WithErrorStyle styles the output as an error message. +func WithErrorStyle() Option { + return func(c *config) { + c.Style = ErrorStyle + } +} + +// WithWarningStyle styles the output as an error message. +func WithWarningStyle() Option { + return func(c *config) { + c.Style = WarningStyle + } +} + +// WithSuccessStyle styles the output as a success message. +func WithSuccessStyle() Option { + return func(c *config) { + c.Style = SuccessStyle + } +} + +func WithStyle(style string) Option { + return func(c *config) { + c.Style = style + } +} + +// WithWriter specifies the writer for the output. +func WithWriter(w io.Writer) Option { + return func(c *config) { c.Writer = w } +} + +var ( + colorHeader = color.New(color.Bold) + colorInfo = color.New() + colorError = color.New(color.FgRed) + colorErrorBold = color.New(color.FgRed, color.Bold) + colorSuccess = color.New(color.FgGreen) + colorSuccessBold = color.New(color.FgGreen, color.Bold) + colorWarning = color.New(color.FgYellow) + colorWarningBold = color.New(color.FgYellow, color.Bold) +) diff --git a/cli/cmd/common/usage.go b/cli/cmd/common/usage.go new file mode 100644 index 0000000000..b4b4cdf780 --- /dev/null +++ b/cli/cmd/common/usage.go @@ -0,0 +1,86 @@ +package common + +import ( + "bytes" + "flag" + "fmt" + "io" + "strings" + + "github.com/kr/text" +) + +// Taken from https://github.com/hashicorp/consul/blob/b5b9c8d953cd3c79c6b795946839f4cf5012f507/command/flags/usage.go +// This was done so we don't depend on internal Consul implementation. + +// Usage returns a usage string nicely formatted. +func Usage(txt string, flags *flag.FlagSet) string { + u := &Usager{ + Usage: txt, + Flags: flags, + } + return u.String() +} + +type Usager struct { + Usage string + Flags *flag.FlagSet +} + +func (u *Usager) String() string { + out := new(bytes.Buffer) + out.WriteString(strings.TrimSpace(u.Usage)) + out.WriteString("\n") + out.WriteString("\n") + + if u.Flags != nil { + var cmdFlags *flag.FlagSet + u.Flags.VisitAll(func(f *flag.Flag) { + if cmdFlags == nil { + cmdFlags = flag.NewFlagSet("", flag.ContinueOnError) + } + cmdFlags.Var(f.Value, f.Name, f.Usage) + }) + + if cmdFlags != nil { + printTitle(out, "Command Options") + cmdFlags.VisitAll(func(f *flag.Flag) { + printFlag(out, f) + }) + } + } + + return strings.TrimRight(out.String(), "\n") +} + +// printTitle prints a consistently-formatted title to the given writer. +func printTitle(w io.Writer, s string) { + fmt.Fprintf(w, "%s\n\n", s) +} + +// printFlag prints a single flag to the given writer. +func printFlag(w io.Writer, f *flag.Flag) { + example, _ := flag.UnquoteUsage(f) + if example != "" { + fmt.Fprintf(w, " -%s=<%s>\n", f.Name, example) + } else { + fmt.Fprintf(w, " -%s\n", f.Name) + } + + indented := wrapAtLength(f.Usage, 5) + fmt.Fprintf(w, "%s\n\n", indented) +} + +// maxLineLength is the maximum width of any line. +const maxLineLength int = 72 + +// wrapAtLength wraps the given text at the maxLineLength, taking into account +// any provided left padding. +func wrapAtLength(s string, pad int) string { + wrapped := text.Wrap(s, maxLineLength-pad) + lines := strings.Split(wrapped, "\n") + for i, line := range lines { + lines[i] = strings.Repeat(" ", pad) + line + } + return strings.Join(lines, "\n") +} diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go new file mode 100644 index 0000000000..71abba1d3d --- /dev/null +++ b/cli/cmd/install/install.go @@ -0,0 +1,500 @@ +package install + +import ( + "errors" + "fmt" + "os" + "strings" + "sync" + "time" + + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" + "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart/loader" + helmCLI "helm.sh/helm/v3/pkg/cli" + "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/getter" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + _ "k8s.io/client-go/plugin/pkg/client/auth" + "sigs.k8s.io/yaml" +) + +const ( + flagNamePreset = "preset" + defaultPreset = "" + + defaultReleaseName = "consul" + + flagNameConfigFile = "config-file" + flagNameSetStringValues = "set-string" + flagNameSetValues = "set" + flagNameFileValues = "set-file" + + flagNameDryRun = "dry-run" + defaultDryRun = false + + flagNameAutoApprove = "auto-approve" + defaultAutoApprove = false + + flagNameNamespace = "namespace" + defaultNamespace = "consul" + + helmRepository = "https://helm.releases.hashicorp.com" +) + +type Command struct { + *common.BaseCommand + + kubernetes kubernetes.Interface + + set *flag.Sets + + flagPreset string + flagNamespace string + flagDryRun bool + flagAutoApprove bool + flagValueFiles []string + flagSetStringValues []string + flagSetValues []string + flagFileValues []string + + flagKubeConfig string + flagKubeContext string + + once sync.Once + help string +} + +func (c *Command) init() { + // Store all the possible preset values in 'presetList'. Printed in the help message. + var presetList []string + for name := range presets { + presetList = append(presetList, name) + } + + c.set = flag.NewSets() + { + f := c.set.NewSet("Command Options") + f.BoolVar(&flag.BoolVar{ + Name: flagNameAutoApprove, + Target: &c.flagAutoApprove, + Default: defaultAutoApprove, + Usage: "Skip confirmation prompt.", + }) + f.BoolVar(&flag.BoolVar{ + Name: flagNameDryRun, + Target: &c.flagDryRun, + Default: defaultDryRun, + Usage: "Run pre-install checks and display summary of installation.", + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameConfigFile, + Aliases: []string{"f"}, + Target: &c.flagValueFiles, + Usage: "Path to a file to customize the installation, such as Consul Helm chart values file. Can be specified multiple times.", + }) + f.StringVar(&flag.StringVar{ + Name: flagNameNamespace, + Target: &c.flagNamespace, + Default: defaultNamespace, + Usage: fmt.Sprintf("Namespace for the Consul installation. Defaults to \"%q\".", defaultNamespace), + }) + f.StringVar(&flag.StringVar{ + Name: flagNamePreset, + Target: &c.flagPreset, + Default: defaultPreset, + Usage: fmt.Sprintf("Use an installation preset, one of %s. Defaults to \"%q\"", strings.Join(presetList, ", "), defaultPreset), + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameSetValues, + Target: &c.flagSetValues, + Usage: "Set a value to customize. Can be specified multiple times. Supports Consul Helm chart values.", + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameFileValues, + Target: &c.flagFileValues, + Usage: "Set a value to customize via a file. The contents of the file will be set as the value. Can be " + + "specified multiple times. Supports Consul Helm chart values.", + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameSetStringValues, + Target: &c.flagSetStringValues, + Usage: "Set a string value to customize. Can be specified multiple times. Supports Consul Helm chart values.", + }) + + f = c.set.NewSet("Global Options") + f.StringVar(&flag.StringVar{ + Name: "kubeconfig", + Aliases: []string{"c"}, + Target: &c.flagKubeConfig, + Default: "", + Usage: "Path to kubeconfig file.", + }) + f.StringVar(&flag.StringVar{ + Name: "context", + Target: &c.flagKubeContext, + Default: "", + Usage: "Kubernetes context to use.", + }) + } + + c.help = c.set.Help() + + // c.Init() calls the embedded BaseCommand's initialization function. + c.Init() +} + +func (c *Command) Run(args []string) int { + c.once.Do(c.init) + + defer func() { + if err := c.Close(); err != nil { + c.UI.Output(err.Error()) + } + }() + + // The logger is initialized in main with the name cli. Here, we reset the name to install so log lines would be prefixed with install. + c.Log.ResetNamed("install") + + if err := c.validateFlags(args); err != nil { + c.UI.Output(err.Error()) + return 1 + } + + // A hack to set namespace via the HELM_NAMESPACE env var until we merge a PR that will allow us to use the latest + // Helm templates. + prevHelmNSEnv := os.Getenv("HELM_NAMESPACE") + os.Setenv("HELM_NAMESPACE", c.flagNamespace) + // helmCLI.New() will create a settings object which is used by the Helm Go SDK calls. + // Any overrides by our kubeconfig and kubecontext flags is done here. The Kube client that + // is created will use this command's flags first, then the HELM_KUBECONTEXT environment variable, + // then call out to genericclioptions.ConfigFlag + settings := helmCLI.New() + os.Setenv("HELM_NAMESPACE", prevHelmNSEnv) + + if c.flagKubeConfig != "" { + settings.KubeConfig = c.flagKubeConfig + } + if c.flagKubeContext != "" { + settings.KubeContext = c.flagKubeContext + } + + // Setup logger to stream Helm library logs + var uiLogger = func(s string, args ...interface{}) { + logMsg := fmt.Sprintf(s, args...) + c.UI.Output(logMsg, terminal.WithInfoStyle()) + } + + // Set up the kubernetes client to use for non Helm SDK calls to the Kubernetes API + // The Helm SDK will use settings.RESTClientGetter for its calls as well, so this will + // use a consistent method to target the right cluster for both Helm SDK and non Helm SDK calls. + if c.kubernetes == nil { + restConfig, err := settings.RESTClientGetter().ToRESTConfig() + if err != nil { + c.UI.Output("Retrieving Kubernetes auth: %v", err, terminal.WithErrorStyle()) + return 1 + } + c.kubernetes, err = kubernetes.NewForConfig(restConfig) + if err != nil { + c.UI.Output("Initializing Kubernetes client: %v", err, terminal.WithErrorStyle()) + return 1 + } + } + + c.UI.Output("Pre-Install Checks", terminal.WithHeaderStyle()) + + if err := c.checkForPreviousInstallations(settings, uiLogger); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // Ensure there's no previous PVCs lying around. + if err := c.checkForPreviousPVCs(); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // Ensure there's no previous bootstrap secret lying around. + if err := c.checkForPreviousSecrets(); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // Handle preset, value files, and set values logic. + vals, err := c.mergeValuesFlagsWithPrecedence(settings) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + valuesYaml, err := yaml.Marshal(vals) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // Print out the installation summary. + if !c.flagAutoApprove { + c.UI.Output("Consul Installation Summary", terminal.WithHeaderStyle()) + c.UI.Output("Installation name: %s", defaultReleaseName, terminal.WithInfoStyle()) + c.UI.Output("Namespace: %s", c.flagNamespace, terminal.WithInfoStyle()) + + if len(vals) == 0 { + c.UI.Output("Overrides: "+string(valuesYaml), terminal.WithInfoStyle()) + } else { + c.UI.Output("Overrides:"+"\n"+string(valuesYaml), terminal.WithInfoStyle()) + } + } + + // Without informing the user, default global.name to consul if it hasn't been set already. We don't allow setting + // the release name, and since that is hardcoded to "consul", setting global.name to "consul" makes it so resources + // aren't double prefixed with "consul-consul-...". + vals = mergeMaps(convert(globalNameConsul), vals) + + // Dry Run should exit here, no need to actual locate/download the charts. + if c.flagDryRun { + c.UI.Output("Dry run complete - installation can proceed.", terminal.WithInfoStyle()) + return 0 + } + + if !c.flagAutoApprove { + confirmation, err := c.UI.Input(&terminal.Input{ + Prompt: "Proceed with installation? (y/N)", + Style: terminal.InfoStyle, + Secret: false, + }) + + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + confirmation = strings.TrimSuffix(confirmation, "\n") + if !(strings.ToLower(confirmation) == "y" || strings.ToLower(confirmation) == "yes") { + c.UI.Output("Install aborted. To learn how to customize your installation, run:\nconsul-k8s install --help", terminal.WithInfoStyle()) + return 1 + } + } + + c.UI.Output("Running Installation", terminal.WithHeaderStyle()) + + // Setup action configuration for Helm Go SDK function calls. + actionConfig := new(action.Configuration) + if err := actionConfig.Init(settings.RESTClientGetter(), c.flagNamespace, + os.Getenv("HELM_DRIVER"), uiLogger); err != nil { + c.UI.Output(err.Error()) + return 1 + } + + // Setup the installation action. + install := action.NewInstall(actionConfig) + install.ReleaseName = defaultReleaseName + install.Namespace = c.flagNamespace + install.CreateNamespace = true + install.ChartPathOptions.RepoURL = helmRepository + install.Wait = true + install.Timeout = time.Minute * 10 + + // Locate the chart, install it in some cache locally. + chartPath, err := install.ChartPathOptions.LocateChart("consul", settings) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // Actually load the chart into memory. + chart, err := loader.Load(chartPath) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + c.UI.Output("Downloaded charts", terminal.WithSuccessStyle()) + + // Run the install. + _, err = install.Run(chart, vals) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + c.UI.Output("Consul installed into namespace %q", c.flagNamespace, terminal.WithSuccessStyle()) + + return 0 +} +func (c *Command) Help() string { + c.once.Do(c.init) + s := "Usage: consul-k8s install [flags]" + "\n" + "Install Consul onto a Kubernetes cluster." + "\n" + return s + "\n" + c.help +} + +func (c *Command) Synopsis() string { + return "Install Consul on Kubernetes." +} + +// checkForPreviousInstallations uses the helm Go SDK to find helm releases in all namespaces where the chart name is +// "consul", and returns an error if there is an existing installation. +// Note that this function is tricky to test because mocking out the action.Configuration struct requires a +// RegistryClient field that is from an internal helm package, so we are not unit testing it. +func (c *Command) checkForPreviousInstallations(settings *helmCLI.EnvSettings, uiLogger action.DebugLog) error { + // Need a specific action config to call helm list, where namespace is NOT specified. + listConfig := new(action.Configuration) + if err := listConfig.Init(settings.RESTClientGetter(), "", + os.Getenv("HELM_DRIVER"), uiLogger); err != nil { + return fmt.Errorf("couldn't initialize helm config: %s", err) + } + + lister := action.NewList(listConfig) + lister.AllNamespaces = true + res, err := lister.Run() + if err != nil { + return fmt.Errorf("couldn't check for installations: %s", err) + } + + for _, rel := range res { + if rel.Chart.Metadata.Name == "consul" { + // TODO: In the future the user will be prompted with our own uninstall command. + return fmt.Errorf("existing Consul installation found (name=%s, namespace=%s) - run helm "+ + "delete %s -n %s if you wish to re-install", + rel.Name, rel.Namespace, rel.Name, rel.Namespace) + } + } + c.UI.Output("No existing installations found", terminal.WithSuccessStyle()) + return nil +} + +// checkForPreviousPVCs checks for existing PVCs with a name containing "consul-server" and returns an error and lists +// the PVCs it finds matches. +func (c *Command) checkForPreviousPVCs() error { + pvcs, err := c.kubernetes.CoreV1().PersistentVolumeClaims("").List(c.Ctx, metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("error listing PVCs: %s", err) + } + var previousPVCs []string + for _, pvc := range pvcs.Items { + if strings.Contains(pvc.Name, "consul-server") { + previousPVCs = append(previousPVCs, fmt.Sprintf("%s/%s", pvc.Namespace, pvc.Name)) + } + } + + if len(previousPVCs) > 0 { + return fmt.Errorf("found PVCs from previous installations (%s), delete before re-installing", + strings.Join(previousPVCs, ",")) + } + c.UI.Output("No previous persistent volume claims found", terminal.WithSuccessStyle()) + return nil +} + +// checkForPreviousSecrets checks for the bootstrap token and returns an error if found. +func (c *Command) checkForPreviousSecrets() error { + secrets, err := c.kubernetes.CoreV1().Secrets("").List(c.Ctx, metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("error listing secrets: %s", err) + } + for _, secret := range secrets.Items { + // future TODO: also check for federation secret + if strings.Contains(secret.Name, "consul-bootstrap-acl-token") { + return fmt.Errorf("found consul-acl-bootstrap-token secret from previous installations: %q in namespace %q. To delete, run kubectl delete secret %s --namespace %s", + secret.Name, secret.Namespace, secret.Name, secret.Namespace) + } + } + c.UI.Output("No previous secrets found", terminal.WithSuccessStyle()) + return nil +} + +// mergeValuesFlagsWithPrecedence is responsible for merging all the values to determine the values file for the +// installation based on the following precedence order from lowest to highest: +// 1. -preset +// 2. -f values-file +// 3. -set +// 4. -set-string +// 5. -set-file +// For example, -set-file will override a value provided via -set. +// Within each of these groups the rightmost flag value has the highest precedence. +func (c *Command) mergeValuesFlagsWithPrecedence(settings *helmCLI.EnvSettings) (map[string]interface{}, error) { + p := getter.All(settings) + v := &values.Options{ + ValueFiles: c.flagValueFiles, + StringValues: c.flagSetStringValues, + Values: c.flagSetValues, + FileValues: c.flagFileValues, + } + vals, err := v.MergeValues(p) + if err != nil { + return nil, fmt.Errorf("error merging values: %s", err) + } + if c.flagPreset != defaultPreset { + // Note the ordering of the function call, presets have lower precedence than set vals. + presetMap := presets[c.flagPreset].(map[string]interface{}) + vals = mergeMaps(presetMap, vals) + } + return vals, err +} + +// mergeMaps is a helper function used in Run. Merges two maps giving b precedent. +// @source: https://github.com/helm/helm/blob/main/pkg/cli/values/options.go +func mergeMaps(a, b map[string]interface{}) map[string]interface{} { + out := make(map[string]interface{}, len(a)) + for k, v := range a { + out[k] = v + } + for k, v := range b { + if v, ok := v.(map[string]interface{}); ok { + if bv, ok := out[k]; ok { + if bv, ok := bv.(map[string]interface{}); ok { + out[k] = mergeMaps(bv, v) + continue + } + } + } + out[k] = v + } + return out +} + +// validateFlags is a helper function that performs sanity checks on the user's provided flags. +func (c *Command) validateFlags(args []string) error { + if err := c.set.Parse(args); err != nil { + return err + } + if len(c.set.Args()) > 0 { + return errors.New("should have no non-flag arguments") + } + if len(c.flagValueFiles) != 0 && c.flagPreset != defaultPreset { + return errors.New(fmt.Sprintf("Cannot set both -%s and -%s", flagNameConfigFile, flagNamePreset)) + } + if _, ok := presets[c.flagPreset]; c.flagPreset != defaultPreset && !ok { + return errors.New(fmt.Sprintf("'%s' is not a valid preset", c.flagPreset)) + } + if !validLabel(c.flagNamespace) { + return errors.New(fmt.Sprintf("'%s' is an invalid namespace. Namespaces follow the RFC 1123 label convention and must "+ + "consist of a lower case alphanumeric character or '-' and must start/end with an alphanumeric.", c.flagNamespace)) + } + if len(c.flagValueFiles) != 0 { + for _, filename := range c.flagValueFiles { + if _, err := os.Stat(filename); err != nil && os.IsNotExist(err) { + return errors.New(fmt.Sprintf("File '%s' does not exist.", filename)) + } + } + } + + if c.flagDryRun { + c.UI.Output("Performing dry run installation.", terminal.WithInfoStyle()) + } + return nil +} + +// validLabel is a helper function that checks if a string follows RFC 1123 labels. +func validLabel(s string) bool { + for i, c := range s { + alphanum := ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') + // If the character is not the last or first, it can be a dash. + if i != 0 && i != (len(s)-1) { + alphanum = alphanum || (c == '-') + } + if !alphanum { + return false + } + } + return true +} diff --git a/cli/cmd/install/install_test.go b/cli/cmd/install/install_test.go new file mode 100644 index 0000000000..761db25fb1 --- /dev/null +++ b/cli/cmd/install/install_test.go @@ -0,0 +1,187 @@ +package install + +import ( + "context" + "os" + "testing" + + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" +) + +func TestCheckForPreviousPVCs(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + pvc := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-server-test1", + }, + } + pvc2 := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-server-test2", + }, + } + c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.TODO(), pvc, metav1.CreateOptions{}) + c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.TODO(), pvc2, metav1.CreateOptions{}) + err := c.checkForPreviousPVCs() + require.Error(t, err) + require.Contains(t, err.Error(), "found PVCs from previous installations (default/consul-server-test1,default/consul-server-test2), delete before re-installing") + + // Clear out the client and make sure the check now passes. + c.kubernetes = fake.NewSimpleClientset() + err = c.checkForPreviousPVCs() + require.NoError(t, err) + + // Add a new irrelevant PVC and make sure the check continues to pass. + pvc = &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "irrelevant-pvc", + }, + } + c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.TODO(), pvc, metav1.CreateOptions{}) + err = c.checkForPreviousPVCs() + require.NoError(t, err) +} + +func TestCheckForPreviousSecrets(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + secret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-consul-bootstrap-acl-token", + }, + } + c.kubernetes.CoreV1().Secrets("default").Create(context.TODO(), secret, metav1.CreateOptions{}) + err := c.checkForPreviousSecrets() + require.Error(t, err) + require.Contains(t, err.Error(), "found consul-acl-bootstrap-token secret from previous installations: \"test-consul-bootstrap-acl-token\" in namespace \"default\". To delete, run kubectl delete secret test-consul-bootstrap-acl-token --namespace default") + + // Clear out the client and make sure the check now passes. + c.kubernetes = fake.NewSimpleClientset() + err = c.checkForPreviousSecrets() + require.NoError(t, err) + + // Add a new irrelevant secret and make sure the check continues to pass. + secret = &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "irrelevant-secret", + }, + } + c.kubernetes.CoreV1().Secrets("default").Create(context.TODO(), secret, metav1.CreateOptions{}) + err = c.checkForPreviousSecrets() + require.NoError(t, err) +} + +// TestValidateFlags tests the validate flags function. +func TestValidateFlags(t *testing.T) { + // The following cases should all error, if they fail to this test fails. + testCases := []struct { + description string + input []string + }{ + { + "Should disallow non-flag arguments.", + []string{"foo", "-auto-approve"}, + }, + { + "Should disallow specifying both values file AND presets.", + []string{"-f='f.txt'", "-preset=demo"}, + }, + { + "Should error on invalid presets.", + []string{"-preset=foo"}, + }, + { + "Should error on an invalid namespace. If this failed, TestValidLabel() probably did too.", + []string{"-namespace=\" preset\""}, + }, + { + "Should have errored on a non-existant file.", + []string{"-f=\"does_not_exist.txt\""}, + }, + } + + for _, testCase := range testCases { + c := getInitializedCommand(t) + t.Run(testCase.description, func(t *testing.T) { + if err := c.validateFlags(testCase.input); err == nil { + t.Errorf("Test case should have failed.") + } + }) + } +} + +// TestValidLabel calls validLabel() which checks strings match RFC 1123 label convention. +func TestValidLabel(t *testing.T) { + testCases := []struct { + description string + input string + expected bool + }{ + { + "Standard name with leading numbers works.", + "1234-abc", + true, + }, + { + "All lower case letters works.", + "peppertrout", + true, + }, + { + "Test that dashes in the middle are allowed.", + "pepper-trout", + true, + }, + { + "Capitals violate RFC 1123 lower case label.", + "Peppertrout", + false, + }, + { + "Underscores are not permitted anywhere.", + "ab_cd", + false, + }, + { + "The dash must be in the middle of the word, not on the start/end character.", + "peppertrout-", + false, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.description, func(t *testing.T) { + if result := validLabel(testCase.input); result != testCase.expected { + t.Errorf("Incorrect output, got %v and expected %v", result, testCase.expected) + } + }) + } +} + +// getInitializedCommand sets up a command struct for tests. +func getInitializedCommand(t *testing.T) *Command { + t.Helper() + log := hclog.New(&hclog.LoggerOptions{ + Name: "cli", + Level: hclog.Info, + Output: os.Stdout, + }) + ctx, _ := context.WithCancel(context.Background()) + + baseCommand := &common.BaseCommand{ + Ctx: ctx, + Log: log, + } + + c := &Command{ + BaseCommand: baseCommand, + } + c.init() + return c +} diff --git a/cli/cmd/install/presets.go b/cli/cmd/install/presets.go new file mode 100644 index 0000000000..5aa61874df --- /dev/null +++ b/cli/cmd/install/presets.go @@ -0,0 +1,51 @@ +package install + +import "sigs.k8s.io/yaml" + +const ( + PresetDemo = "demo" + PresetSecure = "secure" +) + +// presets is a map of pre-configured helm values. +var presets = map[string]interface{}{ + PresetDemo: convert(demo), + PresetSecure: convert(secure), +} + +// TODO: enable prometheus in demo installation +var demo = ` +global: + name: consul +connectInject: + enabled: true +server: + replicas: 1 + bootstrapExpect: 1 +` + +var secure = ` +global: + name: consul + acls: + manageSystemACLs: true + tls: + enabled: true +connectInject: + enabled: true +server: + replicas: 1 + bootstrapExpect: 1 +` + +var globalNameConsul = ` +global: + name: consul +` + +// convert is a helper function that converts a YAML string to a map. +func convert(s string) map[string]interface{} { + var m map[string]interface{} + yaml.Unmarshal([]byte(s), &m) + return m +} diff --git a/cli/cmd/version/version.go b/cli/cmd/version/version.go new file mode 100644 index 0000000000..8ae086e89a --- /dev/null +++ b/cli/cmd/version/version.go @@ -0,0 +1,50 @@ +package version + +import ( + "fmt" + "strings" +) + +var ( + // The git commit that was compiled. These will be filled in by the compiler. + GitCommit string + GitDescribe string + + // The main version number that is being run at the moment. + // + // Version must conform to the format expected by + // github.com/hashicorp/go-version for tests to work. + Version = "0.0.1" + + // A pre-release marker for the version. If this is "" (empty string) + // then it means that it is a final release. Otherwise, this is a pre-release + // such as "dev" (in development), "beta", "rc1", etc. + VersionPrerelease = "" +) + +// GetHumanVersion composes the parts of the version in a way that's suitable +// for displaying to humans. +func GetHumanVersion() string { + version := Version + if GitDescribe != "" { + version = GitDescribe + } + + release := VersionPrerelease + if GitDescribe == "" && release == "" { + release = "dev" + } + + if release != "" { + if !strings.HasSuffix(version, "-"+release) { + // if we tagged a prerelease version then the release is in the version already + version += fmt.Sprintf("-%s", release) + } + if GitCommit != "" { + version += fmt.Sprintf(" (%s)", GitCommit) + } + } + + // Strip off any single quotes added by the git information. + return strings.Replace(version, "'", "", -1) +} diff --git a/cli/commands.go b/cli/commands.go new file mode 100644 index 0000000000..81640ef88a --- /dev/null +++ b/cli/commands.go @@ -0,0 +1,28 @@ +package main + +import ( + "context" + + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/cmd/install" + "github.com/hashicorp/go-hclog" + "github.com/mitchellh/cli" +) + +func initializeCommands(ctx context.Context, log hclog.Logger) (*common.BaseCommand, map[string]cli.CommandFactory) { + + baseCommand := &common.BaseCommand{ + Ctx: ctx, + Log: log, + } + + commands := map[string]cli.CommandFactory{ + "install": func() (cli.Command, error) { + return &install.Command{ + BaseCommand: baseCommand, + }, nil + }, + } + + return baseCommand, commands +} diff --git a/cli/go.mod b/cli/go.mod new file mode 100644 index 0000000000..723e092b47 --- /dev/null +++ b/cli/go.mod @@ -0,0 +1,27 @@ +module github.com/hashicorp/consul-k8s/cli + +go 1.16 + +require ( + github.com/bgentry/speakeasy v0.1.0 + github.com/fatih/color v1.9.0 + github.com/golang/protobuf v1.5.2 // indirect + github.com/hashicorp/go-hclog v0.16.2 + github.com/hashicorp/go-multierror v1.1.0 // indirect + github.com/kr/text v0.2.0 + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.12 + github.com/mitchellh/cli v1.1.2 + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/olekukonko/tablewriter v0.0.4 + github.com/posener/complete v1.1.1 + github.com/stretchr/testify v1.7.0 + go.starlark.net v0.0.0-20200707032745-474f21a9602d // indirect + google.golang.org/grpc v1.33.1 // indirect + helm.sh/helm/v3 v3.6.1 + k8s.io/api v0.21.2 + k8s.io/apimachinery v0.21.2 + k8s.io/client-go v0.21.2 + rsc.io/letsencrypt v0.0.3 // indirect + sigs.k8s.io/yaml v1.2.0 +) diff --git a/cli/go.sum b/cli/go.sum new file mode 100644 index 0000000000..0e79467fc8 --- /dev/null +++ b/cli/go.sum @@ -0,0 +1,1200 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE= +github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= +github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= +github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= +github.com/Masterminds/squirrel v1.5.0 h1:JukIZisrUXadA9pl3rMkjhiamxiB0cXiu+HGp/Y8cY8= +github.com/Masterminds/squirrel v1.5.0/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= +github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= +github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/hcsshim v0.8.14 h1:lbPVK25c1cu5xTLITwpUcxoA9vKrKErASPYygvouJns= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= +github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= +github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= +github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1 h1:pgAtgj+A31JBVtEHu2uHuEx0n+2ukqUJnS2vVe5pQNA= +github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng= +github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ= +github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= +github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 h1:qWj4qVYZ95vLWwqyNJCQg7rDsG5wPdze0UaPolH7DUk= +github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.4.4 h1:rtRG4N6Ct7GNssATwgpvMGfnjnwfjnu/Zs9W3Ikzq+M= +github.com/containerd/containerd v1.4.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 h1:6ejg6Lkk8dskcM7wQ28gONkukbQkM4qpj4RnYbpFzrI= +github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= +github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= +github.com/deislabs/oras v0.11.1 h1:oo2J/3vXdcti8cjFi8ghMOkx0OacONxHC8dhJ17NdJ0= +github.com/deislabs/oras v0.11.1/go.mod h1:39lCtf8Q6WDC7ul9cnyWXONNzKvabEKk+AX+L0ImnQk= +github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= +github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v20.10.5+incompatible h1:bjflayQbWg+xOkF2WPEAOi4Y7zWhR7ptoPhV/VqLVDE= +github.com/docker/cli v20.10.5+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= +github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible h1:iWPIG7pWIsCwT6ZtHnTUpoVMnete7O/pzd9HFE3+tn8= +github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ= +github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= +github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= +github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916 h1:yWHOI+vFjEsAakUTSrtqc/SAHrhSkmn48pqjidZX3QA= +github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= +github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4= +github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko= +github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= +github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= +github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.1 h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8= +github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= +github.com/gobuffalo/logger v1.0.1 h1:ZEgyRGgAm4ZAhAO45YXMs5Fp+bzGLESFewzAVBMKuTg= +github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr/v2 v2.7.1 h1:n3CIW5T17T8v4GGK5sWXLVWJhCz7b5aNLSxW6gYim4o= +github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godror/godror v0.13.3/go.mod h1:2ouUT4kdhUBk7TAkHWD4SN0CdI0pgEQbo8FVHhbSKWg= +github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo= +github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= +github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmoiron/sqlx v1.3.1 h1:aLN7YINNZ7cYOPK3QC83dbM6KT0NMqVMw961TqrejlE= +github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= +github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= +github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E= +github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= +github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-shellwords v1.0.11/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v1.12.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw= +github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.1.1 h1:Bp6x9R1Wn16SIz3OfeDr0b7RnCG2OB66Y7PQyC/cvq4= +github.com/mitchellh/copystructure v1.1.1/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.2/go.mod h1:rSAaSIOAGT9odnlyGlUfAJaoc5w2fSBUmeGDbRWPxyQ= +github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= +github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= +github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= +github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= +github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.4.0 h1:LUa41nrWTQNGhzdsZ5lTnkwbNjj6rXTdazA1cSdjkOY= +github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 h1:HXr/qUllAWv9riaI4zh2eXWKmCSDqVS/XH1MRHLKRwk= +github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= +github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= +github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY= +github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +go.starlark.net v0.0.0-20200707032745-474f21a9602d h1:uFqwFYlX7d5ZSp+IqhXxct0SybXrTzEBDvb2CkEhPBs= +go.starlark.net v0.0.0-20200707032745-474f21a9602d/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= +gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +helm.sh/helm/v3 v3.6.1 h1:TQ6q4pAatXr7qh2fbLcb0oNd0I3J7kv26oo5cExKTtc= +helm.sh/helm/v3 v3.6.1/go.mod h1:mIIus8EOqj+obtycw3sidsR4ORr2aFDmXMSI3k+oeVY= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= +k8s.io/api v0.21.2 h1:vz7DqmRsXTCSa6pNxXwQ1IYeAZgdIsua+DZU+o+SX3Y= +k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU= +k8s.io/apiextensions-apiserver v0.21.0 h1:Nd4uBuweg6ImzbxkC1W7xUNZcCV/8Vt10iTdTIVF3hw= +k8s.io/apiextensions-apiserver v0.21.0/go.mod h1:gsQGNtGkc/YoDG9loKI0V+oLZM4ljRPjc/sql5tmvzc= +k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= +k8s.io/apimachinery v0.21.2 h1:vezUc/BHqWlQDnZ+XkrpXSmnANSLbpnlpwo0Lhk0gpc= +k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM= +k8s.io/apiserver v0.21.0 h1:1hWMfsz+cXxB77k6/y0XxWxwl6l9OF26PC9QneUVn1Q= +k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg= +k8s.io/cli-runtime v0.21.0 h1:/V2Kkxtf6x5NI2z+Sd/mIrq4FQyQ8jzZAUD6N5RnN7Y= +k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo= +k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= +k8s.io/client-go v0.21.2 h1:Q1j4L/iMN4pTw6Y4DWppBoUxgKO8LbffEMVEV00MUp0= +k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA= +k8s.io/code-generator v0.21.0/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= +k8s.io/component-base v0.21.0 h1:tLLGp4BBjQaCpS/KiuWh7m2xqvAdsxLm4ATxHSe5Zpg= +k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw= +k8s.io/component-helpers v0.21.0/go.mod h1:tezqefP7lxfvJyR+0a+6QtVrkZ/wIkyMLK4WcQ3Cj8U= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= +k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= +k8s.io/kubectl v0.21.0 h1:WZXlnG/yjcE4LWO2g6ULjFxtzK6H1TKzsfaBFuVIhNg= +k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks= +k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/letsencrypt v0.0.3 h1:H7xDfhkaFFSYEJlKeq38RwX2jYcnTeHuDQyT+mMNMwM= +rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/kustomize/api v0.8.5 h1:bfCXGXDAbFbb/Jv5AhMj2BB8a5VAJuuQ5/KU69WtDjQ= +sigs.k8s.io/kustomize/api v0.8.5/go.mod h1:M377apnKT5ZHJS++6H4rQoCHmWtt6qTpp3mbe7p6OLY= +sigs.k8s.io/kustomize/cmd/config v0.9.7/go.mod h1:MvXCpHs77cfyxRmCNUQjIqCmZyYsbn5PyQpWiq44nW0= +sigs.k8s.io/kustomize/kustomize/v4 v4.0.5/go.mod h1:C7rYla7sI8EnxHE/xEhRBSHMNfcL91fx0uKmUlUhrBk= +sigs.k8s.io/kustomize/kyaml v0.10.15 h1:dSLgG78KyaxN4HylPXdK+7zB3k7sW6q3IcCmcfKA+aI= +sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/cli/main.go b/cli/main.go new file mode 100644 index 0000000000..1285e7625c --- /dev/null +++ b/cli/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "context" + "os" + "os/signal" + "syscall" + + "github.com/hashicorp/consul-k8s/cli/cmd/version" + "github.com/hashicorp/go-hclog" + "github.com/mitchellh/cli" +) + +func main() { + c := cli.NewCLI("consul-k8s", version.GetHumanVersion()) + c.Args = os.Args[1:] + + log := hclog.New(&hclog.LoggerOptions{ + Name: "cli", + Level: hclog.Info, + Output: os.Stdout, + }) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + basecmd, commands := initializeCommands(ctx, log) + c.Commands = commands + defer basecmd.Close() + + ch := make(chan os.Signal) + signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL) + go func() { + <-ch + // Any cleanups, such as cancelling contexts + cancel() + basecmd.Close() + os.Exit(1) + }() + + c.HelpFunc = cli.BasicHelpFunc("consul-k8s") + + exitStatus, err := c.Run() + if err != nil { + log.Info(err.Error()) + } + os.Exit(exitStatus) +} From 341e940699054bd167554175856900341ee75942 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Wed, 15 Sep 2021 19:03:57 -0700 Subject: [PATCH 020/418] =?UTF-8?q?cli:=20add=20LibraryStyle=20for=20helm?= =?UTF-8?q?=20output=20and=20add=20=E2=9C=93=20for=20success=20output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/cmd/common/terminal/basic.go | 6 ++++-- cli/cmd/common/terminal/ui.go | 9 +++++++++ cli/cmd/install/install.go | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/cli/cmd/common/terminal/basic.go b/cli/cmd/common/terminal/basic.go index 15006b876c..99491fabcc 100644 --- a/cli/cmd/common/terminal/basic.go +++ b/cli/cmd/common/terminal/basic.go @@ -88,9 +88,11 @@ func (ui *basicUI) Output(msg string, raw ...interface{}) { case WarningBoldStyle: msg = colorWarningBold.Sprintf(" * %s", msg) case SuccessStyle: - msg = colorSuccess.Sprintf(" + %s", msg) + msg = colorSuccess.Sprintf(" ✓ %s", msg) case SuccessBoldStyle: - msg = colorSuccessBold.Sprintf(" + %s", msg) + msg = colorSuccessBold.Sprintf(" ✓ %s", msg) + case LibraryStyle: + msg = colorLibrary.Sprintf(" --> %s", msg) case InfoStyle: lines := strings.Split(msg, "\n") for i, line := range lines { diff --git a/cli/cmd/common/terminal/ui.go b/cli/cmd/common/terminal/ui.go index f4775cf5cd..38922d6399 100644 --- a/cli/cmd/common/terminal/ui.go +++ b/cli/cmd/common/terminal/ui.go @@ -98,6 +98,7 @@ const ( WarningStyle = "warning" WarningBoldStyle = "warning-bold" InfoStyle = "info" + LibraryStyle = "library" SuccessStyle = "success" SuccessBoldStyle = "success-bold" ) @@ -150,6 +151,13 @@ func WithSuccessStyle() Option { } } +// WithLibraryStyle styles the output as a success message. +func WithLibraryStyle() Option { + return func(c *config) { + c.Style = LibraryStyle + } +} + func WithStyle(style string) Option { return func(c *config) { c.Style = style @@ -166,6 +174,7 @@ var ( colorInfo = color.New() colorError = color.New(color.FgRed) colorErrorBold = color.New(color.FgRed, color.Bold) + colorLibrary = color.New(color.FgCyan) colorSuccess = color.New(color.FgGreen) colorSuccessBold = color.New(color.FgGreen, color.Bold) colorWarning = color.New(color.FgYellow) diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index 71abba1d3d..a772249883 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -186,7 +186,7 @@ func (c *Command) Run(args []string) int { // Setup logger to stream Helm library logs var uiLogger = func(s string, args ...interface{}) { logMsg := fmt.Sprintf(s, args...) - c.UI.Output(logMsg, terminal.WithInfoStyle()) + c.UI.Output(logMsg, terminal.WithLibraryStyle()) } // Set up the kubernetes client to use for non Helm SDK calls to the Kubernetes API From 2b00d24af25c5f82c35feff12529eae3e037a4a7 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Wed, 15 Sep 2021 21:40:38 -0700 Subject: [PATCH 021/418] cli: add -wait and -timeout flags to install and update readme --- cli/README.md | 50 ++++++++++++++++++++------------- cli/cmd/install/install.go | 34 +++++++++++++++++++--- cli/cmd/install/install_test.go | 6 +++- 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/cli/README.md b/cli/README.md index 5f6667b382..14f7c50a47 100644 --- a/cli/README.md +++ b/cli/README.md @@ -31,41 +31,53 @@ rightmost flag value has the highest precedence, i.e `-set foo=bar -set foo=baz` ``` Usage: consul-k8s install [flags] +Install Consul onto a Kubernetes cluster. - Install Consul onto a Kubernetes cluster. - -Flags: - +Command Options: -auto-approve - Skip confirmation prompt. + Skip confirmation prompt. The default is false. - -dry-run - Run pre-install checks and display summary of installation. + -config-file= + Path to a file to customize the installation, such as Consul Helm chart + values file. Can be specified multiple times. This is aliased as "-f". - -config-file,-f= - Path to a file to customize the installation, such as Consul Helm chart values file. Can be specified multiple times. + -dry-run + Run pre-install checks and display summary of installation. The default + is false. -namespace= - Namespace for the Consul installation. Defaults to “consul”. + Namespace for the Consul installation. The default is consul. -preset= - Use an installation preset, one of demo, secure. Defaults to the default configuration of the Consul Helm chart. + Use an installation preset, one of demo, secure. Defaults to none -set= - Set a value to customize. Can be specified multiple times. Supports Consul Helm chart values. + Set a value to customize. Can be specified multiple times. Supports + Consul Helm chart values. -set-file= - Set a value to customize via a file. The contents of the file will be set as the value. Can be specified multiple times. Supports Consul Helm chart values. + Set a value to customize via a file. The contents of the file will be + set as the value. Can be specified multiple times. Supports Consul Helm + chart values. -set-string= - Set a string value to customize. Can be specified multiple times. Supports Consul Helm chart values. + Set a string value to customize. Can be specified multiple times. + Supports Consul Helm chart values. + + -timeout= + Timeout to wait for installation to be ready. The default is 10m. + + -wait + Determines whether to wait for resources in installation to be ready + before exiting command. The default is true. + +Global Options: + -context= + Kubernetes context to use. -Global Flags: --context= - Kubernetes context to use + -kubeconfig= + Path to kubeconfig file. This is aliased as "-c". --kubeconfig, -c= - Path to kubeconfig file ``` diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index a772249883..4317dad452 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -43,6 +43,12 @@ const ( flagNameNamespace = "namespace" defaultNamespace = "consul" + flagNameTimeout = "timeout" + defaultTimeout = "10m" + + flagNameWait = "wait" + defaultWait = true + helmRepository = "https://helm.releases.hashicorp.com" ) @@ -61,6 +67,9 @@ type Command struct { flagSetStringValues []string flagSetValues []string flagFileValues []string + flagTimeout string + timeoutDuration time.Duration + flagWait bool flagKubeConfig string flagKubeContext string @@ -101,13 +110,13 @@ func (c *Command) init() { Name: flagNameNamespace, Target: &c.flagNamespace, Default: defaultNamespace, - Usage: fmt.Sprintf("Namespace for the Consul installation. Defaults to \"%q\".", defaultNamespace), + Usage: "Namespace for the Consul installation.", }) f.StringVar(&flag.StringVar{ Name: flagNamePreset, Target: &c.flagPreset, Default: defaultPreset, - Usage: fmt.Sprintf("Use an installation preset, one of %s. Defaults to \"%q\"", strings.Join(presetList, ", "), defaultPreset), + Usage: fmt.Sprintf("Use an installation preset, one of %s. Defaults to none", strings.Join(presetList, ", ")), }) f.StringSliceVar(&flag.StringSliceVar{ Name: flagNameSetValues, @@ -125,6 +134,18 @@ func (c *Command) init() { Target: &c.flagSetStringValues, Usage: "Set a string value to customize. Can be specified multiple times. Supports Consul Helm chart values.", }) + f.StringVar(&flag.StringVar{ + Name: flagNameTimeout, + Target: &c.flagTimeout, + Default: defaultTimeout, + Usage: "Timeout to wait for installation to be ready.", + }) + f.BoolVar(&flag.BoolVar{ + Name: flagNameWait, + Target: &c.flagWait, + Default: defaultWait, + Usage: "Determines whether to wait for resources in installation to be ready before exiting command.", + }) f = c.set.NewSet("Global Options") f.StringVar(&flag.StringVar{ @@ -294,8 +315,8 @@ func (c *Command) Run(args []string) int { install.Namespace = c.flagNamespace install.CreateNamespace = true install.ChartPathOptions.RepoURL = helmRepository - install.Wait = true - install.Timeout = time.Minute * 10 + install.Wait = c.flagWait + install.Timeout = c.timeoutDuration // Locate the chart, install it in some cache locally. chartPath, err := install.ChartPathOptions.LocateChart("consul", settings) @@ -470,6 +491,11 @@ func (c *Command) validateFlags(args []string) error { return errors.New(fmt.Sprintf("'%s' is an invalid namespace. Namespaces follow the RFC 1123 label convention and must "+ "consist of a lower case alphanumeric character or '-' and must start/end with an alphanumeric.", c.flagNamespace)) } + duration, err := time.ParseDuration(c.flagTimeout) + if err != nil { + return fmt.Errorf("unable to parse -%s: %s", flagNameTimeout, err) + } + c.timeoutDuration = duration if len(c.flagValueFiles) != 0 { for _, filename := range c.flagValueFiles { if _, err := os.Stat(filename); err != nil && os.IsNotExist(err) { diff --git a/cli/cmd/install/install_test.go b/cli/cmd/install/install_test.go index 761db25fb1..0c34d6fe48 100644 --- a/cli/cmd/install/install_test.go +++ b/cli/cmd/install/install_test.go @@ -96,9 +96,13 @@ func TestValidateFlags(t *testing.T) { "Should error on invalid presets.", []string{"-preset=foo"}, }, + { + "Should error on invalid timeout.", + []string{"-timeout=invalid-timeout"}, + }, { "Should error on an invalid namespace. If this failed, TestValidLabel() probably did too.", - []string{"-namespace=\" preset\""}, + []string{"-namespace=\" nsWithSpace\""}, }, { "Should have errored on a non-existant file.", From 9496831619718018f84075c8ba821ae99143dba5 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Wed, 15 Sep 2021 21:48:05 -0700 Subject: [PATCH 022/418] cli: add changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e288ffc87..16d5ddf4d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ ## UNRELEASED +FEATURES: +* CLI + * The `consul-k8s` CLI enables users to deploy and operate Consul on Kubernetes. + * Support `consul-k8s install` command. [[GH-713](https://github.com/hashicorp/consul-k8s/pull/713)] IMPROVEMENTS: * Helm Chart From 4e9cf3a9a39ad2bb6c81f49ebef065f33b694306 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 9 Sep 2021 14:14:31 -0400 Subject: [PATCH 023/418] Create Admin Partitions when enabled (#696) * Create Admin Partitions when enabled --- charts/consul/templates/client-daemonset.yaml | 3 + .../consul/templates/partition-init-job.yaml | 92 ++++++++ .../partition-init-podsecuritypolicy.yaml | 38 ++++ .../consul/templates/partition-init-role.yaml | 40 ++++ .../templates/partition-init-rolebinding.yaml | 23 ++ .../partition-init-serviceaccount.yaml | 22 ++ charts/consul/test/unit/client-daemonset.bats | 23 ++ .../consul/test/unit/partition-init-job.bats | 96 +++++++++ .../partition-init-podsecuritypolicy.bats | 48 +++++ .../consul/test/unit/partition-init-role.bats | 48 +++++ .../test/unit/partition-init-rolebinding.bats | 48 +++++ .../unit/partition-init-serviceaccount.bats | 48 +++++ charts/consul/values.yaml | 12 ++ control-plane/commands.go | 5 + control-plane/go.mod | 2 +- control-plane/go.sum | 5 +- control-plane/subcommand/common/common.go | 11 + .../subcommand/common/common_test.go | 43 ++++ .../subcommand/partition-init/command.go | 199 ++++++++++++++++++ .../partition-init/command_ent_test.go | 150 +++++++++++++ .../subcommand/server-acl-init/command.go | 18 +- 21 files changed, 958 insertions(+), 16 deletions(-) create mode 100644 charts/consul/templates/partition-init-job.yaml create mode 100644 charts/consul/templates/partition-init-podsecuritypolicy.yaml create mode 100644 charts/consul/templates/partition-init-role.yaml create mode 100644 charts/consul/templates/partition-init-rolebinding.yaml create mode 100644 charts/consul/templates/partition-init-serviceaccount.yaml create mode 100644 charts/consul/test/unit/partition-init-job.bats create mode 100644 charts/consul/test/unit/partition-init-podsecuritypolicy.bats create mode 100644 charts/consul/test/unit/partition-init-role.bats create mode 100644 charts/consul/test/unit/partition-init-rolebinding.bats create mode 100644 charts/consul/test/unit/partition-init-serviceaccount.bats create mode 100644 control-plane/subcommand/partition-init/command.go create mode 100644 control-plane/subcommand/partition-init/command_ent_test.go diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index ddf17bc624..822bc3a653 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -233,6 +233,9 @@ spec: {{- if (and .Values.global.metrics.enabled .Values.global.metrics.enableAgentMetrics) }} -hcl='telemetry { prometheus_retention_time = "{{ .Values.global.metrics.agentMetricsRetentionTime }}" }' \ {{- end }} + {{- if .Values.global.adminPartitions.enabled }} + -hcl='partition = "{{ .Values.global.adminPartitions.name }}"' \ + {{- end }} -config-dir=/consul/config \ {{- if .Values.global.acls.manageSystemACLs }} -config-dir=/consul/aclconfig \ diff --git a/charts/consul/templates/partition-init-job.yaml b/charts/consul/templates/partition-init-job.yaml new file mode 100644 index 0000000000..97a2d83edf --- /dev/null +++ b/charts/consul/templates/partition-init-job.yaml @@ -0,0 +1,92 @@ +{{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} +{{- if (and .Values.global.adminPartitions.enabled (not $serverEnabled)) }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "consul.fullname" . }}-partition-init + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "2" + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation +spec: + template: + metadata: + name: {{ template "consul.fullname" . }}-partition-init + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + release: {{ .Release.Name }} + component: partition-init + annotations: + "consul.hashicorp.com/connect-inject": "false" + spec: + restartPolicy: Never + serviceAccountName: {{ template "consul.fullname" . }}-partition-init + {{- if .Values.global.tls.enabled }} + volumes: + - name: consul-ca-cert + secret: + {{- if .Values.global.tls.caCert.secretName }} + secretName: {{ .Values.global.tls.caCert.secretName }} + {{- else }} + secretName: {{ template "consul.fullname" . }}-ca-cert + {{- end }} + items: + - key: {{ default "tls.crt" .Values.global.tls.caCert.secretKey }} + path: tls.crt + {{- end }} + containers: + - name: post-install-job + image: {{ .Values.global.imageK8S }} + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- if .Values.global.tls.enabled }} + volumeMounts: + - name: consul-ca-cert + mountPath: /consul/tls/ca + readOnly: true + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + CONSUL_FULLNAME="{{template "consul.fullname" . }}" + + consul-k8s-control-plane partition-init \ + -log-level={{ .Values.global.logLevel }} \ + -log-json={{ .Values.global.logJSON }} \ + + {{- if and .Values.externalServers.enabled (not .Values.externalServers.hosts) }}{{ fail "externalServers.hosts must be set if externalServers.enabled is true" }}{{ end -}} + {{- range .Values.externalServers.hosts }} + -server-address={{ quote . }} \ + {{- end }} + -server-port={{ .Values.externalServers.httpsPort }} \ + + {{- if .Values.global.tls.enabled }} + -use-https \ + -consul-ca-cert=/consul/tls/ca/tls.crt \ + {{- if not .Values.externalServers.enabled }} + -server-port=8501 \ + {{- end }} + {{- if .Values.externalServers.tlsServerName }} + -consul-tls-server-name={{ .Values.externalServers.tlsServerName }} \ + {{- end }} + {{- end }} + -partition-name={{ .Values.global.adminPartitions.name }} + resources: + requests: + memory: "50Mi" + cpu: "50m" + limits: + memory: "50Mi" + cpu: "50m" +{{- end }} diff --git a/charts/consul/templates/partition-init-podsecuritypolicy.yaml b/charts/consul/templates/partition-init-podsecuritypolicy.yaml new file mode 100644 index 0000000000..9e2ec994cb --- /dev/null +++ b/charts/consul/templates/partition-init-podsecuritypolicy.yaml @@ -0,0 +1,38 @@ +{{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} +{{- if (and .Values.global.adminPartitions.enabled (not $serverEnabled)) }} +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "consul.fullname" . }}-partition-init + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation +spec: + privileged: false + # Allow core volume types. + volumes: + - 'secret' + allowPrivilegeEscalation: false + # This is redundant with non-root + disallow privilege escalation, + # but we can provide it for defense in depth. + requiredDropCapabilities: + - ALL + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'RunAsAny' + fsGroup: + rule: 'RunAsAny' + readOnlyRootFilesystem: false +{{- end }} diff --git a/charts/consul/templates/partition-init-role.yaml b/charts/consul/templates/partition-init-role.yaml new file mode 100644 index 0000000000..68f60f58f7 --- /dev/null +++ b/charts/consul/templates/partition-init-role.yaml @@ -0,0 +1,40 @@ +{{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} +{{- if (and .Values.global.adminPartitions.enabled (not $serverEnabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "consul.fullname" . }}-partition-init + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation +rules: + - apiGroups: [""] + resources: + - secrets + verbs: + - create + - get +{{- if .Values.connectInject.enabled }} + - apiGroups: [""] + resources: + - serviceaccounts + resourceNames: + - {{ template "consul.fullname" . }}-connect-injector-authmethod-svc-account + verbs: + - get +{{- end }} +{{- if .Values.global.enablePodSecurityPolicies }} + - apiGroups: ["policy"] + resources: ["podsecuritypolicies"] + resourceNames: + - {{ template "consul.fullname" . }}-partition-init + verbs: + - use +{{- end }} +{{- end }} diff --git a/charts/consul/templates/partition-init-rolebinding.yaml b/charts/consul/templates/partition-init-rolebinding.yaml new file mode 100644 index 0000000000..61038ecfa6 --- /dev/null +++ b/charts/consul/templates/partition-init-rolebinding.yaml @@ -0,0 +1,23 @@ +{{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} +{{- if (and .Values.global.adminPartitions.enabled (not $serverEnabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "consul.fullname" . }}-partition-init + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "consul.fullname" . }}-partition-init +subjects: + - kind: ServiceAccount + name: {{ template "consul.fullname" . }}-partition-init +{{- end }} diff --git a/charts/consul/templates/partition-init-serviceaccount.yaml b/charts/consul/templates/partition-init-serviceaccount.yaml new file mode 100644 index 0000000000..f39e08a30f --- /dev/null +++ b/charts/consul/templates/partition-init-serviceaccount.yaml @@ -0,0 +1,22 @@ +{{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} +{{- if (and .Values.global.adminPartitions.enabled (not $serverEnabled)) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "consul.fullname" . }}-partition-init + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range . }} + - name: {{ .name }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index 0f79a4fa92..6e892bd31d 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1383,3 +1383,26 @@ rollingUpdate: yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("-recursor=\"1.2.3.4\"")' | tee /dev/stderr) [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# partitions + +@test "client/DaemonSet: -partitions can be set by global.adminPartition.enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.adminPartitions.enabled=true' \ + . | tee /dev/stderr | + yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("partition = \"default\"")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "client/DaemonSet: -partitions can be overridden by global.adminPartition.name" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=test' \ + . | tee /dev/stderr | + yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("partition = \"test\"")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/test/unit/partition-init-job.bats b/charts/consul/test/unit/partition-init-job.bats new file mode 100644 index 0000000000..ac6d5ccd27 --- /dev/null +++ b/charts/consul/test/unit/partition-init-job.bats @@ -0,0 +1,96 @@ +#!/usr/bin/env bats + +load _helpers + +@test "partitionInit/Job: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-job.yaml \ + . +} + +@test "partitionInit/Job: enabled with global.adminPartitions.enabled=true and servers = false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "partitionInit/Job: disabled with global.adminPartitions.enabled=true and servers = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} + +@test "partitionInit/Job: disabled with global.adminPartitions.enabled=true and global.enabled = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enabled=true' \ + . +} + +@test "partitionInit/Job: disabled with global.adminPartitions.enabled=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} + +#-------------------------------------------------------------------- +# global.tls.enabled + +@test "partitionInit/Job: sets TLS flags when global.tls.enabled" { + cd `chart_dir` + local command=$(helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.enabled=false' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.tls.enabled=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].command' | tee /dev/stderr) + + local actual + actual=$(echo $command | jq -r '. | any(contains("-use-https"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + actual=$(echo $command | jq -r '. | any(contains("-consul-ca-cert=/consul/tls/ca/tls.crt"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + actual=$(echo $command | jq -r '. | any(contains("-server-port=8501"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "partitionInit/Job: can overwrite CA secret with the provided one" { + cd `chart_dir` + local ca_cert_volume=$(helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.enabled=false' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=foo-ca-cert' \ + --set 'global.tls.caCert.secretKey=key' \ + --set 'global.tls.caKey.secretName=foo-ca-key' \ + --set 'global.tls.caKey.secretKey=key' \ + . | tee /dev/stderr | + yq '.spec.template.spec.volumes[] | select(.name=="consul-ca-cert")' | tee /dev/stderr) + + # check that the provided ca cert secret is attached as a volume + local actual + actual=$(echo $ca_cert_volume | jq -r '.secret.secretName' | tee /dev/stderr) + [ "${actual}" = "foo-ca-cert" ] + + # check that the volume uses the provided secret key + actual=$(echo $ca_cert_volume | jq -r '.secret.items[0].key' | tee /dev/stderr) + [ "${actual}" = "key" ] +} \ No newline at end of file diff --git a/charts/consul/test/unit/partition-init-podsecuritypolicy.bats b/charts/consul/test/unit/partition-init-podsecuritypolicy.bats new file mode 100644 index 0000000000..d00c915f6e --- /dev/null +++ b/charts/consul/test/unit/partition-init-podsecuritypolicy.bats @@ -0,0 +1,48 @@ +#!/usr/bin/env bats + +load _helpers + +@test "partitionInit/PodSecurityPolicy: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-podsecuritypolicy.yaml \ + . +} + +@test "partitionInit/PodSecurityPolicy: enabled with global.adminPartitions.enabled=true and servers = false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-init-podsecuritypolicy.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "partitionInit/PodSecurityPolicy: disabled with global.adminPartitions.enabled=true and servers = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-podsecuritypolicy.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} + +@test "partitionInit/PodSecurityPolicy: disabled with global.adminPartitions.enabled=true and global.enabled = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-podsecuritypolicy.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enabled=true' \ + . +} + +@test "partitionInit/PodSecurityPolicy: disabled with global.adminPartitions.enabled=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-podsecuritypolicy.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} \ No newline at end of file diff --git a/charts/consul/test/unit/partition-init-role.bats b/charts/consul/test/unit/partition-init-role.bats new file mode 100644 index 0000000000..c434aa3d87 --- /dev/null +++ b/charts/consul/test/unit/partition-init-role.bats @@ -0,0 +1,48 @@ +#!/usr/bin/env bats + +load _helpers + +@test "partitionInit/Role: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-role.yaml \ + . +} + +@test "partitionInit/Role: enabled with global.adminPartitions.enabled=true and servers = false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-init-role.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "partitionInit/Role: disabled with global.adminPartitions.enabled=true and servers = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-role.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} + +@test "partitionInit/Role: disabled with global.adminPartitions.enabled=true and global.enabled = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-role.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enabled=true' \ + . +} + +@test "partitionInit/Role: disabled with global.adminPartitions.enabled=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-role.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} \ No newline at end of file diff --git a/charts/consul/test/unit/partition-init-rolebinding.bats b/charts/consul/test/unit/partition-init-rolebinding.bats new file mode 100644 index 0000000000..d96f6e6cd3 --- /dev/null +++ b/charts/consul/test/unit/partition-init-rolebinding.bats @@ -0,0 +1,48 @@ +#!/usr/bin/env bats + +load _helpers + +@test "partitionInit/RoleBinding: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-rolebinding.yaml \ + . +} + +@test "partitionInit/RoleBinding: enabled with global.adminPartitions.enabled=true and servers = false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-init-rolebinding.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "partitionInit/RoleBinding: disabled with global.adminPartitions.enabled=true and servers = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-rolebinding.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} + +@test "partitionInit/RoleBinding: disabled with global.adminPartitions.enabled=true and global.enabled = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-rolebinding.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enabled=true' \ + . +} + +@test "partitionInit/RoleBinding: disabled with global.adminPartitions.enabled=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-rolebinding.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} \ No newline at end of file diff --git a/charts/consul/test/unit/partition-init-serviceaccount.bats b/charts/consul/test/unit/partition-init-serviceaccount.bats new file mode 100644 index 0000000000..6195969686 --- /dev/null +++ b/charts/consul/test/unit/partition-init-serviceaccount.bats @@ -0,0 +1,48 @@ +#!/usr/bin/env bats + +load _helpers + +@test "partitionInit/ServiceAccount: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-serviceaccount.yaml \ + . +} + +@test "partitionInit/ServiceAccount: enabled with global.adminPartitions.enabled=true and servers = false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-init-serviceaccount.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "partitionInit/ServiceAccount: disabled with global.adminPartitions.enabled=true and servers = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-serviceaccount.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} + +@test "partitionInit/ServiceAccount: disabled with global.adminPartitions.enabled=true and global.enabled = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-serviceaccount.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enabled=true' \ + . +} + +@test "partitionInit/ServiceAccount: disabled with global.adminPartitions.enabled=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-serviceaccount.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} \ No newline at end of file diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 5058f7bd6a..f6b5848198 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -29,6 +29,18 @@ global: # Consul into Kubernetes will have, e.g. `service-name.service.consul`. domain: consul + # [Enterprise Only] Enabling `adminPartitions` allows creation of Admin Partitions in Kubernetes clusters. + # It additionally indicates that you are running Consul Enterprise v1.11+ with a valid Consul Enterprise + # license. Admin partitions enables deploying services across partitions, while sharing + # a set of Consul servers. + adminPartitions: + # If true, the Helm chart will enable Admin Partitions for the cluster. The clients in the server cluster + # must be installed in the default partition. + enabled: false + # The name of the Admin Partition. Must be "default" in the server cluster ie the Kubernetes cluster that + # the Consul server pods are deployed onto. + name: "default" + # The name (and tag) of the Consul Docker image for clients and servers. # This can be overridden per component. This should be pinned to a specific # version tag, otherwise you may inadvertently upgrade your Consul version. diff --git a/control-plane/commands.go b/control-plane/commands.go index a08c15b611..465ccbdd50 100644 --- a/control-plane/commands.go +++ b/control-plane/commands.go @@ -11,6 +11,7 @@ import ( cmdDeleteCompletedJob "github.com/hashicorp/consul-k8s/control-plane/subcommand/delete-completed-job" cmdGetConsulClientCA "github.com/hashicorp/consul-k8s/control-plane/subcommand/get-consul-client-ca" cmdInjectConnect "github.com/hashicorp/consul-k8s/control-plane/subcommand/inject-connect" + cmdPartitionInit "github.com/hashicorp/consul-k8s/control-plane/subcommand/partition-init" cmdServerACLInit "github.com/hashicorp/consul-k8s/control-plane/subcommand/server-acl-init" cmdServiceAddress "github.com/hashicorp/consul-k8s/control-plane/subcommand/service-address" cmdSyncCatalog "github.com/hashicorp/consul-k8s/control-plane/subcommand/sync-catalog" @@ -48,6 +49,10 @@ func init() { return &cmdServerACLInit.Command{UI: ui}, nil }, + "partition-init": func() (cli.Command, error) { + return &cmdPartitionInit.Command{UI: ui}, nil + }, + "sync-catalog": func() (cli.Command, error) { return &cmdSyncCatalog.Command{UI: ui}, nil }, diff --git a/control-plane/go.mod b/control-plane/go.mod index cff0ca7070..b15a09db4b 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/go-cmp v0.5.6 github.com/google/go-querystring v1.0.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/hashicorp/consul/api v1.9.0 + github.com/hashicorp/consul/api v1.4.1-0.20210827004034-d2e50fd130ae github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f diff --git a/control-plane/go.sum b/control-plane/go.sum index 9b7dcb4397..c3d4b34654 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -284,9 +284,10 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.9.0 h1:T6dKIWcaihG2c21YUi0BMAHbJanVXiYuz+mPgqxY3N4= -github.com/hashicorp/consul/api v1.9.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.4.1-0.20210827004034-d2e50fd130ae h1:eWcikXQgBN6yrsbANCTieR1uT+a7WoYYvGUFj8enPow= +github.com/hashicorp/consul/api v1.4.1-0.20210827004034-d2e50fd130ae/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= diff --git a/control-plane/subcommand/common/common.go b/control-plane/subcommand/common/common.go index 6eaa14a78a..4dc2783683 100644 --- a/control-plane/subcommand/common/common.go +++ b/control-plane/subcommand/common/common.go @@ -9,7 +9,9 @@ import ( "strings" "github.com/go-logr/logr" + godiscover "github.com/hashicorp/consul-k8s/control-plane/helper/go-discover" "github.com/hashicorp/consul/api" + "github.com/hashicorp/go-discover" "github.com/hashicorp/go-hclog" "go.uber.org/zap/zapcore" "sigs.k8s.io/controller-runtime/pkg/log/zap" @@ -115,3 +117,12 @@ func WriteFileWithPerms(outputFile, payload string, mode os.FileMode) error { } return os.Chmod(outputFile, mode) } + +// GetResolvedServerAddresses resolves the Consul server address if it has been provided a provider else it returns the server addresses that were input to it. +// It attempts to use go-discover iff there is a single server address, the value of which begins with "provider=", else it returns the server addresses as is. +func GetResolvedServerAddresses(serverAddresses []string, providers map[string]discover.Provider, logger hclog.Logger) ([]string, error) { + if len(serverAddresses) != 1 || !strings.Contains(serverAddresses[0], "provider=") { + return serverAddresses, nil + } + return godiscover.ConsulServerAddresses(serverAddresses[0], providers, logger) +} diff --git a/control-plane/subcommand/common/common_test.go b/control-plane/subcommand/common/common_test.go index 65268defe1..d5ac9a11b1 100644 --- a/control-plane/subcommand/common/common_test.go +++ b/control-plane/subcommand/common/common_test.go @@ -11,7 +11,11 @@ import ( "testing" "time" + "github.com/hashicorp/consul-k8s/control-plane/helper/go-discover/mocks" "github.com/hashicorp/consul/api" + "github.com/hashicorp/go-discover" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) @@ -168,6 +172,45 @@ func TestWriteFileWithPerms(t *testing.T) { require.Equal(t, payload, string(data)) } +func TestGetResolvedServerAddresses(t *testing.T) { + cases := map[string]struct { + inputServerAddresses []string + providerMap func() map[string]discover.Provider + expectedServerAddresses []string + }{ + "without providers and single address": { + inputServerAddresses: []string{"foo.bar"}, + providerMap: func() map[string]discover.Provider { + return nil + }, + expectedServerAddresses: []string{"foo.bar"}, + }, + "without providers and multiple addresses": { + inputServerAddresses: []string{"foo.bar", "hello.car"}, + providerMap: func() map[string]discover.Provider { + return nil + }, + expectedServerAddresses: []string{"foo.bar", "hello.car"}, + }, + "mock provider": { + inputServerAddresses: []string{"provider=mock"}, + providerMap: func() map[string]discover.Provider { + provider := new(mocks.MockProvider) + provider.On("Addrs", mock.Anything, mock.Anything).Return([]string{"127.0.0.1", "foo.bar"}, nil) + providers := make(map[string]discover.Provider) + providers["mock"] = provider + return providers + }, + expectedServerAddresses: []string{"127.0.0.1", "foo.bar"}, + }, + } + for _, testCase := range cases { + addresses, err := GetResolvedServerAddresses(testCase.inputServerAddresses, testCase.providerMap(), hclog.NewNullLogger()) + require.NoError(t, err) + require.Equal(t, testCase.expectedServerAddresses, addresses) + } +} + // startMockServer starts an httptest server used to mock a Consul server's // /v1/acl/login endpoint. apiCallCounter will be incremented on each call to /v1/acl/login. // It returns a consul client pointing at the server. diff --git a/control-plane/subcommand/partition-init/command.go b/control-plane/subcommand/partition-init/command.go new file mode 100644 index 0000000000..bdbb4df21d --- /dev/null +++ b/control-plane/subcommand/partition-init/command.go @@ -0,0 +1,199 @@ +package partition_init + +import ( + "context" + "errors" + "flag" + "fmt" + "sync" + "time" + + "github.com/hashicorp/consul-k8s/control-plane/consul" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" + k8sflags "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" + "github.com/hashicorp/consul/api" + "github.com/hashicorp/go-discover" + "github.com/hashicorp/go-hclog" + "github.com/mitchellh/cli" +) + +type Command struct { + UI cli.Ui + + flags *flag.FlagSet + k8s *k8sflags.K8SFlags + + flagPartitionName string + + // Flags to configure Consul connection + flagServerAddresses []string + flagServerPort uint + flagConsulCACert string + flagConsulTLSServerName string + flagUseHTTPS bool + + flagLogLevel string + flagLogJSON bool + flagTimeout time.Duration + + // ctx is cancelled when the command timeout is reached. + ctx context.Context + retryDuration time.Duration + + // log + log hclog.Logger + + once sync.Once + help string + + providers map[string]discover.Provider +} + +func (c *Command) init() { + c.flags = flag.NewFlagSet("", flag.ContinueOnError) + + c.flags.StringVar(&c.flagPartitionName, "partition-name", "", "The name of the partition being created.") + + c.flags.Var((*flags.AppendSliceValue)(&c.flagServerAddresses), "server-address", + "The IP, DNS name or the cloud auto-join string of the Consul server(s). If providing IPs or DNS names, may be specified multiple times. "+ + "At least one value is required.") + c.flags.UintVar(&c.flagServerPort, "server-port", 8500, "The HTTP or HTTPS port of the Consul server. Defaults to 8500.") + c.flags.StringVar(&c.flagConsulCACert, "consul-ca-cert", "", + "Path to the PEM-encoded CA certificate of the Consul cluster.") + c.flags.StringVar(&c.flagConsulTLSServerName, "consul-tls-server-name", "", + "The server name to set as the SNI header when sending HTTPS requests to Consul.") + c.flags.BoolVar(&c.flagUseHTTPS, "use-https", false, + "Toggle for using HTTPS for all API calls to Consul.") + + c.flags.DurationVar(&c.flagTimeout, "timeout", 10*time.Minute, + "How long we'll try to bootstrap Partitions for before timing out, e.g. 1ms, 2s, 3m") + c.flags.StringVar(&c.flagLogLevel, "log-level", "info", + "Log verbosity level. Supported values (in order of detail) are \"trace\", "+ + "\"debug\", \"info\", \"warn\", and \"error\".") + c.flags.BoolVar(&c.flagLogJSON, "log-json", false, + "Enable or disable JSON output format for logging.") + + c.k8s = &k8sflags.K8SFlags{} + flags.Merge(c.flags, c.k8s.Flags()) + c.help = flags.Usage(help, c.flags) + + // Default retry to 1s. This is exposed for setting in tests. + if c.retryDuration == 0 { + c.retryDuration = 1 * time.Second + } +} + +func (c *Command) Synopsis() string { return synopsis } + +func (c *Command) Help() string { + c.once.Do(c.init) + return c.help +} + +// Run bootstraps Admin Partitions on Consul servers. +// The function will retry its tasks until success, or it exceeds its timeout. +func (c *Command) Run(args []string) int { + c.once.Do(c.init) + if err := c.flags.Parse(args); err != nil { + return 1 + } + if len(c.flags.Args()) > 0 { + c.UI.Error("Should have no non-flag arguments.") + return 1 + } + + // Validate flags + if err := c.validateFlags(); err != nil { + c.UI.Error(err.Error()) + return 1 + } + var cancel context.CancelFunc + c.ctx, cancel = context.WithTimeout(context.Background(), c.flagTimeout) + // The context will only ever be intentionally ended by the timeout. + defer cancel() + + var err error + c.log, err = common.Logger(c.flagLogLevel, c.flagLogJSON) + if err != nil { + c.UI.Error(err.Error()) + return 1 + } + + serverAddresses, err := common.GetResolvedServerAddresses(c.flagServerAddresses, c.providers, c.log) + if err != nil { + c.UI.Error(fmt.Sprintf("Unable to discover any Consul addresses from %q: %s", c.flagServerAddresses[0], err)) + return 1 + } + + scheme := "http" + if c.flagUseHTTPS { + scheme = "https" + } + // For all of the next operations we'll need a Consul client. + serverAddr := fmt.Sprintf("%s:%d", serverAddresses[0], c.flagServerPort) + consulClient, err := consul.NewClient(&api.Config{ + Address: serverAddr, + Scheme: scheme, + TLSConfig: api.TLSConfig{ + Address: c.flagConsulTLSServerName, + CAFile: c.flagConsulCACert, + }, + }) + if err != nil { + c.UI.Error(fmt.Sprintf("Error creating Consul client for addr %q: %s", serverAddr, err)) + return 1 + } + for { + partition, _, err := consulClient.Partitions().Read(c.ctx, c.flagPartitionName, nil) + // The API does not return an error if the Partition does not exist. It returns a nil Partition. + if err != nil { + c.log.Error("Error reading Partition from Consul", "name", c.flagPartitionName, "error", err.Error()) + } else if partition == nil { + // Retry Admin Partition creation until it succeeds, or we reach the command timeout. + _, _, err = consulClient.Partitions().Create(c.ctx, &api.AdminPartition{ + Name: c.flagPartitionName, + Description: "Created by Helm installation", + }, nil) + if err == nil { + c.log.Info("Successfully created Admin Partition", "name", c.flagPartitionName) + return 0 + } + c.log.Error("Error creating partition", "name", c.flagPartitionName, "error", err.Error()) + } else { + c.log.Info("Admin Partition already exists", "name", c.flagPartitionName) + return 0 + } + // Wait on either the retry duration (in which case we continue) or the + // overall command timeout. + c.log.Info("Retrying in " + c.retryDuration.String()) + select { + case <-time.After(c.retryDuration): + continue + case <-c.ctx.Done(): + c.log.Error("Timed out attempting to create partition", "name", c.flagPartitionName) + return 1 + } + } +} + +func (c *Command) validateFlags() error { + if len(c.flagServerAddresses) == 0 { + return errors.New("-server-address must be set at least once") + } + + if c.flagPartitionName == "" { + return errors.New("-partition-name must be set") + } + return nil +} + +const synopsis = "Initialize an Admin Partition on Consul." +const help = ` +Usage: consul-k8s-control-plane partition-init [options] + + Bootstraps Consul with non-default Admin Partitions. + It will run until the partition has been created or the operation times out. It is idempotent + and safe to run multiple times. + +` diff --git a/control-plane/subcommand/partition-init/command_ent_test.go b/control-plane/subcommand/partition-init/command_ent_test.go new file mode 100644 index 0000000000..39e031a8b7 --- /dev/null +++ b/control-plane/subcommand/partition-init/command_ent_test.go @@ -0,0 +1,150 @@ +// +build enterprise + +package partition_init + +import ( + "context" + "strings" + "testing" + "time" + + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil" + "github.com/mitchellh/cli" + "github.com/stretchr/testify/require" +) + +func TestRun_FlagValidation(t *testing.T) { + t.Parallel() + + cases := []struct { + flags []string + expErr string + }{ + { + flags: nil, + expErr: "-server-address must be set at least once", + }, + { + flags: []string{"-server-address", "foo"}, + expErr: "-partition-name must be set", + }, + { + flags: []string{"-server-address", "foo", "-partition-name", "bar", "-log-level", "invalid"}, + expErr: "unknown log level: invalid", + }, + } + + for _, c := range cases { + t.Run(c.expErr, func(tt *testing.T) { + ui := cli.NewMockUi() + cmd := Command{UI: ui} + exitCode := cmd.Run(c.flags) + require.Equal(tt, 1, exitCode, ui.ErrorWriter.String()) + require.Contains(tt, ui.ErrorWriter.String(), c.expErr) + }) + } +} + +func TestRun_PartitionCreate(t *testing.T) { + partitionName := "test-partition" + + server, err := testutil.NewTestServerConfigT(t, nil) + require.NoError(t, err) + server.WaitForLeader(t) + defer server.Stop() + + consul, err := api.NewClient(&api.Config{ + Address: server.HTTPAddr, + }) + require.NoError(t, err) + + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + } + cmd.init() + args := []string{ + "-server-address=" + strings.Split(server.HTTPAddr, ":")[0], + "-server-port=" + strings.Split(server.HTTPAddr, ":")[1], + "-partition-name", partitionName, + } + + responseCode := cmd.Run(args) + + require.Equal(t, 0, responseCode) + + partition, _, err := consul.Partitions().Read(context.Background(), partitionName, nil) + require.NoError(t, err) + require.NotNil(t, partition) + require.Equal(t, partitionName, partition.Name) +} + +func TestRun_PartitionExists(t *testing.T) { + partitionName := "test-partition" + + server, err := testutil.NewTestServerConfigT(t, nil) + require.NoError(t, err) + server.WaitForLeader(t) + defer server.Stop() + + consul, err := api.NewClient(&api.Config{ + Address: server.HTTPAddr, + }) + require.NoError(t, err) + + // Create the Admin Partition before the test runs. + _, _, err = consul.Partitions().Create(context.Background(), &api.AdminPartition{Name: partitionName, Description: "Created before test"}, nil) + require.NoError(t, err) + + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + } + cmd.init() + args := []string{ + "-server-address=" + strings.Split(server.HTTPAddr, ":")[0], + "-server-port=" + strings.Split(server.HTTPAddr, ":")[1], + "-partition-name", partitionName, + } + + responseCode := cmd.Run(args) + + require.Equal(t, 0, responseCode) + + partition, _, err := consul.Partitions().Read(context.Background(), partitionName, nil) + require.NoError(t, err) + require.NotNil(t, partition) + require.Equal(t, partitionName, partition.Name) + require.Equal(t, "Created before test", partition.Description) +} + +func TestRun_ExitsAfterTimeout(t *testing.T) { + partitionName := "test-partition" + + server, err := testutil.NewTestServerConfigT(t, nil) + require.NoError(t, err) + + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + } + cmd.init() + args := []string{ + "-server-address=" + strings.Split(server.HTTPAddr, ":")[0], + "-server-port=" + strings.Split(server.HTTPAddr, ":")[1], + "-partition-name", partitionName, + "-timeout", "500ms", + } + server.Stop() + startTime := time.Now() + responseCode := cmd.Run(args) + completeTime := time.Now() + + require.Equal(t, 1, responseCode) + // While the timeout is 500ms, adding a buffer of 500ms ensures we account for + // some buffer time required for the task to run and assignments to occur. + require.WithinDuration(t, completeTime, startTime, 1*time.Second) +} + +// TODO: Write tests with ACLs enabled diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index f5737632c0..b69b66edbb 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -12,7 +12,6 @@ import ( "time" "github.com/hashicorp/consul-k8s/control-plane/consul" - godiscover "github.com/hashicorp/consul-k8s/control-plane/helper/go-discover" "github.com/hashicorp/consul-k8s/control-plane/subcommand" "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" @@ -287,18 +286,6 @@ func (c *Command) Run(args []string) int { return 1 } - serverAddresses := c.flagServerAddresses - // Check if the provided addresses contain a cloud-auto join string. - // If yes, call godiscover to discover addresses of the Consul servers. - if len(c.flagServerAddresses) == 1 && strings.Contains(c.flagServerAddresses[0], "provider=") { - var err error - serverAddresses, err = godiscover.ConsulServerAddresses(c.flagServerAddresses[0], c.providers, c.log) - if err != nil { - c.UI.Error(fmt.Sprintf("Unable to discover any Consul addresses from %q: %s", c.flagServerAddresses[0], err)) - return 1 - } - } - // The ClientSet might already be set if we're in a test. if c.clientset == nil { if err := c.configureKubeClient(); err != nil { @@ -307,6 +294,11 @@ func (c *Command) Run(args []string) int { } } + serverAddresses, err := common.GetResolvedServerAddresses(c.flagServerAddresses, c.providers, c.log) + if err != nil { + c.UI.Error(fmt.Sprintf("Unable to discover any Consul addresses from %q: %s", c.flagServerAddresses[0], err)) + return 1 + } scheme := "http" if c.flagUseHTTPS { scheme = "https" From cadd64e3f554e7c60da80bae6b41eaa17283f7d7 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 9 Sep 2021 14:21:28 -0400 Subject: [PATCH 024/418] Add support for Partition Service (#706) * Add support for Partition Service - This is a loadBalancer service that allows one to expose the server pods. This allows a constant value for client auto-join even if the node IPs of the server pods change. * Support NodePort along with LoadBalancer as service types for Partition service. - This will allows interop with Kind. Additionally, users can set explicit NodePorts for Serf, HTTPS and RPC endpoints. --- .../consul/templates/partition-service.yaml | 45 ++++++ .../consul/test/unit/partition-service.bats | 133 ++++++++++++++++++ charts/consul/values.yaml | 33 ++++- 3 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 charts/consul/templates/partition-service.yaml create mode 100755 charts/consul/test/unit/partition-service.bats diff --git a/charts/consul/templates/partition-service.yaml b/charts/consul/templates/partition-service.yaml new file mode 100644 index 0000000000..d417c9d348 --- /dev/null +++ b/charts/consul/templates/partition-service.yaml @@ -0,0 +1,45 @@ +{{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} +{{- if (and .Values.global.adminPartitions.enabled $serverEnabled) }} +# Service with an external IP for clients in non-default Admin Partitions +# to discover Consul servers. This service should only point to Consul servers. +apiVersion: v1 +kind: Service +metadata: + name: {{ template "consul.fullname" . }}-partition-service + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: server + annotations: + {{- if .Values.global.adminPartitions.service.annotations }} + {{ tpl .Values.global.adminPartitions.service.annotations . | nindent 4 | trim }} + {{- end }} +spec: + type: "{{ .Values.global.adminPartitions.service.type }}" + ports: + - name: https + port: 8501 + targetPort: 8501 + {{ if (and (eq .Values.global.adminPartitions.service.type "NodePort") .Values.global.adminPartitions.service.nodePort.https) }} + nodePort: {{ .Values.global.adminPartitions.service.nodePort.https }} + {{- end }} + - name: serflan + port: 8301 + targetPort: 8301 + {{ if (and (eq .Values.global.adminPartitions.service.type "NodePort") .Values.global.adminPartitions.service.nodePort.serf) }} + nodePort: {{ .Values.global.adminPartitions.service.nodePort.serf }} + {{- end }} + - name: server + port: 8300 + targetPort: 8300 + {{ if (and (eq .Values.global.adminPartitions.service.type "NodePort") .Values.global.adminPartitions.service.nodePort.rpc) }} + nodePort: {{ .Values.global.adminPartitions.service.nodePort.rpc }} + {{- end }} + selector: + app: {{ template "consul.name" . }} + release: "{{ .Release.Name }}" + component: server +{{- end }} diff --git a/charts/consul/test/unit/partition-service.bats b/charts/consul/test/unit/partition-service.bats new file mode 100755 index 0000000000..b772b32d5e --- /dev/null +++ b/charts/consul/test/unit/partition-service.bats @@ -0,0 +1,133 @@ +#!/usr/bin/env bats + +load _helpers + +@test "partition/Service: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-service.yaml \ + . +} + +@test "partition/Service: enable with global.enabled false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-service.yaml \ + --set 'global.enabled=false' \ + --set 'server.enabled=true' \ + --set 'global.adminPartitions.enabled=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "partition/Service: disable with adminPartitions.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-service.yaml \ + --set 'global.adminPartitions.enabled=false' \ + . +} + +@test "partition/Service: disable with server.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-service.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=false' \ + . +} + +@test "partition/Service: disable with global.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-service.yaml \ + --set 'global.enabled=false' \ + . +} + +#-------------------------------------------------------------------- +# annotations + +@test "partition/Service: no annotations by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-service.yaml \ + --set 'global.adminPartitions.enabled=true' \ + . | tee /dev/stderr | + yq -r '.metadata.annotations | length' | tee /dev/stderr) + [ "${actual}" = "0" ] +} + +@test "partition/Service: can set annotations" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-service.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.service.annotations=key: value' \ + . | tee /dev/stderr | + yq -r '.metadata.annotations.key' | tee /dev/stderr) + [ "${actual}" = "value" ] +} + +#-------------------------------------------------------------------- +# nodePort + +@test "partition/Service: RPC node port can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-service.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.service.type=NodePort' \ + --set 'global.adminPartitions.service.nodePort.rpc=4443' \ + . | tee /dev/stderr | + yq -r '.spec.ports[] | select(.name == "server") | .nodePort' | tee /dev/stderr) + [ "${actual}" == "4443" ] +} + +@test "partition/Service: Serf node port can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-service.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.service.type=NodePort' \ + --set 'global.adminPartitions.service.nodePort.serf=4444' \ + . | tee /dev/stderr | + yq -r '.spec.ports[] | select(.name == "serflan") | .nodePort' | tee /dev/stderr) + [ "${actual}" == "4444" ] +} + +@test "partition/Service: HTTPS node port can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-service.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.service.type=NodePort' \ + --set 'global.adminPartitions.service.nodePort.https=4444' \ + . | tee /dev/stderr | + yq -r '.spec.ports[] | select(.name == "https") | .nodePort' | tee /dev/stderr) + [ "${actual}" == "4444" ] +} + +@test "partition/Service: RPC, Serf and HTTPS node ports can be set" { + cd `chart_dir` + local ports=$(helm template \ + -s templates/partition-service.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.service.type=NodePort' \ + --set 'global.adminPartitions.service.nodePort.rpc=4443' \ + --set 'global.adminPartitions.service.nodePort.https=4444' \ + --set 'global.adminPartitions.service.nodePort.serf=4445' \ + . | tee /dev/stderr | + yq -r '.spec.ports[]' | tee /dev/stderr) + + local actual + actual=$(echo $ports | jq -r 'select(.name == "server") | .nodePort' | tee /dev/stderr) + [ "${actual}" == "4443" ] + + actual=$(echo $ports | jq -r 'select(.name == "https") | .nodePort' | tee /dev/stderr) + [ "${actual}" == "4444" ] + + actual=$(echo $ports | jq -r 'select(.name == "serflan") | .nodePort' | tee /dev/stderr) + [ "${actual}" == "4445" ] +} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index f6b5848198..9e7e3f7557 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -31,8 +31,8 @@ global: # [Enterprise Only] Enabling `adminPartitions` allows creation of Admin Partitions in Kubernetes clusters. # It additionally indicates that you are running Consul Enterprise v1.11+ with a valid Consul Enterprise - # license. Admin partitions enables deploying services across partitions, while sharing - # a set of Consul servers. + # license. Admin partitions enables deploying services across partitions, while sharing + # a set of Consul servers. adminPartitions: # If true, the Helm chart will enable Admin Partitions for the cluster. The clients in the server cluster # must be installed in the default partition. @@ -40,6 +40,35 @@ global: # The name of the Admin Partition. Must be "default" in the server cluster ie the Kubernetes cluster that # the Consul server pods are deployed onto. name: "default" + # Partition service properties. + service: + type: LoadBalancer + # Optionally set the nodePort value of the partition service if using a NodePort service. + # If not set and using a NodePort service, Kubernetes will automatically assign + # a port. + nodePort: + + # RPC node port + # @type: integer + rpc: null + + # Serf node port + # @type: integer + serf: null + + # HTTPS node port + # @type: integer + https: null + + # Annotations to apply to the partition service. + # + # ```yaml + # annotations: | + # "annotation-key": "annotation-value" + # ``` + # + # @type: string + annotations: null # The name (and tag) of the Consul Docker image for clients and servers. # This can be overridden per component. This should be pinned to a specific From a0d8d2f9bbe35bb10eda743f1dae5a5df4d3156a Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 14 Sep 2021 12:05:43 -0400 Subject: [PATCH 025/418] Add support for Admin Partitions to endpoints controller (#717) --- .../templates/connect-inject-deployment.yaml | 3 + .../test/unit/connect-inject-deployment.bats | 26 ++++++ .../connect-inject/endpoints_controller.go | 22 +++-- .../endpoints_controller_test.go | 86 +++++++++++++++++++ .../subcommand/inject-connect/command.go | 5 ++ 5 files changed, 136 insertions(+), 6 deletions(-) diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index 8e00c7f250..0a03ff393b 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -131,6 +131,9 @@ spec: {{- range $value := .Values.connectInject.k8sDenyNamespaces }} -deny-k8s-namespace="{{ $value }}" \ {{- end }} + {{- if .Values.global.adminPartitions.enabled }} + -enable-partitions=true \ + {{- end }} {{- if .Values.global.enableConsulNamespaces }} -enable-namespaces=true \ {{- if .Values.connectInject.consulNamespaces.consulDestinationNamespace }} diff --git a/charts/consul/test/unit/connect-inject-deployment.bats b/charts/consul/test/unit/connect-inject-deployment.bats index de747995a1..98aee11995 100755 --- a/charts/consul/test/unit/connect-inject-deployment.bats +++ b/charts/consul/test/unit/connect-inject-deployment.bats @@ -686,6 +686,32 @@ EOF [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# partitions + +@test "connectInject/Deployment: partitions options disabled by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | any(contains("enable-partitions"))' | tee /dev/stderr) + + [ "${actual}" = "false" ] +} + +@test "connectInject/Deployment: partitions set with .global.adminPartitions.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'global.adminPartitions.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | any(contains("enable-partitions"))' | tee /dev/stderr) + + [ "${actual}" = "true" ] +} + #-------------------------------------------------------------------- # namespaces diff --git a/control-plane/connect-inject/endpoints_controller.go b/control-plane/connect-inject/endpoints_controller.go index 247bcbd55c..4e6a2b73ba 100644 --- a/control-plane/connect-inject/endpoints_controller.go +++ b/control-plane/connect-inject/endpoints_controller.go @@ -72,6 +72,9 @@ type EndpointsController struct { AllowK8sNamespacesSet mapset.Set // Endpoints in the DenyK8sNamespacesSet are ignored. DenyK8sNamespacesSet mapset.Set + // EnableConsulPartitions indicates that a user is running Consul Enterprise + // with version 1.11+ which supports Admin Partitions. + EnableConsulPartitions bool // EnableConsulNamespaces indicates that a user is running Consul Enterprise // with version 1.7+ which supports namespaces. EnableConsulNamespaces bool @@ -805,7 +808,7 @@ func (r *EndpointsController) processUpstreams(pod corev1.Pod) ([]api.Upstream, for _, raw := range strings.Split(raw, ",") { parts := strings.SplitN(raw, ":", 3) - var datacenter, serviceName, preparedQuery, namespace string + var datacenter, serviceName, preparedQuery, namespace, partition string var port int32 if strings.TrimSpace(parts[0]) == "prepared_query" { port, _ = portValue(pod, strings.TrimSpace(parts[2])) @@ -813,13 +816,19 @@ func (r *EndpointsController) processUpstreams(pod corev1.Pod) ([]api.Upstream, } else { port, _ = portValue(pod, strings.TrimSpace(parts[1])) - // If Consul Namespaces are enabled, attempt to parse the + // If Consul Namespaces or Admin Partitions are enabled, attempt to parse the // upstream for a namespace. - if r.EnableConsulNamespaces { - pieces := strings.SplitN(parts[0], ".", 2) - serviceName = strings.TrimSpace(pieces[0]) - if len(pieces) > 1 { + if r.EnableConsulNamespaces || r.EnableConsulPartitions { + pieces := strings.SplitN(parts[0], ".", 3) + switch len(pieces) { + case 3: + partition = strings.TrimSpace(pieces[2]) + fallthrough + case 2: namespace = strings.TrimSpace(pieces[1]) + fallthrough + default: + serviceName = strings.TrimSpace(pieces[0]) } } else { serviceName = strings.TrimSpace(parts[0]) @@ -852,6 +861,7 @@ func (r *EndpointsController) processUpstreams(pod corev1.Pod) ([]api.Upstream, if port > 0 { upstream := api.Upstream{ DestinationType: api.UpstreamDestTypeService, + DestinationPartition: partition, DestinationNamespace: namespace, DestinationName: serviceName, Datacenter: datacenter, diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index a073af12ec..229a8618fd 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -193,6 +193,7 @@ func TestProcessUpstreams(t *testing.T) { configEntry func() api.ConfigEntry consulUnavailable bool consulNamespacesEnabled bool + consulPartitionsEnabled bool }{ { name: "upstream with datacenter without ProxyDefaults", @@ -203,6 +204,7 @@ func TestProcessUpstreams(t *testing.T) { }, expErr: "upstream \"upstream1:1234:dc1\" is invalid: there is no ProxyDefaults config to set mesh gateway mode", consulNamespacesEnabled: false, + consulPartitionsEnabled: false, }, { name: "upstream with datacenter with ProxyDefaults whose mesh gateway mode is not local or remote", @@ -219,6 +221,7 @@ func TestProcessUpstreams(t *testing.T) { return pd }, consulNamespacesEnabled: false, + consulPartitionsEnabled: false, }, { name: "upstream with datacenter with ProxyDefaults and mesh gateway is in local mode", @@ -242,6 +245,7 @@ func TestProcessUpstreams(t *testing.T) { return pd }, consulNamespacesEnabled: false, + consulPartitionsEnabled: false, }, { name: "upstream with datacenter with ProxyDefaults and mesh gateway in remote mode", @@ -265,6 +269,7 @@ func TestProcessUpstreams(t *testing.T) { return pd }, consulNamespacesEnabled: false, + consulPartitionsEnabled: false, }, { name: "when consul is unavailable, we don't return an error", @@ -290,6 +295,7 @@ func TestProcessUpstreams(t *testing.T) { }, consulUnavailable: true, consulNamespacesEnabled: false, + consulPartitionsEnabled: false, }, { name: "single upstream", @@ -306,6 +312,7 @@ func TestProcessUpstreams(t *testing.T) { }, }, consulNamespacesEnabled: false, + consulPartitionsEnabled: false, }, { name: "single upstream with namespace", @@ -323,6 +330,45 @@ func TestProcessUpstreams(t *testing.T) { }, }, consulNamespacesEnabled: true, + consulPartitionsEnabled: false, + }, + { + name: "single upstream with namespace and partition", + pod: func() *corev1.Pod { + pod1 := createPod("pod1", "1.2.3.4", true, true) + pod1.Annotations[annotationUpstreams] = "upstream.foo.bar:1234" + return pod1 + }, + expected: []api.Upstream{ + { + DestinationType: api.UpstreamDestTypeService, + DestinationName: "upstream", + LocalBindPort: 1234, + DestinationNamespace: "foo", + DestinationPartition: "bar", + }, + }, + consulNamespacesEnabled: true, + consulPartitionsEnabled: true, + }, + { + name: "single upstream with partition", + pod: func() *corev1.Pod { + pod1 := createPod("pod1", "1.2.3.4", true, true) + pod1.Annotations[annotationUpstreams] = "upstream.default.bar:1234" + return pod1 + }, + expected: []api.Upstream{ + { + DestinationType: api.UpstreamDestTypeService, + DestinationName: "upstream", + LocalBindPort: 1234, + DestinationNamespace: "default", + DestinationPartition: "bar", + }, + }, + consulNamespacesEnabled: false, + consulPartitionsEnabled: true, }, { name: "multiple upstreams", @@ -344,6 +390,43 @@ func TestProcessUpstreams(t *testing.T) { }, }, consulNamespacesEnabled: false, + consulPartitionsEnabled: false, + }, + { + name: "multiple upstreams with consul namespaces, partitions and datacenters", + pod: func() *corev1.Pod { + pod1 := createPod("pod1", "1.2.3.4", true, true) + pod1.Annotations[annotationUpstreams] = "upstream1:1234, upstream2.bar:2234, upstream3.foo.baz:3234:dc2" + return pod1 + }, + configEntry: func() api.ConfigEntry { + ce, _ := api.MakeConfigEntry(api.ProxyDefaults, "pd") + pd := ce.(*api.ProxyConfigEntry) + pd.MeshGateway.Mode = "remote" + return pd + }, + expected: []api.Upstream{ + { + DestinationType: api.UpstreamDestTypeService, + DestinationName: "upstream1", + LocalBindPort: 1234, + }, + { + DestinationType: api.UpstreamDestTypeService, + DestinationName: "upstream2", + DestinationNamespace: "bar", + LocalBindPort: 2234, + }, { + DestinationType: api.UpstreamDestTypeService, + DestinationName: "upstream3", + DestinationNamespace: "foo", + DestinationPartition: "baz", + LocalBindPort: 3234, + Datacenter: "dc2", + }, + }, + consulNamespacesEnabled: true, + consulPartitionsEnabled: true, }, { name: "multiple upstreams with consul namespaces and datacenters", @@ -394,6 +477,7 @@ func TestProcessUpstreams(t *testing.T) { }, }, consulNamespacesEnabled: false, + consulPartitionsEnabled: false, }, { name: "prepared query and non-query upstreams", @@ -420,6 +504,7 @@ func TestProcessUpstreams(t *testing.T) { }, }, consulNamespacesEnabled: false, + consulPartitionsEnabled: false, }, } for _, tt := range cases { @@ -455,6 +540,7 @@ func TestProcessUpstreams(t *testing.T) { AllowK8sNamespacesSet: mapset.NewSetWith("*"), DenyK8sNamespacesSet: mapset.NewSetWith(), EnableConsulNamespaces: tt.consulNamespacesEnabled, + EnableConsulPartitions: tt.consulPartitionsEnabled, } upstreams, err := ep.processUpstreams(*tt.pod()) diff --git a/control-plane/subcommand/inject-connect/command.go b/control-plane/subcommand/inject-connect/command.go index 530bbdae98..2a078fcb0d 100644 --- a/control-plane/subcommand/inject-connect/command.go +++ b/control-plane/subcommand/inject-connect/command.go @@ -50,6 +50,8 @@ type Command struct { flagAllowK8sNamespacesList []string // K8s namespaces to explicitly inject flagDenyK8sNamespacesList []string // K8s namespaces to deny injection (has precedence) + flagEnablePartitions bool // Use Admin Partitions on all components + // Flags to support Consul namespaces flagEnableNamespaces bool // Use namespacing on all components flagConsulDestinationNamespace string // Consul namespace to register everything if not mirroring @@ -141,6 +143,8 @@ func (c *Command) init() { "K8s namespaces to explicitly deny. Takes precedence over allow. May be specified multiple times.") c.flagSet.StringVar(&c.flagReleaseName, "release-name", "consul", "The Consul Helm installation release name, e.g 'helm install '") c.flagSet.StringVar(&c.flagReleaseNamespace, "release-namespace", "default", "The Consul Helm installation namespace, e.g 'helm install --namespace '") + c.flagSet.BoolVar(&c.flagEnablePartitions, "enable-partitions", false, + "[Enterprise Only] Enables Admin Partitions.") c.flagSet.BoolVar(&c.flagEnableNamespaces, "enable-namespaces", false, "[Enterprise Only] Enables namespaces, in either a single Consul namespace or mirrored.") c.flagSet.StringVar(&c.flagConsulDestinationNamespace, "consul-destination-namespace", "default", @@ -403,6 +407,7 @@ func (c *Command) Run(args []string) int { DenyK8sNamespacesSet: denyK8sNamespaces, MetricsConfig: metricsConfig, ConsulClientCfg: cfg, + EnableConsulPartitions: c.flagEnablePartitions, EnableConsulNamespaces: c.flagEnableNamespaces, ConsulDestinationNamespace: c.flagConsulDestinationNamespace, EnableNSMirroring: c.flagEnableK8SNSMirroring, From df485630d73bf09c327133c2faef046e49cd50e8 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 14 Sep 2021 19:07:57 -0400 Subject: [PATCH 026/418] Only support default partition in server cluster (#721) * Fail if agents in server cluster are created in a partition not "default" * Fail helm upgrades if partition name is updated. - This does not cause the parition-init job from running or the agents from attempting to join the new partition, but the helm upgrade stays in a failed state until an upgrade is run with the partition name reverted. --- charts/consul/templates/client-daemonset.yaml | 2 + .../consul/templates/partition-init-job.yaml | 2 +- .../templates/partition-name-configmap.yaml | 18 +++++++ charts/consul/test/unit/client-daemonset.bats | 13 +++++ .../test/unit/partition-name-configmap.bats | 47 +++++++++++++++++++ charts/consul/values.yaml | 8 ++-- 6 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 charts/consul/templates/partition-name-configmap.yaml create mode 100644 charts/consul/test/unit/partition-name-configmap.bats diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index 822bc3a653..58eb73ca9e 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -1,5 +1,7 @@ {{- if (or (and (ne (.Values.client.enabled | toString) "-") .Values.client.enabled) (and (eq (.Values.client.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and (and .Values.global.tls.enabled .Values.global.tls.httpsOnly) (and .Values.global.metrics.enabled .Values.global.metrics.enableAgentMetrics))}}{{ fail "global.metrics.enableAgentMetrics cannot be enabled if TLS (HTTPS only) is enabled" }}{{ end -}} +{{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} +{{- if (and .Values.global.adminPartitions.enabled $serverEnabled (ne .Values.global.adminPartitions.name "default"))}}{{ fail "global.adminPartitions.name has to be \"default\" in the server cluster" }}{{ end -}} # DaemonSet to run the Consul clients on every node. apiVersion: apps/v1 kind: DaemonSet diff --git a/charts/consul/templates/partition-init-job.yaml b/charts/consul/templates/partition-init-job.yaml index 97a2d83edf..b9d438c436 100644 --- a/charts/consul/templates/partition-init-job.yaml +++ b/charts/consul/templates/partition-init-job.yaml @@ -11,7 +11,7 @@ metadata: heritage: {{ .Release.Service }} release: {{ .Release.Name }} annotations: - "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook": pre-install "helm.sh/hook-weight": "2" "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation spec: diff --git a/charts/consul/templates/partition-name-configmap.yaml b/charts/consul/templates/partition-name-configmap.yaml new file mode 100644 index 0000000000..4d568f0889 --- /dev/null +++ b/charts/consul/templates/partition-name-configmap.yaml @@ -0,0 +1,18 @@ +{{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} +{{- if (and .Values.global.adminPartitions.enabled (not $serverEnabled)) }} +# Immutable ConfigMap which saves the partition name. Attempting to update this configmap +# with a new Admin Partition name will cause the helm upgrade to fail +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "consul.fullname" . }}-partition + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} +immutable: true +data: + partitionName: {{ .Values.global.adminPartitions.name }} +{{- end }} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index 6e892bd31d..d9bd845765 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1402,7 +1402,20 @@ rollingUpdate: -s templates/client-daemonset.yaml \ --set 'global.adminPartitions.enabled=true' \ --set 'global.adminPartitions.name=test' \ + --set 'server.enabled=false' \ . | tee /dev/stderr | yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("partition = \"test\"")' | tee /dev/stderr) [ "${actual}" = "true" ] } + +@test "client/DaemonSet: partition name has to be default in server cluster" { + cd `chart_dir` + run helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=test' \ + . + + [ "$status" -eq 1 ] + [[ "$output" =~ "global.adminPartitions.name has to be \"default\" in the server cluster" ]] +} diff --git a/charts/consul/test/unit/partition-name-configmap.bats b/charts/consul/test/unit/partition-name-configmap.bats new file mode 100644 index 0000000000..e516c9ae13 --- /dev/null +++ b/charts/consul/test/unit/partition-name-configmap.bats @@ -0,0 +1,47 @@ +#!/usr/bin/env bats + +load _helpers + +@test "partitionName/ConfigMap: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-role.yaml \ + . +} + +@test "partitionName/ConfigMap: enabled with global.adminPartitions.enabled=true and servers = false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-init-role.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "partitionName/ConfigMap: disabled with global.adminPartitions.enabled=true and servers = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-role.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=true' \ + . +} + +@test "partitionName/ConfigMap: disabled with global.adminPartitions.enabled=true and global.enabled = true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-role.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enabled=true' \ + . +} + +@test "partitionName/ConfigMap: disabled with global.adminPartitions.enabled=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-role.yaml \ + --set 'global.adminPartitions.enabled=false' \ + . +} \ No newline at end of file diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 9e7e3f7557..6e74e98ae6 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -35,10 +35,12 @@ global: # a set of Consul servers. adminPartitions: # If true, the Helm chart will enable Admin Partitions for the cluster. The clients in the server cluster - # must be installed in the default partition. + # must be installed in the default partition. Creation of Admin Partitions is only supported during installation. + # Admin Partitions cannot be installed via a Helm upgrade operation. Only Helm installs are supported. enabled: false - # The name of the Admin Partition. Must be "default" in the server cluster ie the Kubernetes cluster that - # the Consul server pods are deployed onto. + # The name of the Admin Partition. The partition name cannot be modified once the partition has been installed. + # Changing the partition name would require an un-install and a re-install with the updated name. + # Must be "default" in the server cluster ie the Kubernetes cluster that the Consul server pods are deployed onto. name: "default" # Partition service properties. service: From e8d10b120d6484ef3b9c46e2e57aa0230831167e Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 15 Sep 2021 17:54:33 -0400 Subject: [PATCH 027/418] Update envoy bootstrap config with partition name (#727) --- .../templates/connect-inject-deployment.yaml | 1 + .../test/unit/connect-inject-deployment.bats | 12 +++ .../connect-inject/container_init.go | 14 ++++ .../connect-inject/container_init_test.go | 82 +++++++++++++++++-- control-plane/connect-inject/handler.go | 5 ++ .../subcommand/connect-init/command.go | 3 + .../connect-init/command_ent_test.go | 39 ++++++--- .../subcommand/inject-connect/command.go | 16 +++- .../subcommand/inject-connect/command_test.go | 10 +++ 9 files changed, 160 insertions(+), 22 deletions(-) diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index 0a03ff393b..28336027f5 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -133,6 +133,7 @@ spec: {{- end }} {{- if .Values.global.adminPartitions.enabled }} -enable-partitions=true \ + -partition-name={{ .Values.global.adminPartitions.name }} \ {{- end }} {{- if .Values.global.enableConsulNamespaces }} -enable-namespaces=true \ diff --git a/charts/consul/test/unit/connect-inject-deployment.bats b/charts/consul/test/unit/connect-inject-deployment.bats index 98aee11995..03fbfbc592 100755 --- a/charts/consul/test/unit/connect-inject-deployment.bats +++ b/charts/consul/test/unit/connect-inject-deployment.bats @@ -712,6 +712,18 @@ EOF [ "${actual}" = "true" ] } +@test "connectInject/Deployment: partition name set with .global.adminPartitions.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'global.adminPartitions.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | any(contains("partition-name=default"))' | tee /dev/stderr) + + [ "${actual}" = "true" ] +} + #-------------------------------------------------------------------- # namespaces diff --git a/control-plane/connect-inject/container_init.go b/control-plane/connect-inject/container_init.go index 4c2f44914e..e69a91fbb1 100644 --- a/control-plane/connect-inject/container_init.go +++ b/control-plane/connect-inject/container_init.go @@ -22,6 +22,10 @@ type initContainerCommandData struct { ServiceName string ServiceAccountName string AuthMethod string + // ConsulPartition is the Consul admin partition to register the service + // and proxy in. An empty string indicates partitions are not + // enabled in Consul (necessary for OSS). + ConsulPartition string // ConsulNamespace is the Consul namespace to register the service // and proxy in. An empty string indicates namespaces are not // enabled in Consul (necessary for OSS). @@ -105,6 +109,7 @@ func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod) (cor data := initContainerCommandData{ AuthMethod: h.AuthMethod, + ConsulPartition: h.ConsulPartition, ConsulNamespace: h.consulNamespace(namespace.Name), NamespaceMirroringEnabled: h.EnableK8SNSMirroring, ConsulCACert: h.ConsulCACert, @@ -284,6 +289,9 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD {{- end }} {{- end }} {{- end }} + {{- if .ConsulPartition }} + -partition="{{ .ConsulPartition }}" \ + {{- end }} {{- if .ConsulNamespace }} -consul-service-namespace="{{ .ConsulNamespace }}" \ {{- end }} @@ -300,6 +308,9 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD {{- if .AuthMethod }} -token-file="/consul/connect-inject/acl-token" \ {{- end }} + {{- if .ConsulPartition }} + -partition="{{ .ConsulPartition }}" \ + {{- end }} {{- if .ConsulNamespace }} -namespace="{{ .ConsulNamespace }}" \ {{- end }} @@ -314,6 +325,9 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD {{- if .AuthMethod }} -token-file="/consul/connect-inject/acl-token" \ {{- end }} + {{- if .ConsulPartition }} + -partition="{{ .ConsulPartition }}" \ + {{- end }} {{- if .ConsulNamespace }} -namespace="{{ .ConsulNamespace }}" \ {{- end }} diff --git a/control-plane/connect-inject/container_init_test.go b/control-plane/connect-inject/container_init_test.go index 1603c82d12..e131ba20f7 100644 --- a/control-plane/connect-inject/container_init_test.go +++ b/control-plane/connect-inject/container_init_test.go @@ -310,7 +310,7 @@ func TestHandlerContainerInit_transparentProxy(t *testing.T) { } } -func TestHandlerContainerInit_namespacesEnabled(t *testing.T) { +func TestHandlerContainerInit_namespacesAndPartitionsEnabled(t *testing.T) { minimal := func() *corev1.Pod { return &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -349,7 +349,7 @@ func TestHandlerContainerInit_namespacesEnabled(t *testing.T) { Cmd string // Strings.Contains test }{ { - "whole template, default namespace", + "whole template, default namespace, no partition", func(pod *corev1.Pod) *corev1.Pod { pod.Annotations[annotationService] = "web" return pod @@ -357,6 +357,7 @@ func TestHandlerContainerInit_namespacesEnabled(t *testing.T) { Handler{ EnableNamespaces: true, ConsulDestinationNamespace: "default", + ConsulPartition: "", }, `/bin/sh -ec export CONSUL_HTTP_ADDR="${HOST_IP}:8500" @@ -370,9 +371,33 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -namespace="default" \ -bootstrap > /consul/connect-inject/envoy-bootstrap.yaml`, }, + { + "whole template, default namespace, default partition", + func(pod *corev1.Pod) *corev1.Pod { + pod.Annotations[annotationService] = "web" + return pod + }, + Handler{ + EnableNamespaces: true, + ConsulDestinationNamespace: "default", + ConsulPartition: "default", + }, + `/bin/sh -ec +export CONSUL_HTTP_ADDR="${HOST_IP}:8500" +export CONSUL_GRPC_ADDR="${HOST_IP}:8502" +consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD_NAMESPACE} \ + -partition="default" \ + -consul-service-namespace="default" \ +# Generate the envoy bootstrap code +/consul/connect-inject/consul connect envoy \ + -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -partition="default" \ + -namespace="default" \ + -bootstrap > /consul/connect-inject/envoy-bootstrap.yaml`, + }, { - "whole template, non-default namespace", + "whole template, non-default namespace, no partition", func(pod *corev1.Pod) *corev1.Pod { pod.Annotations[annotationService] = "web" return pod @@ -380,6 +405,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD Handler{ EnableNamespaces: true, ConsulDestinationNamespace: "non-default", + ConsulPartition: "", }, `/bin/sh -ec export CONSUL_HTTP_ADDR="${HOST_IP}:8500" @@ -393,9 +419,33 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -namespace="non-default" \ -bootstrap > /consul/connect-inject/envoy-bootstrap.yaml`, }, + { + "whole template, non-default namespace, non-default partition", + func(pod *corev1.Pod) *corev1.Pod { + pod.Annotations[annotationService] = "web" + return pod + }, + Handler{ + EnableNamespaces: true, + ConsulDestinationNamespace: "non-default", + ConsulPartition: "non-default-part", + }, + `/bin/sh -ec +export CONSUL_HTTP_ADDR="${HOST_IP}:8500" +export CONSUL_GRPC_ADDR="${HOST_IP}:8502" +consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD_NAMESPACE} \ + -partition="non-default-part" \ + -consul-service-namespace="non-default" \ +# Generate the envoy bootstrap code +/consul/connect-inject/consul connect envoy \ + -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -partition="non-default-part" \ + -namespace="non-default" \ + -bootstrap > /consul/connect-inject/envoy-bootstrap.yaml`, + }, { - "Whole template, auth method, non-default namespace, mirroring disabled", + "Whole template, auth method, non-default namespace, mirroring disabled, default partition", func(pod *corev1.Pod) *corev1.Pod { pod.Annotations[annotationService] = "" return pod @@ -404,6 +454,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD AuthMethod: "auth-method", EnableNamespaces: true, ConsulDestinationNamespace: "non-default", + ConsulPartition: "default", }, `/bin/sh -ec export CONSUL_HTTP_ADDR="${HOST_IP}:8500" @@ -413,17 +464,19 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -service-account-name="web" \ -service-name="" \ -auth-method-namespace="non-default" \ + -partition="default" \ -consul-service-namespace="non-default" \ # Generate the envoy bootstrap code /consul/connect-inject/consul connect envoy \ -proxy-id="$(cat /consul/connect-inject/proxyid)" \ -token-file="/consul/connect-inject/acl-token" \ + -partition="default" \ -namespace="non-default" \ -bootstrap > /consul/connect-inject/envoy-bootstrap.yaml`, }, { - "Whole template, auth method, non-default namespace, mirroring enabled", + "Whole template, auth method, non-default namespace, mirroring enabled, non-default partition", func(pod *corev1.Pod) *corev1.Pod { pod.Annotations[annotationService] = "" return pod @@ -433,6 +486,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD EnableNamespaces: true, ConsulDestinationNamespace: "non-default", // Overridden by mirroring EnableK8SNSMirroring: true, + ConsulPartition: "non-default", }, `/bin/sh -ec export CONSUL_HTTP_ADDR="${HOST_IP}:8500" @@ -442,17 +496,19 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -service-account-name="web" \ -service-name="" \ -auth-method-namespace="default" \ + -partition="non-default" \ -consul-service-namespace="k8snamespace" \ # Generate the envoy bootstrap code /consul/connect-inject/consul connect envoy \ -proxy-id="$(cat /consul/connect-inject/proxyid)" \ -token-file="/consul/connect-inject/acl-token" \ + -partition="non-default" \ -namespace="k8snamespace" \ -bootstrap > /consul/connect-inject/envoy-bootstrap.yaml`, }, { - "whole template, default namespace, tproxy enabled", + "whole template, default namespace, tproxy enabled, no partition", func(pod *corev1.Pod) *corev1.Pod { pod.Annotations[annotationService] = "web" return pod @@ -460,6 +516,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD Handler{ EnableNamespaces: true, ConsulDestinationNamespace: "default", + ConsulPartition: "", EnableTransparentProxy: true, }, `/bin/sh -ec @@ -480,15 +537,15 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -proxy-id="$(cat /consul/connect-inject/proxyid)" \ -proxy-uid=5995`, }, - { - "whole template, non-default namespace, tproxy enabled", + "whole template, non-default namespace, tproxy enabled, default partition", func(pod *corev1.Pod) *corev1.Pod { pod.Annotations[annotationService] = "web" return pod }, Handler{ EnableNamespaces: true, + ConsulPartition: "default", ConsulDestinationNamespace: "non-default", EnableTransparentProxy: true, }, @@ -496,23 +553,26 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD export CONSUL_HTTP_ADDR="${HOST_IP}:8500" export CONSUL_GRPC_ADDR="${HOST_IP}:8502" consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD_NAMESPACE} \ + -partition="default" \ -consul-service-namespace="non-default" \ # Generate the envoy bootstrap code /consul/connect-inject/consul connect envoy \ -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -partition="default" \ -namespace="non-default" \ -bootstrap > /consul/connect-inject/envoy-bootstrap.yaml # Apply traffic redirection rules. /consul/connect-inject/consul connect redirect-traffic \ + -partition="default" \ -namespace="non-default" \ -proxy-id="$(cat /consul/connect-inject/proxyid)" \ -proxy-uid=5995`, }, { - "Whole template, auth method, non-default namespace, mirroring enabled, tproxy enabled", + "Whole template, auth method, non-default namespace, mirroring enabled, tproxy enabled, non-default partition", func(pod *corev1.Pod) *corev1.Pod { pod.Annotations[annotationService] = "web" return pod @@ -520,6 +580,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD Handler{ AuthMethod: "auth-method", EnableNamespaces: true, + ConsulPartition: "non-default", ConsulDestinationNamespace: "non-default", // Overridden by mirroring EnableK8SNSMirroring: true, EnableTransparentProxy: true, @@ -532,18 +593,21 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -service-account-name="web" \ -service-name="web" \ -auth-method-namespace="default" \ + -partition="non-default" \ -consul-service-namespace="k8snamespace" \ # Generate the envoy bootstrap code /consul/connect-inject/consul connect envoy \ -proxy-id="$(cat /consul/connect-inject/proxyid)" \ -token-file="/consul/connect-inject/acl-token" \ + -partition="non-default" \ -namespace="k8snamespace" \ -bootstrap > /consul/connect-inject/envoy-bootstrap.yaml # Apply traffic redirection rules. /consul/connect-inject/consul connect redirect-traffic \ -token-file="/consul/connect-inject/acl-token" \ + -partition="non-default" \ -namespace="k8snamespace" \ -proxy-id="$(cat /consul/connect-inject/proxyid)" \ -proxy-uid=5995`, diff --git a/control-plane/connect-inject/handler.go b/control-plane/connect-inject/handler.go index 39124a1718..aad0c4c53f 100644 --- a/control-plane/connect-inject/handler.go +++ b/control-plane/connect-inject/handler.go @@ -61,6 +61,11 @@ type Handler struct { // If not set, will use HTTP. ConsulCACert string + // ConsulPartition is the name of the Admin Partition that the controller + // is deployed in. It is an enterprise feature requiring Consul Enterprise 1.11+. + // Its value is an empty string if partitions aren't enabled. + ConsulPartition string + // EnableNamespaces indicates that a user is running Consul Enterprise // with version 1.7+ which is namespace aware. It enables Consul namespaces, // with injection into either a single Consul namespace or mirrored from diff --git a/control-plane/subcommand/connect-init/command.go b/control-plane/subcommand/connect-init/command.go index d8158b5f20..a131f77024 100644 --- a/control-plane/subcommand/connect-init/command.go +++ b/control-plane/subcommand/connect-init/command.go @@ -32,6 +32,7 @@ type Command struct { UI cli.Ui flagACLAuthMethod string // Auth Method to use for ACLs, if enabled. + flagPartition string // Admin Partition name. Consul Enterprise 1.11+ feature. flagPodName string // Pod name. flagPodNamespace string // Pod namespace. flagAuthMethodNamespace string // Consul namespace the auth-method is defined in. @@ -57,6 +58,7 @@ type Command struct { func (c *Command) init() { c.flagSet = flag.NewFlagSet("", flag.ContinueOnError) c.flagSet.StringVar(&c.flagACLAuthMethod, "acl-auth-method", "", "Name of the auth method to login to.") + c.flagSet.StringVar(&c.flagPartition, "partition", "", "Name of the Admin Partition of deployment.") c.flagSet.StringVar(&c.flagPodName, "pod-name", "", "Name of the pod.") c.flagSet.StringVar(&c.flagPodNamespace, "pod-namespace", "", "Name of the pod namespace.") c.flagSet.StringVar(&c.flagAuthMethodNamespace, "auth-method-namespace", "", "Consul namespace the auth-method is defined in") @@ -118,6 +120,7 @@ func (c *Command) Run(args []string) int { } } cfg := api.DefaultConfig() + cfg.Partition = c.flagPartition cfg.Namespace = c.flagConsulServiceNamespace c.http.MergeOntoConfig(cfg) consulClient, err := consul.NewClient(cfg) diff --git a/control-plane/subcommand/connect-init/command_ent_test.go b/control-plane/subcommand/connect-init/command_ent_test.go index 532a0e5066..010d325794 100644 --- a/control-plane/subcommand/connect-init/command_ent_test.go +++ b/control-plane/subcommand/connect-init/command_ent_test.go @@ -26,84 +26,97 @@ func TestRun_ServicePollingWithACLsAndTLSWithNamespaces(t *testing.T) { consulServiceNamespace string acls bool authMethodNamespace string + adminPartition string }{ { - name: "ACLs enabled, no tls, serviceNS=default, authMethodNS=default", + name: "ACLs enabled, no tls, serviceNS=default, authMethodNS=default, partition=default", tls: false, consulServiceNamespace: "default", authMethodNamespace: "default", acls: true, + adminPartition: "default", }, { - name: "ACLs enabled, tls, serviceNS=default, authMethodNS=default", + name: "ACLs enabled, tls, serviceNS=default, authMethodNS=default, partition=default", tls: true, consulServiceNamespace: "default", authMethodNamespace: "default", acls: true, + adminPartition: "default", }, { - name: "ACLs enabled, no tls, serviceNS=default-ns, authMethodNS=default", + name: "ACLs enabled, no tls, serviceNS=default-ns, authMethodNS=default, partition=default", tls: false, consulServiceNamespace: "default-ns", authMethodNamespace: "default", acls: true, + adminPartition: "default", }, { - name: "ACLs enabled, tls, serviceNS=default-ns, authMethodNS=default", + name: "ACLs enabled, tls, serviceNS=default-ns, authMethodNS=default, partition=default", tls: true, consulServiceNamespace: "default-ns", authMethodNamespace: "default", acls: true, + adminPartition: "default", }, { - name: "ACLs enabled, no tls, serviceNS=other, authMethodNS=other", + name: "ACLs enabled, no tls, serviceNS=other, authMethodNS=other, partition=default", tls: false, consulServiceNamespace: "other", authMethodNamespace: "other", acls: true, + adminPartition: "default", }, { - name: "ACLs enabled, tls, serviceNS=other, authMethodNS=other", + name: "ACLs enabled, tls, serviceNS=other, authMethodNS=other, partition=default", tls: true, consulServiceNamespace: "other", authMethodNamespace: "other", acls: true, + adminPartition: "default", }, { - name: "ACLs disabled, no tls, serviceNS=default, authMethodNS=default", + name: "ACLs disabled, no tls, serviceNS=default, authMethodNS=default, partition=default", tls: false, consulServiceNamespace: "default", authMethodNamespace: "default", + adminPartition: "default", }, { - name: "ACLs disabled, tls, serviceNS=default, authMethodNS=default", + name: "ACLs disabled, tls, serviceNS=default, authMethodNS=default, partition=default", tls: true, consulServiceNamespace: "default", authMethodNamespace: "default", + adminPartition: "default", }, { - name: "ACLs disabled, no tls, serviceNS=default-ns, authMethodNS=default", + name: "ACLs disabled, no tls, serviceNS=default-ns, authMethodNS=default, partition=default", tls: false, consulServiceNamespace: "default-ns", authMethodNamespace: "default", + adminPartition: "default", }, { - name: "ACLs disabled, tls, serviceNS=default-ns, authMethodNS=default", + name: "ACLs disabled, tls, serviceNS=default-ns, authMethodNS=default, partition=default", tls: true, consulServiceNamespace: "default-ns", authMethodNamespace: "default", + adminPartition: "default", }, { - name: "ACLs disabled, no tls, serviceNS=other, authMethodNS=other", + name: "ACLs disabled, no tls, serviceNS=other, authMethodNS=other, partition=default", tls: false, consulServiceNamespace: "other", authMethodNamespace: "other", + adminPartition: "default", }, { - name: "ACLs disabled, tls, serviceNS=other, authMethodNS=other", + name: "ACLs disabled, tls, serviceNS=other, authMethodNS=other, partition=default", tls: true, consulServiceNamespace: "other", authMethodNamespace: "other", + adminPartition: "default", }, } for _, c := range cases { @@ -139,6 +152,7 @@ func TestRun_ServicePollingWithACLsAndTLSWithNamespaces(t *testing.T) { Scheme: "http", Address: server.HTTPAddr, Namespace: c.consulServiceNamespace, + Partition: c.adminPartition, } if c.acls { cfg.Token = masterToken @@ -174,6 +188,7 @@ func TestRun_ServicePollingWithACLsAndTLSWithNamespaces(t *testing.T) { tokenSinkFile: tokenFile, proxyIDFile: proxyFile, serviceRegistrationPollingAttempts: 5, + flagPartition: c.adminPartition, } // We build the http-addr because normally it's defined by the init container setting // CONSUL_HTTP_ADDR when it processes the command template. diff --git a/control-plane/subcommand/inject-connect/command.go b/control-plane/subcommand/inject-connect/command.go index 2a078fcb0d..1495c8d7c0 100644 --- a/control-plane/subcommand/inject-connect/command.go +++ b/control-plane/subcommand/inject-connect/command.go @@ -50,7 +50,8 @@ type Command struct { flagAllowK8sNamespacesList []string // K8s namespaces to explicitly inject flagDenyK8sNamespacesList []string // K8s namespaces to deny injection (has precedence) - flagEnablePartitions bool // Use Admin Partitions on all components + flagEnablePartitions bool // Use Admin Partitions on all components + flagPartitionName string // Name of Admin Partition if enabled. // Flags to support Consul namespaces flagEnableNamespaces bool // Use namespacing on all components @@ -145,6 +146,8 @@ func (c *Command) init() { c.flagSet.StringVar(&c.flagReleaseNamespace, "release-namespace", "default", "The Consul Helm installation namespace, e.g 'helm install --namespace '") c.flagSet.BoolVar(&c.flagEnablePartitions, "enable-partitions", false, "[Enterprise Only] Enables Admin Partitions.") + c.flagSet.StringVar(&c.flagPartitionName, "partition-name", "", + "[Enterprise Only] Name of the Admin Partition.") c.flagSet.BoolVar(&c.flagEnableNamespaces, "enable-namespaces", false, "[Enterprise Only] Enables namespaces, in either a single Consul namespace or mirrored.") c.flagSet.StringVar(&c.flagConsulDestinationNamespace, "consul-destination-namespace", "default", @@ -232,6 +235,14 @@ func (c *Command) Run(args []string) int { return 1 } + if c.flagEnablePartitions && c.flagPartitionName == "" { + c.UI.Error("-partition-name must set if -enable-partitions is set to 'true'") + } + + if c.flagPartitionName != "" && !c.flagEnablePartitions { + c.UI.Error("-enable-partitions must be set to 'true' if -partition-name is set") + } + // Proxy resources. var sidecarProxyCPULimit, sidecarProxyCPURequest, sidecarProxyMemoryLimit, sidecarProxyMemoryRequest resource.Quantity var err error @@ -338,6 +349,8 @@ func (c *Command) Run(args []string) int { } } + cfg.Partition = c.flagPartitionName + // Set up Consul client. if c.consulClient == nil { var err error @@ -451,6 +464,7 @@ func (c *Command) Run(args []string) int { MetricsConfig: metricsConfig, InitContainerResources: initResources, ConsulSidecarResources: consulSidecarResources, + ConsulPartition: c.flagPartitionName, AllowK8sNamespacesSet: allowK8sNamespaces, DenyK8sNamespacesSet: denyK8sNamespaces, EnableNamespaces: c.flagEnableNamespaces, diff --git a/control-plane/subcommand/inject-connect/command_test.go b/control-plane/subcommand/inject-connect/command_test.go index 5273d10313..a0417a9079 100644 --- a/control-plane/subcommand/inject-connect/command_test.go +++ b/control-plane/subcommand/inject-connect/command_test.go @@ -47,6 +47,16 @@ func TestRun_FlagValidation(t *testing.T) { "-ca-file", "bar"}, expErr: "error reading Consul's CA cert file \"bar\"", }, + { + flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", + "-enable-partitions", "true"}, + expErr: "-partition-name must set if -enable-partitions is set to 'true'", + }, + { + flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", + "-partition-name", "default"}, + expErr: "-enable-partitions must be set to 'true' if -partition-name is set", + }, { flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", "-default-sidecar-proxy-cpu-limit=unparseable"}, From 3623c6e304874455bbded2fca3a937eae05040c2 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 15 Sep 2021 18:02:38 -0400 Subject: [PATCH 028/418] Update ConfigEntries to be Partition aware (#724) * Add partition support to config entries * Fail if namespaces are not enabled and admin partitions are enabled --- .../templates/connect-inject-deployment.yaml | 1 + .../templates/controller-deployment.yaml | 4 ++ .../consul/templates/crd-servicedefaults.yaml | 8 ++++ .../templates/crd-serviceintentions.yaml | 3 ++ .../test/unit/connect-inject-deployment.bats | 13 +++++++ .../test/unit/controller-deployment.bats | 38 +++++++++++++++++++ .../api/v1alpha1/servicedefaults_types.go | 3 ++ .../v1alpha1/servicedefaults_types_test.go | 6 +++ .../api/v1alpha1/serviceintentions_types.go | 3 ++ .../v1alpha1/serviceintentions_types_test.go | 15 ++++++++ .../consul.hashicorp.com_servicedefaults.yaml | 8 ++++ ...onsul.hashicorp.com_serviceintentions.yaml | 3 ++ control-plane/go.mod | 2 +- control-plane/go.sum | 4 +- .../subcommand/controller/command.go | 9 ++++- control-plane/subcommand/flags/http.go | 4 ++ 16 files changed, 120 insertions(+), 4 deletions(-) diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index 28336027f5..ed7266d7ee 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -2,6 +2,7 @@ {{- if not (or (and (ne (.Values.client.enabled | toString) "-") .Values.client.enabled) (and (eq (.Values.client.enabled | toString) "-") .Values.global.enabled)) }}{{ fail "clients must be enabled for connect injection" }}{{ end }} {{- if not .Values.client.grpc }}{{ fail "client.grpc must be true for connect injection" }}{{ end }} {{- if and .Values.connectInject.consulNamespaces.mirroringK8S (not .Values.global.enableConsulNamespaces) }}{{ fail "global.enableConsulNamespaces must be true if mirroringK8S=true" }}{{ end }} +{{- if and .Values.global.adminPartitions.enabled (not .Values.global.enableConsulNamespaces) }}{{ fail "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" }}{{ end }} {{- if .Values.connectInject.centralConfig }}{{- if eq (toString .Values.connectInject.centralConfig.enabled) "false" }}{{ fail "connectInject.centralConfig.enabled cannot be set to false; to disable, set enable_central_service_config to false in server.extraConfig and client.extraConfig" }}{{ end -}}{{ end -}} {{- if .Values.connectInject.centralConfig }}{{- if .Values.connectInject.centralConfig.defaultProtocol }}{{ fail "connectInject.centralConfig.defaultProtocol is no longer supported; instead you must migrate to CRDs (see www.consul.io/docs/k8s/crds/upgrade-to-crds)" }}{{ end }}{{ end -}} {{- if .Values.connectInject.centralConfig }}{{ if .Values.connectInject.centralConfig.proxyDefaults }}{{- if ne (trim .Values.connectInject.centralConfig.proxyDefaults) `{}` }}{{ fail "connectInject.centralConfig.proxyDefaults is no longer supported; instead you must migrate to CRDs (see www.consul.io/docs/k8s/crds/upgrade-to-crds)" }}{{ end }}{{ end }}{{ end -}} diff --git a/charts/consul/templates/controller-deployment.yaml b/charts/consul/templates/controller-deployment.yaml index 5cee3b4cde..151c08b1e8 100644 --- a/charts/consul/templates/controller-deployment.yaml +++ b/charts/consul/templates/controller-deployment.yaml @@ -1,4 +1,5 @@ {{- if .Values.controller.enabled }} +{{- if and .Values.global.adminPartitions.enabled (not .Values.global.enableConsulNamespaces) }}{{ fail "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" }}{{ end }} apiVersion: apps/v1 kind: Deployment metadata: @@ -64,6 +65,9 @@ spec: -log-json={{ .Values.global.logJSON }} \ -webhook-tls-cert-dir=/tmp/controller-webhook/certs \ -datacenter={{ .Values.global.datacenter }} \ + {{- if .Values.global.adminPartitions.enabled }} + -partition={{ .Values.global.adminPartitions.name }} \ + {{- end }} -enable-leader-election \ {{- if .Values.global.enableConsulNamespaces }} -enable-namespaces=true \ diff --git a/charts/consul/templates/crd-servicedefaults.yaml b/charts/consul/templates/crd-servicedefaults.yaml index 5f6443be43..329a4d35bd 100644 --- a/charts/consul/templates/crd-servicedefaults.yaml +++ b/charts/consul/templates/crd-servicedefaults.yaml @@ -206,6 +206,10 @@ spec: description: Namespace is only accepted within a service-defaults config entry. type: string + partition: + description: Partition is only accepted within a service-defaults + config entry. + type: string passiveHealthCheck: description: PassiveHealthCheck configuration determines how upstream proxy instances will be monitored for removal from @@ -294,6 +298,10 @@ spec: description: Namespace is only accepted within a service-defaults config entry. type: string + partition: + description: Partition is only accepted within a service-defaults + config entry. + type: string passiveHealthCheck: description: PassiveHealthCheck configuration determines how upstream proxy instances will be monitored for removal diff --git a/charts/consul/templates/crd-serviceintentions.yaml b/charts/consul/templates/crd-serviceintentions.yaml index d3c8dbe45a..7901083e3f 100644 --- a/charts/consul/templates/crd-serviceintentions.yaml +++ b/charts/consul/templates/crd-serviceintentions.yaml @@ -96,6 +96,9 @@ spec: namespace: description: Namespace is the namespace for the Name parameter. type: string + partition: + description: Partition is the Admin Partition for the Name parameter. + type: string permissions: description: Permissions is the list of all additional L7 attributes that extend the intention match criteria. Permission precedence diff --git a/charts/consul/test/unit/connect-inject-deployment.bats b/charts/consul/test/unit/connect-inject-deployment.bats index 03fbfbc592..8d78e0fdc7 100755 --- a/charts/consul/test/unit/connect-inject-deployment.bats +++ b/charts/consul/test/unit/connect-inject-deployment.bats @@ -694,6 +694,7 @@ EOF local actual=$(helm template \ -s templates/connect-inject-deployment.yaml \ --set 'connectInject.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].command | any(contains("enable-partitions"))' | tee /dev/stderr) @@ -706,6 +707,7 @@ EOF -s templates/connect-inject-deployment.yaml \ --set 'connectInject.enabled=true' \ --set 'global.adminPartitions.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].command | any(contains("enable-partitions"))' | tee /dev/stderr) @@ -724,6 +726,17 @@ EOF [ "${actual}" = "true" ] } +@test "connectInject/Deployment: fails if namespaces are disabled and .global.adminPartitions.enabled=true" { + cd `chart_dir` + run helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enableConsulNamespaces=false' \ + --set 'connectInject.enabled=true' . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" ]] +} + #-------------------------------------------------------------------- # namespaces diff --git a/charts/consul/test/unit/controller-deployment.bats b/charts/consul/test/unit/controller-deployment.bats index d78b7654c5..158c6edaaa 100644 --- a/charts/consul/test/unit/controller-deployment.bats +++ b/charts/consul/test/unit/controller-deployment.bats @@ -190,6 +190,44 @@ load _helpers [ "${actual}" = "" ] } +#-------------------------------------------------------------------- +# partitions + +@test "controller/Deployment: partitions options disabled by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/controller-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | any(contains("partition"))' | tee /dev/stderr) + + [ "${actual}" = "false" ] +} + +@test "controller/Deployment: partition name set with .global.adminPartitions.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/controller-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | any(contains("partition=default"))' | tee /dev/stderr) + + [ "${actual}" = "true" ] +} + +@test "controller/Deployment: fails if namespaces are disabled and .global.adminPartitions.enabled=true" { + cd `chart_dir` + run helm template \ + -s templates/controller-deployment.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enableConsulNamespaces=false' \ + --set 'controller.enabled=true' . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" ]] +} #-------------------------------------------------------------------- # namespaces diff --git a/control-plane/api/v1alpha1/servicedefaults_types.go b/control-plane/api/v1alpha1/servicedefaults_types.go index ba3127bd4a..8ad227b671 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types.go +++ b/control-plane/api/v1alpha1/servicedefaults_types.go @@ -89,6 +89,8 @@ type Upstream struct { Name string `json:"name,omitempty"` // Namespace is only accepted within a service-defaults config entry. Namespace string `json:"namespace,omitempty"` + // Partition is only accepted within a service-defaults config entry. + Partition string `json:"partition,omitempty"` // EnvoyListenerJSON is a complete override ("escape hatch") for the upstream's // listener. // Note: This escape hatch is NOT compatible with the discovery chain and @@ -322,6 +324,7 @@ func (in *Upstream) toConsul() *capi.UpstreamConfig { return &capi.UpstreamConfig{ Name: in.Name, Namespace: in.Namespace, + Partition: in.Partition, EnvoyListenerJSON: in.EnvoyListenerJSON, EnvoyClusterJSON: in.EnvoyClusterJSON, Protocol: in.Protocol, diff --git a/control-plane/api/v1alpha1/servicedefaults_types_test.go b/control-plane/api/v1alpha1/servicedefaults_types_test.go index d4d0696ae1..04f86de8eb 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types_test.go +++ b/control-plane/api/v1alpha1/servicedefaults_types_test.go @@ -68,6 +68,7 @@ func TestServiceDefaults_ToConsul(t *testing.T) { Defaults: &Upstream{ Name: "upstream-default", Namespace: "ns", + Partition: "part", EnvoyListenerJSON: `{"key": "value"}`, EnvoyClusterJSON: `{"key": "value"}`, Protocol: "http2", @@ -91,6 +92,7 @@ func TestServiceDefaults_ToConsul(t *testing.T) { { Name: "upstream-override-1", Namespace: "ns", + Partition: "part", EnvoyListenerJSON: `{"key": "value"}`, EnvoyClusterJSON: `{"key": "value"}`, Protocol: "http2", @@ -113,6 +115,7 @@ func TestServiceDefaults_ToConsul(t *testing.T) { { Name: "upstream-default", Namespace: "ns", + Partition: "part", EnvoyListenerJSON: `{"key": "value"}`, EnvoyClusterJSON: `{"key": "value"}`, Protocol: "http2", @@ -169,6 +172,7 @@ func TestServiceDefaults_ToConsul(t *testing.T) { Defaults: &capi.UpstreamConfig{ Name: "upstream-default", Namespace: "ns", + Partition: "part", EnvoyListenerJSON: `{"key": "value"}`, EnvoyClusterJSON: `{"key": "value"}`, Protocol: "http2", @@ -190,6 +194,7 @@ func TestServiceDefaults_ToConsul(t *testing.T) { { Name: "upstream-override-1", Namespace: "ns", + Partition: "part", EnvoyListenerJSON: `{"key": "value"}`, EnvoyClusterJSON: `{"key": "value"}`, Protocol: "http2", @@ -210,6 +215,7 @@ func TestServiceDefaults_ToConsul(t *testing.T) { { Name: "upstream-default", Namespace: "ns", + Partition: "part", EnvoyListenerJSON: `{"key": "value"}`, EnvoyClusterJSON: `{"key": "value"}`, Protocol: "http2", diff --git a/control-plane/api/v1alpha1/serviceintentions_types.go b/control-plane/api/v1alpha1/serviceintentions_types.go index 8abfe41ef9..4a9aba6eca 100644 --- a/control-plane/api/v1alpha1/serviceintentions_types.go +++ b/control-plane/api/v1alpha1/serviceintentions_types.go @@ -77,6 +77,8 @@ type SourceIntention struct { Name string `json:"name,omitempty"` // Namespace is the namespace for the Name parameter. Namespace string `json:"namespace,omitempty"` + // Partition is the Admin Partition for the Name parameter. + Partition string `json:"partition,omitempty"` // Action is required for an L4 intention, and should be set to one of // "allow" or "deny" for the action that should be taken if this intention matches a request. Action IntentionAction `json:"action,omitempty"` @@ -306,6 +308,7 @@ func (in *SourceIntention) toConsul() *capi.SourceIntention { return &capi.SourceIntention{ Name: in.Name, Namespace: in.Namespace, + Partition: in.Partition, Action: in.Action.toConsul(), Permissions: in.Permissions.toConsul(), Description: in.Description, diff --git a/control-plane/api/v1alpha1/serviceintentions_types_test.go b/control-plane/api/v1alpha1/serviceintentions_types_test.go index 27dfdb41f4..37c6808e4e 100644 --- a/control-plane/api/v1alpha1/serviceintentions_types_test.go +++ b/control-plane/api/v1alpha1/serviceintentions_types_test.go @@ -51,18 +51,21 @@ func TestServiceIntentions_MatchesConsul(t *testing.T) { { Name: "svc1", Namespace: "test", + Partition: "test", Action: "allow", Description: "allow access from svc1", }, { Name: "*", Namespace: "not-test", + Partition: "not-test", Action: "deny", Description: "disallow access from namespace not-test", }, { Name: "svc-2", Namespace: "bar", + Partition: "bar", Permissions: IntentionPermissions{ { Action: "allow", @@ -101,6 +104,7 @@ func TestServiceIntentions_MatchesConsul(t *testing.T) { { Name: "svc1", Namespace: "test", + Partition: "test", Action: "allow", Precedence: 0, Description: "allow access from svc1", @@ -108,6 +112,7 @@ func TestServiceIntentions_MatchesConsul(t *testing.T) { { Name: "*", Namespace: "not-test", + Partition: "not-test", Action: "deny", Precedence: 1, Description: "disallow access from namespace not-test", @@ -115,6 +120,7 @@ func TestServiceIntentions_MatchesConsul(t *testing.T) { { Name: "svc-2", Namespace: "bar", + Partition: "bar", Permissions: []*capi.IntentionPermission{ { Action: "allow", @@ -249,18 +255,21 @@ func TestServiceIntentions_ToConsul(t *testing.T) { { Name: "svc1", Namespace: "test", + Partition: "test", Action: "allow", Description: "allow access from svc1", }, { Name: "*", Namespace: "not-test", + Partition: "not-test", Action: "deny", Description: "disallow access from namespace not-test", }, { Name: "svc-2", Namespace: "bar", + Partition: "bar", Permissions: IntentionPermissions{ { Action: "allow", @@ -299,18 +308,21 @@ func TestServiceIntentions_ToConsul(t *testing.T) { { Name: "svc1", Namespace: "test", + Partition: "test", Action: "allow", Description: "allow access from svc1", }, { Name: "*", Namespace: "not-test", + Partition: "not-test", Action: "deny", Description: "disallow access from namespace not-test", }, { Name: "svc-2", Namespace: "bar", + Partition: "bar", Permissions: []*capi.IntentionPermission{ { Action: "allow", @@ -601,16 +613,19 @@ func TestServiceIntentions_Validate(t *testing.T) { { Name: "web", Namespace: "web", + Partition: "web", Action: "allow", }, { Name: "db", Namespace: "db", + Partition: "db", Action: "deny", }, { Name: "bar", Namespace: "bar", + Partition: "bar", Permissions: IntentionPermissions{ { Action: "allow", 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 bed1204c43..08da8480f1 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml @@ -200,6 +200,10 @@ spec: description: Namespace is only accepted within a service-defaults config entry. type: string + partition: + description: Partition is only accepted within a service-defaults + config entry. + type: string passiveHealthCheck: description: PassiveHealthCheck configuration determines how upstream proxy instances will be monitored for removal from @@ -288,6 +292,10 @@ spec: description: Namespace is only accepted within a service-defaults config entry. type: string + partition: + description: Partition is only accepted within a service-defaults + config entry. + type: string passiveHealthCheck: description: PassiveHealthCheck configuration determines how upstream proxy instances will be monitored for removal 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 b2af5c1ea2..d3420d1e77 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml @@ -90,6 +90,9 @@ spec: namespace: description: Namespace is the namespace for the Name parameter. type: string + partition: + description: Partition is the Admin Partition for the Name parameter. + type: string permissions: description: Permissions is the list of all additional L7 attributes that extend the intention match criteria. Permission precedence diff --git a/control-plane/go.mod b/control-plane/go.mod index b15a09db4b..adaedabaef 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/go-cmp v0.5.6 github.com/google/go-querystring v1.0.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/hashicorp/consul/api v1.4.1-0.20210827004034-d2e50fd130ae + github.com/hashicorp/consul/api v1.10.1-0.20210913215352-5b658d2f392d github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f diff --git a/control-plane/go.sum b/control-plane/go.sum index c3d4b34654..7a0487c1db 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -284,8 +284,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.4.1-0.20210827004034-d2e50fd130ae h1:eWcikXQgBN6yrsbANCTieR1uT+a7WoYYvGUFj8enPow= -github.com/hashicorp/consul/api v1.4.1-0.20210827004034-d2e50fd130ae/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= +github.com/hashicorp/consul/api v1.10.1-0.20210913215352-5b658d2f392d h1:IBMYvG34CbxQqM55tBk8aVtmIQxvcczI0BqyxmbQDBs= +github.com/hashicorp/consul/api v1.10.1-0.20210913215352-5b658d2f392d/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= diff --git a/control-plane/subcommand/controller/command.go b/control-plane/subcommand/controller/command.go index 939ef86775..1e574d539f 100644 --- a/control-plane/subcommand/controller/command.go +++ b/control-plane/subcommand/controller/command.go @@ -7,9 +7,11 @@ import ( "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/consul" "github.com/hashicorp/consul-k8s/control-plane/controller" cmdCommon "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" + "github.com/hashicorp/consul/api" "github.com/mitchellh/cli" "go.uber.org/zap/zapcore" "k8s.io/apimachinery/pkg/runtime" @@ -30,6 +32,7 @@ type Command struct { flagEnableLeaderElection bool flagEnableWebhooks bool flagDatacenter string + flagPartition string flagLogLevel string flagLogJSON bool @@ -62,6 +65,8 @@ func (c *Command) init() { "Enabling this will ensure there is only one active controller manager.") c.flagSet.StringVar(&c.flagDatacenter, "datacenter", "", "Name of the Consul datacenter the controller is operating in. This is added as metadata on managed custom resources.") + c.flagSet.StringVar(&c.flagPartition, "partition", "", + "Name of the Consul Admin Partition the controller is operating in. The config entries are created in this partition.") c.flagSet.BoolVar(&c.flagEnableNamespaces, "enable-namespaces", false, "[Enterprise Only] Enables Consul Enterprise namespaces, in either a single Consul namespace or mirrored.") c.flagSet.StringVar(&c.flagConsulDestinationNamespace, "consul-destination-namespace", "default", @@ -128,7 +133,9 @@ func (c *Command) Run(args []string) int { return 1 } - consulClient, err := c.httpFlags.APIClient() + cfg := api.DefaultConfig() + c.httpFlags.MergeOntoConfig(cfg) + consulClient, err := consul.NewClient(cfg) if err != nil { setupLog.Error(err, "connecting to Consul agent") return 1 diff --git a/control-plane/subcommand/flags/http.go b/control-plane/subcommand/flags/http.go index 8830ad5e00..b88acafcfd 100644 --- a/control-plane/subcommand/flags/http.go +++ b/control-plane/subcommand/flags/http.go @@ -23,6 +23,7 @@ type HTTPFlags struct { certFile StringValue keyFile StringValue tlsServerName StringValue + partition StringValue } func (f *HTTPFlags) Flags() *flag.FlagSet { @@ -56,6 +57,8 @@ func (f *HTTPFlags) Flags() *flag.FlagSet { fs.Var(&f.tlsServerName, "tls-server-name", "The server name to use as the SNI host when connecting via TLS. This "+ "can also be specified via the CONSUL_TLS_SERVER_NAME environment variable.") + fs.Var(&f.partition, "partition", + "[Enterprise Only] Name of the Consul Admin Partition the controller is operating in. The config entries are created in this partition.") return fs } @@ -110,6 +113,7 @@ func (f *HTTPFlags) MergeOntoConfig(c *api.Config) { f.certFile.Merge(&c.TLSConfig.CertFile) f.keyFile.Merge(&c.TLSConfig.KeyFile) f.tlsServerName.Merge(&c.TLSConfig.Address) + f.partition.Merge(&c.Partition) } func Merge(dst, src *flag.FlagSet) { From 0b073c6b5ca0d9e237fead1e127d1603d6375b65 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 17 Sep 2021 08:21:02 -0400 Subject: [PATCH 029/418] Add Admin Partition support to ingress and terminating gateways. --- .../ingress-gateways-deployment.yaml | 10 ++++ .../terminating-gateways-deployment.yaml | 10 ++++ .../unit/ingress-gateways-deployment.bats | 51 +++++++++++++++++++ .../unit/terminating-gateways-deployment.bats | 51 +++++++++++++++++++ 4 files changed, 122 insertions(+) diff --git a/charts/consul/templates/ingress-gateways-deployment.yaml b/charts/consul/templates/ingress-gateways-deployment.yaml index 6d63d361af..36671fb2b8 100644 --- a/charts/consul/templates/ingress-gateways-deployment.yaml +++ b/charts/consul/templates/ingress-gateways-deployment.yaml @@ -1,6 +1,7 @@ {{- if .Values.ingressGateways.enabled }} {{- if not .Values.connectInject.enabled }}{{ fail "connectInject.enabled must be true" }}{{ end -}} {{- if not .Values.client.grpc }}{{ fail "client.grpc must be true" }}{{ end -}} +{{- if and .Values.global.adminPartitions.enabled (not .Values.global.enableConsulNamespaces) }}{{ fail "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" }}{{ end }} {{- if not (or (and (ne (.Values.client.enabled | toString) "-") .Values.client.enabled) (and (eq (.Values.client.enabled | toString) "-") .Values.global.enabled)) }}{{ fail "clients must be enabled" }}{{ end -}} {{- if .Values.global.lifecycleSidecarContainer }}{{ fail "global.lifecycleSidecarContainer has been renamed to global.consulSidecarContainer. Please set values using global.consulSidecarContainer." }}{{ end }} @@ -217,6 +218,9 @@ spec: {{- if $root.Values.global.enableConsulNamespaces }} namespace = "{{ (default $defaults.consulNamespace .consulNamespace) }}" {{- end }} + {{- if $root.Values.global.adminPartitions.enabled }} + partition = "{{ $root.Values.global.adminPartitions.name }}" + {{- end }} port = ${WAN_PORT} address = "${WAN_ADDR}" tagged_addresses { @@ -340,6 +344,9 @@ spec: {{- if $root.Values.global.enableConsulNamespaces }} - -namespace={{ default $defaults.consulNamespace .consulNamespace }} {{- end }} + {{- if $root.Values.global.adminPartitions.enabled }} + - -partition={{ $root.Values.global.adminPartitions.name }} + {{- end }} livenessProbe: tcpSocket: port: 21000 @@ -374,6 +381,9 @@ spec: {{- if $root.Values.global.enableConsulNamespaces }} -namespace={{ default $defaults.consulNamespace .consulNamespace }} \ {{- end }} + {{- if $root.Values.global.adminPartitions.enabled }} + -partition={{ $root.Values.global.adminPartitions.name }} \ + {{- end }} -id="${POD_NAME}" # consul-sidecar ensures the ingress gateway is always registered with diff --git a/charts/consul/templates/terminating-gateways-deployment.yaml b/charts/consul/templates/terminating-gateways-deployment.yaml index f1a1a2fb26..a53743918d 100644 --- a/charts/consul/templates/terminating-gateways-deployment.yaml +++ b/charts/consul/templates/terminating-gateways-deployment.yaml @@ -1,6 +1,7 @@ {{- if .Values.terminatingGateways.enabled }} {{- if not .Values.connectInject.enabled }}{{ fail "connectInject.enabled must be true" }}{{ end -}} {{- if not .Values.client.grpc }}{{ fail "client.grpc must be true" }}{{ end -}} +{{- if and .Values.global.adminPartitions.enabled (not .Values.global.enableConsulNamespaces) }}{{ fail "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" }}{{ end }} {{- if not (or (and (ne (.Values.client.enabled | toString) "-") .Values.client.enabled) (and (eq (.Values.client.enabled | toString) "-") .Values.global.enabled)) }}{{ fail "clients must be enabled" }}{{ end -}} {{- if .Values.global.lifecycleSidecarContainer }}{{ fail "global.lifecycleSidecarContainer has been renamed to global.consulSidecarContainer. Please set values using global.consulSidecarContainer." }}{{ end }} @@ -183,6 +184,9 @@ spec: {{- if $root.Values.global.enableConsulNamespaces }} namespace = "{{ (default $defaults.consulNamespace .consulNamespace) }}" {{- end }} + {{- if $root.Values.global.adminPartitions.enabled }} + partition = "{{ $root.Values.global.adminPartitions.name }}" + {{- end }} address = "${POD_IP}" port = 8443 {{- if (and $root.Values.global.metrics.enabled $root.Values.global.metrics.enableGatewayMetrics) }} @@ -290,6 +294,9 @@ spec: {{- if $root.Values.global.enableConsulNamespaces }} - -namespace={{ default $defaults.consulNamespace .consulNamespace }} {{- end }} + {{- if $root.Values.global.adminPartitions.enabled }} + - -partition={{ $root.Values.global.adminPartitions.name }} + {{- end }} livenessProbe: tcpSocket: port: 8443 @@ -320,6 +327,9 @@ spec: {{- if $root.Values.global.enableConsulNamespaces }} -namespace={{ default $defaults.consulNamespace .consulNamespace }} \ {{- end }} + {{- if $root.Values.global.adminPartitions.enabled }} + -partition={{ $root.Values.global.adminPartitions.name }} \ + {{- end }} -id="${POD_NAME}" # consul-sidecar ensures the terminating gateway is always registered with diff --git a/charts/consul/test/unit/ingress-gateways-deployment.bats b/charts/consul/test/unit/ingress-gateways-deployment.bats index 15fd1e1ef0..c4b623e4be 100644 --- a/charts/consul/test/unit/ingress-gateways-deployment.bats +++ b/charts/consul/test/unit/ingress-gateways-deployment.bats @@ -1405,6 +1405,57 @@ EOF [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# partitions + +@test "ingressGateways/Deployment: partition command flag is not present by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq -s -r '.[0].spec.template.spec.containers[0]' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.command | any(contains("-partition"))' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(echo $object | yq -r '.lifecycle.preStop.exec.command | any(contains("-partition"))' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "ingressGateways/Deployment: partition command flag is specified through partition name" { + cd `chart_dir` + local object=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=default' \ + . | tee /dev/stderr | + yq -s -r '.[0].spec.template.spec.containers[0]' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.command | any(contains("-partition=default"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | yq -r '.lifecycle.preStop.exec.command | any(contains("-partition=default"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "ingressGateways/Deployment: fails if admin partitions are enabled but namespaces aren't" { + cd `chart_dir` + run helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.enableConsulNamespaces=false' \ + --set 'global.adminPartitions.enabled=true' . + + [ "$status" -eq 1 ] + [[ "$output" =~ "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" ]] +} + #-------------------------------------------------------------------- # multiple gateways diff --git a/charts/consul/test/unit/terminating-gateways-deployment.bats b/charts/consul/test/unit/terminating-gateways-deployment.bats index b0e82ba4f2..5a36e639be 100644 --- a/charts/consul/test/unit/terminating-gateways-deployment.bats +++ b/charts/consul/test/unit/terminating-gateways-deployment.bats @@ -1215,6 +1215,57 @@ EOF [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# partitions + +@test "terminatingGateways/Deployment: partition command flag is not present by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/terminating-gateways-deployment.yaml \ + --set 'terminatingGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq -s -r '.[0].spec.template.spec.containers[0]' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.command | any(contains("-partition"))' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(echo $object | yq -r '.lifecycle.preStop.exec.command | any(contains("-partition"))' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "terminatingGateways/Deployment: partition command flag is specified through partition name" { + cd `chart_dir` + local object=$(helm template \ + -s templates/terminating-gateways-deployment.yaml \ + --set 'terminatingGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=default' \ + . | tee /dev/stderr | + yq -s -r '.[0].spec.template.spec.containers[0]' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.command | any(contains("-partition=default"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | yq -r '.lifecycle.preStop.exec.command | any(contains("-partition=default"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "terminatingGateways/Deployment: fails if admin partitions are enabled but namespaces aren't" { + cd `chart_dir` + run helm template \ + -s templates/terminating-gateways-deployment.yaml \ + --set 'terminatingGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.enableConsulNamespaces=false' \ + --set 'global.adminPartitions.enabled=true' . + + [ "$status" -eq 1 ] + [[ "$output" =~ "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" ]] +} + #-------------------------------------------------------------------- # multiple gateways From fbb6ced3f585901fe815a393767a25e3449f464d Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 17 Sep 2021 08:22:16 -0400 Subject: [PATCH 030/418] Fix tests and use "-partition" flag --- .circleci/config.yml | 4 +-- .../templates/connect-inject-deployment.yaml | 2 +- .../test/unit/connect-inject-deployment.bats | 12 --------- .../api/v1alpha1/ingressgateway_types.go | 2 +- control-plane/api/v1alpha1/mesh_types.go | 2 +- .../api/v1alpha1/proxydefaults_types.go | 2 +- .../api/v1alpha1/servicedefaults_types.go | 2 +- .../api/v1alpha1/serviceintentions_types.go | 2 +- .../api/v1alpha1/serviceresolver_types.go | 2 +- .../api/v1alpha1/servicerouter_types.go | 2 +- .../api/v1alpha1/servicesplitter_types.go | 2 +- .../api/v1alpha1/terminatinggateway_types.go | 2 +- .../endpoints_controller_ent_test.go | 4 +-- .../endpoints_controller_test.go | 25 +++---------------- control-plane/go.mod | 2 +- control-plane/go.sum | 2 ++ .../subcommand/connect-init/command.go | 3 --- .../connect-init/command_ent_test.go | 1 - .../subcommand/controller/command.go | 3 --- control-plane/subcommand/flags/http.go | 6 ++++- control-plane/subcommand/flags/usage_test.go | 4 +++ .../subcommand/inject-connect/command.go | 15 +++++------ .../subcommand/inject-connect/command_test.go | 2 +- 23 files changed, 36 insertions(+), 67 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e7435d7449..f4da6ac895 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,8 +9,8 @@ executors: - image: docker.mirror.hashicorp.services/circleci/golang:1.16 environment: TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.10.2 # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.10.2+ent # Consul's enterprise version to use in tests + CONSUL_VERSION: 1.11.0-alpha # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.0+ent-alpha # Consul's enterprise version to use in tests control-plane-path : &control-plane-path control-plane acceptance-test-path: &acceptance-test-path charts/consul/test/acceptance diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index ed7266d7ee..f3f9f9a754 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -134,7 +134,7 @@ spec: {{- end }} {{- if .Values.global.adminPartitions.enabled }} -enable-partitions=true \ - -partition-name={{ .Values.global.adminPartitions.name }} \ + -partition={{ .Values.global.adminPartitions.name }} \ {{- end }} {{- if .Values.global.enableConsulNamespaces }} -enable-namespaces=true \ diff --git a/charts/consul/test/unit/connect-inject-deployment.bats b/charts/consul/test/unit/connect-inject-deployment.bats index 8d78e0fdc7..75df185d3f 100755 --- a/charts/consul/test/unit/connect-inject-deployment.bats +++ b/charts/consul/test/unit/connect-inject-deployment.bats @@ -714,18 +714,6 @@ EOF [ "${actual}" = "true" ] } -@test "connectInject/Deployment: partition name set with .global.adminPartitions.enabled=true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/connect-inject-deployment.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.adminPartitions.enabled=true' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command | any(contains("partition-name=default"))' | tee /dev/stderr) - - [ "${actual}" = "true" ] -} - @test "connectInject/Deployment: fails if namespaces are disabled and .global.adminPartitions.enabled=true" { cd `chart_dir` run helm template \ diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index 6813b51f35..4dbe4cc03a 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -210,7 +210,7 @@ func (in *IngressGateway) MatchesConsul(candidate capi.ConfigEntry) bool { return false } // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.IngressGatewayConfigEntry{}, "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.IngressGatewayConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } func (in *IngressGateway) Validate(namespacesEnabled bool) error { diff --git a/control-plane/api/v1alpha1/mesh_types.go b/control-plane/api/v1alpha1/mesh_types.go index c637c1a783..671da5c8e7 100644 --- a/control-plane/api/v1alpha1/mesh_types.go +++ b/control-plane/api/v1alpha1/mesh_types.go @@ -150,7 +150,7 @@ func (in *Mesh) MatchesConsul(candidate capi.ConfigEntry) bool { return false } // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.MeshConfigEntry{}, "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.MeshConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } func (in *Mesh) Validate(_ bool) error { diff --git a/control-plane/api/v1alpha1/proxydefaults_types.go b/control-plane/api/v1alpha1/proxydefaults_types.go index bf4024eafa..a296962d11 100644 --- a/control-plane/api/v1alpha1/proxydefaults_types.go +++ b/control-plane/api/v1alpha1/proxydefaults_types.go @@ -174,7 +174,7 @@ func (in *ProxyDefaults) MatchesConsul(candidate api.ConfigEntry) bool { return false } // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ProxyConfigEntry{}, "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty(), + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ProxyConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty(), cmp.Comparer(transparentProxyConfigComparer)) } diff --git a/control-plane/api/v1alpha1/servicedefaults_types.go b/control-plane/api/v1alpha1/servicedefaults_types.go index 8ad227b671..339f7ff32d 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types.go +++ b/control-plane/api/v1alpha1/servicedefaults_types.go @@ -367,7 +367,7 @@ func (in *ServiceDefaults) MatchesConsul(candidate capi.ConfigEntry) bool { return false } // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ServiceConfigEntry{}, "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty(), + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ServiceConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty(), cmp.Comparer(transparentProxyConfigComparer)) } diff --git a/control-plane/api/v1alpha1/serviceintentions_types.go b/control-plane/api/v1alpha1/serviceintentions_types.go index 4a9aba6eca..50dcb98476 100644 --- a/control-plane/api/v1alpha1/serviceintentions_types.go +++ b/control-plane/api/v1alpha1/serviceintentions_types.go @@ -235,7 +235,7 @@ func (in *ServiceIntentions) MatchesConsul(candidate api.ConfigEntry) bool { return cmp.Equal( in.ToConsul(""), configEntry, - cmpopts.IgnoreFields(capi.ServiceIntentionsConfigEntry{}, "Namespace", "Meta", "ModifyIndex", "CreateIndex"), + cmpopts.IgnoreFields(capi.ServiceIntentionsConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreFields(capi.SourceIntention{}, "LegacyID", "LegacyMeta", "LegacyCreateTime", "LegacyUpdateTime", "Precedence", "Type"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty(), diff --git a/control-plane/api/v1alpha1/serviceresolver_types.go b/control-plane/api/v1alpha1/serviceresolver_types.go index d606cfdf30..ef8f69db2e 100644 --- a/control-plane/api/v1alpha1/serviceresolver_types.go +++ b/control-plane/api/v1alpha1/serviceresolver_types.go @@ -281,7 +281,7 @@ func (in *ServiceResolver) MatchesConsul(candidate capi.ConfigEntry) bool { return false } // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ServiceResolverConfigEntry{}, "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ServiceResolverConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } func (in *ServiceResolver) ConsulGlobalResource() bool { diff --git a/control-plane/api/v1alpha1/servicerouter_types.go b/control-plane/api/v1alpha1/servicerouter_types.go index a1a86d7b80..a6077fff7f 100644 --- a/control-plane/api/v1alpha1/servicerouter_types.go +++ b/control-plane/api/v1alpha1/servicerouter_types.go @@ -240,7 +240,7 @@ func (in *ServiceRouter) MatchesConsul(candidate capi.ConfigEntry) bool { return false } // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ServiceRouterConfigEntry{}, "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ServiceRouterConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } func (in *ServiceRouter) Validate(namespacesEnabled bool) error { diff --git a/control-plane/api/v1alpha1/servicesplitter_types.go b/control-plane/api/v1alpha1/servicesplitter_types.go index 45e0e7cb66..97b9e65237 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types.go +++ b/control-plane/api/v1alpha1/servicesplitter_types.go @@ -159,7 +159,7 @@ func (in *ServiceSplitter) MatchesConsul(candidate capi.ConfigEntry) bool { return false } // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ServiceSplitterConfigEntry{}, "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ServiceSplitterConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } func (in *ServiceSplitter) Validate(namespacesEnabled bool) error { diff --git a/control-plane/api/v1alpha1/terminatinggateway_types.go b/control-plane/api/v1alpha1/terminatinggateway_types.go index d8138b1a42..18ede3b47d 100644 --- a/control-plane/api/v1alpha1/terminatinggateway_types.go +++ b/control-plane/api/v1alpha1/terminatinggateway_types.go @@ -173,7 +173,7 @@ func (in *TerminatingGateway) MatchesConsul(candidate capi.ConfigEntry) bool { return false } // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.TerminatingGatewayConfigEntry{}, "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.TerminatingGatewayConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } func (in *TerminatingGateway) Validate(namespacesEnabled bool) error { diff --git a/control-plane/connect-inject/endpoints_controller_ent_test.go b/control-plane/connect-inject/endpoints_controller_ent_test.go index 1ab5cfe254..4b75426346 100644 --- a/control-plane/connect-inject/endpoints_controller_ent_test.go +++ b/control-plane/connect-inject/endpoints_controller_ent_test.go @@ -308,7 +308,7 @@ func TestReconcileCreateEndpointWithNamespaces(t *testing.T) { require.NoError(t, err) require.EqualValues(t, 1, len(check)) // Ignoring Namespace because the response from ENT includes it and OSS does not. - var ignoredFields = []string{"Node", "Definition", "Namespace"} + var ignoredFields = []string{"Node", "Definition", "Namespace", "Partition"} require.True(t, cmp.Equal(check[setup.expectedAgentHealthChecks[i].CheckID], setup.expectedAgentHealthChecks[i], cmpopts.IgnoreFields(api.AgentCheck{}, ignoredFields...))) } } @@ -1308,7 +1308,7 @@ func TestReconcileUpdateEndpointWithNamespaces(t *testing.T) { require.NoError(t, err) require.EqualValues(t, 1, len(check)) // Ignoring Namespace because the response from ENT includes it and OSS does not. - var ignoredFields = []string{"Node", "Definition", "Namespace"} + var ignoredFields = []string{"Node", "Definition", "Namespace", "Partition"} require.True(t, cmp.Equal(check[tt.expectedAgentHealthChecks[i].CheckID], tt.expectedAgentHealthChecks[i], cmpopts.IgnoreFields(api.AgentCheck{}, ignoredFields...))) } } diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index 229a8618fd..5f1a0dadd8 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -351,25 +351,6 @@ func TestProcessUpstreams(t *testing.T) { consulNamespacesEnabled: true, consulPartitionsEnabled: true, }, - { - name: "single upstream with partition", - pod: func() *corev1.Pod { - pod1 := createPod("pod1", "1.2.3.4", true, true) - pod1.Annotations[annotationUpstreams] = "upstream.default.bar:1234" - return pod1 - }, - expected: []api.Upstream{ - { - DestinationType: api.UpstreamDestTypeService, - DestinationName: "upstream", - LocalBindPort: 1234, - DestinationNamespace: "default", - DestinationPartition: "bar", - }, - }, - consulNamespacesEnabled: false, - consulPartitionsEnabled: true, - }, { name: "multiple upstreams", pod: func() *corev1.Pod { @@ -1096,7 +1077,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { // of the regular require.Equal call since it supports ignoring certain // fields. diff := cmp.Diff(tt.expectedProxySvcInstances[i].ServiceProxy, instance.ServiceProxy, - cmpopts.IgnoreFields(api.Upstream{}, "DestinationNamespace")) + cmpopts.IgnoreFields(api.Upstream{}, "DestinationNamespace", "DestinationPartition")) require.Empty(t, diff, "expected objects to be equal") } @@ -1118,7 +1099,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { require.NoError(t, err) require.EqualValues(t, len(check), 1) // Ignoring Namespace because the response from ENT includes it and OSS does not. - var ignoredFields = []string{"Node", "Definition", "Namespace"} + var ignoredFields = []string{"Node", "Definition", "Namespace", "Partition"} require.True(t, cmp.Equal(check[tt.expectedAgentHealthChecks[i].CheckID], tt.expectedAgentHealthChecks[i], cmpopts.IgnoreFields(api.AgentCheck{}, ignoredFields...))) } } @@ -2464,7 +2445,7 @@ func TestReconcileUpdateEndpoint(t *testing.T) { require.NoError(t, err) require.EqualValues(t, len(check), 1) // Ignoring Namespace because the response from ENT includes it and OSS does not. - var ignoredFields = []string{"Node", "Definition", "Namespace"} + var ignoredFields = []string{"Node", "Definition", "Namespace", "Partition"} require.True(t, cmp.Equal(check[tt.expectedAgentHealthChecks[i].CheckID], tt.expectedAgentHealthChecks[i], cmpopts.IgnoreFields(api.AgentCheck{}, ignoredFields...))) } } diff --git a/control-plane/go.mod b/control-plane/go.mod index adaedabaef..cf90cff87d 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/go-cmp v0.5.6 github.com/google/go-querystring v1.0.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/hashicorp/consul/api v1.10.1-0.20210913215352-5b658d2f392d + github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f diff --git a/control-plane/go.sum b/control-plane/go.sum index 7a0487c1db..73b2ec8e4e 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -286,6 +286,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.10.1-0.20210913215352-5b658d2f392d h1:IBMYvG34CbxQqM55tBk8aVtmIQxvcczI0BqyxmbQDBs= github.com/hashicorp/consul/api v1.10.1-0.20210913215352-5b658d2f392d/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= +github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf h1:fouyN8SkrE4py09XaOru4PCM9zunem39CjOrMJMrKsc= +github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= diff --git a/control-plane/subcommand/connect-init/command.go b/control-plane/subcommand/connect-init/command.go index a131f77024..d8158b5f20 100644 --- a/control-plane/subcommand/connect-init/command.go +++ b/control-plane/subcommand/connect-init/command.go @@ -32,7 +32,6 @@ type Command struct { UI cli.Ui flagACLAuthMethod string // Auth Method to use for ACLs, if enabled. - flagPartition string // Admin Partition name. Consul Enterprise 1.11+ feature. flagPodName string // Pod name. flagPodNamespace string // Pod namespace. flagAuthMethodNamespace string // Consul namespace the auth-method is defined in. @@ -58,7 +57,6 @@ type Command struct { func (c *Command) init() { c.flagSet = flag.NewFlagSet("", flag.ContinueOnError) c.flagSet.StringVar(&c.flagACLAuthMethod, "acl-auth-method", "", "Name of the auth method to login to.") - c.flagSet.StringVar(&c.flagPartition, "partition", "", "Name of the Admin Partition of deployment.") c.flagSet.StringVar(&c.flagPodName, "pod-name", "", "Name of the pod.") c.flagSet.StringVar(&c.flagPodNamespace, "pod-namespace", "", "Name of the pod namespace.") c.flagSet.StringVar(&c.flagAuthMethodNamespace, "auth-method-namespace", "", "Consul namespace the auth-method is defined in") @@ -120,7 +118,6 @@ func (c *Command) Run(args []string) int { } } cfg := api.DefaultConfig() - cfg.Partition = c.flagPartition cfg.Namespace = c.flagConsulServiceNamespace c.http.MergeOntoConfig(cfg) consulClient, err := consul.NewClient(cfg) diff --git a/control-plane/subcommand/connect-init/command_ent_test.go b/control-plane/subcommand/connect-init/command_ent_test.go index 010d325794..83f456cb2e 100644 --- a/control-plane/subcommand/connect-init/command_ent_test.go +++ b/control-plane/subcommand/connect-init/command_ent_test.go @@ -188,7 +188,6 @@ func TestRun_ServicePollingWithACLsAndTLSWithNamespaces(t *testing.T) { tokenSinkFile: tokenFile, proxyIDFile: proxyFile, serviceRegistrationPollingAttempts: 5, - flagPartition: c.adminPartition, } // We build the http-addr because normally it's defined by the init container setting // CONSUL_HTTP_ADDR when it processes the command template. diff --git a/control-plane/subcommand/controller/command.go b/control-plane/subcommand/controller/command.go index 1e574d539f..0e7a84a540 100644 --- a/control-plane/subcommand/controller/command.go +++ b/control-plane/subcommand/controller/command.go @@ -32,7 +32,6 @@ type Command struct { flagEnableLeaderElection bool flagEnableWebhooks bool flagDatacenter string - flagPartition string flagLogLevel string flagLogJSON bool @@ -65,8 +64,6 @@ func (c *Command) init() { "Enabling this will ensure there is only one active controller manager.") c.flagSet.StringVar(&c.flagDatacenter, "datacenter", "", "Name of the Consul datacenter the controller is operating in. This is added as metadata on managed custom resources.") - c.flagSet.StringVar(&c.flagPartition, "partition", "", - "Name of the Consul Admin Partition the controller is operating in. The config entries are created in this partition.") c.flagSet.BoolVar(&c.flagEnableNamespaces, "enable-namespaces", false, "[Enterprise Only] Enables Consul Enterprise namespaces, in either a single Consul namespace or mirrored.") c.flagSet.StringVar(&c.flagConsulDestinationNamespace, "consul-destination-namespace", "default", diff --git a/control-plane/subcommand/flags/http.go b/control-plane/subcommand/flags/http.go index b88acafcfd..090ef3bad1 100644 --- a/control-plane/subcommand/flags/http.go +++ b/control-plane/subcommand/flags/http.go @@ -58,7 +58,7 @@ func (f *HTTPFlags) Flags() *flag.FlagSet { "The server name to use as the SNI host when connecting via TLS. This "+ "can also be specified via the CONSUL_TLS_SERVER_NAME environment variable.") fs.Var(&f.partition, "partition", - "[Enterprise Only] Name of the Consul Admin Partition the controller is operating in. The config entries are created in this partition.") + "[Enterprise Only] Name of the Consul Admin Partition to query. Default to \"default\" if Admin Partitions are enabled.") return fs } @@ -96,6 +96,10 @@ func (f *HTTPFlags) ReadTokenFile() (string, error) { return strings.TrimSpace(string(data)), nil } +func (f *HTTPFlags) Partition() string { + return f.partition.String() +} + func (f *HTTPFlags) APIClient() (*api.Client, error) { c := api.DefaultConfig() diff --git a/control-plane/subcommand/flags/usage_test.go b/control-plane/subcommand/flags/usage_test.go index 0b9c4793c9..2cf18ed166 100644 --- a/control-plane/subcommand/flags/usage_test.go +++ b/control-plane/subcommand/flags/usage_test.go @@ -47,6 +47,10 @@ HTTP API Options can also be set to HTTPS by setting the environment variable CONSUL_HTTP_SSL=true. + -partition= + [Enterprise Only] Name of the Consul Admin Partition to query. + Default to "default" if Admin Partitions are enabled. + -tls-server-name= The server name to use as the SNI host when connecting via TLS. This can also be specified via the CONSUL_TLS_SERVER_NAME diff --git a/control-plane/subcommand/inject-connect/command.go b/control-plane/subcommand/inject-connect/command.go index 1495c8d7c0..e93e07a48e 100644 --- a/control-plane/subcommand/inject-connect/command.go +++ b/control-plane/subcommand/inject-connect/command.go @@ -50,8 +50,7 @@ type Command struct { flagAllowK8sNamespacesList []string // K8s namespaces to explicitly inject flagDenyK8sNamespacesList []string // K8s namespaces to deny injection (has precedence) - flagEnablePartitions bool // Use Admin Partitions on all components - flagPartitionName string // Name of Admin Partition if enabled. + flagEnablePartitions bool // Use Admin Partitions on all components // Flags to support Consul namespaces flagEnableNamespaces bool // Use namespacing on all components @@ -146,8 +145,6 @@ func (c *Command) init() { c.flagSet.StringVar(&c.flagReleaseNamespace, "release-namespace", "default", "The Consul Helm installation namespace, e.g 'helm install --namespace '") c.flagSet.BoolVar(&c.flagEnablePartitions, "enable-partitions", false, "[Enterprise Only] Enables Admin Partitions.") - c.flagSet.StringVar(&c.flagPartitionName, "partition-name", "", - "[Enterprise Only] Name of the Admin Partition.") c.flagSet.BoolVar(&c.flagEnableNamespaces, "enable-namespaces", false, "[Enterprise Only] Enables namespaces, in either a single Consul namespace or mirrored.") c.flagSet.StringVar(&c.flagConsulDestinationNamespace, "consul-destination-namespace", "default", @@ -235,12 +232,14 @@ func (c *Command) Run(args []string) int { return 1 } - if c.flagEnablePartitions && c.flagPartitionName == "" { + if c.flagEnablePartitions && c.http.Partition() == "" { c.UI.Error("-partition-name must set if -enable-partitions is set to 'true'") + return 1 } - if c.flagPartitionName != "" && !c.flagEnablePartitions { + if c.http.Partition() != "" && !c.flagEnablePartitions { c.UI.Error("-enable-partitions must be set to 'true' if -partition-name is set") + return 1 } // Proxy resources. @@ -349,8 +348,6 @@ func (c *Command) Run(args []string) int { } } - cfg.Partition = c.flagPartitionName - // Set up Consul client. if c.consulClient == nil { var err error @@ -464,7 +461,7 @@ func (c *Command) Run(args []string) int { MetricsConfig: metricsConfig, InitContainerResources: initResources, ConsulSidecarResources: consulSidecarResources, - ConsulPartition: c.flagPartitionName, + ConsulPartition: c.http.Partition(), AllowK8sNamespacesSet: allowK8sNamespaces, DenyK8sNamespacesSet: denyK8sNamespaces, EnableNamespaces: c.flagEnableNamespaces, diff --git a/control-plane/subcommand/inject-connect/command_test.go b/control-plane/subcommand/inject-connect/command_test.go index a0417a9079..88dcd20768 100644 --- a/control-plane/subcommand/inject-connect/command_test.go +++ b/control-plane/subcommand/inject-connect/command_test.go @@ -54,7 +54,7 @@ func TestRun_FlagValidation(t *testing.T) { }, { flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", - "-partition-name", "default"}, + "-partition", "default"}, expErr: "-enable-partitions must be set to 'true' if -partition-name is set", }, { From f3f544df17a19d500c5e93e6927461bb86903bca Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 17 Sep 2021 09:10:46 -0400 Subject: [PATCH 031/418] Add Changelog --- CHANGELOG.md | 97 ++++++++++++++++++++++++++++++++++++++++++++ control-plane/go.sum | 2 - 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 16d5ddf4d9..ad3d26ed0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,103 @@ FEATURES: * CLI * The `consul-k8s` CLI enables users to deploy and operate Consul on Kubernetes. * Support `consul-k8s install` command. [[GH-713](https://github.com/hashicorp/consul-k8s/pull/713)] +* Helm Chart + * Add support for Admin Partitions. **(Consul Enterprise only)** + **ALPHA** [[GH-729](https://github.com/hashicorp/consul-k8s/pull/729)] + * This feature allows Consul to be deployed across multiple Kubernetes clusters while sharing a single set of Consul +servers. The services on each cluster can be independently managed. This feature is an alpha feature. It requires: + * a flat pod and node network in order for inter-partition networking to work. + * TLS to be enabled. + * Consul Namespaces enabled. + + Transparent Proxy is unsupported for cross partition communication. + +To enable Admin Partitions on the server cluster use the following config. + +```yaml +global: + enableConsulNamespaces: true + tls: + enabled: true + image: hashicorp/consul-enterprise:1.11.0-ent-alpha + adminPartitions: + enabled: true +server: + exposeGossipAndRPCPorts: true + enterpriseLicense: + secretName: license + secretKey: key +connectInject: + enabled: true + transparentProxy: + defaultEnabled: false + consulNamespaces: + mirroringK8S: true +controller: + enabled: true +``` + +Identify the LoadBalancer External IP of the `partition-service` + +```bash +kubectl get svc consul-consul-partition-service -o json | jq -r '.status.loadBalancer.ingress[0].ip' +``` + +Migrate the TLS CA credentials from the server cluster to the workload clusters + +```bash +kubectl get secret consul-consul-ca-key --context "server-context" -o yaml | kubectl apply --context "workload-context" -f - +kubectl get secret consul-consul-ca-cert --context "server-context" -o yaml | kubectl apply --context "workload-context" -f - +``` + +Configure the workload cluster using the following config. + +```yaml +global: + enabled: false + enableConsulNamespaces: true + image: hashicorp/consul-enterprise:1.11.0-ent-alpha + adminPartitions: + enabled: true + name: "alpha" # Name of Admin Partition + tls: + enabled: true + caCert: + secretName: consul-consul-ca-cert + secretKey: tls.crt + caKey: + secretName: consul-consul-ca-key + secretKey: tls.key +server: + enterpriseLicense: + secretName: license + secretKey: key +externalServers: + enabled: true + hosts: [ "loadbalancer IP" ] # external IP of partition service LB + tlsServerName: server.dc1.consul +client: + enabled: true + exposeGossipPorts: true + join: [ "loadbalancer IP" ] # external IP of partition service LB +connectInject: + enabled: true + consulNamespaces: + mirroringK8S: true +controller: + enabled: true +``` + +This should lead to the workload cluster having only Consul agents that connect with the Consul server. Services in this +cluster behave like independent services. They can be configured to communicate with services in other partitions by +configuring the upstream configuration on the individual services. + +* Control Plane + * Add support for Admin Partitions. **(Consul Enterprise only)** ** + ALPHA** [[GH-729](https://github.com/hashicorp/consul-k8s/pull/729)] + * Add Partition-Init job that runs in Kubernetes clusters that do not have servers running to provision Admin + Partitions. + * Update endpoints-controller, config-entry controller and config entries to add partition config to them. IMPROVEMENTS: * Helm Chart diff --git a/control-plane/go.sum b/control-plane/go.sum index 73b2ec8e4e..dffc93655e 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -284,8 +284,6 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.10.1-0.20210913215352-5b658d2f392d h1:IBMYvG34CbxQqM55tBk8aVtmIQxvcczI0BqyxmbQDBs= -github.com/hashicorp/consul/api v1.10.1-0.20210913215352-5b658d2f392d/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf h1:fouyN8SkrE4py09XaOru4PCM9zunem39CjOrMJMrKsc= github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= From c0b538a7485023fc184b150f8101f1e765c04c22 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 17 Sep 2021 13:10:21 -0400 Subject: [PATCH 032/418] Update chart version to consul-k8s 0.34.0 --- charts/consul/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index ebfb71a532..c5c603f99e 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: consul -version: 0.33.0 +version: 0.34.0 appVersion: 1.10.2 kubeVersion: ">=1.17.0-0" description: Official HashiCorp Consul Chart @@ -15,7 +15,7 @@ annotations: - name: consul image: hashicorp/consul:1.10.2 - name: consul-k8s-control-plane - image: hashicorp/consul-k8s-control-plane:0.33.0 + image: hashicorp/consul-k8s-control-plane:0.34.0 - name: envoy image: envoyproxy/envoy-alpine:v1.18.4 artifacthub.io/license: MPL-2.0 From a3e00be7a2ae675d6a9f804dc76f9bb36edaaf0c Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Fri, 17 Sep 2021 17:21:55 +0000 Subject: [PATCH 033/418] Release v0.34.0 --- CHANGELOG.md | 2 +- control-plane/version/version.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad3d26ed0f..e4b5447381 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.34.0 (September 17, 2021) FEATURES: * CLI * The `consul-k8s` CLI enables users to deploy and operate Consul on Kubernetes. diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 6107828dca..7ceeae9be6 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.33.0" + Version = "0.34.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 4516af800e8465c95742ef2c8e0acff67371380d Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Fri, 17 Sep 2021 17:36:31 +0000 Subject: [PATCH 034/418] Putting source back into Dev Mode --- CHANGELOG.md | 2 ++ control-plane/version/version.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4b5447381..4f77eee557 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## UNRELEASED + ## 0.34.0 (September 17, 2021) FEATURES: * CLI diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 7ceeae9be6..b13386cc0a 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 94ff1d81e2ceb367c3b808760520496370988e25 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 17 Sep 2021 17:10:03 -0400 Subject: [PATCH 035/418] Release 0.34.1 --- CHANGELOG.md | 4 ++++ charts/consul/Chart.yaml | 4 ++-- charts/consul/values.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f77eee557..70bea2362a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## UNRELEASED +BUG FIX: +* Helm + * Fix consul-k8s image version in values file. [[GH-732](https://github.com/hashicorp/consul-k8s/pull/732)] + ## 0.34.0 (September 17, 2021) FEATURES: * CLI diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index c5c603f99e..b76187558a 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: consul -version: 0.34.0 +version: 0.34.1 appVersion: 1.10.2 kubeVersion: ">=1.17.0-0" description: Official HashiCorp Consul Chart @@ -15,7 +15,7 @@ annotations: - name: consul image: hashicorp/consul:1.10.2 - name: consul-k8s-control-plane - image: hashicorp/consul-k8s-control-plane:0.34.0 + image: hashicorp/consul-k8s-control-plane:0.34.1 - name: envoy image: envoyproxy/envoy-alpine:v1.18.4 artifacthub.io/license: MPL-2.0 diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 6e74e98ae6..e1c0726deb 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -105,7 +105,7 @@ global: # image that is used for functionality such as catalog sync. # This can be overridden per component. # @default: hashicorp/consul-k8s-control-plane: - imageK8S: "hashicorp/consul-k8s-control-plane:0.33.0" + imageK8S: "hashicorp/consul-k8s-control-plane:0.34.1" # The name of the datacenter that the agents should # register as. This can't be changed once the Consul cluster is up and running From 8874267481400752e8a5c2f54410b19f6d7bedd6 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Fri, 17 Sep 2021 21:14:25 +0000 Subject: [PATCH 036/418] Release v0.34.1 --- CHANGELOG.md | 2 +- control-plane/version/version.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70bea2362a..bde0e3aa56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.34.1 (September 17, 2021) BUG FIX: * Helm diff --git a/control-plane/version/version.go b/control-plane/version/version.go index b13386cc0a..da6d280c5f 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.34.0" + Version = "0.34.1" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 81af131b74fb7f6a5456c93f3b66dc2225803827 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Fri, 17 Sep 2021 21:26:17 +0000 Subject: [PATCH 037/418] Putting source back into Dev Mode --- CHANGELOG.md | 2 ++ control-plane/version/version.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bde0e3aa56..44927129ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## UNRELEASED + ## 0.34.1 (September 17, 2021) BUG FIX: diff --git a/control-plane/version/version.go b/control-plane/version/version.go index da6d280c5f..6194e7ee7c 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 729325ec407b8017d1f29e2ac78a62d4504ede2e Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 23 Sep 2021 09:33:40 -0700 Subject: [PATCH 038/418] Update to alpine 3.14 (#737) --- control-plane/build-support/docker/Release.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control-plane/build-support/docker/Release.dockerfile b/control-plane/build-support/docker/Release.dockerfile index 33b21e155f..d07f3d994e 100644 --- a/control-plane/build-support/docker/Release.dockerfile +++ b/control-plane/build-support/docker/Release.dockerfile @@ -5,7 +5,7 @@ # We don't rebuild the software because we want the exact checksums and # binary signatures to match the software and our builds aren't fully # reproducible currently. -FROM alpine:3.13 +FROM alpine:3.14 # NAME and VERSION are the name of the software in releases.hashicorp.com # and the version to download. Example: NAME=consul VERSION=1.2.3. From e2d07a3e03dff873a5fd8600fde10a93cdaeb4c7 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 23 Sep 2021 10:17:25 -0700 Subject: [PATCH 039/418] Update CHANGELOG.md (#739) --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44927129ba..744c065350 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,12 @@ ## UNRELEASED +IMPROVEMENTS: +* Control Plane + * Upgrade Docker image Alpine version from 3.13 to 3.14. [[GH-737](https://github.com/hashicorp/consul-k8s/pull/737)] + ## 0.34.1 (September 17, 2021) -BUG FIX: +BUG FIXES: * Helm * Fix consul-k8s image version in values file. [[GH-732](https://github.com/hashicorp/consul-k8s/pull/732)] From 9a974c1a9c9fe0594460352b25ef05fd4ba13734 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Thu, 23 Sep 2021 10:55:04 -0700 Subject: [PATCH 040/418] cli: uninstall command (#725) Uninstalls Consul on Kubernetes with options to delete all Consul installation related resources. Also removes a hack using HELM_NAMESPACE environment variable to set the Helm Go SDK Kube Client namespace and replaces it with common.InitActionConfig, which also uses a slight hack. That hack can be removed when https://github.com/helm/helm/pull/10148 is merged. --- cli/README.md | 46 ++- cli/cmd/common/utils.go | 39 +++ cli/cmd/install/install.go | 184 +++++----- cli/cmd/install/install_test.go | 10 +- cli/cmd/uninstall/uninstall.go | 507 ++++++++++++++++++++++++++++ cli/cmd/uninstall/uninstall_test.go | 197 +++++++++++ cli/commands.go | 6 + cli/go.mod | 2 + cli/go.sum | 1 + 9 files changed, 889 insertions(+), 103 deletions(-) create mode 100644 cli/cmd/common/utils.go create mode 100644 cli/cmd/uninstall/uninstall.go create mode 100644 cli/cmd/uninstall/uninstall_test.go diff --git a/cli/README.md b/cli/README.md index 14f7c50a47..1820b1cdd3 100644 --- a/cli/README.md +++ b/cli/README.md @@ -4,10 +4,11 @@ This repository contains a CLI tool for installing and operating [Consul](https: ## Installation & Setup Currently the tool is not available on any releases page. Instead clone the repository and run `go build -o bin/consul-k8s` -and proceed to run the binary. +from this directory and proceed to run the binary. ## Commands * [consul-k8s install](#consul-k8s-install) +* [consul-k8s uninstall](#consul-k8s-uninstall) ### consul-k8s install This command installs Consul on a Kubernetes cluster. It allows `demo` and `secure` installations via preset configurations @@ -81,3 +82,46 @@ Global Options: Path to kubeconfig file. This is aliased as "-c". ``` + +### consul-k8s uninstall +This command uninstalls Consul on Kubernetes, while prompting whether to uninstall the release and whether to delete all +related resources such as PVCs, Secrets, and ServiceAccounts. + +Get started with: +```bash +consul-k8s uninstall +``` + +``` +Usage: consul-k8s uninstall [flags] +Uninstall Consul with options to delete data and resources associated with Consul installation. + +Command Options: + + -auto-approve + Skip approval prompt for uninstalling Consul. The default is false. + + -name= + Name of the installation. This can be used to uninstall and/or delete + the resources of a specific Helm release. + + -namespace= + Namespace for the Consul installation. + + -timeout= + Timeout to wait for uninstall. The default is 10m. + + -wipe-data + When used in combination with -auto-approve, all persisted data (PVCs + and Secrets) from previous installations will be deleted. Only set this + to true when data from previous installations is no longer necessary. + The default is false. + +Global Options: + + -context= + Kubernetes context to use. + + -kubeconfig= + Path to kubeconfig file. This is aliased as "-c". +``` \ No newline at end of file diff --git a/cli/cmd/common/utils.go b/cli/cmd/common/utils.go new file mode 100644 index 0000000000..5c044a0e03 --- /dev/null +++ b/cli/cmd/common/utils.go @@ -0,0 +1,39 @@ +package common + +import ( + "fmt" + "os" + "strings" + + "helm.sh/helm/v3/pkg/action" + helmCLI "helm.sh/helm/v3/pkg/cli" + "k8s.io/cli-runtime/pkg/genericclioptions" +) + +const ( + DefaultReleaseName = "consul" + DefaultReleaseNamespace = "consul" +) + +// Abort returns true if the raw input string is not equal to "y" or "yes". +func Abort(raw string) bool { + confirmation := strings.TrimSuffix(raw, "\n") + if !(strings.ToLower(confirmation) == "y" || strings.ToLower(confirmation) == "yes") { + return true + } + return false +} + +// InitActionConfig initializes a Helm Go SDK action configuration. This function currently uses a hack to override the +// namespace field that gets set in the K8s client set up by the SDK. +func InitActionConfig(actionConfig *action.Configuration, namespace string, settings *helmCLI.EnvSettings, logger action.DebugLog) (*action.Configuration, error) { + getter := settings.RESTClientGetter() + configFlags := getter.(*genericclioptions.ConfigFlags) + configFlags.Namespace = &namespace + err := actionConfig.Init(settings.RESTClientGetter(), namespace, + os.Getenv("HELM_DRIVER"), logger) + if err != nil { + return nil, fmt.Errorf("error setting up helm action configuration to find existing installations: %s", err) + } + return actionConfig, nil +} diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index 4317dad452..9e1d406ed8 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -27,8 +27,6 @@ const ( flagNamePreset = "preset" defaultPreset = "" - defaultReleaseName = "consul" - flagNameConfigFile = "config-file" flagNameSetStringValues = "set-string" flagNameSetValues = "set" @@ -41,7 +39,6 @@ const ( defaultAutoApprove = false flagNameNamespace = "namespace" - defaultNamespace = "consul" flagNameTimeout = "timeout" defaultTimeout = "10m" @@ -86,82 +83,80 @@ func (c *Command) init() { } c.set = flag.NewSets() - { - f := c.set.NewSet("Command Options") - f.BoolVar(&flag.BoolVar{ - Name: flagNameAutoApprove, - Target: &c.flagAutoApprove, - Default: defaultAutoApprove, - Usage: "Skip confirmation prompt.", - }) - f.BoolVar(&flag.BoolVar{ - Name: flagNameDryRun, - Target: &c.flagDryRun, - Default: defaultDryRun, - Usage: "Run pre-install checks and display summary of installation.", - }) - f.StringSliceVar(&flag.StringSliceVar{ - Name: flagNameConfigFile, - Aliases: []string{"f"}, - Target: &c.flagValueFiles, - Usage: "Path to a file to customize the installation, such as Consul Helm chart values file. Can be specified multiple times.", - }) - f.StringVar(&flag.StringVar{ - Name: flagNameNamespace, - Target: &c.flagNamespace, - Default: defaultNamespace, - Usage: "Namespace for the Consul installation.", - }) - f.StringVar(&flag.StringVar{ - Name: flagNamePreset, - Target: &c.flagPreset, - Default: defaultPreset, - Usage: fmt.Sprintf("Use an installation preset, one of %s. Defaults to none", strings.Join(presetList, ", ")), - }) - f.StringSliceVar(&flag.StringSliceVar{ - Name: flagNameSetValues, - Target: &c.flagSetValues, - Usage: "Set a value to customize. Can be specified multiple times. Supports Consul Helm chart values.", - }) - f.StringSliceVar(&flag.StringSliceVar{ - Name: flagNameFileValues, - Target: &c.flagFileValues, - Usage: "Set a value to customize via a file. The contents of the file will be set as the value. Can be " + - "specified multiple times. Supports Consul Helm chart values.", - }) - f.StringSliceVar(&flag.StringSliceVar{ - Name: flagNameSetStringValues, - Target: &c.flagSetStringValues, - Usage: "Set a string value to customize. Can be specified multiple times. Supports Consul Helm chart values.", - }) - f.StringVar(&flag.StringVar{ - Name: flagNameTimeout, - Target: &c.flagTimeout, - Default: defaultTimeout, - Usage: "Timeout to wait for installation to be ready.", - }) - f.BoolVar(&flag.BoolVar{ - Name: flagNameWait, - Target: &c.flagWait, - Default: defaultWait, - Usage: "Determines whether to wait for resources in installation to be ready before exiting command.", - }) - - f = c.set.NewSet("Global Options") - f.StringVar(&flag.StringVar{ - Name: "kubeconfig", - Aliases: []string{"c"}, - Target: &c.flagKubeConfig, - Default: "", - Usage: "Path to kubeconfig file.", - }) - f.StringVar(&flag.StringVar{ - Name: "context", - Target: &c.flagKubeContext, - Default: "", - Usage: "Kubernetes context to use.", - }) - } + f := c.set.NewSet("Command Options") + f.BoolVar(&flag.BoolVar{ + Name: flagNameAutoApprove, + Target: &c.flagAutoApprove, + Default: defaultAutoApprove, + Usage: "Skip confirmation prompt.", + }) + f.BoolVar(&flag.BoolVar{ + Name: flagNameDryRun, + Target: &c.flagDryRun, + Default: defaultDryRun, + Usage: "Run pre-install checks and display summary of installation.", + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameConfigFile, + Aliases: []string{"f"}, + Target: &c.flagValueFiles, + Usage: "Path to a file to customize the installation, such as Consul Helm chart values file. Can be specified multiple times.", + }) + f.StringVar(&flag.StringVar{ + Name: flagNameNamespace, + Target: &c.flagNamespace, + Default: common.DefaultReleaseNamespace, + Usage: "Namespace for the Consul installation.", + }) + f.StringVar(&flag.StringVar{ + Name: flagNamePreset, + Target: &c.flagPreset, + Default: defaultPreset, + Usage: fmt.Sprintf("Use an installation preset, one of %s. Defaults to none", strings.Join(presetList, ", ")), + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameSetValues, + Target: &c.flagSetValues, + Usage: "Set a value to customize. Can be specified multiple times. Supports Consul Helm chart values.", + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameFileValues, + Target: &c.flagFileValues, + Usage: "Set a value to customize via a file. The contents of the file will be set as the value. Can be " + + "specified multiple times. Supports Consul Helm chart values.", + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameSetStringValues, + Target: &c.flagSetStringValues, + Usage: "Set a string value to customize. Can be specified multiple times. Supports Consul Helm chart values.", + }) + f.StringVar(&flag.StringVar{ + Name: flagNameTimeout, + Target: &c.flagTimeout, + Default: defaultTimeout, + Usage: "Timeout to wait for installation to be ready.", + }) + f.BoolVar(&flag.BoolVar{ + Name: flagNameWait, + Target: &c.flagWait, + Default: defaultWait, + Usage: "Determines whether to wait for resources in installation to be ready before exiting command.", + }) + + f = c.set.NewSet("Global Options") + f.StringVar(&flag.StringVar{ + Name: "kubeconfig", + Aliases: []string{"c"}, + Target: &c.flagKubeConfig, + Default: "", + Usage: "Path to kubeconfig file.", + }) + f.StringVar(&flag.StringVar{ + Name: "context", + Target: &c.flagKubeContext, + Default: "", + Usage: "Kubernetes context to use.", + }) c.help = c.set.Help() @@ -172,31 +167,27 @@ func (c *Command) init() { func (c *Command) Run(args []string) int { c.once.Do(c.init) + // The logger is initialized in main with the name cli. Here, we reset the name to install so log lines would be prefixed with install. + c.Log.ResetNamed("install") + defer func() { if err := c.Close(); err != nil { - c.UI.Output(err.Error()) + c.Log.Error(err.Error()) + os.Exit(1) } }() - // The logger is initialized in main with the name cli. Here, we reset the name to install so log lines would be prefixed with install. - c.Log.ResetNamed("install") - if err := c.validateFlags(args); err != nil { c.UI.Output(err.Error()) return 1 } - // A hack to set namespace via the HELM_NAMESPACE env var until we merge a PR that will allow us to use the latest - // Helm templates. - prevHelmNSEnv := os.Getenv("HELM_NAMESPACE") - os.Setenv("HELM_NAMESPACE", c.flagNamespace) // helmCLI.New() will create a settings object which is used by the Helm Go SDK calls. + settings := helmCLI.New() + // Any overrides by our kubeconfig and kubecontext flags is done here. The Kube client that // is created will use this command's flags first, then the HELM_KUBECONTEXT environment variable, // then call out to genericclioptions.ConfigFlag - settings := helmCLI.New() - os.Setenv("HELM_NAMESPACE", prevHelmNSEnv) - if c.flagKubeConfig != "" { settings.KubeConfig = c.flagKubeConfig } @@ -260,7 +251,7 @@ func (c *Command) Run(args []string) int { // Print out the installation summary. if !c.flagAutoApprove { c.UI.Output("Consul Installation Summary", terminal.WithHeaderStyle()) - c.UI.Output("Installation name: %s", defaultReleaseName, terminal.WithInfoStyle()) + c.UI.Output("Installation name: %s", common.DefaultReleaseName, terminal.WithInfoStyle()) c.UI.Output("Namespace: %s", c.flagNamespace, terminal.WithInfoStyle()) if len(vals) == 0 { @@ -292,8 +283,7 @@ func (c *Command) Run(args []string) int { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 } - confirmation = strings.TrimSuffix(confirmation, "\n") - if !(strings.ToLower(confirmation) == "y" || strings.ToLower(confirmation) == "yes") { + if common.Abort(confirmation) { c.UI.Output("Install aborted. To learn how to customize your installation, run:\nconsul-k8s install --help", terminal.WithInfoStyle()) return 1 } @@ -303,15 +293,15 @@ func (c *Command) Run(args []string) int { // Setup action configuration for Helm Go SDK function calls. actionConfig := new(action.Configuration) - if err := actionConfig.Init(settings.RESTClientGetter(), c.flagNamespace, - os.Getenv("HELM_DRIVER"), uiLogger); err != nil { - c.UI.Output(err.Error()) + actionConfig, err = common.InitActionConfig(actionConfig, c.flagNamespace, settings, uiLogger) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 } // Setup the installation action. install := action.NewInstall(actionConfig) - install.ReleaseName = defaultReleaseName + install.ReleaseName = common.DefaultReleaseName install.Namespace = c.flagNamespace install.CreateNamespace = true install.ChartPathOptions.RepoURL = helmRepository diff --git a/cli/cmd/install/install_test.go b/cli/cmd/install/install_test.go index 0c34d6fe48..b299b84f5f 100644 --- a/cli/cmd/install/install_test.go +++ b/cli/cmd/install/install_test.go @@ -26,8 +26,8 @@ func TestCheckForPreviousPVCs(t *testing.T) { Name: "consul-server-test2", }, } - c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.TODO(), pvc, metav1.CreateOptions{}) - c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.TODO(), pvc2, metav1.CreateOptions{}) + c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.Background(), pvc, metav1.CreateOptions{}) + c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.Background(), pvc2, metav1.CreateOptions{}) err := c.checkForPreviousPVCs() require.Error(t, err) require.Contains(t, err.Error(), "found PVCs from previous installations (default/consul-server-test1,default/consul-server-test2), delete before re-installing") @@ -43,7 +43,7 @@ func TestCheckForPreviousPVCs(t *testing.T) { Name: "irrelevant-pvc", }, } - c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.TODO(), pvc, metav1.CreateOptions{}) + c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.Background(), pvc, metav1.CreateOptions{}) err = c.checkForPreviousPVCs() require.NoError(t, err) } @@ -56,7 +56,7 @@ func TestCheckForPreviousSecrets(t *testing.T) { Name: "test-consul-bootstrap-acl-token", }, } - c.kubernetes.CoreV1().Secrets("default").Create(context.TODO(), secret, metav1.CreateOptions{}) + c.kubernetes.CoreV1().Secrets("default").Create(context.Background(), secret, metav1.CreateOptions{}) err := c.checkForPreviousSecrets() require.Error(t, err) require.Contains(t, err.Error(), "found consul-acl-bootstrap-token secret from previous installations: \"test-consul-bootstrap-acl-token\" in namespace \"default\". To delete, run kubectl delete secret test-consul-bootstrap-acl-token --namespace default") @@ -72,7 +72,7 @@ func TestCheckForPreviousSecrets(t *testing.T) { Name: "irrelevant-secret", }, } - c.kubernetes.CoreV1().Secrets("default").Create(context.TODO(), secret, metav1.CreateOptions{}) + c.kubernetes.CoreV1().Secrets("default").Create(context.Background(), secret, metav1.CreateOptions{}) err = c.checkForPreviousSecrets() require.NoError(t, err) } diff --git a/cli/cmd/uninstall/uninstall.go b/cli/cmd/uninstall/uninstall.go new file mode 100644 index 0000000000..2e1d870c00 --- /dev/null +++ b/cli/cmd/uninstall/uninstall.go @@ -0,0 +1,507 @@ +package uninstall + +import ( + "fmt" + "os" + "strings" + "sync" + "time" + + "github.com/cenkalti/backoff" + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" + "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + "helm.sh/helm/v3/pkg/action" + helmCLI "helm.sh/helm/v3/pkg/cli" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +const ( + flagAutoApprove = "auto-approve" + defaultAutoApprove = false + + flagNamespace = "namespace" + defaultAllNamespaces = "" + + flagReleaseName = "name" + defaultAnyReleaseName = "" + + flagWipeData = "wipe-data" + defaultWipeData = false + + flagTimeout = "timeout" + defaultTimeout = "10m" +) + +type Command struct { + *common.BaseCommand + + kubernetes kubernetes.Interface + + set *flag.Sets + + flagNamespace string + flagReleaseName string + flagAutoApprove bool + flagWipeData bool + flagTimeout string + timeoutDuration time.Duration + + flagKubeConfig string + flagKubeContext string + + once sync.Once + help string +} + +func (c *Command) init() { + c.set = flag.NewSets() + f := c.set.NewSet("Command Options") + f.BoolVar(&flag.BoolVar{ + Name: flagAutoApprove, + Target: &c.flagAutoApprove, + Default: defaultAutoApprove, + Usage: "Skip approval prompt for uninstalling Consul.", + }) + f.BoolVar(&flag.BoolVar{ + Name: flagWipeData, + Target: &c.flagWipeData, + Default: defaultWipeData, + Usage: "When used in combination with -auto-approve, all persisted data (PVCs and Secrets) from previous installations will be deleted. Only set this to true when data from previous installations is no longer necessary.", + }) + f.StringVar(&flag.StringVar{ + Name: flagNamespace, + Target: &c.flagNamespace, + Default: defaultAllNamespaces, + Usage: "Namespace for the Consul installation.", + }) + f.StringVar(&flag.StringVar{ + Name: flagReleaseName, + Target: &c.flagReleaseName, + Default: defaultAnyReleaseName, + Usage: "Name of the installation. This can be used to uninstall and/or delete the resources of a specific Helm release.", + }) + f.StringVar(&flag.StringVar{ + Name: flagTimeout, + Target: &c.flagTimeout, + Default: defaultTimeout, + Usage: "Timeout to wait for uninstall.", + }) + + f = c.set.NewSet("Global Options") + f.StringVar(&flag.StringVar{ + Name: "kubeconfig", + Aliases: []string{"c"}, + Target: &c.flagKubeConfig, + Default: "", + Usage: "Path to kubeconfig file.", + }) + f.StringVar(&flag.StringVar{ + Name: "context", + Target: &c.flagKubeContext, + Default: "", + Usage: "Kubernetes context to use.", + }) + + c.help = c.set.Help() + + // c.Init() calls the embedded BaseCommand's initialization function. + c.Init() +} + +func (c *Command) Run(args []string) int { + c.once.Do(c.init) + + // The logger is initialized in main with the name cli. Here, we reset the name to uninstall so log lines would be prefixed with uninstall. + c.Log.ResetNamed("uninstall") + + defer func() { + if err := c.Close(); err != nil { + c.Log.Error(err.Error()) + os.Exit(1) + } + }() + + if err := c.set.Parse(args); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + if len(c.set.Args()) > 0 { + c.UI.Output("Should have no non-flag arguments.", terminal.WithErrorStyle()) + return 1 + } + if c.flagWipeData && !c.flagAutoApprove { + c.UI.Output("Can't set -wipe-data alone. Omit this flag to interactively uninstall, or use it with -auto-approve to wipe all data during the uninstall.", terminal.WithErrorStyle()) + return 1 + } + duration, err := time.ParseDuration(c.flagTimeout) + if err != nil { + c.UI.Output("unable to parse -%s: %s", flagTimeout, err, terminal.WithErrorStyle()) + return 1 + } + c.timeoutDuration = duration + + // helmCLI.New() will create a settings object which is used by the Helm Go SDK calls. + settings := helmCLI.New() + if c.flagKubeConfig != "" { + settings.KubeConfig = c.flagKubeConfig + } + if c.flagKubeContext != "" { + settings.KubeContext = c.flagKubeContext + } + + // Set up the kubernetes client to use for non Helm SDK calls to the Kubernetes API + // The Helm SDK will use settings.RESTClientGetter for its calls as well, so this will + // use a consistent method to target the right cluster for both Helm SDK and non Helm SDK calls. + if c.kubernetes == nil { + restConfig, err := settings.RESTClientGetter().ToRESTConfig() + if err != nil { + c.UI.Output("retrieving Kubernetes auth: %v", err, terminal.WithErrorStyle()) + return 1 + } + c.kubernetes, err = kubernetes.NewForConfig(restConfig) + if err != nil { + c.UI.Output("initializing Kubernetes client: %v", err, terminal.WithErrorStyle()) + return 1 + } + } + + // Setup logger to stream Helm library logs. + var uiLogger = func(s string, args ...interface{}) { + logMsg := fmt.Sprintf(s, args...) + c.UI.Output(logMsg, terminal.WithLibraryStyle()) + } + + c.UI.Output("Existing Installation", terminal.WithHeaderStyle()) + + // Search for Consul installation by calling `helm list`. Depends on what's already specified. + actionConfig := new(action.Configuration) + actionConfig, err = common.InitActionConfig(actionConfig, c.flagNamespace, settings, uiLogger) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + found, foundReleaseName, foundReleaseNamespace, err := c.findExistingInstallation(actionConfig) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + if !found { + c.UI.Output("No existing Consul installations.", terminal.WithSuccessStyle()) + } else { + c.UI.Output("Existing Consul installation found.", terminal.WithSuccessStyle()) + c.UI.Output("Consul Uninstall Summary", terminal.WithHeaderStyle()) + c.UI.Output("Name: %s", foundReleaseName, terminal.WithInfoStyle()) + c.UI.Output("Namespace: %s", foundReleaseNamespace, terminal.WithInfoStyle()) + + // Prompt for approval to uninstall Helm release. + if !c.flagAutoApprove { + confirmation, err := c.UI.Input(&terminal.Input{ + Prompt: "Proceed with uninstall? (y/N)", + Style: terminal.InfoStyle, + Secret: false, + }) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + if common.Abort(confirmation) { + c.UI.Output("Uninstall aborted. To learn how to customize the uninstall, run:\nconsul-k8s uninstall --help", terminal.WithInfoStyle()) + return 1 + } + } + + // Actually call out to `helm delete`. + actionConfig, err = common.InitActionConfig(actionConfig, foundReleaseNamespace, settings, uiLogger) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + uninstaller := action.NewUninstall(actionConfig) + uninstaller.Timeout = c.timeoutDuration + res, err := uninstaller.Run(foundReleaseName) + if err != nil { + c.UI.Output("unable to uninstall: %s", err, terminal.WithErrorStyle()) + return 1 + } + if res != nil && res.Info != "" { + c.UI.Output("Uninstall result: %s", res.Info, terminal.WithInfoStyle()) + } + c.UI.Output("Successfully uninstalled Consul Helm release", terminal.WithSuccessStyle()) + } + + // If -auto-approve=true and -wipe-data=false, we should only uninstall the release, and skip deleting resources. + if c.flagAutoApprove && !c.flagWipeData { + c.UI.Output("Skipping deleting PVCs, secrets, and service accounts.", terminal.WithSuccessStyle()) + return 0 + } + + // At this point, even if no Helm release was found and uninstalled, there could + // still be PVCs, Secrets, and Service Accounts left behind from a previous installation. + // If there isn't a foundReleaseName and foundReleaseNamespace, we'll use the values of the + // flags c.flagReleaseName and c.flagNamespace. If those are empty we'll fall back to defaults "consul" for the + // installation name and "consul" for the namespace. + if !found { + if c.flagReleaseName == "" || c.flagNamespace == "" { + foundReleaseName = common.DefaultReleaseName + foundReleaseNamespace = common.DefaultReleaseNamespace + } else { + foundReleaseName = c.flagReleaseName + foundReleaseNamespace = c.flagNamespace + } + } + + c.UI.Output("Other Consul Resources", terminal.WithHeaderStyle()) + if c.flagAutoApprove { + c.UI.Output("Deleting data for installation: ", terminal.WithInfoStyle()) + c.UI.Output("Name: %s", foundReleaseName, terminal.WithInfoStyle()) + c.UI.Output("Namespace %s", foundReleaseNamespace, terminal.WithInfoStyle()) + } + // Prompt with a warning for approval before deleting PVCs, Secrets, Service Accounts, Roles, and Role Bindings. + if !c.flagAutoApprove { + confirmation, err := c.UI.Input(&terminal.Input{ + Prompt: fmt.Sprintf("WARNING: Proceed with deleting PVCs, Secrets, Service Accounts, Roles, and Role Bindings for the following installation? \n\n Name: %s \n Namespace: %s \n\n Only approve if all data from this installation can be deleted. (y/N)", foundReleaseName, foundReleaseNamespace), + Style: terminal.WarningStyle, + Secret: false, + }) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + if common.Abort(confirmation) { + c.UI.Output("Uninstall aborted without deleting PVCs and Secrets.", terminal.WithInfoStyle()) + return 1 + } + } + + if err := c.deletePVCs(foundReleaseName, foundReleaseNamespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if err := c.deleteSecrets(foundReleaseName, foundReleaseNamespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if err := c.deleteServiceAccounts(foundReleaseName, foundReleaseNamespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if err := c.deleteRoles(foundReleaseName, foundReleaseNamespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if err := c.deleteRoleBindings(foundReleaseName, foundReleaseNamespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + return 0 +} + +func (c *Command) Help() string { + c.once.Do(c.init) + s := "Usage: consul-k8s uninstall [flags]" + "\n" + "Uninstall Consul with options to delete data and resources associated with Consul installation." + "\n\n" + c.help + return s +} + +func (c *Command) Synopsis() string { + return "Uninstall Consul deployment." +} + +func (c *Command) findExistingInstallation(actionConfig *action.Configuration) (bool, string, string, error) { + lister := action.NewList(actionConfig) + // lister.All will search for helm installations in all states, such as deployed, pending, uninstalling, etc. + lister.All = true + if c.flagNamespace == defaultAllNamespaces { + lister.AllNamespaces = true + } + res, err := lister.Run() + if err != nil { + return false, "", "", fmt.Errorf("error finding existing installations: %s", err) + } + + found := false + foundReleaseName := "" + foundReleaseNamespace := "" + for _, rel := range res { + if rel.Chart.Metadata.Name == "consul" { + if c.flagNamespace != defaultAllNamespaces && c.flagNamespace == rel.Namespace { + // If we found a chart named "consul" and -namespace was specified, we only found the release if the + // release namespace matches the -namespace flag. + found = true + foundReleaseName = rel.Name + foundReleaseNamespace = rel.Namespace + break + } + if c.flagNamespace == defaultAllNamespaces { + found = true + foundReleaseName = rel.Name + foundReleaseNamespace = rel.Namespace + break + } + } + } + + return found, foundReleaseName, foundReleaseNamespace, nil +} + +// deletePVCs deletes any pvcs that have the label release={{foundReleaseName}} and waits for them to be deleted. +func (c *Command) deletePVCs(foundReleaseName, foundReleaseNamespace string) error { + var pvcNames []string + pvcSelector := metav1.ListOptions{LabelSelector: fmt.Sprintf("release=%s", foundReleaseName)} + pvcs, err := c.kubernetes.CoreV1().PersistentVolumeClaims(foundReleaseNamespace).List(c.Ctx, pvcSelector) + if err != nil { + return fmt.Errorf("deletePVCs: %s", err) + } + if len(pvcs.Items) == 0 { + c.UI.Output("No PVCs found.", terminal.WithSuccessStyle()) + return nil + } + for _, pvc := range pvcs.Items { + err := c.kubernetes.CoreV1().PersistentVolumeClaims(foundReleaseNamespace).Delete(c.Ctx, pvc.Name, metav1.DeleteOptions{}) + if err != nil { + return fmt.Errorf("deletePVCs: error deleting PVC %q: %s", pvc.Name, err) + } + pvcNames = append(pvcNames, pvc.Name) + } + err = backoff.Retry(func() error { + pvcs, err := c.kubernetes.CoreV1().PersistentVolumeClaims(foundReleaseNamespace).List(c.Ctx, pvcSelector) + if err != nil { + return fmt.Errorf("deletePVCs: %s", err) + } + if len(pvcs.Items) > 0 { + return fmt.Errorf("deletePVCs: pvcs still exist") + } + return nil + }, backoff.WithMaxRetries(backoff.NewConstantBackOff(100*time.Millisecond), 1800)) + if err != nil { + return fmt.Errorf("deletePVCs: timed out waiting for PVCs to be deleted") + } + if len(pvcNames) > 0 { + for _, pvc := range pvcNames { + c.UI.Output("Deleted PVC => %s", pvc, terminal.WithSuccessStyle()) + } + c.UI.Output("PVCs deleted.", terminal.WithSuccessStyle()) + } + return nil +} + +// deleteSecrets deletes any secrets that have foundReleaseName in their name. +func (c *Command) deleteSecrets(foundReleaseName, foundReleaseNamespace string) error { + var secretNames []string + secrets, err := c.kubernetes.CoreV1().Secrets(foundReleaseNamespace).List(c.Ctx, metav1.ListOptions{}) + if err != nil { + return fmt.Errorf("deleteSecrets: %s", err) + } + if len(secrets.Items) == 0 { + c.UI.Output("No Consul secrets found.", terminal.WithSuccessStyle()) + return nil + } + for _, secret := range secrets.Items { + if strings.HasPrefix(secret.Name, foundReleaseName) { + err := c.kubernetes.CoreV1().Secrets(foundReleaseNamespace).Delete(c.Ctx, secret.Name, metav1.DeleteOptions{}) + if err != nil { + return fmt.Errorf("deleteSecrets: error deleting Secret %q: %s", secret.Name, err) + } + secretNames = append(secretNames, secret.Name) + } + } + if len(secretNames) > 0 { + for _, secret := range secretNames { + c.UI.Output("Deleted Secret => %s", secret, terminal.WithSuccessStyle()) + } + c.UI.Output("Consul secrets deleted.", terminal.WithSuccessStyle()) + } + return nil +} + +// deleteServiceAccounts deletes service accounts that have the label release={{foundReleaseName}}. +func (c *Command) deleteServiceAccounts(foundReleaseName, foundReleaseNamespace string) error { + var serviceAccountNames []string + saSelector := metav1.ListOptions{LabelSelector: fmt.Sprintf("release=%s", foundReleaseName)} + sas, err := c.kubernetes.CoreV1().ServiceAccounts(foundReleaseNamespace).List(c.Ctx, saSelector) + if err != nil { + return fmt.Errorf("deleteServiceAccounts: %s", err) + } + if len(sas.Items) == 0 { + c.UI.Output("No Consul service accounts found.", terminal.WithSuccessStyle()) + return nil + } + for _, sa := range sas.Items { + err := c.kubernetes.CoreV1().ServiceAccounts(foundReleaseNamespace).Delete(c.Ctx, sa.Name, metav1.DeleteOptions{}) + if err != nil { + return fmt.Errorf("deleteServiceAccounts: error deleting ServiceAccount %q: %s", sa.Name, err) + } + serviceAccountNames = append(serviceAccountNames, sa.Name) + } + if len(serviceAccountNames) > 0 { + for _, sa := range serviceAccountNames { + c.UI.Output("Deleted Service Account => %s", sa, terminal.WithSuccessStyle()) + } + c.UI.Output("Consul service accounts deleted.", terminal.WithSuccessStyle()) + } + return nil +} + +// deleteRoles deletes roles that have the label release={{foundReleaseName}}. +func (c *Command) deleteRoles(foundReleaseName, foundReleaseNamespace string) error { + var roleNames []string + roleSelector := metav1.ListOptions{LabelSelector: fmt.Sprintf("release=%s", foundReleaseName)} + roles, err := c.kubernetes.RbacV1().Roles(foundReleaseNamespace).List(c.Ctx, roleSelector) + if err != nil { + return fmt.Errorf("deleteRoles: %s", err) + } + if len(roles.Items) == 0 { + c.UI.Output("No Consul roles found.", terminal.WithSuccessStyle()) + return nil + } + for _, role := range roles.Items { + err := c.kubernetes.RbacV1().Roles(foundReleaseNamespace).Delete(c.Ctx, role.Name, metav1.DeleteOptions{}) + if err != nil { + return fmt.Errorf("deleteRoles: error deleting Role %q: %s", role.Name, err) + } + roleNames = append(roleNames, role.Name) + } + if len(roleNames) > 0 { + for _, role := range roleNames { + c.UI.Output("Deleted Role => %s", role, terminal.WithSuccessStyle()) + } + c.UI.Output("Consul roles deleted.", terminal.WithSuccessStyle()) + } + return nil +} + +// deleteRoleBindings deletes rolebindings that have the label release={{foundReleaseName}}. +func (c *Command) deleteRoleBindings(foundReleaseName, foundReleaseNamespace string) error { + var rolebindingNames []string + rolebindingSelector := metav1.ListOptions{LabelSelector: fmt.Sprintf("release=%s", foundReleaseName)} + rolebindings, err := c.kubernetes.RbacV1().RoleBindings(foundReleaseNamespace).List(c.Ctx, rolebindingSelector) + if err != nil { + return fmt.Errorf("deleteRoleBindings: %s", err) + } + if len(rolebindings.Items) == 0 { + c.UI.Output("No Consul rolebindings found.", terminal.WithSuccessStyle()) + return nil + } + for _, rolebinding := range rolebindings.Items { + err := c.kubernetes.RbacV1().RoleBindings(foundReleaseNamespace).Delete(c.Ctx, rolebinding.Name, metav1.DeleteOptions{}) + if err != nil { + return fmt.Errorf("deleteRoleBindings: error deleting Role %q: %s", rolebinding.Name, err) + } + rolebindingNames = append(rolebindingNames, rolebinding.Name) + } + if len(rolebindingNames) > 0 { + for _, rolebinding := range rolebindingNames { + c.UI.Output("Deleted Role Binding => %s", rolebinding, terminal.WithSuccessStyle()) + } + c.UI.Output("Consul rolebindings deleted.", terminal.WithSuccessStyle()) + } + return nil +} diff --git a/cli/cmd/uninstall/uninstall_test.go b/cli/cmd/uninstall/uninstall_test.go new file mode 100644 index 0000000000..8473cd6e61 --- /dev/null +++ b/cli/cmd/uninstall/uninstall_test.go @@ -0,0 +1,197 @@ +package uninstall + +import ( + "context" + "os" + "testing" + + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" +) + +func TestDeletePVCs(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + pvc := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-server-test1", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + pvc2 := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-server-test2", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + pvc3 := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "unrelated-pvc", + Labels: map[string]string{ + "release": "unrelated", + }, + }, + } + _, err := c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.Background(), pvc, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.Background(), pvc2, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.Background(), pvc3, metav1.CreateOptions{}) + require.NoError(t, err) + err = c.deletePVCs("consul", "default") + require.NoError(t, err) + pvcs, err := c.kubernetes.CoreV1().PersistentVolumeClaims("default").List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + require.Len(t, pvcs.Items, 1) +} + +func TestDeleteSecrets(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + secret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-secret1", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + secret2 := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-secret2", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + _, err := c.kubernetes.CoreV1().Secrets("default").Create(context.Background(), secret, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.CoreV1().Secrets("default").Create(context.Background(), secret2, metav1.CreateOptions{}) + require.NoError(t, err) + err = c.deleteSecrets("consul", "default") + require.NoError(t, err) + secrets, err := c.kubernetes.CoreV1().Secrets("default").List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + require.Len(t, secrets.Items, 0) +} + +func TestDeleteServiceAccounts(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + sa := &v1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-sa1", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + sa2 := &v1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-sa2", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + _, err := c.kubernetes.CoreV1().ServiceAccounts("default").Create(context.Background(), sa, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.CoreV1().ServiceAccounts("default").Create(context.Background(), sa2, metav1.CreateOptions{}) + require.NoError(t, err) + err = c.deleteServiceAccounts("consul", "default") + require.NoError(t, err) + sas, err := c.kubernetes.CoreV1().ServiceAccounts("default").List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + require.Len(t, sas.Items, 0) +} + +func TestDeleteRoles(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + role := &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-role1", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + role2 := &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-role2", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + _, err := c.kubernetes.RbacV1().Roles("default").Create(context.Background(), role, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.RbacV1().Roles("default").Create(context.Background(), role2, metav1.CreateOptions{}) + require.NoError(t, err) + err = c.deleteRoles("consul", "default") + require.NoError(t, err) + roles, err := c.kubernetes.RbacV1().Roles("default").List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + require.Len(t, roles.Items, 0) +} + +func TestDeleteRoleBindings(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + rolebinding := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-role1", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + rolebinding2 := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-role2", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + _, err := c.kubernetes.RbacV1().RoleBindings("default").Create(context.Background(), rolebinding, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.RbacV1().RoleBindings("default").Create(context.Background(), rolebinding2, metav1.CreateOptions{}) + require.NoError(t, err) + err = c.deleteRoleBindings("consul", "default") + require.NoError(t, err) + rolebindings, err := c.kubernetes.RbacV1().RoleBindings("default").List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + require.Len(t, rolebindings.Items, 0) +} + +// getInitializedCommand sets up a command struct for tests. +func getInitializedCommand(t *testing.T) *Command { + t.Helper() + log := hclog.New(&hclog.LoggerOptions{ + Name: "cli", + Level: hclog.Info, + Output: os.Stdout, + }) + ctx, _ := context.WithCancel(context.Background()) + + baseCommand := &common.BaseCommand{ + Ctx: ctx, + Log: log, + } + + c := &Command{ + BaseCommand: baseCommand, + } + c.init() + return c +} diff --git a/cli/commands.go b/cli/commands.go index 81640ef88a..2725c5d4bf 100644 --- a/cli/commands.go +++ b/cli/commands.go @@ -5,6 +5,7 @@ import ( "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/consul-k8s/cli/cmd/install" + "github.com/hashicorp/consul-k8s/cli/cmd/uninstall" "github.com/hashicorp/go-hclog" "github.com/mitchellh/cli" ) @@ -22,6 +23,11 @@ func initializeCommands(ctx context.Context, log hclog.Logger) (*common.BaseComm BaseCommand: baseCommand, }, nil }, + "uninstall": func() (cli.Command, error) { + return &uninstall.Command{ + BaseCommand: baseCommand, + }, nil + }, } return baseCommand, commands diff --git a/cli/go.mod b/cli/go.mod index 723e092b47..38ed649c60 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -4,6 +4,7 @@ go 1.16 require ( github.com/bgentry/speakeasy v0.1.0 + github.com/cenkalti/backoff v2.2.1+incompatible github.com/fatih/color v1.9.0 github.com/golang/protobuf v1.5.2 // indirect github.com/hashicorp/go-hclog v0.16.2 @@ -21,6 +22,7 @@ require ( helm.sh/helm/v3 v3.6.1 k8s.io/api v0.21.2 k8s.io/apimachinery v0.21.2 + k8s.io/cli-runtime v0.21.0 k8s.io/client-go v0.21.2 rsc.io/letsencrypt v0.0.3 // indirect sigs.k8s.io/yaml v1.2.0 diff --git a/cli/go.sum b/cli/go.sum index 0e79467fc8..7ccb6c8963 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -125,6 +125,7 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0Bsq github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= From d87f2e675428b931b03aef3fb89292643700c318 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 28 Sep 2021 16:25:28 -0700 Subject: [PATCH 041/418] Add table of contents to helm ref (#742) --- .../fixtures/full-values.golden | 22 +- hack/helm-reference-gen/main.go | 25 ++- hack/helm-reference-gen/main_test.go | 210 ++++++++++++++---- 3 files changed, 209 insertions(+), 48 deletions(-) diff --git a/hack/helm-reference-gen/fixtures/full-values.golden b/hack/helm-reference-gen/fixtures/full-values.golden index 08f25c945f..e29c4d4f5e 100644 --- a/hack/helm-reference-gen/fixtures/full-values.golden +++ b/hack/helm-reference-gen/fixtures/full-values.golden @@ -1,3 +1,23 @@ +## Top-Level Stanzas + +Use these links to navigate to a particular top-level stanza. + +- [`global`](#global) +- [`server`](#server) +- [`externalServers`](#externalservers) +- [`client`](#client) +- [`dns`](#dns) +- [`ui`](#ui) +- [`syncCatalog`](#synccatalog) +- [`connectInject`](#connectinject) +- [`controller`](#controller) +- [`meshGateway`](#meshgateway) +- [`ingressGateways`](#ingressgateways) +- [`terminatingGateways`](#terminatinggateways) +- [`tests`](#tests) + +## All Values + ### global - `global` ((#v-global)) - Holds values that affect multiple components of the chart. @@ -1541,4 +1561,4 @@ When using helm install, the test Pod is not submitted to the cluster so this is only useful when running helm template. - - `enabled` ((#v-tests-enabled)) (`boolean: true`) \ No newline at end of file + - `enabled` ((#v-tests-enabled)) (`boolean: true`) diff --git a/hack/helm-reference-gen/main.go b/hack/helm-reference-gen/main.go index eac978fdbf..23bd74e8cd 100644 --- a/hack/helm-reference-gen/main.go +++ b/hack/helm-reference-gen/main.go @@ -22,6 +22,11 @@ import ( "gopkg.in/yaml.v3" ) +const ( + tocPrefix = "## Top-Level Stanzas\n\nUse these links to navigate to a particular top-level stanza.\n\n" + tocSuffix = "\n## All Values" +) + var ( // typeAnnotation matches the @type annotation. It captures the value of @type. typeAnnotation = regexp.MustCompile(`(?m).*@type: (.*)$`) @@ -147,7 +152,15 @@ func GenerateDocs(yamlStr string) (string, error) { } children, err := generateDocsFromNode(docNodeTmpl, node) - return strings.ReplaceAll(strings.Join(children, "\n\n"), "[Enterprise Only]", ""), err + if err != nil { + return "", err + } + + enterpriseSubst := strings.ReplaceAll(strings.Join(children, "\n\n"), "[Enterprise Only]", "") + + // Add table of contents. + toc := generateTOC(node) + return toc + "\n\n" + enterpriseSubst + "\n", nil } // Parse parses yamlStr into a tree of DocNode's. @@ -389,3 +402,13 @@ func buildDocNode(nodeContentIdx int, currNode *yaml.Node, nodeContent []*yaml.N } return DocNode{}, fmt.Errorf("fell through cases unexpectedly at breadcrumb: %s", parentBreadcrumb) } + +func generateTOC(node DocNode) string { + toc := tocPrefix + + for _, c := range node.Children { + toc += fmt.Sprintf("- [`%s`](#%s)\n", c.Key, strings.ToLower(c.Key)) + } + + return toc + tocSuffix +} diff --git a/hack/helm-reference-gen/main_test.go b/hack/helm-reference-gen/main_test.go index affb4cfe7d..ed8b00fb90 100644 --- a/hack/helm-reference-gen/main_test.go +++ b/hack/helm-reference-gen/main_test.go @@ -20,27 +20,42 @@ func Test(t *testing.T) { # Line 1 # Line 2 key: value`, - Exp: `### key + Exp: `- [$key$](#key) -- $key$ ((#v-key)) ($string: value$) - Line 1\n Line 2`, +## All Values + +### key + +- $key$ ((#v-key)) ($string: value$) - Line 1\n Line 2 +`, }, "integer value": { Input: `--- # Line 1 # Line 2 replicas: 3`, - Exp: `### replicas + Exp: `- [$replicas$](#replicas) + +## All Values + +### replicas -- $replicas$ ((#v-replicas)) ($integer: 3$) - Line 1\n Line 2`, +- $replicas$ ((#v-replicas)) ($integer: 3$) - Line 1\n Line 2 +`, }, "boolean value": { Input: `--- # Line 1 # Line 2 enabled: true`, - Exp: `### enabled + Exp: `- [$enabled$](#enabled) + +## All Values -- $enabled$ ((#v-enabled)) ($boolean: true$) - Line 1\n Line 2`, +### enabled + +- $enabled$ ((#v-enabled)) ($boolean: true$) - Line 1\n Line 2 +`, }, "map": { Input: `--- @@ -50,11 +65,16 @@ map: # Key line 1 # Key line 2 key: value`, - Exp: `### map + Exp: `- [$map$](#map) + +## All Values + +### map - $map$ ((#v-map)) - Map line 1\n Map line 2 - - $key$ ((#v-map-key)) ($string: value$) - Key line 1\n Key line 2`, + - $key$ ((#v-map-key)) ($string: value$) - Key line 1\n Key line 2 +`, }, "map with multiple keys": { Input: `--- @@ -68,7 +88,11 @@ map: int: 1 # Bool docs bool: true`, - Exp: `### map + Exp: `- [$map$](#map) + +## All Values + +### map - $map$ ((#v-map)) - Map line 1\n Map line 2 @@ -77,16 +101,22 @@ map: - $int$ ((#v-map-int)) ($integer: 1$) - Int docs - - $bool$ ((#v-map-bool)) ($boolean: true$) - Bool docs`, + - $bool$ ((#v-map-bool)) ($boolean: true$) - Bool docs +`, }, "null value": { Input: `--- # key docs # @type: string key: null`, - Exp: `### key + Exp: `- [$key$](#key) + +## All Values -- $key$ ((#v-key)) ($string: null$) - key docs`, +### key + +- $key$ ((#v-key)) ($string: null$) - key docs +`, }, "description with empty line": { Input: `--- @@ -94,9 +124,14 @@ key: null`, # # line 2 key: value`, - Exp: `### key + Exp: `- [$key$](#key) -- $key$ ((#v-key)) ($string: value$) - line 1\n\n line 2`, +## All Values + +### key + +- $key$ ((#v-key)) ($string: value$) - line 1\n\n line 2 +`, }, "array of strings": { Input: `--- @@ -104,9 +139,14 @@ key: value`, # @type: array serverAdditionalDNSSANs: [] `, - Exp: `### serverAdditionalDNSSANs + Exp: `- [$serverAdditionalDNSSANs$](#serveradditionaldnssans) + +## All Values + +### serverAdditionalDNSSANs -- $serverAdditionalDNSSANs$ ((#v-serveradditionaldnssans)) ($array: []$) - line 1`, +- $serverAdditionalDNSSANs$ ((#v-serveradditionaldnssans)) ($array: []$) - line 1 +`, }, "map with empty string values": { Input: `--- @@ -117,13 +157,18 @@ gossipEncryption: # secretKey secretKey: "" `, - Exp: `### gossipEncryption + Exp: `- [$gossipEncryption$](#gossipencryption) + +## All Values + +### gossipEncryption - $gossipEncryption$ ((#v-gossipencryption)) - gossipEncryption - $secretName$ ((#v-gossipencryption-secretname)) ($string: ""$) - secretName - - $secretKey$ ((#v-gossipencryption-secretkey)) ($string: ""$) - secretKey`, + - $secretKey$ ((#v-gossipencryption-secretkey)) ($string: ""$) - secretKey +`, }, "map with null string values": { Input: `--- @@ -133,13 +178,18 @@ bootstrapToken: # @type: string secretKey: null `, - Exp: `### bootstrapToken + Exp: `- [$bootstrapToken$](#bootstraptoken) + +## All Values + +### bootstrapToken - $bootstrapToken$ ((#v-bootstraptoken)) - $secretName$ ((#v-bootstraptoken-secretname)) ($string: null$) - - $secretKey$ ((#v-bootstraptoken-secretkey)) ($string: null$)`, + - $secretKey$ ((#v-bootstraptoken-secretkey)) ($string: null$) +`, }, "resource settings": { Input: `--- @@ -167,7 +217,11 @@ lifecycleSidecarContainer: memory: "50Mi" cpu: "20m" `, - Exp: `### lifecycleSidecarContainer + Exp: `- [$lifecycleSidecarContainer$](#lifecyclesidecarcontainer) + +## All Values + +### lifecycleSidecarContainer - $lifecycleSidecarContainer$ ((#v-lifecyclesidecarcontainer)) - lifecycle @@ -196,7 +250,8 @@ lifecycleSidecarContainer: - $memory$ ((#v-lifecyclesidecarcontainer-resources-limits-memory)) ($string: 50Mi$) - - $cpu$ ((#v-lifecyclesidecarcontainer-resources-limits-cpu)) ($string: 20m$)`, + - $cpu$ ((#v-lifecyclesidecarcontainer-resources-limits-cpu)) ($string: 20m$) +`, }, "default as dash": { Input: `--- @@ -208,22 +263,32 @@ server: # @type: boolean enabled: "-" `, - Exp: `### server + Exp: `- [$server$](#server) + +## All Values + +### server - $server$ ((#v-server)) - $enabled$ ((#v-server-enabled)) ($boolean: global.enabled$) - If true, the chart will install all the resources necessary for a Consul server cluster. If you're running Consul externally and want agents - within Kubernetes to join that cluster, this should probably be false.`, + within Kubernetes to join that cluster, this should probably be false. +`, }, "extraConfig {}": { Input: `--- extraConfig: | {} `, - Exp: `### extraConfig + Exp: `- [$extraConfig$](#extraconfig) + +## All Values + +### extraConfig -- $extraConfig$ ((#v-extraconfig)) ($string: {}$)`, +- $extraConfig$ ((#v-extraconfig)) ($string: {}$) +`, }, "affinity": { Input: `--- @@ -238,36 +303,56 @@ affinity: | component: server topologyKey: kubernetes.io/hostname `, - Exp: `### affinity + Exp: `- [$affinity$](#affinity) + +## All Values -- $affinity$ ((#v-affinity)) ($string$) - Affinity Settings`, +### affinity + +- $affinity$ ((#v-affinity)) ($string$) - Affinity Settings +`, }, "k8sAllowNamespaces": { Input: `--- # @type: array k8sAllowNamespaces: ["*"]`, - Exp: `### k8sAllowNamespaces + Exp: `- [$k8sAllowNamespaces$](#k8sallownamespaces) + +## All Values + +### k8sAllowNamespaces -- $k8sAllowNamespaces$ ((#v-k8sallownamespaces)) ($array: ["*"]$)`, +- $k8sAllowNamespaces$ ((#v-k8sallownamespaces)) ($array: ["*"]$) +`, }, "k8sDenyNamespaces": { Input: `--- # @type: array k8sDenyNamespaces: ["kube-system", "kube-public"]`, - Exp: `### k8sDenyNamespaces + Exp: `- [$k8sDenyNamespaces$](#k8sdenynamespaces) + +## All Values + +### k8sDenyNamespaces -- $k8sDenyNamespaces$ ((#v-k8sdenynamespaces)) ($array: ["kube-system", "kube-public"]$)`, +- $k8sDenyNamespaces$ ((#v-k8sdenynamespaces)) ($array: ["kube-system", "kube-public"]$) +`, }, "gateways": { Input: `--- # @type: array gateways: - name: ingress-gateway`, - Exp: `### gateways + Exp: `- [$gateways$](#gateways) + +## All Values + +### gateways - $gateways$ ((#v-gateways)) ($array$) - - $name$ ((#v-gateways-name)) ($string: ingress-gateway$)`, + - $name$ ((#v-gateways-name)) ($string: ingress-gateway$) +`, }, "enterprise alert": { Input: `--- @@ -275,9 +360,14 @@ gateways: # line 2 key: value `, - Exp: `### key + Exp: `- [$key$](#key) + +## All Values + +### key -- $key$ ((#v-key)) ($string: value$) - line 1\n line 2`, +- $key$ ((#v-key)) ($string: value$) - line 1\n line 2 +`, }, "yaml comments in examples": { Input: `--- @@ -291,7 +381,11 @@ key: value # $$$ key: value `, - Exp: `### key + Exp: `- [$key$](#key) + +## All Values + +### key - $key$ ((#v-key)) ($string: value$) - Examples: @@ -300,7 +394,8 @@ key: value image: "consul:1.5.0" # Consul Enterprise 1.5.0 image: "hashicorp/consul-enterprise:1.5.0-ent" - $$$`, + $$$ +`, }, "type override uses last match": { Input: `--- @@ -308,9 +403,14 @@ key: value # @type: override-2 key: value `, - Exp: `### key + Exp: `- [$key$](#key) + +## All Values -- $key$ ((#v-key)) ($override-2: value$)`, +### key + +- $key$ ((#v-key)) ($override-2: value$) +`, }, "recurse false": { Input: `--- @@ -324,33 +424,49 @@ ports: - port: 8443 nodePort: null `, - Exp: `### key + Exp: `- [$key$](#key) +- [$ports$](#ports) + +## All Values + +### key - $key$ ((#v-key)) ($string: value$) ### ports -- $ports$ ((#v-ports)) ($array$) - port docs`, +- $ports$ ((#v-ports)) ($array$) - port docs +`, }, "@type: map": { Input: `--- # @type: map key: null `, - Exp: `### key + Exp: `- [$key$](#key) + +## All Values -- $key$ ((#v-key)) ($map$)`, +### key + +- $key$ ((#v-key)) ($map$) +`, }, "if of type map and not annotated with @type": { Input: `--- key: foo: bar `, - Exp: `### key + Exp: `- [$key$](#key) + +## All Values + +### key - $key$ ((#v-key)) - - $foo$ ((#v-key-foo)) ($string: bar$)`, + - $foo$ ((#v-key-foo)) ($string: bar$) +`, }, } @@ -368,6 +484,8 @@ key: // Swap \n for real \n. exp = strings.Replace(exp, "\\n", "\n", -1) + exp = tocPrefix + exp + require.Equal(t, exp, out) }) } From 28128f6223177b333aecafab03a052b57f88aa69 Mon Sep 17 00:00:00 2001 From: NicoletaPopoviciu <87660255+NicoletaPopoviciu@users.noreply.github.com> Date: Wed, 29 Sep 2021 11:54:25 -0400 Subject: [PATCH 042/418] Enable adding extra containers to clients and servers via helm configuration. (#749) Co-authored-by: Iryna Shustava Co-authored-by: Luke Kysow <1034429+lkysow@users.noreply.github.com> --- CHANGELOG.md | 2 + charts/consul/templates/client-daemonset.yaml | 3 + .../consul/templates/server-statefulset.yaml | 3 + charts/consul/test/unit/client-daemonset.bats | 76 ++++++++++++++++++ .../consul/test/unit/server-statefulset.bats | 77 ++++++++++++++++++- charts/consul/values.yaml | 26 +++++++ 6 files changed, 186 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 744c065350..b4de5b5ce4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ IMPROVEMENTS: * Control Plane * Upgrade Docker image Alpine version from 3.13 to 3.14. [[GH-737](https://github.com/hashicorp/consul-k8s/pull/737)] +* Helm Chart + * Enable adding extra containers to server and client Pods. [[GH-749](https://github.com/hashicorp/consul-k8s/pull/749)] ## 0.34.1 (September 17, 2021) diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index 58eb73ca9e..d2a2dcb583 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -362,6 +362,9 @@ spec: securityContext: {{- toYaml .Values.client.containerSecurityContext.client | nindent 12 }} {{- end }} + {{- if .Values.client.extraContainers }} + {{ toYaml .Values.client.extraContainers | nindent 8 }} + {{- end }} {{- if (or .Values.global.acls.manageSystemACLs (and .Values.global.tls.enabled (not .Values.global.tls.enableAutoEncrypt))) }} initContainers: {{- if .Values.global.acls.manageSystemACLs }} diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 09668f2859..05460ed217 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -351,6 +351,9 @@ spec: securityContext: {{- toYaml .Values.server.containerSecurityContext.server | nindent 12 }} {{- end }} + {{- if .Values.server.extraContainers }} + {{ toYaml .Values.server.extraContainers | nindent 8 }} + {{- end }} {{- if .Values.server.nodeSelector }} nodeSelector: {{ tpl .Values.server.nodeSelector . | indent 8 | trim }} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index d9bd845765..ce202bca3e 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1419,3 +1419,79 @@ rollingUpdate: [ "$status" -eq 1 ] [[ "$output" =~ "global.adminPartitions.name has to be \"default\" in the server cluster" ]] } + +#-------------------------------------------------------------------- +# extraContainers + +@test "client/DaemonSet: extraContainers adds extra container" { + cd `chart_dir` + + # Test that it defines the extra container + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'client.extraContainers[0].image=test-image' \ + --set 'client.extraContainers[0].name=test-container' \ + --set 'client.extraContainers[0].ports[0].name=test-port' \ + --set 'client.extraContainers[0].ports[0].containerPort=9410' \ + --set 'client.extraContainers[0].ports[0].protocol=TCP' \ + --set 'client.extraContainers[0].env[0].name=TEST_ENV' \ + --set 'client.extraContainers[0].env[0].value=test_env_value' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[] | select(.name == "test-container")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.name' | tee /dev/stderr) + [ "${actual}" = "test-container" ] + + local actual=$(echo $object | + yq -r '.image' | tee /dev/stderr) + [ "${actual}" = "test-image" ] + + local actual=$(echo $object | + yq -r '.ports[0].name' | tee /dev/stderr) + [ "${actual}" = "test-port" ] + + local actual=$(echo $object | + yq -r '.ports[0].containerPort' | tee /dev/stderr) + [ "${actual}" = "9410" ] + + local actual=$(echo $object | + yq -r '.ports[0].protocol' | tee /dev/stderr) + [ "${actual}" = "TCP" ] + + local actual=$(echo $object | + yq -r '.env[0].name' | tee /dev/stderr) + [ "${actual}" = "TEST_ENV" ] + + local actual=$(echo $object | + yq -r '.env[0].value' | tee /dev/stderr) + [ "${actual}" = "test_env_value" ] + +} + +@test "client/DaemonSet: extraContainers supports adding two containers" { + cd `chart_dir` + + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'client.extraContainers[0].image=test-image' \ + --set 'client.extraContainers[0].name=test-container' \ + --set 'client.extraContainers[1].image=test-image' \ + --set 'client.extraContainers[1].name=test-container-2' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers | length' | tee /dev/stderr) + + [ "${object}" = 3 ] + +} + +@test "client/DaemonSet: no extra client containers added by default" { + cd `chart_dir` + + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers | length' | tee /dev/stderr) + + [ "${object}" = 1 ] +} diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 78dd6a873e..ac2be4c2c9 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -1308,7 +1308,6 @@ load _helpers [ "${actual}" = '{"name":"CONSUL_LICENSE_PATH","value":"/consul/license/bar"}' ] } - @test "server/StatefulSet: -recursor can be set by global.recursors" { cd `chart_dir` local actual=$(helm template \ @@ -1318,3 +1317,79 @@ load _helpers yq -r -c '.spec.template.spec.containers[0].command | join(" ") | contains("-recursor=\"1.2.3.4\"")' | tee /dev/stderr) [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# extraContainers + +@test "server/StatefulSet: adds extra container" { + cd `chart_dir` + + # Test that it defines the extra container + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'server.extraContainers[0].image=test-image' \ + --set 'server.extraContainers[0].name=test-container' \ + --set 'server.extraContainers[0].ports[0].name=test-port' \ + --set 'server.extraContainers[0].ports[0].containerPort=9410' \ + --set 'server.extraContainers[0].ports[0].protocol=TCP' \ + --set 'server.extraContainers[0].env[0].name=TEST_ENV' \ + --set 'server.extraContainers[0].env[0].value=test_env_value' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[] | select(.name == "test-container")' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.name' | tee /dev/stderr) + [ "${actual}" = "test-container" ] + + local actual=$(echo $object | + yq -r '.image' | tee /dev/stderr) + [ "${actual}" = "test-image" ] + + local actual=$(echo $object | + yq -r '.ports[0].name' | tee /dev/stderr) + [ "${actual}" = "test-port" ] + + local actual=$(echo $object | + yq -r '.ports[0].containerPort' | tee /dev/stderr) + [ "${actual}" = "9410" ] + + local actual=$(echo $object | + yq -r '.ports[0].protocol' | tee /dev/stderr) + [ "${actual}" = "TCP" ] + + local actual=$(echo $object | + yq -r '.env[0].name' | tee /dev/stderr) + [ "${actual}" = "TEST_ENV" ] + + local actual=$(echo $object | + yq -r '.env[0].value' | tee /dev/stderr) + [ "${actual}" = "test_env_value" ] + +} + +@test "server/StatefulSet: adds two extra containers" { + cd `chart_dir` + + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'server.extraContainers[0].image=test-image' \ + --set 'server.extraContainers[0].name=test-container' \ + --set 'server.extraContainers[1].image=test-image' \ + --set 'server.extraContainers[1].name=test-container-2' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers | length' | tee /dev/stderr) + + [ "${object}" = 3 ] + +} + +@test "server/StatefulSet: no extra containers added by default" { + cd `chart_dir` + + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers | length' | tee /dev/stderr) + + [ "${object}" = 1 ] +} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index e1c0726deb..9105565572 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -596,6 +596,19 @@ server: # @type: array extraVolumes: [] + # A list of sidecar containers. + # Example: + # + # ```yaml + # extraContainers: + # - name: extra-container + # image: example-image:latest + # command: + # - ... + # ``` + # @type: array + extraContainers: [] + # This value defines the affinity (https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity) # for server pods. It defaults to allowing only a single server pod on each node, which # minimizes risk of the cluster becoming unusable if a node is lost. If you need @@ -925,6 +938,19 @@ client: # @type: array extraVolumes: [] + # A list of sidecar containers. + # Example: + # + # ```yaml + # extraContainers: + # - name: extra-container + # image: example-image:latest + # command: + # - ... + # ``` + # @type: array + extraContainers: [] + # Toleration Settings for Client pods # This should be a multi-line string matching the Toleration array # in a PodSpec. From 6305e749ddcedfe49159d70bcccee008c5b1f8a1 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Thu, 30 Sep 2021 11:43:27 -0600 Subject: [PATCH 043/418] acceptance-tests-framework: create ent image from values.yaml isntead of Chart.yaml (#752) --- .../acceptance/framework/config/config.go | 43 +++++++++++++------ .../framework/config/config_test.go | 39 +++++++++-------- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/charts/consul/test/acceptance/framework/config/config.go b/charts/consul/test/acceptance/framework/config/config.go index 4aab38f7d7..5346e248cc 100644 --- a/charts/consul/test/acceptance/framework/config/config.go +++ b/charts/consul/test/acceptance/framework/config/config.go @@ -1,7 +1,6 @@ package config import ( - "errors" "fmt" "io/ioutil" "path/filepath" @@ -91,38 +90,56 @@ func (t *TestConfig) HelmValuesFromConfig() (map[string]string, error) { return helmValues, nil } -// entImage parses out consul version from Chart.yaml +type values struct { + Global globalValues `yaml:"global"` +} + +type globalValues struct { + Image string `yaml:"image"` +} + +// entImage parses out consul version from values.yaml // and sets global.image to the consul enterprise image with that version. func (t *TestConfig) entImage() (string, error) { if t.helmChartPath == "" { t.helmChartPath = HelmChartPath } - // Unmarshal Chart.yaml to get appVersion (i.e. Consul version) - chart, err := ioutil.ReadFile(filepath.Join(t.helmChartPath, "Chart.yaml")) + // Unmarshal values.yaml to current global.image value. + valuesContents, err := ioutil.ReadFile(filepath.Join(t.helmChartPath, "values.yaml")) if err != nil { return "", err } - var chartMap map[string]interface{} - err = yaml.Unmarshal(chart, &chartMap) + var v values + err = yaml.Unmarshal(valuesContents, &v) if err != nil { return "", err } - appVersion, ok := chartMap["appVersion"].(string) - if !ok { - return "", errors.New("unable to cast chartMap.appVersion to string") + // Check if the image contains digest instead of a tag. + // If it does, we want to use that image instead rather than + // trying to change the tag to an enterprise tag. + if strings.Contains(v.Global.Image, "@sha256") { + return v.Global.Image, nil } + + // Otherwise, assume that we have an image tag with a version in it. + consulImageSplits := strings.Split(v.Global.Image, ":") + if len(consulImageSplits) != 2 { + return "", fmt.Errorf("could not determine consul version from global.image: %s", v.Global.Image) + } + consulImageVersion := consulImageSplits[1] + var preRelease string // Handle versions like 1.9.0-rc1. - if strings.Contains(appVersion, "-") { - split := strings.Split(appVersion, "-") - appVersion = split[0] + if strings.Contains(consulImageVersion, "-") { + split := strings.Split(consulImageVersion, "-") + consulImageVersion = split[0] preRelease = fmt.Sprintf("-%s", split[1]) } - return fmt.Sprintf("hashicorp/consul-enterprise:%s-ent%s", appVersion, preRelease), nil + return fmt.Sprintf("hashicorp/consul-enterprise:%s-ent%s", consulImageVersion, preRelease), nil } // setIfNotEmpty sets key to val in map m if value is not empty. diff --git a/charts/consul/test/acceptance/framework/config/config_test.go b/charts/consul/test/acceptance/framework/config/config_test.go index 3e1679be88..df320687b8 100644 --- a/charts/consul/test/acceptance/framework/config/config_test.go +++ b/charts/consul/test/acceptance/framework/config/config_test.go @@ -116,39 +116,42 @@ func TestConfig_HelmValuesFromConfig(t *testing.T) { func TestConfig_HelmValuesFromConfig_EntImage(t *testing.T) { tests := []struct { - appVersion string - expImage string - expErr string + consulImage string + expImage string + expErr string }{ { - appVersion: "1.9.0", - expImage: "hashicorp/consul-enterprise:1.9.0-ent", + consulImage: "hashicorp/consul:1.9.0", + expImage: "hashicorp/consul-enterprise:1.9.0-ent", }, { - appVersion: "1.8.5-rc1", - expImage: "hashicorp/consul-enterprise:1.8.5-ent-rc1", + consulImage: "hashicorp/consul:1.8.5-rc1", + expImage: "hashicorp/consul-enterprise:1.8.5-ent-rc1", }, { - appVersion: "1.7.0-beta3", - expImage: "hashicorp/consul-enterprise:1.7.0-ent-beta3", + consulImage: "hashicorp/consul:1.7.0-beta3", + expImage: "hashicorp/consul-enterprise:1.7.0-ent-beta3", }, { - appVersion: "1", - expErr: "unable to cast chartMap.appVersion to string", + consulImage: "invalid", + expErr: "could not determine consul version from global.image: invalid", + }, + { + consulImage: "hashicorp/consul@sha256:oioi2452345kjhlkh", + expImage: "hashicorp/consul@sha256:oioi2452345kjhlkh", }, } for _, tt := range tests { - t.Run(tt.appVersion, func(t *testing.T) { + t.Run(tt.consulImage, func(t *testing.T) { - // Write Chart.yaml to a temp dir which will then get parsed. - chartYAML := fmt.Sprintf(`apiVersion: v1 -name: consul -appVersion: %s -`, tt.appVersion) + // Write values.yaml to a temp dir which will then get parsed. + valuesYAML := fmt.Sprintf(`global: + image: %s +`, tt.consulImage) tmp, err := ioutil.TempDir("", "") require.NoError(t, err) defer os.RemoveAll(tmp) - require.NoError(t, ioutil.WriteFile(filepath.Join(tmp, "Chart.yaml"), []byte(chartYAML), 0644)) + require.NoError(t, ioutil.WriteFile(filepath.Join(tmp, "values.yaml"), []byte(valuesYAML), 0644)) cfg := TestConfig{ EnableEnterprise: true, From ff27e8a0004f08ffd38031999585259c0b13ce47 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 30 Sep 2021 13:10:48 -0700 Subject: [PATCH 044/418] Add support for version command (#741) * Use correct name for binary * Add support for version command - Also refactor the version code out into top-level version pkg to match how the control-plane is factored --- CHANGELOG.md | 4 +- cli/README.md | 2 +- cli/cmd/version/version.go | 67 ++++++++------------- cli/commands.go | 8 +++ cli/main.go | 2 +- cli/version/version.go | 50 +++++++++++++++ control-plane/subcommand/version/command.go | 2 +- 7 files changed, 89 insertions(+), 46 deletions(-) create mode 100644 cli/version/version.go diff --git a/CHANGELOG.md b/CHANGELOG.md index b4de5b5ce4..9f7e305e76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,9 @@ IMPROVEMENTS: * Control Plane * Upgrade Docker image Alpine version from 3.13 to 3.14. [[GH-737](https://github.com/hashicorp/consul-k8s/pull/737)] * Helm Chart - * Enable adding extra containers to server and client Pods. [[GH-749](https://github.com/hashicorp/consul-k8s/pull/749)] + * Enable adding extra containers to server and client Pods. [[GH-749](https://github.com/hashicorp/consul-k8s/pull/749)] +* CLI + * Add `version` command. [[GH-741](https://github.com/hashicorp/consul-k8s/pull/741)] ## 0.34.1 (September 17, 2021) diff --git a/cli/README.md b/cli/README.md index 1820b1cdd3..cad0f51b7e 100644 --- a/cli/README.md +++ b/cli/README.md @@ -124,4 +124,4 @@ Global Options: -kubeconfig= Path to kubeconfig file. This is aliased as "-c". -``` \ No newline at end of file +``` diff --git a/cli/cmd/version/version.go b/cli/cmd/version/version.go index 8ae086e89a..417baaff4a 100644 --- a/cli/cmd/version/version.go +++ b/cli/cmd/version/version.go @@ -2,49 +2,32 @@ package version import ( "fmt" - "strings" -) + "sync" -var ( - // The git commit that was compiled. These will be filled in by the compiler. - GitCommit string - GitDescribe string - - // The main version number that is being run at the moment. - // - // Version must conform to the format expected by - // github.com/hashicorp/go-version for tests to work. - Version = "0.0.1" - - // A pre-release marker for the version. If this is "" (empty string) - // then it means that it is a final release. Otherwise, this is a pre-release - // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + "github.com/hashicorp/consul-k8s/cli/cmd/common" ) -// GetHumanVersion composes the parts of the version in a way that's suitable -// for displaying to humans. -func GetHumanVersion() string { - version := Version - if GitDescribe != "" { - version = GitDescribe - } - - release := VersionPrerelease - if GitDescribe == "" && release == "" { - release = "dev" - } - - if release != "" { - if !strings.HasSuffix(version, "-"+release) { - // if we tagged a prerelease version then the release is in the version already - version += fmt.Sprintf("-%s", release) - } - if GitCommit != "" { - version += fmt.Sprintf(" (%s)", GitCommit) - } - } - - // Strip off any single quotes added by the git information. - return strings.Replace(version, "'", "", -1) +type Command struct { + *common.BaseCommand + + Version string + once sync.Once +} + +func (c *Command) init() { + c.Init() +} + +func (c *Command) Run(_ []string) int { + c.once.Do(c.init) + c.UI.Output(fmt.Sprintf("consul-k8s %s", c.Version)) + return 0 +} + +func (c *Command) Synopsis() string { + return "Prints the version of the CLI." +} + +func (c *Command) Help() string { + return "Usage: consul version [options]\n" } diff --git a/cli/commands.go b/cli/commands.go index 2725c5d4bf..3fc4a7d936 100644 --- a/cli/commands.go +++ b/cli/commands.go @@ -6,6 +6,8 @@ import ( "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/consul-k8s/cli/cmd/install" "github.com/hashicorp/consul-k8s/cli/cmd/uninstall" + cmdversion "github.com/hashicorp/consul-k8s/cli/cmd/version" + "github.com/hashicorp/consul-k8s/cli/version" "github.com/hashicorp/go-hclog" "github.com/mitchellh/cli" ) @@ -28,6 +30,12 @@ func initializeCommands(ctx context.Context, log hclog.Logger) (*common.BaseComm BaseCommand: baseCommand, }, nil }, + "version": func() (cli.Command, error) { + return &cmdversion.Command{ + BaseCommand: baseCommand, + Version: version.GetHumanVersion(), + }, nil + }, } return baseCommand, commands diff --git a/cli/main.go b/cli/main.go index 1285e7625c..0c3705f0df 100644 --- a/cli/main.go +++ b/cli/main.go @@ -6,7 +6,7 @@ import ( "os/signal" "syscall" - "github.com/hashicorp/consul-k8s/cli/cmd/version" + "github.com/hashicorp/consul-k8s/cli/version" "github.com/hashicorp/go-hclog" "github.com/mitchellh/cli" ) diff --git a/cli/version/version.go b/cli/version/version.go new file mode 100644 index 0000000000..6194e7ee7c --- /dev/null +++ b/cli/version/version.go @@ -0,0 +1,50 @@ +package version + +import ( + "fmt" + "strings" +) + +var ( + // The git commit that was compiled. These will be filled in by the compiler. + GitCommit string + GitDescribe string + + // The main version number that is being run at the moment. + // + // Version must conform to the format expected by + // github.com/hashicorp/go-version for tests to work. + Version = "0.34.1" + + // A pre-release marker for the version. If this is "" (empty string) + // then it means that it is a final release. Otherwise, this is a pre-release + // such as "dev" (in development), "beta", "rc1", etc. + VersionPrerelease = "dev" +) + +// GetHumanVersion composes the parts of the version in a way that's suitable +// for displaying to humans. +func GetHumanVersion() string { + version := Version + if GitDescribe != "" { + version = GitDescribe + } + + release := VersionPrerelease + if GitDescribe == "" && release == "" { + release = "dev" + } + + if release != "" { + if !strings.HasSuffix(version, "-"+release) { + // if we tagged a prerelease version then the release is in the version already + version += fmt.Sprintf("-%s", release) + } + if GitCommit != "" { + version += fmt.Sprintf(" (%s)", GitCommit) + } + } + + // Strip off any single quotes added by the git information. + return strings.Replace(version, "'", "", -1) +} diff --git a/control-plane/subcommand/version/command.go b/control-plane/subcommand/version/command.go index 3b53129762..58768a1f92 100644 --- a/control-plane/subcommand/version/command.go +++ b/control-plane/subcommand/version/command.go @@ -12,7 +12,7 @@ type Command struct { } func (c *Command) Run(_ []string) int { - c.UI.Output(fmt.Sprintf("consul-k8s %s", c.Version)) + c.UI.Output(fmt.Sprintf("consul-k8s-control-plane %s", c.Version)) return 0 } From 6254b1fbb88ba72b20b22da4216a2ff3e61a4fac Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Thu, 30 Sep 2021 14:14:45 -0700 Subject: [PATCH 045/418] ci: fix installing helm prerequisite (#753) Grab helm binary from releases page rather than apt installing it. The apt install stopped working because of an expired certificate on baltocdn: https://app.circleci.com/pipelines/github/hashicorp/consul-k8s/2798/workflows/54156ea4-54c6-4622-a4ec-4a623a266cb5/jobs/18933 --- .circleci/config.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f4da6ac895..7f76b6b469 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,11 +45,10 @@ commands: chmod +x ./kubectl sudo mv ./kubectl /usr/local/bin/kubectl - curl https://baltocdn.com/helm/signing.asc | sudo apt-key add - - sudo apt-get install apt-transport-https --yes - echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list - sudo apt-get update - sudo apt-get install helm + wget https://get.helm.sh/helm-v3.7.0-linux-amd64.tar.gz + tar -zxvf helm-v3.7.0-linux-amd64.tar.gz + sudo mv linux-amd64/helm /usr/local/bin/helm + create-kind-clusters: parameters: version: From a376f18917e60242db517377a2d4ee258b0faf1b Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 1 Oct 2021 11:43:41 -0400 Subject: [PATCH 046/418] acceptance tests for admin partitions (#747) * Add acceptance tests for Admin Partitions - This tests is a multi cluster test that uses 2 Kubernetes clusters. Servers are installed on one of them and only agents in another. - It asserts that the agents in the agent-only cluster are created in the correct partition. - Updates have been made to the metrics test to account for partitions being emmitted by the envoy metrics. --- .../kustomization.yaml | 5 + .../cases/static-client-partition/patch.yaml | 10 ++ .../acceptance/tests/metrics/metrics_test.go | 8 +- .../acceptance/tests/partitions/main_test.go | 22 +++ .../tests/partitions/partitions_test.go | 146 ++++++++++++++++++ 5 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml create mode 100644 charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/patch.yaml create mode 100644 charts/consul/test/acceptance/tests/partitions/main_test.go create mode 100644 charts/consul/test/acceptance/tests/partitions/partitions_test.go diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml b/charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml new file mode 100644 index 0000000000..974fbd4fe1 --- /dev/null +++ b/charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml @@ -0,0 +1,5 @@ +bases: + - ../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/patch.yaml b/charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/patch.yaml new file mode 100644 index 0000000000..42857c3d2b --- /dev/null +++ b/charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/patch.yaml @@ -0,0 +1,10 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: static-client +spec: + template: + metadata: + annotations: + "consul.hashicorp.com/connect-inject": "true" + "consul.hashicorp.com/connect-service-upstreams": "static-server.default.secondary:1234" \ No newline at end of file diff --git a/charts/consul/test/acceptance/tests/metrics/metrics_test.go b/charts/consul/test/acceptance/tests/metrics/metrics_test.go index d4b3469d1d..44bec20f8b 100644 --- a/charts/consul/test/acceptance/tests/metrics/metrics_test.go +++ b/charts/consul/test/acceptance/tests/metrics/metrics_test.go @@ -75,13 +75,13 @@ func TestComponentMetrics(t *testing.T) { require.Contains(t, metricsOutput, `consul_acl_ResolveToken{quantile="0.5"}`) // Ingress Gateway Metrics - assertGatewayMetricsEnabled(t, ctx, ns, "ingress-gateway", `envoy_cluster_assignment_stale{local_cluster="ingress-gateway",consul_source_service="ingress-gateway",consul_source_namespace="default",consul_source_datacenter="dc1",envoy_cluster_name="local_agent"} 0`) + assertGatewayMetricsEnabled(t, ctx, ns, "ingress-gateway", `envoy_cluster_assignment_stale{local_cluster="ingress-gateway",consul_source_service="ingress-gateway"`) // Terminating Gateway Metrics - assertGatewayMetricsEnabled(t, ctx, ns, "terminating-gateway", `envoy_cluster_assignment_stale{local_cluster="terminating-gateway",consul_source_service="terminating-gateway",consul_source_namespace="default",consul_source_datacenter="dc1",envoy_cluster_name="local_agent"} 0`) + assertGatewayMetricsEnabled(t, ctx, ns, "terminating-gateway", `envoy_cluster_assignment_stale{local_cluster="terminating-gateway",consul_source_service="terminating-gateway"`) // Mesh Gateway Metrics - assertGatewayMetricsEnabled(t, ctx, ns, "mesh-gateway", `envoy_cluster_assignment_stale{local_cluster="mesh-gateway",consul_source_service="mesh-gateway",consul_source_namespace="default",consul_source_datacenter="dc1",envoy_cluster_name="local_agent"} 0`) + assertGatewayMetricsEnabled(t, ctx, ns, "mesh-gateway", `envoy_cluster_assignment_stale{local_cluster="mesh-gateway",consul_source_service="mesh-gateway"`) } // Test that merged service and envoy metrics are accessible from the @@ -124,7 +124,7 @@ func TestAppMetrics(t *testing.T) { metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+staticClientName, "--", "curl", "--silent", "--show-error", fmt.Sprintf("http://%s:20200/metrics", podIP)) require.NoError(t, err) // This assertion represents the metrics from the envoy sidecar. - require.Contains(t, metricsOutput, `envoy_cluster_assignment_stale{local_cluster="server",consul_source_service="server",consul_source_namespace="default",consul_source_datacenter="dc1",envoy_cluster_name="local_agent"} 0`) + require.Contains(t, metricsOutput, `envoy_cluster_assignment_stale{local_cluster="server",consul_source_service="server"`) // This assertion represents the metrics from the application. require.Contains(t, metricsOutput, `service_started_total 1`) } diff --git a/charts/consul/test/acceptance/tests/partitions/main_test.go b/charts/consul/test/acceptance/tests/partitions/main_test.go new file mode 100644 index 0000000000..c26f293f10 --- /dev/null +++ b/charts/consul/test/acceptance/tests/partitions/main_test.go @@ -0,0 +1,22 @@ +package partitions + +import ( + "fmt" + "os" + "testing" + + testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" +) + +var suite testsuite.Suite + +func TestMain(m *testing.M) { + suite = testsuite.NewSuite(m) + + if suite.Config().EnableMultiCluster { + os.Exit(suite.Run()) + } else { + fmt.Println("Skipping partitions tests because -enable-multi-cluster is not set") + os.Exit(0) + } +} diff --git a/charts/consul/test/acceptance/tests/partitions/partitions_test.go b/charts/consul/test/acceptance/tests/partitions/partitions_test.go new file mode 100644 index 0000000000..bb6c1553eb --- /dev/null +++ b/charts/consul/test/acceptance/tests/partitions/partitions_test.go @@ -0,0 +1,146 @@ +package partitions + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Test that Connect works in a default installation. +// i.e. without ACLs because TLS is required for setting up Admin Partitions. +func TestPartitions(t *testing.T) { + env := suite.Environment() + cfg := suite.Config() + + if !cfg.EnableEnterprise { + t.Skipf("skipping this test because -enable-enterprise is not set") + } + + if !cfg.UseKind { + t.Skipf("skipping this test because Admin Partition tests are only supported in Kind for now") + } + + primaryContext := env.DefaultContext(t) + secondaryContext := env.Context(t, environment.SecondaryContextName) + + ctx := context.Background() + + primaryHelmValues := map[string]string{ + "global.datacenter": "dc1", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-alpha", + + "global.adminPartitions.enabled": "true", + "global.enableConsulNamespaces": "true", + "global.tls.enabled": "true", + + "server.exposeGossipAndRPCPorts": "true", + + "connectInject.enabled": "true", + } + + if cfg.UseKind { + primaryHelmValues["global.adminPartitions.service.type"] = "NodePort" + primaryHelmValues["global.adminPartitions.service.nodePort.https"] = "30000" + } + + releaseName := helpers.RandomName() + + // Install the consul cluster with servers in the default kubernetes context. + primaryConsulCluster := consul.NewHelmCluster(t, primaryHelmValues, primaryContext, cfg, releaseName) + primaryConsulCluster.Create(t) + + // Get the TLS CA certificate and key secret from the primary cluster and apply it to secondary cluster + tlsCert := fmt.Sprintf("%s-consul-ca-cert", releaseName) + logger.Logf(t, "retrieving ca cert secret %s from the primary cluster and applying to the secondary", tlsCert) + caCertSecret, err := primaryContext.KubernetesClient(t).CoreV1().Secrets(primaryContext.KubectlOptions(t).Namespace).Get(ctx, tlsCert, metav1.GetOptions{}) + caCertSecret.ResourceVersion = "" + require.NoError(t, err) + _, err = secondaryContext.KubernetesClient(t).CoreV1().Secrets(secondaryContext.KubectlOptions(t).Namespace).Create(ctx, caCertSecret, metav1.CreateOptions{}) + require.NoError(t, err) + + tlsKey := fmt.Sprintf("%s-consul-ca-key", releaseName) + logger.Logf(t, "retrieving ca key secret %s from the primary cluster and applying to the secondary", tlsKey) + caKeySecret, err := primaryContext.KubernetesClient(t).CoreV1().Secrets(primaryContext.KubectlOptions(t).Namespace).Get(ctx, tlsKey, metav1.GetOptions{}) + caKeySecret.ResourceVersion = "" + require.NoError(t, err) + _, err = secondaryContext.KubernetesClient(t).CoreV1().Secrets(secondaryContext.KubectlOptions(t).Namespace).Create(ctx, caKeySecret, metav1.CreateOptions{}) + require.NoError(t, err) + + var partitionSvcIP string + if !cfg.UseKind { + // Get the IP of the partition service to configure the external server address in the values file for the workload cluster. + partitionServiceName := fmt.Sprintf("%s-partition-secret", releaseName) + logger.Logf(t, "retrieving partition service to determine external IP for servers") + partitionsSvc, err := primaryContext.KubernetesClient(t).CoreV1().Services(primaryContext.KubectlOptions(t).Namespace).Get(ctx, partitionServiceName, metav1.GetOptions{}) + require.NoError(t, err) + partitionSvcIP = partitionsSvc.Status.LoadBalancer.Ingress[0].IP + } else { + nodeList, err := primaryContext.KubernetesClient(t).CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + // Get the address of the (only) node from the Kind cluster. + partitionSvcIP = nodeList.Items[0].Status.Addresses[0].Address + } + + // Create secondary cluster + secondaryHelmValues := map[string]string{ + "global.datacenter": "dc1", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-alpha", + "global.enabled": "false", + + "global.adminPartitions.enabled": "true", + "global.adminPartitions.name": "secondary", + "global.enableConsulNamespaces": "true", + + "global.tls.enabled": "true", + "global.tls.caCert.secretName": tlsCert, + "global.tls.caCert.secretKey": "tls.crt", + "global.tls.caKey.secretName": tlsKey, + "global.tls.caKey.secretKey": "tls.key", + + "externalServers.enabled": "true", + "externalServers.hosts[0]": partitionSvcIP, + "externalServers.tlsServerName": "server.dc1.consul", + + "client.enabled": "true", + "client.exposeGossipPorts": "true", + "client.join[0]": partitionSvcIP, + + "connectInject.enabled": "true", + } + + if cfg.UseKind { + secondaryHelmValues["externalServers.httpsPort"] = "30000" + } + + // Install the consul cluster without servers in the secondary kubernetes context. + secondaryConsulCluster := consul.NewHelmCluster(t, secondaryHelmValues, secondaryContext, cfg, releaseName) + secondaryConsulCluster.Create(t) + + agentPodList, err := secondaryContext.KubernetesClient(t).CoreV1().Pods(secondaryContext.KubectlOptions(t).Namespace).List(ctx, metav1.ListOptions{LabelSelector: "app=consul,component=client"}) + require.NoError(t, err) + require.Len(t, agentPodList.Items, 1) + + output, err := k8s.RunKubectlAndGetOutputE(t, secondaryContext.KubectlOptions(t), "logs", agentPodList.Items[0].Name, "-n", secondaryContext.KubectlOptions(t).Namespace) + require.NoError(t, err) + require.Contains(t, output, "Partition: 'secondary'") + + // TODO: These can be enabled once mesh gateways are used for communication between services. Currently we cant setup a flat pod network on Kind. + // Check that we can connect services over the mesh gateways + + //logger.Log(t, "creating static-server in workload cluster") + //k8s.DeployKustomize(t, secondaryContext.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + + //logger.Log(t, "creating static-client in server cluster") + //k8s.DeployKustomize(t, primaryContext.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partition") + + //logger.Log(t, "checking that connection is successful") + //k8s.CheckStaticServerConnectionSuccessful(t, primaryContext.KubectlOptions(t), "http://localhost:1234") +} From 237e02ec5e1c71331ea4338f0963e126067b7995 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Fri, 1 Oct 2021 13:54:58 -0400 Subject: [PATCH 047/418] Automatically Generate and Use Gossip Encryption Key (#738) * Add global.gossipEncryption.autogenerate to values.yaml * Add description of key autogen * Add initial autogen-encryption-job yaml * Fix run condition on autogen * autogen is false by default * Set secretName/Key correctly, flesh out curling k8s a bit * Add some basic bats tests * Add tests for user set values for secretName and secretKey * Beef up comment for gossip encryption * Add notes * Update values.yaml to include autoGenerate * Add gossip-encryption-autogen-job.yaml * Port over autogen-encryption-job to gossip-encryption-autogen-job * Rename autogen-encryption-job.bats to gossip-encryption-autogen-job.bats * Remove change made to statefulset * Add check that secretName and secretKey are not set * Fix test failures * Set GOSSIP_KEY properly in server statefulset * Remove setting secretName and secretKey for autogen * Check if secret exists via 200 resp * Add gossip autogen to client daemonset * Send the key to secrets * Base64 encrypt consul key * Add podsecuritypolicy, role, rolebinding, and SA * Rename -gossip-encryption-autogen to -gossip-encryption-autogenerate * Rename *-autogen-* to *-autogeneration-* * Remove text about respecting user set secretName and secretKey for autogen * Rename gossip-encryption-autogen to gossip-encryption-autogeneration * Add some great tests! * Update changelog * Fix filename reference in job bats file * Update charts/consul/templates/gossip-encryption-autogeneration-job.yaml Co-authored-by: Iryna Shustava * Update charts/consul/test/unit/gossip-encryption-autogeneration-job.bats Co-authored-by: Iryna Shustava * Don't do the pre-check, but don't replace the current secret * Update charts/consul/test/unit/gossip-encryption-autogeneration-job.bats Co-authored-by: Iryna Shustava * Only give role create and get perms * Update charts/consul/test/unit/gossip-encryption-autogeneration-podsecurity.bats Co-authored-by: Iryna Shustava * Update charts/consul/values.yaml Co-authored-by: Iryna Shustava * Return kubectl command to what it was * Test that GOSSIP_KEY gets passed in on the encrypt flag * Autogen job does not run as root * Add check that gossip encryption is getting set * Fix test for gossip encryption in acceptance tests * Update charts/consul/test/acceptance/tests/basic/basic_test.go Co-authored-by: Ashwin Venkatesh * Rename s/autogeneration/autogenerate/ for gossip-encryption-autogeneration-* * Use correct filename in bats * Rename podsecuritypolicy test to be correct * Change v1 to metaV1 * Update charts/consul/test/acceptance/tests/basic/basic_test.go Co-authored-by: Luke Kysow <1034429+lkysow@users.noreply.github.com> * Test the other keyring value * Remove arbitrary test * Remove document separator * Remove temp dir from job * Remove get perm from autogenerate role * Add -encrypt flag test for client-daemonset * Change autogen to a feature in the CHANGELOG * Update comment on values.yaml * Update charts/consul/test/acceptance/tests/basic/basic_test.go Co-authored-by: Ashwin Venkatesh Co-authored-by: Iryna Shustava Co-authored-by: Ashwin Venkatesh Co-authored-by: Luke Kysow <1034429+lkysow@users.noreply.github.com> --- CHANGELOG.md | 4 ++ charts/consul/templates/client-daemonset.yaml | 9 ++- .../gossip-encryption-autogenerate-job.yaml | 71 +++++++++++++++++++ ...yption-autogenerate-podsecuritypolicy.yaml | 39 ++++++++++ .../gossip-encryption-autogenerate-role.yaml | 30 ++++++++ ...p-encryption-autogenerate-rolebinding.yaml | 22 ++++++ ...ncryption-autogenerate-serviceaccount.yaml | 21 ++++++ .../consul/templates/server-statefulset.yaml | 9 ++- .../test/acceptance/tests/basic/basic_test.go | 28 +++++++- charts/consul/test/unit/client-daemonset.bats | 21 ++++++ .../gossip-encryption-autogenerate-job.bats | 63 ++++++++++++++++ ...yption-autogenerate-podsecuritypolicy.bats | 28 ++++++++ .../gossip-encryption-autogenerate-role.bats | 28 ++++++++ ...p-encryption-autogenerate-rolebinding.bats | 29 ++++++++ ...ncryption-autogenerate-serviceaccount.bats | 50 +++++++++++++ .../consul/test/unit/server-statefulset.bats | 22 ++++++ charts/consul/values.yaml | 27 +++---- 17 files changed, 478 insertions(+), 23 deletions(-) create mode 100644 charts/consul/templates/gossip-encryption-autogenerate-job.yaml create mode 100644 charts/consul/templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml create mode 100644 charts/consul/templates/gossip-encryption-autogenerate-role.yaml create mode 100644 charts/consul/templates/gossip-encryption-autogenerate-rolebinding.yaml create mode 100644 charts/consul/templates/gossip-encryption-autogenerate-serviceaccount.yaml create mode 100644 charts/consul/test/unit/gossip-encryption-autogenerate-job.bats create mode 100644 charts/consul/test/unit/gossip-encryption-autogenerate-podsecuritypolicy.bats create mode 100644 charts/consul/test/unit/gossip-encryption-autogenerate-role.bats create mode 100644 charts/consul/test/unit/gossip-encryption-autogenerate-rolebinding.bats create mode 100644 charts/consul/test/unit/gossip-encryption-autogenerate-serviceaccount.bats diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f7e305e76..7bc08371b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## UNRELEASED +FEATURES: +* Helm Chart + * Add automatic generation of gossip encryption with `global.gossipEncryption.autoGenerate=true`. [[GH-738](https://github.com/hashicorp/consul-k8s/pull/738)] + IMPROVEMENTS: * Control Plane * Upgrade Docker image Alpine version from 3.13 to 3.14. [[GH-737](https://github.com/hashicorp/consul-k8s/pull/737)] diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index d2a2dcb583..d4e1c05107 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -168,12 +168,17 @@ spec: fieldPath: status.podIP - name: CONSUL_DISABLE_PERM_MGMT value: "true" - {{- if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }} + {{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} - name: GOSSIP_KEY valueFrom: secretKeyRef: + {{- if .Values.global.gossipEncryption.autoGenerate }} + name: {{ template "consul.fullname" . }}-gossip-encryption-key + key: key + {{- else if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }} name: {{ .Values.global.gossipEncryption.secretName }} key: {{ .Values.global.gossipEncryption.secretKey }} + {{- end }} {{- end }} {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload (not .Values.global.acls.manageSystemACLs)) }} - name: CONSUL_LICENSE_PATH @@ -252,7 +257,7 @@ spec: {{- end }} -datacenter={{ .Values.global.datacenter }} \ -data-dir=/consul/data \ - {{- if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }} + {{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} -encrypt="${GOSSIP_KEY}" \ {{- end }} {{- if .Values.client.join }} diff --git a/charts/consul/templates/gossip-encryption-autogenerate-job.yaml b/charts/consul/templates/gossip-encryption-autogenerate-job.yaml new file mode 100644 index 0000000000..ae5c0674d1 --- /dev/null +++ b/charts/consul/templates/gossip-encryption-autogenerate-job.yaml @@ -0,0 +1,71 @@ +{{- if .Values.global.gossipEncryption.autoGenerate }} +{{- if (or .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }} + {{ fail "If global.gossipEncryption.autoGenerate is true, global.gossipEncryption.secretName and global.gossipEncryption.secretKey must not be set." }} +{{ end }} +# automatically generate encryption key for gossip protocol and save it in Kubernetes secret +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "1" + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation +spec: + template: + metadata: + name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + release: {{ .Release.Name }} + component: gossip-encryption-autogeneneration + annotations: + "consul.hashicorp.com/connect-inject": "false" + spec: + restartPolicy: Never + serviceAccountName: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate + securityContext: + runAsNonRoot: true + runAsGroup: 1000 + runAsUser: 100 + fsGroup: 1000 + containers: + - name: gossip-encryption-autogen + image: "{{ .Values.global.image }}" + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + # We're using POST requests below to create secrets via Kubernetes API. + # Note that in the subsequent runs of the job, POST requests will + # return a 409 because these secrets would already exist; + # we are ignoring these response codes. + command: + - "/bin/sh" + - "-ec" + - | + secretName={{ template "consul.fullname" . }}-gossip-encryption-key + secretKey=key + keyValue=$(consul keygen | base64) + curl -s -X POST --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \ + https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}/api/v1/namespaces/${NAMESPACE}/secrets \ + -H "Authorization: Bearer $( cat /var/run/secrets/kubernetes.io/serviceaccount/token )" \ + -H "Content-Type: application/json" \ + -H "Accept: application/json" \ + -d "{ \"kind\": \"Secret\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"${secretName}\", \"namespace\": \"${NAMESPACE}\" }, \"type\": \"Opaque\", \"data\": { \"${secretKey}\": \"${keyValue}\" }}" > /dev/null + resources: + requests: + memory: "50Mi" + cpu: "50m" + limits: + memory: "50Mi" + cpu: "50m" +{{- end }} diff --git a/charts/consul/templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml b/charts/consul/templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml new file mode 100644 index 0000000000..6121fbbe30 --- /dev/null +++ b/charts/consul/templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml @@ -0,0 +1,39 @@ +{{- if .Values.global.gossipEncryption.autoGenerate }} +--- +apiVersion: policy/v1beta1 +kind: PodSecurityPolicy +metadata: + name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation +spec: + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + # This is redundant with non-root + disallow privilege escalation, + # but we can provide it for defense in depth. + requiredDropCapabilities: + - ALL + # Allow core volume types. + volumes: + - 'secret' + hostNetwork: false + hostIPC: false + hostPID: false + runAsUser: + rule: 'RunAsAny' + seLinux: + rule: 'RunAsAny' + supplementalGroups: + rule: 'RunAsAny' + fsGroup: + rule: 'RunAsAny' + readOnlyRootFilesystem: false +{{- end }} diff --git a/charts/consul/templates/gossip-encryption-autogenerate-role.yaml b/charts/consul/templates/gossip-encryption-autogenerate-role.yaml new file mode 100644 index 0000000000..5f9d354f38 --- /dev/null +++ b/charts/consul/templates/gossip-encryption-autogenerate-role.yaml @@ -0,0 +1,30 @@ +{{- if .Values.global.gossipEncryption.autoGenerate }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation +rules: +- apiGroups: [""] + resources: + - secrets + verbs: + - create +{{- if .Values.global.enablePodSecurityPolicies }} +- apiGroups: ["policy"] + resources: + - podsecuritypolicies + verbs: + - use + resourceNames: + - {{ template "consul.fullname" . }}-gossip-encryption-autogenerate +{{- end }} +{{- end }} diff --git a/charts/consul/templates/gossip-encryption-autogenerate-rolebinding.yaml b/charts/consul/templates/gossip-encryption-autogenerate-rolebinding.yaml new file mode 100644 index 0000000000..caef0d221e --- /dev/null +++ b/charts/consul/templates/gossip-encryption-autogenerate-rolebinding.yaml @@ -0,0 +1,22 @@ +{{- if .Values.global.gossipEncryption.autoGenerate }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate +subjects: +- kind: ServiceAccount + name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate +{{- end }} diff --git a/charts/consul/templates/gossip-encryption-autogenerate-serviceaccount.yaml b/charts/consul/templates/gossip-encryption-autogenerate-serviceaccount.yaml new file mode 100644 index 0000000000..a711f9a4c1 --- /dev/null +++ b/charts/consul/templates/gossip-encryption-autogenerate-serviceaccount.yaml @@ -0,0 +1,21 @@ +{{- if .Values.global.gossipEncryption.autoGenerate }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "consul.fullname" . }}-gossip-encryption-autogenerate + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-delete-policy": before-hook-creation +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range . }} + - name: {{ .name }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 05460ed217..fe2dcff468 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -156,12 +156,17 @@ spec: fieldPath: metadata.namespace - name: CONSUL_DISABLE_PERM_MGMT value: "true" - {{- if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }} + {{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} - name: GOSSIP_KEY valueFrom: secretKeyRef: + {{- if .Values.global.gossipEncryption.autoGenerate }} + name: {{ template "consul.fullname" . }}-gossip-encryption-key + key: key + {{- else if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }} name: {{ .Values.global.gossipEncryption.secretName }} key: {{ .Values.global.gossipEncryption.secretKey }} + {{- end }} {{- end }} {{- if .Values.global.tls.enabled }} - name: CONSUL_HTTP_ADDR @@ -223,7 +228,7 @@ spec: -datacenter={{ .Values.global.datacenter }} \ -data-dir=/consul/data \ -domain={{ .Values.global.domain }} \ - {{- if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }} + {{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} -encrypt="${GOSSIP_KEY}" \ {{- end }} {{- if .Values.server.connect }} diff --git a/charts/consul/test/acceptance/tests/basic/basic_test.go b/charts/consul/test/acceptance/tests/basic/basic_test.go index cc3cdc9877..95861e5f98 100644 --- a/charts/consul/test/acceptance/tests/basic/basic_test.go +++ b/charts/consul/test/acceptance/tests/basic/basic_test.go @@ -1,8 +1,10 @@ package basic import ( + "context" "fmt" "strconv" + "strings" "testing" "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" @@ -10,6 +12,7 @@ import ( "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // Test that the basic installation, i.e. just @@ -39,9 +42,10 @@ func TestBasicInstallation(t *testing.T) { t.Run(name, func(t *testing.T) { releaseName := helpers.RandomName() helmValues := map[string]string{ - "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), - "global.tls.enabled": strconv.FormatBool(c.secure), - "global.tls.enableAutoEncrypt": strconv.FormatBool(c.autoEncrypt), + "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), + "global.tls.enabled": strconv.FormatBool(c.secure), + "global.gossipEncryption.autoGenerate": strconv.FormatBool(c.secure), + "global.tls.enableAutoEncrypt": strconv.FormatBool(c.autoEncrypt), } consulCluster := consul.NewHelmCluster(t, helmValues, suite.Environment().DefaultContext(t), suite.Config(), releaseName) @@ -63,6 +67,24 @@ func TestBasicInstallation(t *testing.T) { kv, _, err := client.KV().Get(randomKey, nil) require.NoError(t, err) require.Equal(t, kv.Value, randomValue) + + // Check that autogenerated gossip encryption key is being used + if c.secure { + secretName := fmt.Sprintf("%s-consul-gossip-encryption-key", releaseName) + secretKey := "key" + + keyring, err := client.Operator().KeyringList(nil) + require.NoError(t, err) + + testContext := suite.Environment().DefaultContext(t) + secret, err := testContext.KubernetesClient(t).CoreV1().Secrets(testContext.KubectlOptions(t).Namespace).Get(context.Background(), secretName, metav1.GetOptions{}) + require.NoError(t, err) + gossipEncryptionKey := strings.TrimSpace(string(secret.Data[secretKey])) + + require.Len(t, keyring, 2) + require.Contains(t, keyring[0].Keys, gossipEncryptionKey) + require.Contains(t, keyring[1].Keys, gossipEncryptionKey) + } }) } } diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index ce202bca3e..cbbbc10ef9 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -606,6 +606,27 @@ load _helpers [ "${actual}" = "" ] } +@test "client/DaemonSet: gossip encryption autogeneration properly sets secretName and secretKey" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY") | .valueFrom.secretKeyRef | [.name=="RELEASE-NAME-consul-gossip-encryption-key", .key="key"] | all' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "client/DaemonSet: gossip encryption key is passed in via the -encrypt flag" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[] | select(.name=="consul") | .command | any(contains("-encrypt=\"${GOSSIP_KEY}\""))' + | tee /dev/stderr) + [ "${actual}" = "true" ] +} + @test "client/DaemonSet: gossip encryption disabled in client DaemonSet when secretName is missing" { cd `chart_dir` local actual=$(helm template \ diff --git a/charts/consul/test/unit/gossip-encryption-autogenerate-job.bats b/charts/consul/test/unit/gossip-encryption-autogenerate-job.bats new file mode 100644 index 0000000000..b78b9c231d --- /dev/null +++ b/charts/consul/test/unit/gossip-encryption-autogenerate-job.bats @@ -0,0 +1,63 @@ +#!/usr/bin/env bats + +load _helpers + +@test "gossipEncryptionAutogenerate/Job: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/gossip-encryption-autogenerate-job.yaml \ + . +} + +@test "gossipEncryptionAutogenerate/Job: enabled with global.gossipEncryption.autoGenerate=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/gossip-encryption-autogenerate-job.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "gossipEncryptionAutogenerate/Job: disabled when global.gossipEncryption.autoGenerate=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/gossip-encryption-autogenerate-job.yaml \ + --set 'global.gossipEncryption.autoGenerate=false' \ + . +} + +@test "gossipEncryptionAutogenerate/Job: fails if global.gossipEncryption.autoGenerate=true and global.gossipEncryption.secretName and global.gossipEncryption.secretKey are set" { + cd `chart_dir` + run helm template \ + -s templates/gossip-encryption-autogenerate-job.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + --set 'global.gossipEncryption.secretName=name' \ + --set 'global.gossipEncryption.secretKey=key' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "If global.gossipEncryption.autoGenerate is true, global.gossipEncryption.secretName and global.gossipEncryption.secretKey must not be set." ]] +} + +@test "gossipEncryptionAutogenerate/Job: fails if global.gossipEncryption.autoGenerate=true and global.gossipEncryption.secretName is set" { + cd `chart_dir` + run helm template \ + -s templates/gossip-encryption-autogenerate-job.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + --set 'global.gossipEncryption.secretName=name' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "If global.gossipEncryption.autoGenerate is true, global.gossipEncryption.secretName and global.gossipEncryption.secretKey must not be set." ]] +} + +@test "gossipEncryptionAutogenerate/Job: fails if global.gossipEncryption.autoGenerate=true and global.gossipEncryption.secretKey is set" { + cd `chart_dir` + run helm template \ + -s templates/gossip-encryption-autogenerate-job.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + --set 'global.gossipEncryption.secretKey=key' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "If global.gossipEncryption.autoGenerate is true, global.gossipEncryption.secretName and global.gossipEncryption.secretKey must not be set." ]] +} + diff --git a/charts/consul/test/unit/gossip-encryption-autogenerate-podsecuritypolicy.bats b/charts/consul/test/unit/gossip-encryption-autogenerate-podsecuritypolicy.bats new file mode 100644 index 0000000000..810147bed3 --- /dev/null +++ b/charts/consul/test/unit/gossip-encryption-autogenerate-podsecuritypolicy.bats @@ -0,0 +1,28 @@ +#!/usr/bin/env bats + +load _helpers + +@test "gossipEncryptionAutogenerate/PodSecurityPolicy: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml \ + . +} + +@test "gossipEncryptionAutogenerate/PodSecurityPolicy: disabled with global.gossipEncryption.autoGenerate=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml \ + --set 'global.gossipEncryption.autoGenerate=false' \ + . +} + +@test "gossipEncryptionAutogenerate/PodSecurityPolicy: enabled with global.gossipEncryption.autoGenerate=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + . | tee /dev/stderr | + yq -s 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/test/unit/gossip-encryption-autogenerate-role.bats b/charts/consul/test/unit/gossip-encryption-autogenerate-role.bats new file mode 100644 index 0000000000..7707a872f0 --- /dev/null +++ b/charts/consul/test/unit/gossip-encryption-autogenerate-role.bats @@ -0,0 +1,28 @@ +#!/usr/bin/env bats + +load _helpers + +@test "gossipEncryptionAutogenerate/Role: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/gossip-encryption-autogenerate-role.yaml \ + . +} + +@test "gossipEncryptionAutogenerate/Role: disabled with global.gossipEncryption.autoGenerate=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/gossip-encryption-autogenerate-role.yaml \ + --set 'global.gossipEncryption.autoGenerate=false' \ + . +} + +@test "gossipEncryptionAutogenerate/Role: enabled when global.gossipEncryption.autoGenerate=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/gossip-encryption-autogenerate-role.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/test/unit/gossip-encryption-autogenerate-rolebinding.bats b/charts/consul/test/unit/gossip-encryption-autogenerate-rolebinding.bats new file mode 100644 index 0000000000..9847beaa24 --- /dev/null +++ b/charts/consul/test/unit/gossip-encryption-autogenerate-rolebinding.bats @@ -0,0 +1,29 @@ + +#!/usr/bin/env bats + +load _helpers + +@test "gossipEncryptionAutogenerate/RoleBinding: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/gossip-encryption-autogenerate-rolebinding.yaml \ + . +} + +@test "gossipEncryptionAutogenerate/RoleBinding: disabled with global.gossipEncryption.autoGenerate=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/gossip-encryption-autogenerate-rolebinding.yaml \ + --set 'global.gossipEncryption.autoGenerate=false' \ + . +} + +@test "gossipEncryptionAutogenerate/RoleBinding: enabled with global.gossipEncryption.autoGenerate=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/gossip-encryption-autogenerate-rolebinding.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/test/unit/gossip-encryption-autogenerate-serviceaccount.bats b/charts/consul/test/unit/gossip-encryption-autogenerate-serviceaccount.bats new file mode 100644 index 0000000000..782d1b1ad6 --- /dev/null +++ b/charts/consul/test/unit/gossip-encryption-autogenerate-serviceaccount.bats @@ -0,0 +1,50 @@ +#!/usr/bin/env bats + +load _helpers + +@test "gossipEncryptionAutogenerate/ServiceAccount: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/gossip-encryption-autogenerate-serviceaccount.yaml \ + . +} + +@test "gossipEncryptionAutogenerate/ServiceAccount: disabled with global.gossipEncryption.autoGenerate=false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/gossip-encryption-autogenerate-serviceaccount.yaml \ + --set 'global.gossipEncryption.autoGenerate=false' \ + . +} + +@test "gossipEncryptionAutogenerate/ServiceAccount: enabled with global.gossipEncryption.autoGenerate=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/gossip-encryption-autogenerate-serviceaccount.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# global.imagePullSecrets + +@test "gossipEncryptionAutogenerate/ServiceAccount: can set image pull secrets" { + cd `chart_dir` + local object=$(helm template \ + -s templates/gossip-encryption-autogenerate-serviceaccount.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + --set 'global.imagePullSecrets[0].name=my-secret' \ + --set 'global.imagePullSecrets[1].name=my-secret2' \ + . | tee /dev/stderr) + + local actual=$(echo "$object" | + yq -r '.imagePullSecrets[0].name' | tee /dev/stderr) + [ "${actual}" = "my-secret" ] + + local actual=$(echo "$object" | + yq -r '.imagePullSecrets[1].name' | tee /dev/stderr) + [ "${actual}" = "my-secret2" ] +} + diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index ac2be4c2c9..a7e48a3951 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -842,6 +842,28 @@ load _helpers [ "${actual}" = "" ] } +@test "server/StatefulSet: gossip encryption autogeneration properly sets secretName and secretKey" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY") | .valueFrom.secretKeyRef | [.name=="RELEASE-NAME-consul-gossip-encryption-key", .key="key"] | all' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "server/StatefulSet: gossip encryption key is passed via the -encrypt flag" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.gossipEncryption.autoGenerate=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[] | select(.name=="consul") | .command | any(contains("-encrypt=\"${GOSSIP_KEY}\""))' + | tee /dev/stderr) + [ "${actual}" = "true" ] +} + + @test "server/StatefulSet: gossip encryption disabled in server StatefulSet when secretName is missing" { cd `chart_dir` local actual=$(helm template \ diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 9105565572..a0d4472a74 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -117,26 +117,21 @@ global: # created by this chart. See https://kubernetes.io/docs/concepts/policy/pod-security-policy/. enablePodSecurityPolicies: false - # Configures which Kubernetes secret to retrieve Consul's - # gossip encryption key from (see `-encrypt` (https://consul.io/docs/agent/options#_encrypt)). If secretName or - # secretKey are not set, gossip encryption will not be enabled. The secret must - # be in the same namespace that Consul is installed into. + # Configures Consul's gossip encryption key, set as a Kubernetes secret + # (see `-encrypt` (https://consul.io/docs/agent/options#_encrypt)). + # By default, gossip encryption is not enabled. The gossip encryption key may be set automatically or manually. + # The recommended method is to automatically generate the key. + # To automatically generate and set a gossip encryption key, set autoGenerate to true. + # Values for secretName and secretKey should not be set if autoGenerate is true. + # To manually generate a gossip encryption key, set secretName and secretKey and use Consul to generate + # a Kubernetes secret referencing these values. # - # The secret can be created by running: - # - # ```shell - # $ kubectl create secret generic consul-gossip-encryption-key --from-literal=key=$(consul keygen) # ``` - # - # To reference, use: - # - # ```yaml - # global: - # gossipEncryption: - # secretName: consul-gossip-encryption-key - # secretKey: key + # $ kubectl create secret generic consul-gossip-encryption-key --from-literal=key=$(consul keygen) # ``` gossipEncryption: + # Automatically generate a gossip encryption key and save it to a Kubernetes secret. + autoGenerate: false # secretName is the name of the Kubernetes secret that holds the gossip # encryption key. The secret must be in the same namespace that Consul is installed into. secretName: "" From 2443bff0ee4ddb8690ff9ac6ebf9e6ea8e9b97ad Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 5 Oct 2021 15:53:51 -0400 Subject: [PATCH 048/418] Fix Helm test that I broke (#755) * Atoning for my sins * Fix the issue in client-daemonset bats too --- charts/consul/test/unit/client-daemonset.bats | 2 +- charts/consul/test/unit/server-statefulset.bats | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index cbbbc10ef9..e0560c8c60 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -622,7 +622,7 @@ load _helpers -s templates/client-daemonset.yaml \ --set 'global.gossipEncryption.autoGenerate=true' \ . | tee /dev/stderr | - yq '.spec.template.spec.containers[] | select(.name=="consul") | .command | any(contains("-encrypt=\"${GOSSIP_KEY}\""))' + yq '.spec.template.spec.containers[] | select(.name=="consul") | .command | any(contains("-encrypt=\"${GOSSIP_KEY}\""))' \ | tee /dev/stderr) [ "${actual}" = "true" ] } diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index a7e48a3951..6418cef313 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -858,7 +858,7 @@ load _helpers -s templates/server-statefulset.yaml \ --set 'global.gossipEncryption.autoGenerate=true' \ . | tee /dev/stderr | - yq '.spec.template.spec.containers[] | select(.name=="consul") | .command | any(contains("-encrypt=\"${GOSSIP_KEY}\""))' + yq '.spec.template.spec.containers[] | select(.name=="consul") | .command | any(contains("-encrypt=\"${GOSSIP_KEY}\""))' \ | tee /dev/stderr) [ "${actual}" = "true" ] } From 57fc0c92d211f4bc81247de7455e7902b4417c50 Mon Sep 17 00:00:00 2001 From: Mark <47016163+mark-vw@users.noreply.github.com> Date: Tue, 5 Oct 2021 15:47:13 -0700 Subject: [PATCH 049/418] add resource config for mesh gw service-init (#758) * Add resource settings for mesh gw service-init --- .../templates/mesh-gateway-deployment.yaml | 10 ++--- .../test/unit/mesh-gateway-deployment.bats | 44 +++++++++++++++++++ charts/consul/values.yaml | 12 +++++ 3 files changed, 59 insertions(+), 7 deletions(-) diff --git a/charts/consul/templates/mesh-gateway-deployment.yaml b/charts/consul/templates/mesh-gateway-deployment.yaml index de3f0ff689..4d87baf678 100644 --- a/charts/consul/templates/mesh-gateway-deployment.yaml +++ b/charts/consul/templates/mesh-gateway-deployment.yaml @@ -225,13 +225,9 @@ spec: mountPath: /consul/tls/ca readOnly: true {{- end }} - resources: - requests: - memory: "50Mi" - cpu: "50m" - limits: - memory: "50Mi" - cpu: "50m" + {{- if .Values.meshGateway.initServiceInitContainer.resources }} + resources: {{ toYaml .Values.meshGateway.initServiceInitContainer.resources | nindent 12 }} + {{- end }} containers: - name: mesh-gateway image: {{ .Values.global.imageEnvoy | quote }} diff --git a/charts/consul/test/unit/mesh-gateway-deployment.bats b/charts/consul/test/unit/mesh-gateway-deployment.bats index 4e12efa89d..aab58a8413 100755 --- a/charts/consul/test/unit/mesh-gateway-deployment.bats +++ b/charts/consul/test/unit/mesh-gateway-deployment.bats @@ -437,6 +437,50 @@ key2: value2' \ [ "${actual}" = "cpu2" ] } +#-------------------------------------------------------------------- +# service-init container resources + +@test "meshGateway/Deployment: init service-init container has default resources" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.initContainers[1].resources' | tee /dev/stderr) + + [ $(echo "${actual}" | yq -r '.requests.memory') = "50Mi" ] + [ $(echo "${actual}" | yq -r '.requests.cpu') = "50m" ] + [ $(echo "${actual}" | yq -r '.limits.memory') = "50Mi" ] + [ $(echo "${actual}" | yq -r '.limits.cpu') = "50m" ] +} + +@test "meshGateway/Deployment: init service-init container resources can be set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'meshGateway.initServiceInitContainer.resources.requests.memory=memory' \ + --set 'meshGateway.initServiceInitContainer.resources.requests.cpu=cpu' \ + --set 'meshGateway.initServiceInitContainer.resources.limits.memory=memory2' \ + --set 'meshGateway.initServiceInitContainer.resources.limits.cpu=cpu2' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.initContainers[1].resources' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.requests.memory' | tee /dev/stderr) + [ "${actual}" = "memory" ] + + local actual=$(echo $object | yq -r '.requests.cpu' | tee /dev/stderr) + [ "${actual}" = "cpu" ] + + local actual=$(echo $object | yq -r '.limits.memory' | tee /dev/stderr) + [ "${actual}" = "memory2" ] + + local actual=$(echo $object | yq -r '.limits.cpu' | tee /dev/stderr) + [ "${actual}" = "cpu2" ] +} + #-------------------------------------------------------------------- # consul sidecar resources diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index a0d4472a74..49defa4f03 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2004,6 +2004,18 @@ meshGateway: memory: "150Mi" cpu: "50m" + # Resource settings for the `service-init` init container. + # @recurse: false + # @type: map + initServiceInitContainer: + resources: + requests: + memory: "50Mi" + cpu: "50m" + limits: + memory: "50Mi" + cpu: "50m" + # By default, we set an anti-affinity so that two gateway pods won't be # on the same node. NOTE: Gateways require that Consul client agents are # also running on the nodes alongside each gateway pod. From 18de67cb62e60cb4385686dd9c36dc6016e17697 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Wed, 6 Oct 2021 09:26:35 -0700 Subject: [PATCH 050/418] Add changelog entry for GH-758 (#762) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bc08371b9..ec5596255b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ FEATURES: * Helm Chart * Add automatic generation of gossip encryption with `global.gossipEncryption.autoGenerate=true`. [[GH-738](https://github.com/hashicorp/consul-k8s/pull/738)] + * Add support for configuring resources for mesh gateway `service-init` container. [[GH-758](https://github.com/hashicorp/consul-k8s/pull/758)] IMPROVEMENTS: * Control Plane From 0792f7dfd8480aa02f80e3dd45fa7bc67051f9eb Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Wed, 6 Oct 2021 17:40:13 -0600 Subject: [PATCH 051/418] Acceptance tests fixes (#765) * Pin to a previous version of the tf azure provider because of the issue with AKS API. * Bump all k8s minor versions by 1. The oldest is now 1.18 and the newest is 1.22. Also swap GKE and EKS versions because GKE only supports 1.19+ * Update to the latest version of the EKS module which fixes an issue with kubeconfig file permissions --- .circleci/config.yml | 25 ++++++++----------- README.md | 2 +- charts/consul/test/terraform/aks/main.tf | 4 +-- charts/consul/test/terraform/eks/main.tf | 8 +++--- charts/consul/test/terraform/eks/variables.tf | 4 +-- charts/consul/test/terraform/gke/main.tf | 2 +- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7f76b6b469..c309f2cc64 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -449,7 +449,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.20.7" + version: "v1.21.2" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} @@ -481,7 +481,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.20.7" + version: "v1.21.2" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} @@ -561,7 +561,7 @@ jobs: ######################## # ACCEPTANCE TESTS ######################## - acceptance-gke-1-17: + acceptance-gke-1-19: environment: - TEST_RESULTS: /tmp/test-results docker: @@ -627,7 +627,7 @@ jobs: fail_only: true failure_message: "GKE acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - acceptance-aks-1-19: + acceptance-aks-1-20: environment: - TEST_RESULTS: /tmp/test-results docker: @@ -717,11 +717,6 @@ jobs: echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV - # Change file permissions of the kubecofig files to avoid warnings by helm. - # TODO: remove when https://github.com/terraform-aws-modules/terraform-aws-eks/pull/1114 is merged. - chmod 600 "$primary_kubeconfig" - chmod 600 "$secondary_kubeconfig" - # Restore go module cache if there is one - restore_cache: keys: @@ -801,7 +796,7 @@ jobs: fail_only: true failure_message: "OpenShift acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - acceptance-kind-1-21: + acceptance-kind-1-22: environment: - TEST_RESULTS: /tmp/test-results machine: @@ -811,7 +806,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.21.1" + version: "v1.22.1" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} @@ -832,7 +827,7 @@ jobs: path: /tmp/test-results - slack/status: fail_only: true - failure_message: "Acceptance tests against Kind with Kubernetes v1.21 failed. Check the logs at: ${CIRCLE_BUILD_URL}" + failure_message: "Acceptance tests against Kind with Kubernetes v1.22 failed. Check the logs at: ${CIRCLE_BUILD_URL}" update-helm-charts-index: docker: @@ -947,16 +942,16 @@ workflows: # - acceptance-openshift: # requires: # - cleanup-azure-resources - - acceptance-gke-1-17: + - acceptance-gke-1-19: requires: - cleanup-gcp-resources - acceptance-eks-1-18: requires: - cleanup-eks-resources - - acceptance-aks-1-19: + - acceptance-aks-1-20: requires: - cleanup-azure-resources - - acceptance-kind-1-21 + - acceptance-kind-1-22 # update-helm-charts-index: <-- Disable until we can figure out a release workflow. We currently don't want it to trigger on a tag because the tag is pushed by the eco-releases pipeline. # jobs: # - helm-chart-pipeline-approval: diff --git a/README.md b/README.md index 34c00c052a..cc5b1985c2 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ use Consul with Kubernetes, please see the ### Prerequisites * **Helm 3.0+** (Helm 2 is not supported) - * **Kubernetes 1.17+** - This is the earliest version of Kubernetes tested. + * **Kubernetes 1.18+** - This is the earliest version of Kubernetes tested. It is possible that this chart works with earlier versions but it is untested. diff --git a/charts/consul/test/terraform/aks/main.tf b/charts/consul/test/terraform/aks/main.tf index 0406afd0b2..774b94b68c 100644 --- a/charts/consul/test/terraform/aks/main.tf +++ b/charts/consul/test/terraform/aks/main.tf @@ -1,5 +1,5 @@ provider "azurerm" { - version = "~> 2.0" + version = "2.78.0" features {} } @@ -24,7 +24,7 @@ resource "azurerm_kubernetes_cluster" "default" { location = azurerm_resource_group.default[count.index].location resource_group_name = azurerm_resource_group.default[count.index].name dns_prefix = "consul-k8s-${random_id.suffix[count.index].dec}" - kubernetes_version = "1.19.13" + kubernetes_version = "1.20.9" default_node_pool { name = "default" diff --git a/charts/consul/test/terraform/eks/main.tf b/charts/consul/test/terraform/eks/main.tf index b16646af33..3aa79db821 100644 --- a/charts/consul/test/terraform/eks/main.tf +++ b/charts/consul/test/terraform/eks/main.tf @@ -51,7 +51,7 @@ module "eks" { count = var.cluster_count source = "terraform-aws-modules/eks/aws" - version = "12.2.0" + version = "17.20.0" cluster_name = "consul-k8s-${random_id.suffix[count.index].dec}" cluster_version = "1.18" @@ -69,9 +69,9 @@ module "eks" { } } - manage_aws_auth = false - write_kubeconfig = true - config_output_path = pathexpand("~/.kube/consul-k8s-${random_id.suffix[count.index].dec}") + manage_aws_auth = false + write_kubeconfig = true + kubeconfig_output_path = pathexpand("~/.kube/consul-k8s-${random_id.suffix[count.index].dec}") tags = var.tags } diff --git a/charts/consul/test/terraform/eks/variables.tf b/charts/consul/test/terraform/eks/variables.tf index a401312a45..cab209fda0 100644 --- a/charts/consul/test/terraform/eks/variables.tf +++ b/charts/consul/test/terraform/eks/variables.tf @@ -14,7 +14,7 @@ variable "role_arn" { } variable "tags" { - type = map - default = {} + type = map + default = {} description = "Tags to attach to the created resources." } diff --git a/charts/consul/test/terraform/gke/main.tf b/charts/consul/test/terraform/gke/main.tf index a6c294e2e6..8f86ad1290 100644 --- a/charts/consul/test/terraform/gke/main.tf +++ b/charts/consul/test/terraform/gke/main.tf @@ -10,7 +10,7 @@ resource "random_id" "suffix" { data "google_container_engine_versions" "main" { location = var.zone - version_prefix = "1.17." + version_prefix = "1.19." } resource "google_container_cluster" "cluster" { From 8b2d39bbca7e65559fde2503046433ccd0aa2376 Mon Sep 17 00:00:00 2001 From: Saad Date: Thu, 7 Oct 2021 00:26:06 -0700 Subject: [PATCH 052/418] Finished basic tests for checking Consul clients and servers. --- cli/cmd/status/status.go | 285 ++++++++++++++++++++++++++++++++++ cli/cmd/status/status_test.go | 196 +++++++++++++++++++++++ cli/commands.go | 6 + 3 files changed, 487 insertions(+) create mode 100644 cli/cmd/status/status.go create mode 100644 cli/cmd/status/status_test.go diff --git a/cli/cmd/status/status.go b/cli/cmd/status/status.go new file mode 100644 index 0000000000..af258fc361 --- /dev/null +++ b/cli/cmd/status/status.go @@ -0,0 +1,285 @@ +package status + +import ( + "errors" + "fmt" + "helm.sh/helm/v3/pkg/release" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "os" + "sync" + + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" + "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + "helm.sh/helm/v3/pkg/action" + helmCLI "helm.sh/helm/v3/pkg/cli" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/yaml" +) + +type Command struct { + *common.BaseCommand + + kubernetes kubernetes.Interface + + set *flag.Sets + + flagKubeConfig string + flagKubeContext string + + once sync.Once + help string +} + +func (c *Command) init() { + c.set = flag.NewSets() + { + f := c.set.NewSet("Global Options") + f.StringVar(&flag.StringVar{ + Name: "kubeconfig", + Aliases: []string{"c"}, + Target: &c.flagKubeConfig, + Default: "", + Usage: "Path to kubeconfig file.", + }) + f.StringVar(&flag.StringVar{ + Name: "context", + Target: &c.flagKubeContext, + Default: "", + Usage: "Kubernetes context to use.", + }) + } + + c.help = c.set.Help() + + // c.Init() calls the embedded BaseCommand's initialization function. + c.Init() +} + +func (c *Command) Run(args []string) int { + c.once.Do(c.init) + + // The logger is initialized in main with the name cli. Here, we reset the name to status so log lines would be prefixed with status. + c.Log.ResetNamed("status") + + defer func() { + if err := c.Close(); err != nil { + c.Log.Error(err.Error()) + os.Exit(1) + } + }() + + if err := c.validateFlags(args); err != nil { + c.UI.Output(err.Error()) + return 1 + } + + // helmCLI.New() will create a settings object which is used by the Helm Go SDK calls. + settings := helmCLI.New() + if c.flagKubeConfig != "" { + settings.KubeConfig = c.flagKubeConfig + } + if c.flagKubeContext != "" { + settings.KubeContext = c.flagKubeContext + } + + // Set up the kubernetes client to use for non Helm SDK calls to the Kubernetes API + // The Helm SDK will use settings.RESTClientGetter for its calls as well, so this will + // use a consistent method to target the right cluster for both Helm SDK and non Helm SDK calls. + if c.kubernetes == nil { + restConfig, err := settings.RESTClientGetter().ToRESTConfig() + if err != nil { + c.UI.Output("retrieving Kubernetes auth: %v", err, terminal.WithErrorStyle()) + return 1 + } + c.kubernetes, err = kubernetes.NewForConfig(restConfig) + if err != nil { + c.UI.Output("initializing Kubernetes client: %v", err, terminal.WithErrorStyle()) + return 1 + } + } + + // Setup logger to stream Helm library logs. + var uiLogger = func(s string, args ...interface{}) { + logMsg := fmt.Sprintf(s, args...) + c.UI.Output(logMsg, terminal.WithLibraryStyle()) + } + + c.UI.Output("Consul-K8s Status Summary", terminal.WithHeaderStyle()) + releaseName, namespace, err := c.checkForPreviousInstallations(settings, uiLogger) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if err := c.checkHelmInstallation(settings, uiLogger, releaseName, namespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if s, err := c.checkConsulServers(namespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } else { + c.UI.Output(s, terminal.WithSuccessStyle()) + } + + if s, err := c.checkConsulClients(namespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } else { + c.UI.Output(s, terminal.WithSuccessStyle()) + } + + + + + + + return 0 +} + +// validateFlags is a helper function that performs sanity checks on the user's provided flags. +func (c *Command) validateFlags(args []string) error { + if err := c.set.Parse(args); err != nil { + return err + } + if len(c.set.Args()) > 0 { + return errors.New("should have no non-flag arguments") + } + return nil +} + +// checkForPreviousInstallations uses the helm Go SDK to find helm releases in all namespaces where the chart name is +// "consul", and returns the release name and namespace if found, or an error if not found. +func (c *Command) checkForPreviousInstallations(settings *helmCLI.EnvSettings, uiLogger action.DebugLog) (string, string, error) { + // Need a specific action config to call helm list, where namespace is NOT specified. + listConfig := new(action.Configuration) + if err := listConfig.Init(settings.RESTClientGetter(), "", + os.Getenv("HELM_DRIVER"), uiLogger); err != nil { + return "", "", fmt.Errorf("couldn't initialize helm config: %s", err) + } + + lister := action.NewList(listConfig) + lister.AllNamespaces = true + res, err := lister.Run() + if err != nil { + return "", "", fmt.Errorf("couldn't check for installations: %s", err) + } + + for _, rel := range res { + if rel.Chart.Metadata.Name == "consul" { + c.UI.Output("Installation name: %s", rel.Name, terminal.WithInfoStyle()) + c.UI.Output("Namespace: %s", rel.Namespace, terminal.WithInfoStyle()) + return rel.Name, rel.Namespace, nil + } + } + c.UI.Output("Consul installation found.", terminal.WithSuccessStyle()) + return "", "", errors.New("couldn't find installation") +} + +// checkHelmInstallation uses the helm Go SDK to depict the status of a named release. This function then prints +// the version of the release, it's status (unknown, deployed, uninstalled, ...), and the overwritten values. +func (c *Command) checkHelmInstallation(settings *helmCLI.EnvSettings, uiLogger action.DebugLog, releaseName, namespace string) error { + // Need a specific action config to call helm status, where namespace comes from the previous call to list. + statusConfig := new(action.Configuration) + if err := statusConfig.Init(settings.RESTClientGetter(), namespace, + os.Getenv("HELM_DRIVER"), uiLogger); err != nil { + return fmt.Errorf("couldn't initialize helm config: %s", err) + } + + statuser := action.NewStatus(statusConfig) + rel, err := statuser.Run(releaseName) + if err != nil { + return fmt.Errorf("couldn't check for installations: %s", err) + } + + c.UI.Output("Status: %s", rel.Info.Status, terminal.WithInfoStyle()) + c.UI.Output("Version: %d", rel.Version, terminal.WithInfoStyle()) + c.UI.Output("Time Deployed: %v", rel.Info.LastDeployed, terminal.WithInfoStyle()) + + valuesYaml, err := yaml.Marshal(rel.Config) + if err != nil { + c.UI.Output("Config:" + "\n" + "%+v", err, terminal.WithInfoStyle()) + } else if len(rel.Config) == 0 { + c.UI.Output("Config: " + string(valuesYaml), terminal.WithInfoStyle()) + } else { + c.UI.Output("Config:" + "\n" + string(valuesYaml), terminal.WithInfoStyle()) + } + + // Check the status of the hooks. + if len(rel.Hooks) > 1 { + c.UI.Output("Status Of Helm Hooks:") + + for _, hook := range rel.Hooks { + // Remember that we only report the status of pre-install or pre-upgrade hooks. + if validEvent(hook.Events) { + c.UI.Output("%s %s: %s", hook.Name, hook.Kind, hook.LastRun.Phase.String()) + } + } + c.UI.Output("") + } + + + return nil +} + +// Helper function that checks if the given hook's events are pre-install or pre-upgrade. +func validEvent(events []release.HookEvent) bool { + for _, event := range events { + if event.String() == "pre-install" || event.String() == "pre-upgrade" { + return true + } + } + return false +} + +// checkConsulServers uses the Kubernetes list function to report if the consul servers are healthy. +func (c *Command) checkConsulServers(namespace string) (string, error) { + servers, err := c.kubernetes.AppsV1().StatefulSets(namespace).List(c.Ctx, + metav1.ListOptions{LabelSelector: "app=consul,chart=consul-helm,component=server"}) + if err != nil { + return "", err + } else if len(servers.Items) == 0 { + return "", errors.New("no server stateful set found") + } else if len(servers.Items) > 1 { + return "", errors.New("found multiple server stateful sets") + } + + desiredReplicas := int(*servers.Items[0].Spec.Replicas) + readyReplicas := int(servers.Items[0].Status.ReadyReplicas) + if readyReplicas < desiredReplicas { + return "", fmt.Errorf("%d/%d Consul servers unhealthy", desiredReplicas - readyReplicas, desiredReplicas) + } + return fmt.Sprintf("Consul servers healthy (%d/%d)", readyReplicas, desiredReplicas), nil +} + +// checkConsulClients uses the Kubernetes list function to report if the consul clients are healthy. +func (c *Command) checkConsulClients(namespace string) (string, error) { + clients, err := c.kubernetes.AppsV1().DaemonSets(namespace).List(c.Ctx, + metav1.ListOptions{LabelSelector: "app=consul,chart=consul-helm"}) + if err != nil { + return "", err + } else if len(clients.Items) == 0 { + return "", errors.New("no client daemon set found") + } else if len(clients.Items) > 1 { + return "", errors.New("found multiple client daemon sets") + } + desiredReplicas := int(clients.Items[0].Status.DesiredNumberScheduled) + readyReplicas := int(clients.Items[0].Status.NumberReady) + if readyReplicas < desiredReplicas { + return "", fmt.Errorf("%d/%d Consul clients unhealthy", desiredReplicas - readyReplicas, desiredReplicas) + } + return fmt.Sprintf("Consul clients healthy (%d/%d)", readyReplicas, desiredReplicas), nil +} + +func (c *Command) Help() string { + c.once.Do(c.init) + s := "Usage: consul-k8s status" + "\n\n" + "Get the status of the current Consul installation." + "\n" + + c.help + return s +} + +func (c *Command) Synopsis() string { + return "Status of Consul-K8s install." +} \ No newline at end of file diff --git a/cli/cmd/status/status_test.go b/cli/cmd/status/status_test.go new file mode 100644 index 0000000000..250ae735be --- /dev/null +++ b/cli/cmd/status/status_test.go @@ -0,0 +1,196 @@ +package status + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/require" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" +) + + +// getInitializedCommand sets up a command struct for tests. +func getInitializedCommand(t *testing.T) *Command { + t.Helper() + log := hclog.New(&hclog.LoggerOptions{ + Name: "cli", + Level: hclog.Info, + Output: os.Stdout, + }) + ctx, _ := context.WithCancel(context.Background()) + + baseCommand := &common.BaseCommand{ + Ctx: ctx, + Log: log, + } + + c := &Command{ + BaseCommand: baseCommand, + } + c.init() + return c +} + +/* Just using this to play around with the Go debugger. */ +func TestDebugger(t *testing.T) { + c := getInitializedCommand(t) + c.Run([]string{}) +} + +//Any feedback on this test is much appreciated! My first time using the K8s Testing library. -- Saad. +func TestCheckConsulServers(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + + // First check that no stateful sets causes an error. + _, err := c.checkConsulServers("default") + require.Error(t, err) + require.Contains(t, err.Error(), "no server stateful set found") + + // Next create a stateful set with 3 desired replicas and 3 ready replicas. + var replicas int32 + replicas = 3 + + ss := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-server-test1", + Namespace: "default", + Labels: map[string]string{"app":"consul", "chart": "consul-helm", "component": "server"}, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &replicas, + }, + Status: appsv1.StatefulSetStatus{ + Replicas: replicas, + ReadyReplicas: replicas, + }, + } + + c.kubernetes.AppsV1().StatefulSets("default").Create(context.Background(), ss, metav1.CreateOptions{}) + + // Now we run the checkConsulServers() function and it should succeed. + s, err := c.checkConsulServers("default") + require.NoError(t, err) + require.Equal(t, "Consul servers healthy (3/3)", s) + + // If you then create another stateful set it should error. + ss2 := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-server-test2", + Namespace: "default", + Labels: map[string]string{"app":"consul", "chart": "consul-helm", "component": "server"}, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &replicas, + }, + Status: appsv1.StatefulSetStatus{ + Replicas: replicas, + ReadyReplicas: replicas, + }, + } + c.kubernetes.AppsV1().StatefulSets("default").Create(context.Background(), ss2, metav1.CreateOptions{}) + + _, err = c.checkConsulServers("default") + require.Error(t, err) + require.Contains(t, err.Error(), "found multiple server stateful sets") + + // Clear out the client and now run a test where the stateful set isn't ready. + c.kubernetes = fake.NewSimpleClientset() + + ss3 := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-server-test3", + Namespace: "default", + Labels: map[string]string{"app":"consul", "chart": "consul-helm", "component": "server"}, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &replicas, + }, + Status: appsv1.StatefulSetStatus{ + Replicas: replicas, + ReadyReplicas: replicas - 1, // Let's just set one of the servers to unhealthy + }, + } + c.kubernetes.AppsV1().StatefulSets("default").Create(context.Background(), ss3, metav1.CreateOptions{}) + + _, err = c.checkConsulServers("default") + require.Error(t, err) + require.Contains(t, err.Error(), fmt.Sprintf("%d/%d Consul servers unhealthy", 1, replicas)) +} + +// This test is very similar to TestCheckConsulServers() in structure. +func TestCheckConsulClients(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + + // No client daemon set should cause an error. + _, err := c.checkConsulClients("default") + require.Error(t, err) + require.Contains(t, err.Error(), "no client daemon set found") + + // Next create a daemon set. + var desired int32 + desired = 3 + ds := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-client-test1", + Namespace: "default", + Labels: map[string]string{"app":"consul", "chart": "consul-helm"}, + }, + Status: appsv1.DaemonSetStatus{ + DesiredNumberScheduled: desired, + NumberReady: desired, + }, + } + + c.kubernetes.AppsV1().DaemonSets("default").Create(context.Background(), ds, metav1.CreateOptions{}) + + // Now run checkConsulClients() and make sure it succeeds. + s, err := c.checkConsulClients("default") + require.NoError(t, err) + require.Equal(t, "Consul clients healthy (3/3)", s) + + // Creating another daemon set should cause an error. + ds2 := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-client-test2", + Namespace: "default", + Labels: map[string]string{"app":"consul", "chart": "consul-helm"}, + }, + Status: appsv1.DaemonSetStatus{ + DesiredNumberScheduled: desired, + NumberReady: desired, + }, + } + c.kubernetes.AppsV1().DaemonSets("default").Create(context.Background(), ds2, metav1.CreateOptions{}) + + _, err = c.checkConsulClients("default") + require.Error(t, err) + require.Contains(t, err.Error(), "found multiple client daemon sets") + + // Clear out the client and run a test with fewer than desired daemon sets ready. + c.kubernetes = fake.NewSimpleClientset() + + ds3 := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-client-test2", + Namespace: "default", + Labels: map[string]string{"app":"consul", "chart": "consul-helm"}, + }, + Status: appsv1.DaemonSetStatus{ + DesiredNumberScheduled: desired, + NumberReady: desired - 1, + }, + } + c.kubernetes.AppsV1().DaemonSets("default").Create(context.Background(), ds3, metav1.CreateOptions{}) + + _, err = c.checkConsulClients("default") + require.Error(t, err) + require.Contains(t, err.Error(), fmt.Sprintf("%d/%d Consul clients unhealthy", 1, desired)) +} diff --git a/cli/commands.go b/cli/commands.go index 2725c5d4bf..20fdc2624c 100644 --- a/cli/commands.go +++ b/cli/commands.go @@ -2,6 +2,7 @@ package main import ( "context" + "github.com/hashicorp/consul-k8s/cli/cmd/status" "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/consul-k8s/cli/cmd/install" @@ -28,6 +29,11 @@ func initializeCommands(ctx context.Context, log hclog.Logger) (*common.BaseComm BaseCommand: baseCommand, }, nil }, + "status": func() (cli.Command, error) { + return &status.Command{ + BaseCommand: baseCommand, + }, nil + }, } return baseCommand, commands From a9a68e9d733fcc1937a5f820cf292f5257cb2de6 Mon Sep 17 00:00:00 2001 From: Saad Date: Thu, 7 Oct 2021 00:46:27 -0700 Subject: [PATCH 053/418] Revert "Acceptance tests fixes (#765)" This reverts commit 0792f7dfd8480aa02f80e3dd45fa7bc67051f9eb. --- .circleci/config.yml | 25 +++++++++++-------- README.md | 2 +- charts/consul/test/terraform/aks/main.tf | 4 +-- charts/consul/test/terraform/eks/main.tf | 8 +++--- charts/consul/test/terraform/eks/variables.tf | 4 +-- charts/consul/test/terraform/gke/main.tf | 2 +- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c309f2cc64..7f76b6b469 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -449,7 +449,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.21.2" + version: "v1.20.7" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} @@ -481,7 +481,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.21.2" + version: "v1.20.7" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} @@ -561,7 +561,7 @@ jobs: ######################## # ACCEPTANCE TESTS ######################## - acceptance-gke-1-19: + acceptance-gke-1-17: environment: - TEST_RESULTS: /tmp/test-results docker: @@ -627,7 +627,7 @@ jobs: fail_only: true failure_message: "GKE acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - acceptance-aks-1-20: + acceptance-aks-1-19: environment: - TEST_RESULTS: /tmp/test-results docker: @@ -717,6 +717,11 @@ jobs: echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV + # Change file permissions of the kubecofig files to avoid warnings by helm. + # TODO: remove when https://github.com/terraform-aws-modules/terraform-aws-eks/pull/1114 is merged. + chmod 600 "$primary_kubeconfig" + chmod 600 "$secondary_kubeconfig" + # Restore go module cache if there is one - restore_cache: keys: @@ -796,7 +801,7 @@ jobs: fail_only: true failure_message: "OpenShift acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - acceptance-kind-1-22: + acceptance-kind-1-21: environment: - TEST_RESULTS: /tmp/test-results machine: @@ -806,7 +811,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.22.1" + version: "v1.21.1" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} @@ -827,7 +832,7 @@ jobs: path: /tmp/test-results - slack/status: fail_only: true - failure_message: "Acceptance tests against Kind with Kubernetes v1.22 failed. Check the logs at: ${CIRCLE_BUILD_URL}" + failure_message: "Acceptance tests against Kind with Kubernetes v1.21 failed. Check the logs at: ${CIRCLE_BUILD_URL}" update-helm-charts-index: docker: @@ -942,16 +947,16 @@ workflows: # - acceptance-openshift: # requires: # - cleanup-azure-resources - - acceptance-gke-1-19: + - acceptance-gke-1-17: requires: - cleanup-gcp-resources - acceptance-eks-1-18: requires: - cleanup-eks-resources - - acceptance-aks-1-20: + - acceptance-aks-1-19: requires: - cleanup-azure-resources - - acceptance-kind-1-22 + - acceptance-kind-1-21 # update-helm-charts-index: <-- Disable until we can figure out a release workflow. We currently don't want it to trigger on a tag because the tag is pushed by the eco-releases pipeline. # jobs: # - helm-chart-pipeline-approval: diff --git a/README.md b/README.md index cc5b1985c2..34c00c052a 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ use Consul with Kubernetes, please see the ### Prerequisites * **Helm 3.0+** (Helm 2 is not supported) - * **Kubernetes 1.18+** - This is the earliest version of Kubernetes tested. + * **Kubernetes 1.17+** - This is the earliest version of Kubernetes tested. It is possible that this chart works with earlier versions but it is untested. diff --git a/charts/consul/test/terraform/aks/main.tf b/charts/consul/test/terraform/aks/main.tf index 774b94b68c..0406afd0b2 100644 --- a/charts/consul/test/terraform/aks/main.tf +++ b/charts/consul/test/terraform/aks/main.tf @@ -1,5 +1,5 @@ provider "azurerm" { - version = "2.78.0" + version = "~> 2.0" features {} } @@ -24,7 +24,7 @@ resource "azurerm_kubernetes_cluster" "default" { location = azurerm_resource_group.default[count.index].location resource_group_name = azurerm_resource_group.default[count.index].name dns_prefix = "consul-k8s-${random_id.suffix[count.index].dec}" - kubernetes_version = "1.20.9" + kubernetes_version = "1.19.13" default_node_pool { name = "default" diff --git a/charts/consul/test/terraform/eks/main.tf b/charts/consul/test/terraform/eks/main.tf index 3aa79db821..b16646af33 100644 --- a/charts/consul/test/terraform/eks/main.tf +++ b/charts/consul/test/terraform/eks/main.tf @@ -51,7 +51,7 @@ module "eks" { count = var.cluster_count source = "terraform-aws-modules/eks/aws" - version = "17.20.0" + version = "12.2.0" cluster_name = "consul-k8s-${random_id.suffix[count.index].dec}" cluster_version = "1.18" @@ -69,9 +69,9 @@ module "eks" { } } - manage_aws_auth = false - write_kubeconfig = true - kubeconfig_output_path = pathexpand("~/.kube/consul-k8s-${random_id.suffix[count.index].dec}") + manage_aws_auth = false + write_kubeconfig = true + config_output_path = pathexpand("~/.kube/consul-k8s-${random_id.suffix[count.index].dec}") tags = var.tags } diff --git a/charts/consul/test/terraform/eks/variables.tf b/charts/consul/test/terraform/eks/variables.tf index cab209fda0..a401312a45 100644 --- a/charts/consul/test/terraform/eks/variables.tf +++ b/charts/consul/test/terraform/eks/variables.tf @@ -14,7 +14,7 @@ variable "role_arn" { } variable "tags" { - type = map - default = {} + type = map + default = {} description = "Tags to attach to the created resources." } diff --git a/charts/consul/test/terraform/gke/main.tf b/charts/consul/test/terraform/gke/main.tf index 8f86ad1290..a6c294e2e6 100644 --- a/charts/consul/test/terraform/gke/main.tf +++ b/charts/consul/test/terraform/gke/main.tf @@ -10,7 +10,7 @@ resource "random_id" "suffix" { data "google_container_engine_versions" "main" { location = var.zone - version_prefix = "1.19." + version_prefix = "1.17." } resource "google_container_cluster" "cluster" { From adefa30bd859c61de6445834da5335389a6f04e1 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 7 Oct 2021 08:26:35 -0400 Subject: [PATCH 054/418] Revert "Revert "Acceptance tests fixes (#765)"" This reverts commit a9a68e9d733fcc1937a5f820cf292f5257cb2de6. --- .circleci/config.yml | 25 ++++++++----------- README.md | 2 +- charts/consul/test/terraform/aks/main.tf | 4 +-- charts/consul/test/terraform/eks/main.tf | 8 +++--- charts/consul/test/terraform/eks/variables.tf | 4 +-- charts/consul/test/terraform/gke/main.tf | 2 +- 6 files changed, 20 insertions(+), 25 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7f76b6b469..c309f2cc64 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -449,7 +449,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.20.7" + version: "v1.21.2" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} @@ -481,7 +481,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.20.7" + version: "v1.21.2" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} @@ -561,7 +561,7 @@ jobs: ######################## # ACCEPTANCE TESTS ######################## - acceptance-gke-1-17: + acceptance-gke-1-19: environment: - TEST_RESULTS: /tmp/test-results docker: @@ -627,7 +627,7 @@ jobs: fail_only: true failure_message: "GKE acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - acceptance-aks-1-19: + acceptance-aks-1-20: environment: - TEST_RESULTS: /tmp/test-results docker: @@ -717,11 +717,6 @@ jobs: echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV - # Change file permissions of the kubecofig files to avoid warnings by helm. - # TODO: remove when https://github.com/terraform-aws-modules/terraform-aws-eks/pull/1114 is merged. - chmod 600 "$primary_kubeconfig" - chmod 600 "$secondary_kubeconfig" - # Restore go module cache if there is one - restore_cache: keys: @@ -801,7 +796,7 @@ jobs: fail_only: true failure_message: "OpenShift acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - acceptance-kind-1-21: + acceptance-kind-1-22: environment: - TEST_RESULTS: /tmp/test-results machine: @@ -811,7 +806,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.21.1" + version: "v1.22.1" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} @@ -832,7 +827,7 @@ jobs: path: /tmp/test-results - slack/status: fail_only: true - failure_message: "Acceptance tests against Kind with Kubernetes v1.21 failed. Check the logs at: ${CIRCLE_BUILD_URL}" + failure_message: "Acceptance tests against Kind with Kubernetes v1.22 failed. Check the logs at: ${CIRCLE_BUILD_URL}" update-helm-charts-index: docker: @@ -947,16 +942,16 @@ workflows: # - acceptance-openshift: # requires: # - cleanup-azure-resources - - acceptance-gke-1-17: + - acceptance-gke-1-19: requires: - cleanup-gcp-resources - acceptance-eks-1-18: requires: - cleanup-eks-resources - - acceptance-aks-1-19: + - acceptance-aks-1-20: requires: - cleanup-azure-resources - - acceptance-kind-1-21 + - acceptance-kind-1-22 # update-helm-charts-index: <-- Disable until we can figure out a release workflow. We currently don't want it to trigger on a tag because the tag is pushed by the eco-releases pipeline. # jobs: # - helm-chart-pipeline-approval: diff --git a/README.md b/README.md index 34c00c052a..cc5b1985c2 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ use Consul with Kubernetes, please see the ### Prerequisites * **Helm 3.0+** (Helm 2 is not supported) - * **Kubernetes 1.17+** - This is the earliest version of Kubernetes tested. + * **Kubernetes 1.18+** - This is the earliest version of Kubernetes tested. It is possible that this chart works with earlier versions but it is untested. diff --git a/charts/consul/test/terraform/aks/main.tf b/charts/consul/test/terraform/aks/main.tf index 0406afd0b2..774b94b68c 100644 --- a/charts/consul/test/terraform/aks/main.tf +++ b/charts/consul/test/terraform/aks/main.tf @@ -1,5 +1,5 @@ provider "azurerm" { - version = "~> 2.0" + version = "2.78.0" features {} } @@ -24,7 +24,7 @@ resource "azurerm_kubernetes_cluster" "default" { location = azurerm_resource_group.default[count.index].location resource_group_name = azurerm_resource_group.default[count.index].name dns_prefix = "consul-k8s-${random_id.suffix[count.index].dec}" - kubernetes_version = "1.19.13" + kubernetes_version = "1.20.9" default_node_pool { name = "default" diff --git a/charts/consul/test/terraform/eks/main.tf b/charts/consul/test/terraform/eks/main.tf index b16646af33..3aa79db821 100644 --- a/charts/consul/test/terraform/eks/main.tf +++ b/charts/consul/test/terraform/eks/main.tf @@ -51,7 +51,7 @@ module "eks" { count = var.cluster_count source = "terraform-aws-modules/eks/aws" - version = "12.2.0" + version = "17.20.0" cluster_name = "consul-k8s-${random_id.suffix[count.index].dec}" cluster_version = "1.18" @@ -69,9 +69,9 @@ module "eks" { } } - manage_aws_auth = false - write_kubeconfig = true - config_output_path = pathexpand("~/.kube/consul-k8s-${random_id.suffix[count.index].dec}") + manage_aws_auth = false + write_kubeconfig = true + kubeconfig_output_path = pathexpand("~/.kube/consul-k8s-${random_id.suffix[count.index].dec}") tags = var.tags } diff --git a/charts/consul/test/terraform/eks/variables.tf b/charts/consul/test/terraform/eks/variables.tf index a401312a45..cab209fda0 100644 --- a/charts/consul/test/terraform/eks/variables.tf +++ b/charts/consul/test/terraform/eks/variables.tf @@ -14,7 +14,7 @@ variable "role_arn" { } variable "tags" { - type = map - default = {} + type = map + default = {} description = "Tags to attach to the created resources." } diff --git a/charts/consul/test/terraform/gke/main.tf b/charts/consul/test/terraform/gke/main.tf index a6c294e2e6..8f86ad1290 100644 --- a/charts/consul/test/terraform/gke/main.tf +++ b/charts/consul/test/terraform/gke/main.tf @@ -10,7 +10,7 @@ resource "random_id" "suffix" { data "google_container_engine_versions" "main" { location = var.zone - version_prefix = "1.17." + version_prefix = "1.19." } resource "google_container_cluster" "cluster" { From 6d4e53094b1827b18645f9565e59d5b64bd762bc Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 7 Oct 2021 11:18:50 -0400 Subject: [PATCH 055/418] Revert "Finished basic tests for checking Consul clients and servers." This reverts commit 8b2d39bbca7e65559fde2503046433ccd0aa2376. --- cli/cmd/status/status.go | 285 ---------------------------------- cli/cmd/status/status_test.go | 196 ----------------------- cli/commands.go | 6 - 3 files changed, 487 deletions(-) delete mode 100644 cli/cmd/status/status.go delete mode 100644 cli/cmd/status/status_test.go diff --git a/cli/cmd/status/status.go b/cli/cmd/status/status.go deleted file mode 100644 index af258fc361..0000000000 --- a/cli/cmd/status/status.go +++ /dev/null @@ -1,285 +0,0 @@ -package status - -import ( - "errors" - "fmt" - "helm.sh/helm/v3/pkg/release" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "os" - "sync" - - "github.com/hashicorp/consul-k8s/cli/cmd/common" - "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" - "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" - "helm.sh/helm/v3/pkg/action" - helmCLI "helm.sh/helm/v3/pkg/cli" - "k8s.io/client-go/kubernetes" - "sigs.k8s.io/yaml" -) - -type Command struct { - *common.BaseCommand - - kubernetes kubernetes.Interface - - set *flag.Sets - - flagKubeConfig string - flagKubeContext string - - once sync.Once - help string -} - -func (c *Command) init() { - c.set = flag.NewSets() - { - f := c.set.NewSet("Global Options") - f.StringVar(&flag.StringVar{ - Name: "kubeconfig", - Aliases: []string{"c"}, - Target: &c.flagKubeConfig, - Default: "", - Usage: "Path to kubeconfig file.", - }) - f.StringVar(&flag.StringVar{ - Name: "context", - Target: &c.flagKubeContext, - Default: "", - Usage: "Kubernetes context to use.", - }) - } - - c.help = c.set.Help() - - // c.Init() calls the embedded BaseCommand's initialization function. - c.Init() -} - -func (c *Command) Run(args []string) int { - c.once.Do(c.init) - - // The logger is initialized in main with the name cli. Here, we reset the name to status so log lines would be prefixed with status. - c.Log.ResetNamed("status") - - defer func() { - if err := c.Close(); err != nil { - c.Log.Error(err.Error()) - os.Exit(1) - } - }() - - if err := c.validateFlags(args); err != nil { - c.UI.Output(err.Error()) - return 1 - } - - // helmCLI.New() will create a settings object which is used by the Helm Go SDK calls. - settings := helmCLI.New() - if c.flagKubeConfig != "" { - settings.KubeConfig = c.flagKubeConfig - } - if c.flagKubeContext != "" { - settings.KubeContext = c.flagKubeContext - } - - // Set up the kubernetes client to use for non Helm SDK calls to the Kubernetes API - // The Helm SDK will use settings.RESTClientGetter for its calls as well, so this will - // use a consistent method to target the right cluster for both Helm SDK and non Helm SDK calls. - if c.kubernetes == nil { - restConfig, err := settings.RESTClientGetter().ToRESTConfig() - if err != nil { - c.UI.Output("retrieving Kubernetes auth: %v", err, terminal.WithErrorStyle()) - return 1 - } - c.kubernetes, err = kubernetes.NewForConfig(restConfig) - if err != nil { - c.UI.Output("initializing Kubernetes client: %v", err, terminal.WithErrorStyle()) - return 1 - } - } - - // Setup logger to stream Helm library logs. - var uiLogger = func(s string, args ...interface{}) { - logMsg := fmt.Sprintf(s, args...) - c.UI.Output(logMsg, terminal.WithLibraryStyle()) - } - - c.UI.Output("Consul-K8s Status Summary", terminal.WithHeaderStyle()) - releaseName, namespace, err := c.checkForPreviousInstallations(settings, uiLogger) - if err != nil { - c.UI.Output(err.Error(), terminal.WithErrorStyle()) - return 1 - } - - if err := c.checkHelmInstallation(settings, uiLogger, releaseName, namespace); err != nil { - c.UI.Output(err.Error(), terminal.WithErrorStyle()) - return 1 - } - - if s, err := c.checkConsulServers(namespace); err != nil { - c.UI.Output(err.Error(), terminal.WithErrorStyle()) - return 1 - } else { - c.UI.Output(s, terminal.WithSuccessStyle()) - } - - if s, err := c.checkConsulClients(namespace); err != nil { - c.UI.Output(err.Error(), terminal.WithErrorStyle()) - return 1 - } else { - c.UI.Output(s, terminal.WithSuccessStyle()) - } - - - - - - - return 0 -} - -// validateFlags is a helper function that performs sanity checks on the user's provided flags. -func (c *Command) validateFlags(args []string) error { - if err := c.set.Parse(args); err != nil { - return err - } - if len(c.set.Args()) > 0 { - return errors.New("should have no non-flag arguments") - } - return nil -} - -// checkForPreviousInstallations uses the helm Go SDK to find helm releases in all namespaces where the chart name is -// "consul", and returns the release name and namespace if found, or an error if not found. -func (c *Command) checkForPreviousInstallations(settings *helmCLI.EnvSettings, uiLogger action.DebugLog) (string, string, error) { - // Need a specific action config to call helm list, where namespace is NOT specified. - listConfig := new(action.Configuration) - if err := listConfig.Init(settings.RESTClientGetter(), "", - os.Getenv("HELM_DRIVER"), uiLogger); err != nil { - return "", "", fmt.Errorf("couldn't initialize helm config: %s", err) - } - - lister := action.NewList(listConfig) - lister.AllNamespaces = true - res, err := lister.Run() - if err != nil { - return "", "", fmt.Errorf("couldn't check for installations: %s", err) - } - - for _, rel := range res { - if rel.Chart.Metadata.Name == "consul" { - c.UI.Output("Installation name: %s", rel.Name, terminal.WithInfoStyle()) - c.UI.Output("Namespace: %s", rel.Namespace, terminal.WithInfoStyle()) - return rel.Name, rel.Namespace, nil - } - } - c.UI.Output("Consul installation found.", terminal.WithSuccessStyle()) - return "", "", errors.New("couldn't find installation") -} - -// checkHelmInstallation uses the helm Go SDK to depict the status of a named release. This function then prints -// the version of the release, it's status (unknown, deployed, uninstalled, ...), and the overwritten values. -func (c *Command) checkHelmInstallation(settings *helmCLI.EnvSettings, uiLogger action.DebugLog, releaseName, namespace string) error { - // Need a specific action config to call helm status, where namespace comes from the previous call to list. - statusConfig := new(action.Configuration) - if err := statusConfig.Init(settings.RESTClientGetter(), namespace, - os.Getenv("HELM_DRIVER"), uiLogger); err != nil { - return fmt.Errorf("couldn't initialize helm config: %s", err) - } - - statuser := action.NewStatus(statusConfig) - rel, err := statuser.Run(releaseName) - if err != nil { - return fmt.Errorf("couldn't check for installations: %s", err) - } - - c.UI.Output("Status: %s", rel.Info.Status, terminal.WithInfoStyle()) - c.UI.Output("Version: %d", rel.Version, terminal.WithInfoStyle()) - c.UI.Output("Time Deployed: %v", rel.Info.LastDeployed, terminal.WithInfoStyle()) - - valuesYaml, err := yaml.Marshal(rel.Config) - if err != nil { - c.UI.Output("Config:" + "\n" + "%+v", err, terminal.WithInfoStyle()) - } else if len(rel.Config) == 0 { - c.UI.Output("Config: " + string(valuesYaml), terminal.WithInfoStyle()) - } else { - c.UI.Output("Config:" + "\n" + string(valuesYaml), terminal.WithInfoStyle()) - } - - // Check the status of the hooks. - if len(rel.Hooks) > 1 { - c.UI.Output("Status Of Helm Hooks:") - - for _, hook := range rel.Hooks { - // Remember that we only report the status of pre-install or pre-upgrade hooks. - if validEvent(hook.Events) { - c.UI.Output("%s %s: %s", hook.Name, hook.Kind, hook.LastRun.Phase.String()) - } - } - c.UI.Output("") - } - - - return nil -} - -// Helper function that checks if the given hook's events are pre-install or pre-upgrade. -func validEvent(events []release.HookEvent) bool { - for _, event := range events { - if event.String() == "pre-install" || event.String() == "pre-upgrade" { - return true - } - } - return false -} - -// checkConsulServers uses the Kubernetes list function to report if the consul servers are healthy. -func (c *Command) checkConsulServers(namespace string) (string, error) { - servers, err := c.kubernetes.AppsV1().StatefulSets(namespace).List(c.Ctx, - metav1.ListOptions{LabelSelector: "app=consul,chart=consul-helm,component=server"}) - if err != nil { - return "", err - } else if len(servers.Items) == 0 { - return "", errors.New("no server stateful set found") - } else if len(servers.Items) > 1 { - return "", errors.New("found multiple server stateful sets") - } - - desiredReplicas := int(*servers.Items[0].Spec.Replicas) - readyReplicas := int(servers.Items[0].Status.ReadyReplicas) - if readyReplicas < desiredReplicas { - return "", fmt.Errorf("%d/%d Consul servers unhealthy", desiredReplicas - readyReplicas, desiredReplicas) - } - return fmt.Sprintf("Consul servers healthy (%d/%d)", readyReplicas, desiredReplicas), nil -} - -// checkConsulClients uses the Kubernetes list function to report if the consul clients are healthy. -func (c *Command) checkConsulClients(namespace string) (string, error) { - clients, err := c.kubernetes.AppsV1().DaemonSets(namespace).List(c.Ctx, - metav1.ListOptions{LabelSelector: "app=consul,chart=consul-helm"}) - if err != nil { - return "", err - } else if len(clients.Items) == 0 { - return "", errors.New("no client daemon set found") - } else if len(clients.Items) > 1 { - return "", errors.New("found multiple client daemon sets") - } - desiredReplicas := int(clients.Items[0].Status.DesiredNumberScheduled) - readyReplicas := int(clients.Items[0].Status.NumberReady) - if readyReplicas < desiredReplicas { - return "", fmt.Errorf("%d/%d Consul clients unhealthy", desiredReplicas - readyReplicas, desiredReplicas) - } - return fmt.Sprintf("Consul clients healthy (%d/%d)", readyReplicas, desiredReplicas), nil -} - -func (c *Command) Help() string { - c.once.Do(c.init) - s := "Usage: consul-k8s status" + "\n\n" + "Get the status of the current Consul installation." + "\n" + - c.help - return s -} - -func (c *Command) Synopsis() string { - return "Status of Consul-K8s install." -} \ No newline at end of file diff --git a/cli/cmd/status/status_test.go b/cli/cmd/status/status_test.go deleted file mode 100644 index 250ae735be..0000000000 --- a/cli/cmd/status/status_test.go +++ /dev/null @@ -1,196 +0,0 @@ -package status - -import ( - "context" - "fmt" - "os" - "testing" - - "github.com/hashicorp/consul-k8s/cli/cmd/common" - "github.com/hashicorp/go-hclog" - "github.com/stretchr/testify/require" - appsv1 "k8s.io/api/apps/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/kubernetes/fake" -) - - -// getInitializedCommand sets up a command struct for tests. -func getInitializedCommand(t *testing.T) *Command { - t.Helper() - log := hclog.New(&hclog.LoggerOptions{ - Name: "cli", - Level: hclog.Info, - Output: os.Stdout, - }) - ctx, _ := context.WithCancel(context.Background()) - - baseCommand := &common.BaseCommand{ - Ctx: ctx, - Log: log, - } - - c := &Command{ - BaseCommand: baseCommand, - } - c.init() - return c -} - -/* Just using this to play around with the Go debugger. */ -func TestDebugger(t *testing.T) { - c := getInitializedCommand(t) - c.Run([]string{}) -} - -//Any feedback on this test is much appreciated! My first time using the K8s Testing library. -- Saad. -func TestCheckConsulServers(t *testing.T) { - c := getInitializedCommand(t) - c.kubernetes = fake.NewSimpleClientset() - - // First check that no stateful sets causes an error. - _, err := c.checkConsulServers("default") - require.Error(t, err) - require.Contains(t, err.Error(), "no server stateful set found") - - // Next create a stateful set with 3 desired replicas and 3 ready replicas. - var replicas int32 - replicas = 3 - - ss := &appsv1.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-server-test1", - Namespace: "default", - Labels: map[string]string{"app":"consul", "chart": "consul-helm", "component": "server"}, - }, - Spec: appsv1.StatefulSetSpec{ - Replicas: &replicas, - }, - Status: appsv1.StatefulSetStatus{ - Replicas: replicas, - ReadyReplicas: replicas, - }, - } - - c.kubernetes.AppsV1().StatefulSets("default").Create(context.Background(), ss, metav1.CreateOptions{}) - - // Now we run the checkConsulServers() function and it should succeed. - s, err := c.checkConsulServers("default") - require.NoError(t, err) - require.Equal(t, "Consul servers healthy (3/3)", s) - - // If you then create another stateful set it should error. - ss2 := &appsv1.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-server-test2", - Namespace: "default", - Labels: map[string]string{"app":"consul", "chart": "consul-helm", "component": "server"}, - }, - Spec: appsv1.StatefulSetSpec{ - Replicas: &replicas, - }, - Status: appsv1.StatefulSetStatus{ - Replicas: replicas, - ReadyReplicas: replicas, - }, - } - c.kubernetes.AppsV1().StatefulSets("default").Create(context.Background(), ss2, metav1.CreateOptions{}) - - _, err = c.checkConsulServers("default") - require.Error(t, err) - require.Contains(t, err.Error(), "found multiple server stateful sets") - - // Clear out the client and now run a test where the stateful set isn't ready. - c.kubernetes = fake.NewSimpleClientset() - - ss3 := &appsv1.StatefulSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-server-test3", - Namespace: "default", - Labels: map[string]string{"app":"consul", "chart": "consul-helm", "component": "server"}, - }, - Spec: appsv1.StatefulSetSpec{ - Replicas: &replicas, - }, - Status: appsv1.StatefulSetStatus{ - Replicas: replicas, - ReadyReplicas: replicas - 1, // Let's just set one of the servers to unhealthy - }, - } - c.kubernetes.AppsV1().StatefulSets("default").Create(context.Background(), ss3, metav1.CreateOptions{}) - - _, err = c.checkConsulServers("default") - require.Error(t, err) - require.Contains(t, err.Error(), fmt.Sprintf("%d/%d Consul servers unhealthy", 1, replicas)) -} - -// This test is very similar to TestCheckConsulServers() in structure. -func TestCheckConsulClients(t *testing.T) { - c := getInitializedCommand(t) - c.kubernetes = fake.NewSimpleClientset() - - // No client daemon set should cause an error. - _, err := c.checkConsulClients("default") - require.Error(t, err) - require.Contains(t, err.Error(), "no client daemon set found") - - // Next create a daemon set. - var desired int32 - desired = 3 - ds := &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-client-test1", - Namespace: "default", - Labels: map[string]string{"app":"consul", "chart": "consul-helm"}, - }, - Status: appsv1.DaemonSetStatus{ - DesiredNumberScheduled: desired, - NumberReady: desired, - }, - } - - c.kubernetes.AppsV1().DaemonSets("default").Create(context.Background(), ds, metav1.CreateOptions{}) - - // Now run checkConsulClients() and make sure it succeeds. - s, err := c.checkConsulClients("default") - require.NoError(t, err) - require.Equal(t, "Consul clients healthy (3/3)", s) - - // Creating another daemon set should cause an error. - ds2 := &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-client-test2", - Namespace: "default", - Labels: map[string]string{"app":"consul", "chart": "consul-helm"}, - }, - Status: appsv1.DaemonSetStatus{ - DesiredNumberScheduled: desired, - NumberReady: desired, - }, - } - c.kubernetes.AppsV1().DaemonSets("default").Create(context.Background(), ds2, metav1.CreateOptions{}) - - _, err = c.checkConsulClients("default") - require.Error(t, err) - require.Contains(t, err.Error(), "found multiple client daemon sets") - - // Clear out the client and run a test with fewer than desired daemon sets ready. - c.kubernetes = fake.NewSimpleClientset() - - ds3 := &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "consul-client-test2", - Namespace: "default", - Labels: map[string]string{"app":"consul", "chart": "consul-helm"}, - }, - Status: appsv1.DaemonSetStatus{ - DesiredNumberScheduled: desired, - NumberReady: desired - 1, - }, - } - c.kubernetes.AppsV1().DaemonSets("default").Create(context.Background(), ds3, metav1.CreateOptions{}) - - _, err = c.checkConsulClients("default") - require.Error(t, err) - require.Contains(t, err.Error(), fmt.Sprintf("%d/%d Consul clients unhealthy", 1, desired)) -} diff --git a/cli/commands.go b/cli/commands.go index 9edfb17eb4..3fc4a7d936 100644 --- a/cli/commands.go +++ b/cli/commands.go @@ -2,7 +2,6 @@ package main import ( "context" - "github.com/hashicorp/consul-k8s/cli/cmd/status" "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/consul-k8s/cli/cmd/install" @@ -31,11 +30,6 @@ func initializeCommands(ctx context.Context, log hclog.Logger) (*common.BaseComm BaseCommand: baseCommand, }, nil }, - "status": func() (cli.Command, error) { - return &status.Command{ - BaseCommand: baseCommand, - }, nil - }, "version": func() (cli.Command, error) { return &cmdversion.Command{ BaseCommand: baseCommand, From 778863051e5e1949eb965d7bc5cc54d3005acc01 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Thu, 7 Oct 2021 10:31:09 -0700 Subject: [PATCH 056/418] CLI smoke tests (#743) * Rename acceptance module and move it to top level * Runs smoke tests for CLI install/uninstall --- .circleci/config.yml | 56 ++-- .../workflows/golangci-lint-acceptance.yml | 2 +- .../framework/config/config.go | 2 +- .../framework/config/config_test.go | 0 acceptance/framework/consul/cli_cluster.go | 265 ++++++++++++++++++ .../framework/consul/consul_cluster.go | 38 +-- .../framework/consul/consul_cluster_test.go | 2 +- .../framework/environment/environment.go | 4 +- .../framework/flags/flags.go | 2 +- .../framework/flags/flags_test.go | 0 .../framework/helpers/helpers.go | 3 +- .../framework/k8s/debug.go | 4 +- .../framework/k8s/deploy.go | 4 +- .../framework/k8s/kubectl.go | 2 +- .../framework/logger/logger.go | 0 .../framework/suite/suite.go | 6 +- .../test/acceptance => acceptance}/go.mod | 2 +- .../test/acceptance => acceptance}/go.sum | 0 .../tests/basic/basic_test.go | 6 +- .../tests/basic/main_test.go | 2 +- acceptance/tests/cli/main_test.go | 15 + acceptance/tests/cli/smoke_test.go | 35 +++ acceptance/tests/connect/connect_helper.go | 122 ++++++++ .../connect/connect_inject_namespaces_test.go | 8 +- .../tests/connect/connect_inject_test.go | 104 +------ .../tests/connect/main_test.go | 2 +- .../tests/consul-dns/consul_dns_test.go | 6 +- .../tests/consul-dns/main_test.go | 2 +- .../controller/controller_namespaces_test.go | 8 +- .../tests/controller/controller_test.go | 8 +- .../tests/controller/main_test.go | 2 +- .../tests/example/example_test.go | 6 +- .../tests/example/main_test.go | 2 +- .../bases/mesh-gateway/kustomization.yaml | 0 .../bases/mesh-gateway/proxydefaults.yaml | 0 .../static-client/anyuid-scc-rolebinding.yaml | 0 .../bases/static-client/deployment.yaml | 0 .../bases/static-client/kustomization.yaml | 0 .../privileged-scc-rolebinding.yaml | 0 .../bases/static-client/psp-rolebinding.yaml | 0 .../fixtures/bases/static-client/service.yaml | 0 .../bases/static-client/serviceaccount.yaml | 0 .../bases/static-metrics-app/deployment.yaml | 0 .../static-metrics-app/kustomization.yaml | 0 .../bases/static-metrics-app/service.yaml | 0 .../static-server/anyuid-scc-rolebinding.yaml | 0 .../bases/static-server/deployment.yaml | 0 .../bases/static-server/kustomization.yaml | 0 .../privileged-scc-rolebinding.yaml | 0 .../bases/static-server/psp-rolebinding.yaml | 0 .../fixtures/bases/static-server/service.yaml | 0 .../bases/static-server/serviceaccount.yaml | 0 .../static-client-inject/kustomization.yaml | 0 .../cases/static-client-inject/patch.yaml | 0 .../static-client-multi-dc/kustomization.yaml | 0 .../cases/static-client-multi-dc/patch.yaml | 0 .../kustomization.yaml | 0 .../cases/static-client-namespaces/patch.yaml | 0 .../static-client-tproxy/kustomization.yaml | 0 .../cases/static-client-tproxy/patch.yaml | 0 .../static-server-inject/kustomization.yaml | 0 .../cases/static-server-inject/patch.yaml | 0 .../tests/fixtures/crds/ingressgateway.yaml | 0 .../tests/fixtures/crds/mesh.yaml | 0 .../tests/fixtures/crds/proxydefaults.yaml | 0 .../tests/fixtures/crds/servicedefaults.yaml | 0 .../fixtures/crds/serviceintentions.yaml | 0 .../tests/fixtures/crds/serviceresolver.yaml | 0 .../tests/fixtures/crds/servicerouter.yaml | 0 .../tests/fixtures/crds/servicesplitter.yaml | 0 .../fixtures/crds/terminatinggateway.yaml | 0 .../ingress_gateway_namespaces_test.go | 8 +- .../ingress-gateway/ingress_gateway_test.go | 8 +- .../tests/ingress-gateway/main_test.go | 2 +- .../tests/mesh-gateway/main_test.go | 2 +- .../tests/mesh-gateway/mesh_gateway_test.go | 10 +- .../tests/metrics/main_test.go | 2 +- .../tests/metrics/metrics_test.go | 10 +- .../tests/sync/main_test.go | 2 +- .../sync/sync_catalog_namespaces_test.go | 8 +- .../tests/sync/sync_catalog_test.go | 8 +- .../tests/terminating-gateway/main_test.go | 2 +- .../terminating_gateway_namespaces_test.go | 8 +- .../terminating_gateway_test.go | 8 +- 84 files changed, 579 insertions(+), 219 deletions(-) rename {charts/consul/test/acceptance => acceptance}/framework/config/config.go (98%) rename {charts/consul/test/acceptance => acceptance}/framework/config/config_test.go (100%) create mode 100644 acceptance/framework/consul/cli_cluster.go rename {charts/consul/test/acceptance => acceptance}/framework/consul/consul_cluster.go (97%) rename {charts/consul/test/acceptance => acceptance}/framework/consul/consul_cluster_test.go (97%) rename {charts/consul/test/acceptance => acceptance}/framework/environment/environment.go (95%) rename {charts/consul/test/acceptance => acceptance}/framework/flags/flags.go (98%) rename {charts/consul/test/acceptance => acceptance}/framework/flags/flags_test.go (100%) rename {charts/consul/test/acceptance => acceptance}/framework/helpers/helpers.go (97%) rename {charts/consul/test/acceptance => acceptance}/framework/k8s/debug.go (97%) rename {charts/consul/test/acceptance => acceptance}/framework/k8s/deploy.go (97%) rename {charts/consul/test/acceptance => acceptance}/framework/k8s/kubectl.go (98%) rename {charts/consul/test/acceptance => acceptance}/framework/logger/logger.go (100%) rename {charts/consul/test/acceptance => acceptance}/framework/suite/suite.go (81%) rename {charts/consul/test/acceptance => acceptance}/go.mod (80%) rename {charts/consul/test/acceptance => acceptance}/go.sum (100%) rename {charts/consul/test/acceptance => acceptance}/tests/basic/basic_test.go (91%) rename {charts/consul/test/acceptance => acceptance}/tests/basic/main_test.go (63%) create mode 100644 acceptance/tests/cli/main_test.go create mode 100644 acceptance/tests/cli/smoke_test.go create mode 100644 acceptance/tests/connect/connect_helper.go rename {charts/consul/test/acceptance => acceptance}/tests/connect/connect_inject_namespaces_test.go (97%) rename {charts/consul/test/acceptance => acceptance}/tests/connect/connect_inject_test.go (50%) rename {charts/consul/test/acceptance => acceptance}/tests/connect/main_test.go (63%) rename {charts/consul/test/acceptance => acceptance}/tests/consul-dns/consul_dns_test.go (92%) rename {charts/consul/test/acceptance => acceptance}/tests/consul-dns/main_test.go (63%) rename {charts/consul/test/acceptance => acceptance}/tests/controller/controller_namespaces_test.go (98%) rename {charts/consul/test/acceptance => acceptance}/tests/controller/controller_test.go (98%) rename {charts/consul/test/acceptance => acceptance}/tests/controller/main_test.go (64%) rename {charts/consul/test/acceptance => acceptance}/tests/example/example_test.go (89%) rename {charts/consul/test/acceptance => acceptance}/tests/example/main_test.go (89%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/mesh-gateway/kustomization.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/mesh-gateway/proxydefaults.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-client/anyuid-scc-rolebinding.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-client/deployment.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-client/kustomization.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-client/privileged-scc-rolebinding.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-client/psp-rolebinding.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-client/service.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-client/serviceaccount.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-metrics-app/deployment.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-metrics-app/kustomization.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-metrics-app/service.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-server/anyuid-scc-rolebinding.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-server/deployment.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-server/kustomization.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-server/privileged-scc-rolebinding.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-server/psp-rolebinding.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-server/service.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/bases/static-server/serviceaccount.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-client-inject/kustomization.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-client-inject/patch.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-client-multi-dc/patch.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-client-namespaces/kustomization.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-client-namespaces/patch.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-client-tproxy/kustomization.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-client-tproxy/patch.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-server-inject/kustomization.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-server-inject/patch.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/crds/ingressgateway.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/crds/mesh.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/crds/proxydefaults.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/crds/servicedefaults.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/crds/serviceintentions.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/crds/serviceresolver.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/crds/servicerouter.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/crds/servicesplitter.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/crds/terminatinggateway.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/ingress-gateway/ingress_gateway_namespaces_test.go (96%) rename {charts/consul/test/acceptance => acceptance}/tests/ingress-gateway/ingress_gateway_test.go (91%) rename {charts/consul/test/acceptance => acceptance}/tests/ingress-gateway/main_test.go (64%) rename {charts/consul/test/acceptance => acceptance}/tests/mesh-gateway/main_test.go (78%) rename {charts/consul/test/acceptance => acceptance}/tests/mesh-gateway/mesh_gateway_test.go (96%) rename {charts/consul/test/acceptance => acceptance}/tests/metrics/main_test.go (63%) rename {charts/consul/test/acceptance => acceptance}/tests/metrics/metrics_test.go (93%) rename {charts/consul/test/acceptance => acceptance}/tests/sync/main_test.go (63%) rename {charts/consul/test/acceptance => acceptance}/tests/sync/sync_catalog_namespaces_test.go (92%) rename {charts/consul/test/acceptance => acceptance}/tests/sync/sync_catalog_test.go (88%) rename {charts/consul/test/acceptance => acceptance}/tests/terminating-gateway/main_test.go (65%) rename {charts/consul/test/acceptance => acceptance}/tests/terminating-gateway/terminating_gateway_namespaces_test.go (96%) rename {charts/consul/test/acceptance => acceptance}/tests/terminating-gateway/terminating_gateway_test.go (95%) diff --git a/.circleci/config.yml b/.circleci/config.yml index c309f2cc64..981c0dc0b9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,8 +13,10 @@ executors: CONSUL_ENT_VERSION: 1.11.0+ent-alpha # Consul's enterprise version to use in tests control-plane-path : &control-plane-path control-plane -acceptance-test-path: &acceptance-test-path charts/consul/test/acceptance -acceptance-framework-path: &acceptance-framework-path charts/consul/test/acceptance/framework +cli-path : &cli-path cli +acceptance-mod-path: &acceptance-mod-path acceptance +acceptance-test-path: &acceptance-test-path acceptance/tests +acceptance-framework-path: &acceptance-framework-path acceptance/framework charts-consul-path: &charts-consul-path charts/consul helm-gen-path: &helm-gen-path hack/helm-reference-gen gke-terraform-path: &gke-terraform-path charts/consul/test/terraform/gke @@ -69,13 +71,21 @@ commands: consul-k8s-image: type: string default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" + go-path: + type: string + default: "/home/circleci/.go_workspace" steps: - when: condition: << parameters.failfast >> steps: + - run: + name: Build CLI binary + working_directory: *cli-path + command: | + go build -o << parameters.go-path >>/bin/consul-k8s - run: name: Run acceptance tests - working_directory: charts/consul/test/acceptance/tests + working_directory: *acceptance-test-path no_output_timeout: 2h command: | # Enterprise tests can't run on fork PRs because they require @@ -113,7 +123,7 @@ commands: steps: - run: name: Run acceptance tests - working_directory: charts/consul/test/acceptance/tests + working_directory: *acceptance-test-path no_output_timeout: 2h command: | # Enterprise tests can't run on fork PRs because they require @@ -294,23 +304,23 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "charts/consul/test/acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} - run: name: go mod download - working_directory: *acceptance-test-path + working_directory: *acceptance-mod-path command: go mod download # Save go module cache if the go.mod file has changed - save_cache: - key: consul-helm-acceptance-modcache-v1-{{ checksum "charts/consul/test/acceptance/go.mod" }} + key: consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} paths: - "/go/pkg/mod" # check go fmt output because it does not report non-zero when there are fmt changes - run: name: check go fmt - working_directory: *acceptance-test-path + working_directory: *acceptance-mod-path command: | files=$(go fmt ./...) if [ -n "$files" ]; then @@ -321,7 +331,7 @@ jobs: - run: name: go vet - working_directory: *acceptance-test-path + working_directory: *acceptance-mod-path command: go vet ./... go-fmt-and-vet-helm-gen: @@ -370,7 +380,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "charts/consul/test/acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -452,13 +462,13 @@ jobs: version: "v1.21.2" - restore_cache: keys: - - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} + - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} - run: name: go mod download - working_directory: *acceptance-test-path + working_directory: *acceptance-mod-path command: go mod download - save_cache: - key: consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} + key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} paths: - ~/.go_workspace/pkg/mod - run: mkdir -p $TEST_RESULTS @@ -484,13 +494,13 @@ jobs: version: "v1.21.2" - restore_cache: keys: - - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} + - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} - run: name: go mod download - working_directory: *acceptance-test-path + working_directory: *acceptance-mod-path command: go mod download - save_cache: - key: consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} + key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} paths: - ~/.go_workspace/pkg/mod - run: mkdir -p $TEST_RESULTS @@ -604,7 +614,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "charts/consul/test/acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -659,7 +669,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "charts/consul/test/acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -720,7 +730,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "charts/consul/test/acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -773,7 +783,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "charts/consul/test/acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -809,13 +819,13 @@ jobs: version: "v1.22.1" - restore_cache: keys: - - consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} + - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} - run: name: go mod download - working_directory: *acceptance-test-path + working_directory: *acceptance-mod-path command: go mod download - save_cache: - key: consul-helm-modcache-v2-{{ checksum "charts/consul/test/acceptance/go.mod" }} + key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} paths: - ~/.go_workspace/pkg/mod - run: mkdir -p $TEST_RESULTS diff --git a/.github/workflows/golangci-lint-acceptance.yml b/.github/workflows/golangci-lint-acceptance.yml index 1f60c2c19b..d41efb33af 100644 --- a/.github/workflows/golangci-lint-acceptance.yml +++ b/.github/workflows/golangci-lint-acceptance.yml @@ -20,4 +20,4 @@ jobs: # TODO: we may need to modify this when monorepo comes, it could be helpful for when we test # only control-plane components in a PR, or some other scenario. # working-directory: somedir - working-directory: charts/consul/test/acceptance + working-directory: acceptance diff --git a/charts/consul/test/acceptance/framework/config/config.go b/acceptance/framework/config/config.go similarity index 98% rename from charts/consul/test/acceptance/framework/config/config.go rename to acceptance/framework/config/config.go index 5346e248cc..500a10001d 100644 --- a/charts/consul/test/acceptance/framework/config/config.go +++ b/acceptance/framework/config/config.go @@ -13,7 +13,7 @@ import ( // HelmChartPath is the path to the helm chart. // Note: this will need to be changed if this file is moved. const ( - HelmChartPath = "../../../.." + HelmChartPath = "../../../charts/consul" LicenseSecretName = "license" LicenseSecretKey = "key" ) diff --git a/charts/consul/test/acceptance/framework/config/config_test.go b/acceptance/framework/config/config_test.go similarity index 100% rename from charts/consul/test/acceptance/framework/config/config_test.go rename to acceptance/framework/config/config_test.go diff --git a/acceptance/framework/consul/cli_cluster.go b/acceptance/framework/consul/cli_cluster.go new file mode 100644 index 0000000000..7d07cb4da3 --- /dev/null +++ b/acceptance/framework/consul/cli_cluster.go @@ -0,0 +1,265 @@ +package consul + +import ( + "context" + "fmt" + "os/exec" + "testing" + "time" + + "github.com/gruntwork-io/terratest/modules/helm" + terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" + terratestLogger "github.com/gruntwork-io/terratest/modules/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/config" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil/retry" + "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +const ( + consulNS = "consul" + CLIReleaseName = "consul" +) + +// CLICluster +type CLICluster struct { + ctx environment.TestContext + namespace string + helmOptions *helm.Options + kubectlOptions *terratestk8s.KubectlOptions + values map[string]string + releaseName string + kubernetesClient kubernetes.Interface + kubeConfig string + kubeContext string + noCleanupOnFailure bool + debugDirectory string + logger terratestLogger.TestLogger +} + +func NewCLICluster( + t *testing.T, + helmValues map[string]string, + ctx environment.TestContext, + cfg *config.TestConfig, + releaseName string, +) Cluster { + + // Create the namespace so the PSPs, SCCs, and enterprise secret can be created in the right namespace. + createOrUpdateNamespace(t, ctx.KubernetesClient(t), consulNS) + + if cfg.EnablePodSecurityPolicies { + configurePodSecurityPolicies(t, ctx.KubernetesClient(t), cfg, consulNS) + } + + if cfg.EnableOpenshift && cfg.EnableTransparentProxy { + configureSCCs(t, ctx.KubernetesClient(t), cfg, consulNS) + } + + if cfg.EnterpriseLicense != "" { + createOrUpdateLicenseSecret(t, ctx.KubernetesClient(t), cfg, consulNS) + } + + // Deploy with the following defaults unless helmValues overwrites it. + values := defaultValues() + valuesFromConfig, err := cfg.HelmValuesFromConfig() + require.NoError(t, err) + + // Merge all helm values + mergeMaps(values, valuesFromConfig) + mergeMaps(values, helmValues) + + logger := terratestLogger.New(logger.TestLogger{}) + + kopts := ctx.KubectlOptions(t) + kopts.Namespace = consulNS + hopts := &helm.Options{ + SetValues: values, + KubectlOptions: kopts, + Logger: logger, + } + return &CLICluster{ + ctx: ctx, + helmOptions: hopts, + kubectlOptions: kopts, + namespace: cfg.KubeNamespace, + values: values, + releaseName: releaseName, + kubernetesClient: ctx.KubernetesClient(t), + kubeConfig: cfg.Kubeconfig, + kubeContext: cfg.KubeContext, + noCleanupOnFailure: cfg.NoCleanupOnFailure, + debugDirectory: cfg.DebugDirectory, + logger: logger, + } +} + +func (h *CLICluster) Create(t *testing.T) { + t.Helper() + + // Make sure we delete the cluster if we receive an interrupt signal and + // register cleanup so that we delete the cluster when test finishes. + helpers.Cleanup(t, h.noCleanupOnFailure, func() { + h.Destroy(t) + }) + + // The install command itself will fail if there are prior installations, so it's sufficient to just run the install + // command. + args := []string{"install"} + kubeconfig := h.kubeConfig + if kubeconfig != "" { + args = append(args, "-kubeconfig", kubeconfig) + } + kubecontext := h.kubeContext + if kubecontext != "" { + args = append(args, "-context", kubecontext) + } + + for k, v := range h.values { + args = append(args, "-set", fmt.Sprintf("%s=%s", k, v)) + + } + + // Match the timeout for the helm tests. + args = append(args, "-timeout", "15m") + args = append(args, "-auto-approve") + + cmd := exec.Command("consul-k8s", args...) + out, err := cmd.Output() + if err != nil { + h.logger.Logf(t, "error running command [ consul-k8s %s ]: %s", args, err.Error()) + h.logger.Logf(t, "command stdout: %s", string(out)) + } + require.NoError(t, err) + + helpers.WaitForAllPodsToBeReady(t, h.kubernetesClient, consulNS, fmt.Sprintf("release=%s", h.releaseName)) +} + +func (h *CLICluster) Destroy(t *testing.T) { + t.Helper() + + k8s.WritePodsDebugInfoIfFailed(t, h.kubectlOptions, h.debugDirectory, "release="+h.releaseName) + + args := []string{"uninstall"} + kubeconfig := h.kubeConfig + if kubeconfig != "" { + args = append(args, "-kubeconfig", kubeconfig) + } + kubecontext := h.kubeContext + if kubecontext != "" { + args = append(args, "-context", kubecontext) + } + args = append(args, "-auto-approve", "-wipe-data") + + cmd := exec.Command("consul-k8s", args...) + out, err := cmd.Output() + if err != nil { + h.logger.Logf(t, "error running command [ consul-k8s %s ]: %s", args, err.Error()) + h.logger.Logf(t, "command stdout: %s", string(out)) + } + require.NoError(t, err) +} + +func (h *CLICluster) Upgrade(t *testing.T, helmValues map[string]string) { + t.Helper() + + mergeMaps(h.helmOptions.SetValues, helmValues) + helm.Upgrade(t, h.helmOptions, config.HelmChartPath, h.releaseName) + helpers.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) +} + +func (h *CLICluster) SetupConsulClient(t *testing.T, secure bool) *api.Client { + t.Helper() + + namespace := h.kubectlOptions.Namespace + config := api.DefaultConfig() + localPort := terratestk8s.GetAvailablePort(t) + remotePort := 8500 // use non-secure by default + + if secure { + // Overwrite remote port to HTTPS. + remotePort = 8501 + + // It's OK to skip TLS verification for local traffic. + config.TLSConfig.InsecureSkipVerify = true + config.Scheme = "https" + + // Get the ACL token. First, attempt to read it from the bootstrap token (this will be true in primary Consul servers). + // If the bootstrap token doesn't exist, it means we are running against a secondary cluster + // and will try to read the replication token from the federation secret. + // In secondary servers, we don't create a bootstrap token since ACLs are only bootstrapped in the primary. + // Instead, we provide a replication token that serves the role of the bootstrap token. + + aclSecretName := fmt.Sprintf("%s-consul-bootstrap-acl-token", h.releaseName) + if h.releaseName == CLIReleaseName { + aclSecretName = "consul-bootstrap-acl-token" + } + aclSecret, err := h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), aclSecretName, metav1.GetOptions{}) + if err != nil && errors.IsNotFound(err) { + federationSecret := fmt.Sprintf("%s-consul-federation", h.releaseName) + if h.releaseName == CLIReleaseName { + federationSecret = "consul-federation" + } + aclSecret, err = h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), federationSecret, metav1.GetOptions{}) + require.NoError(t, err) + config.Token = string(aclSecret.Data["replicationToken"]) + } else if err == nil { + config.Token = string(aclSecret.Data["token"]) + } else { + require.NoError(t, err) + } + } + + serverPod := fmt.Sprintf("%s-consul-server-0", h.releaseName) + if h.releaseName == CLIReleaseName { + serverPod = "consul-server-0" + } + tunnel := terratestk8s.NewTunnelWithLogger( + h.kubectlOptions, + terratestk8s.ResourceTypePod, + serverPod, + localPort, + remotePort, + h.logger) + + // Retry creating the port forward since it can fail occasionally. + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 3}, t, func(r *retry.R) { + // NOTE: It's okay to pass in `t` to ForwardPortE despite being in a retry + // because we're using ForwardPortE (not ForwardPort) so the `t` won't + // get used to fail the test, just for logging. + require.NoError(r, tunnel.ForwardPortE(t)) + }) + + t.Cleanup(func() { + tunnel.Close() + }) + + config.Address = fmt.Sprintf("127.0.0.1:%d", localPort) + consulClient, err := api.NewClient(config) + require.NoError(t, err) + + return consulClient +} + +func createOrUpdateNamespace(t *testing.T, client kubernetes.Interface, namespace string) { + _, err := client.CoreV1().Namespaces().Get(context.Background(), namespace, metav1.GetOptions{}) + if errors.IsNotFound(err) { + _, err := client.CoreV1().Namespaces().Create(context.Background(), &v1.Namespace{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: namespace, + }, + }, metav1.CreateOptions{}) + require.NoError(t, err) + } else { + require.NoError(t, err) + } +} diff --git a/charts/consul/test/acceptance/framework/consul/consul_cluster.go b/acceptance/framework/consul/consul_cluster.go similarity index 97% rename from charts/consul/test/acceptance/framework/consul/consul_cluster.go rename to acceptance/framework/consul/consul_cluster.go index 1d2ec6906e..b1e8f8d9e2 100644 --- a/charts/consul/test/acceptance/framework/consul/consul_cluster.go +++ b/acceptance/framework/consul/consul_cluster.go @@ -11,11 +11,11 @@ import ( "github.com/gruntwork-io/terratest/modules/helm" terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" terratestLogger "github.com/gruntwork-io/terratest/modules/logger" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/config" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/environment" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/config" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" @@ -71,16 +71,7 @@ func NewHelmCluster( } // Deploy with the following defaults unless helmValues overwrites it. - values := map[string]string{ - "server.replicas": "1", - "server.bootstrapExpect": "1", - "connectInject.envoyExtraArgs": "--log-level debug", - "connectInject.logLevel": "debug", - // Disable DNS since enabling it changes the policy for the anonymous token, - // which could result in tests passing due to that token having privileges to read services - // (false positive). - "dns.enabled": "false", - } + values := defaultValues() valuesFromConfig, err := cfg.HelmValuesFromConfig() require.NoError(t, err) @@ -262,10 +253,11 @@ func (h *HelmCluster) SetupConsulClient(t *testing.T, secure bool) *api.Client { } } + serverPod := fmt.Sprintf("%s-consul-server-0", h.releaseName) tunnel := terratestk8s.NewTunnelWithLogger( h.helmOptions.KubectlOptions, terratestk8s.ResourceTypePod, - fmt.Sprintf("%s-consul-server-0", h.releaseName), + serverPod, localPort, remotePort, h.logger) @@ -507,6 +499,20 @@ func configureSCCs(t *testing.T, client kubernetes.Interface, cfg *config.TestCo }) } +func defaultValues() map[string]string { + values := map[string]string{ + "server.replicas": "1", + "server.bootstrapExpect": "1", + "connectInject.envoyExtraArgs": "--log-level debug", + "connectInject.logLevel": "debug", + // Disable DNS since enabling it changes the policy for the anonymous token, + // which could result in tests passing due to that token having privileges to read services + // (false positive). + "dns.enabled": "false", + } + return values +} + // mergeValues will merge the values in b with values in a and save in a. // If there are conflicts, the values in b will overwrite the values in a. func mergeMaps(a, b map[string]string) { diff --git a/charts/consul/test/acceptance/framework/consul/consul_cluster_test.go b/acceptance/framework/consul/consul_cluster_test.go similarity index 97% rename from charts/consul/test/acceptance/framework/consul/consul_cluster_test.go rename to acceptance/framework/consul/consul_cluster_test.go index bc0bf28386..f427969ef3 100644 --- a/charts/consul/test/acceptance/framework/consul/consul_cluster_test.go +++ b/acceptance/framework/consul/consul_cluster_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/config" + "github.com/hashicorp/consul-k8s/acceptance/framework/config" "github.com/stretchr/testify/require" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" diff --git a/charts/consul/test/acceptance/framework/environment/environment.go b/acceptance/framework/environment/environment.go similarity index 95% rename from charts/consul/test/acceptance/framework/environment/environment.go rename to acceptance/framework/environment/environment.go index ae6540884b..ad39a09a04 100644 --- a/charts/consul/test/acceptance/framework/environment/environment.go +++ b/acceptance/framework/environment/environment.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/config" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/config" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" diff --git a/charts/consul/test/acceptance/framework/flags/flags.go b/acceptance/framework/flags/flags.go similarity index 98% rename from charts/consul/test/acceptance/framework/flags/flags.go rename to acceptance/framework/flags/flags.go index 345d0b2d37..ca22722ec6 100644 --- a/charts/consul/test/acceptance/framework/flags/flags.go +++ b/acceptance/framework/flags/flags.go @@ -6,7 +6,7 @@ import ( "os" "sync" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/config" + "github.com/hashicorp/consul-k8s/acceptance/framework/config" ) type TestFlags struct { diff --git a/charts/consul/test/acceptance/framework/flags/flags_test.go b/acceptance/framework/flags/flags_test.go similarity index 100% rename from charts/consul/test/acceptance/framework/flags/flags_test.go rename to acceptance/framework/flags/flags_test.go diff --git a/charts/consul/test/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go similarity index 97% rename from charts/consul/test/acceptance/framework/helpers/helpers.go rename to acceptance/framework/helpers/helpers.go index df8ae218a3..e4a2c02c91 100644 --- a/charts/consul/test/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -12,7 +12,7 @@ import ( terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" "github.com/gruntwork-io/terratest/modules/random" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" @@ -52,6 +52,7 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac r.Errorf("%d pods are not ready: %s", len(notReadyPods), strings.Join(notReadyPods, ",")) } }) + logger.Log(t, "Finished waiting for pods to be ready.") } // Sets up a goroutine that will wait for interrupt signals diff --git a/charts/consul/test/acceptance/framework/k8s/debug.go b/acceptance/framework/k8s/debug.go similarity index 97% rename from charts/consul/test/acceptance/framework/k8s/debug.go rename to acceptance/framework/k8s/debug.go index d68df761b0..c01101c6dc 100644 --- a/charts/consul/test/acceptance/framework/k8s/debug.go +++ b/acceptance/framework/k8s/debug.go @@ -10,8 +10,8 @@ import ( "github.com/gruntwork-io/terratest/modules/k8s" terratestLogger "github.com/gruntwork-io/terratest/modules/logger" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/charts/consul/test/acceptance/framework/k8s/deploy.go b/acceptance/framework/k8s/deploy.go similarity index 97% rename from charts/consul/test/acceptance/framework/k8s/deploy.go rename to acceptance/framework/k8s/deploy.go index be8ee98d6f..6616e6f45c 100644 --- a/charts/consul/test/acceptance/framework/k8s/deploy.go +++ b/acceptance/framework/k8s/deploy.go @@ -8,8 +8,8 @@ import ( "time" "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" v1 "k8s.io/api/apps/v1" diff --git a/charts/consul/test/acceptance/framework/k8s/kubectl.go b/acceptance/framework/k8s/kubectl.go similarity index 98% rename from charts/consul/test/acceptance/framework/k8s/kubectl.go rename to acceptance/framework/k8s/kubectl.go index de49b3c46d..318cde217e 100644 --- a/charts/consul/test/acceptance/framework/k8s/kubectl.go +++ b/acceptance/framework/k8s/kubectl.go @@ -8,7 +8,7 @@ import ( "github.com/gruntwork-io/terratest/modules/k8s" terratestLogger "github.com/gruntwork-io/terratest/modules/logger" "github.com/gruntwork-io/terratest/modules/shell" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" ) diff --git a/charts/consul/test/acceptance/framework/logger/logger.go b/acceptance/framework/logger/logger.go similarity index 100% rename from charts/consul/test/acceptance/framework/logger/logger.go rename to acceptance/framework/logger/logger.go diff --git a/charts/consul/test/acceptance/framework/suite/suite.go b/acceptance/framework/suite/suite.go similarity index 81% rename from charts/consul/test/acceptance/framework/suite/suite.go rename to acceptance/framework/suite/suite.go index d421b0b91b..365737f66f 100644 --- a/charts/consul/test/acceptance/framework/suite/suite.go +++ b/acceptance/framework/suite/suite.go @@ -6,9 +6,9 @@ import ( "io/ioutil" "testing" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/config" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/environment" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/flags" + "github.com/hashicorp/consul-k8s/acceptance/framework/config" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/flags" ) type suite struct { diff --git a/charts/consul/test/acceptance/go.mod b/acceptance/go.mod similarity index 80% rename from charts/consul/test/acceptance/go.mod rename to acceptance/go.mod index 08fe978f06..040d14ee87 100644 --- a/charts/consul/test/acceptance/go.mod +++ b/acceptance/go.mod @@ -1,4 +1,4 @@ -module github.com/hashicorp/consul-k8s/charts/consul/test/acceptance +module github.com/hashicorp/consul-k8s/acceptance go 1.14 diff --git a/charts/consul/test/acceptance/go.sum b/acceptance/go.sum similarity index 100% rename from charts/consul/test/acceptance/go.sum rename to acceptance/go.sum diff --git a/charts/consul/test/acceptance/tests/basic/basic_test.go b/acceptance/tests/basic/basic_test.go similarity index 91% rename from charts/consul/test/acceptance/tests/basic/basic_test.go rename to acceptance/tests/basic/basic_test.go index 95861e5f98..5b5c389933 100644 --- a/charts/consul/test/acceptance/tests/basic/basic_test.go +++ b/acceptance/tests/basic/basic_test.go @@ -7,9 +7,9 @@ import ( "strings" "testing" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/charts/consul/test/acceptance/tests/basic/main_test.go b/acceptance/tests/basic/main_test.go similarity index 63% rename from charts/consul/test/acceptance/tests/basic/main_test.go rename to acceptance/tests/basic/main_test.go index 79905fb380..fa858ee4ae 100644 --- a/charts/consul/test/acceptance/tests/basic/main_test.go +++ b/acceptance/tests/basic/main_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testsuite.Suite diff --git a/acceptance/tests/cli/main_test.go b/acceptance/tests/cli/main_test.go new file mode 100644 index 0000000000..85cef25abe --- /dev/null +++ b/acceptance/tests/cli/main_test.go @@ -0,0 +1,15 @@ +package cli + +import ( + "os" + "testing" + + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" +) + +var suite testsuite.Suite + +func TestMain(m *testing.M) { + suite = testsuite.NewSuite(m) + os.Exit(suite.Run()) +} diff --git a/acceptance/tests/cli/smoke_test.go b/acceptance/tests/cli/smoke_test.go new file mode 100644 index 0000000000..51bf2bdbb2 --- /dev/null +++ b/acceptance/tests/cli/smoke_test.go @@ -0,0 +1,35 @@ +package cli + +import ( + "fmt" + "testing" + + "github.com/hashicorp/consul-k8s/acceptance/tests/connect" +) + +// TestCLIConnectInject is a smoke test that the CLI works with Helm hooks. It sets the +// connect.ConnectInjectConnectivityCheck cli flag to true, causing the Create() and Destroy() methods to use the CLI +// for installation/uninstallation. The connect.ConnectInjectConnectivityCheck test leverages secure mode which will +// enable ACLs and TLS, which are set up via Helm hooks. This allows us to verify that core service mesh functionality +// with non-trivial Helm settings are set up appropriately with the CLI. +func TestCLIConnectInject(t *testing.T) { + cases := []struct { + secure bool + autoEncrypt bool + }{ + {false, false}, + {true, false}, + {true, true}, + } + + for _, c := range cases { + name := fmt.Sprintf("secure: %t; auto-encrypt: %t", c.secure, c.autoEncrypt) + t.Run(name, func(t *testing.T) { + cfg := suite.Config() + ctx := suite.Environment().DefaultContext(t) + + connect.ConnectInjectConnectivityCheck(t, ctx, cfg, c.secure, c.autoEncrypt, true) + + }) + } +} diff --git a/acceptance/tests/connect/connect_helper.go b/acceptance/tests/connect/connect_helper.go new file mode 100644 index 0000000000..876188ea32 --- /dev/null +++ b/acceptance/tests/connect/connect_helper.go @@ -0,0 +1,122 @@ +package connect + +import ( + "context" + "strconv" + "testing" + + "github.com/hashicorp/consul-k8s/acceptance/framework/config" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil/retry" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const staticClientName = "static-client" +const staticServerName = "static-server" + +// ConnectInjectConnectivityCheck is a helper function used by the connect tests and cli smoke tests to test service +// mesh connectivity. +func ConnectInjectConnectivityCheck(t *testing.T, ctx environment.TestContext, cfg *config.TestConfig, secure bool, autoEncrypt bool, cli bool) { + helmValues := map[string]string{ + "connectInject.enabled": "true", + + "global.tls.enabled": strconv.FormatBool(secure), + "global.tls.enableAutoEncrypt": strconv.FormatBool(autoEncrypt), + "global.acls.manageSystemACLs": strconv.FormatBool(secure), + } + + releaseName := helpers.RandomName() + var consulCluster consul.Cluster + if cli { + consulCluster = consul.NewCLICluster(t, helmValues, ctx, cfg, consul.CLIReleaseName) + } else { + consulCluster = consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) + } + + consulCluster.Create(t) + + consulClient := consulCluster.SetupConsulClient(t, secure) + + // Check that the ACL token is deleted. + if secure { + // We need to register the cleanup function before we create the deployments + // because golang will execute them in reverse order i.e. the last registered + // cleanup function will be executed first. + t.Cleanup(func() { + retry.Run(t, func(r *retry.R) { + tokens, _, err := consulClient.ACL().TokenList(nil) + require.NoError(r, err) + for _, token := range tokens { + require.NotContains(r, token.Description, staticServerName) + require.NotContains(r, token.Description, staticClientName) + } + }) + }) + } + + logger.Log(t, "creating static-server and static-client deployments") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if cfg.EnableTransparentProxy { + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + } else { + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + } + + // Check that both static-server and static-client have been injected and now have 2 containers. + for _, labelSelector := range []string{"app=static-server", "app=static-client"} { + podList, err := ctx.KubernetesClient(t).CoreV1().Pods(ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 2) + } + + if secure { + logger.Log(t, "checking that the connection is not successful because there's no intention") + if cfg.EnableTransparentProxy { + k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), "http://static-server") + } else { + k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), "http://localhost:1234") + } + + logger.Log(t, "creating intention") + _, err := consulClient.Connect().IntentionUpsert(&api.Intention{ + SourceName: staticClientName, + DestinationName: staticServerName, + Action: api.IntentionActionAllow, + }, nil) + require.NoError(t, err) + } + + logger.Log(t, "checking that connection is successful") + if cfg.EnableTransparentProxy { + // todo: add an assertion that the traffic is going through the proxy + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://static-server") + } else { + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://localhost:1234") + } + + // Test that kubernetes readiness status is synced to Consul. + // Create the file so that the readiness probe of the static-server pod fails. + logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + + // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry + // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. + // We are expecting a "connection reset by peer" error because in a case of health checks, + // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply + // from server, which is the case when a connection is unsuccessful due to intentions in other tests. + logger.Log(t, "checking that connection is unsuccessful") + if cfg.EnableTransparentProxy { + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server port 80: Connection refused"}, "http://static-server") + } else { + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + } +} diff --git a/charts/consul/test/acceptance/tests/connect/connect_inject_namespaces_test.go b/acceptance/tests/connect/connect_inject_namespaces_test.go similarity index 97% rename from charts/consul/test/acceptance/tests/connect/connect_inject_namespaces_test.go rename to acceptance/tests/connect/connect_inject_namespaces_test.go index 56948b215e..da0c18d22d 100644 --- a/charts/consul/test/acceptance/tests/connect/connect_inject_namespaces_test.go +++ b/acceptance/tests/connect/connect_inject_namespaces_test.go @@ -8,10 +8,10 @@ import ( "testing" terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" diff --git a/charts/consul/test/acceptance/tests/connect/connect_inject_test.go b/acceptance/tests/connect/connect_inject_test.go similarity index 50% rename from charts/consul/test/acceptance/tests/connect/connect_inject_test.go rename to acceptance/tests/connect/connect_inject_test.go index 93981fd2cc..283f5eb0b7 100644 --- a/charts/consul/test/acceptance/tests/connect/connect_inject_test.go +++ b/acceptance/tests/connect/connect_inject_test.go @@ -7,19 +7,15 @@ import ( "strings" "testing" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" - "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -const staticClientName = "static-client" -const staticServerName = "static-server" - // Test that Connect works in a default and a secure installation. func TestConnectInject(t *testing.T) { cases := []struct { @@ -37,97 +33,7 @@ func TestConnectInject(t *testing.T) { cfg := suite.Config() ctx := suite.Environment().DefaultContext(t) - helmValues := map[string]string{ - "connectInject.enabled": "true", - - "global.tls.enabled": strconv.FormatBool(c.secure), - "global.tls.enableAutoEncrypt": strconv.FormatBool(c.autoEncrypt), - "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), - } - - releaseName := helpers.RandomName() - consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) - - consulCluster.Create(t) - - consulClient := consulCluster.SetupConsulClient(t, c.secure) - - // Check that the ACL token is deleted. - if c.secure { - // We need to register the cleanup function before we create the deployments - // because golang will execute them in reverse order i.e. the last registered - // cleanup function will be executed first. - t.Cleanup(func() { - retry.Run(t, func(r *retry.R) { - tokens, _, err := consulClient.ACL().TokenList(nil) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, staticServerName) - require.NotContains(r, token.Description, staticClientName) - } - }) - }) - } - - logger.Log(t, "creating static-server and static-client deployments") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") - } else { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") - } - - // Check that both static-server and static-client have been injected and now have 2 containers. - for _, labelSelector := range []string{"app=static-server", "app=static-client"} { - podList, err := ctx.KubernetesClient(t).CoreV1().Pods(ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ - LabelSelector: labelSelector, - }) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - require.Len(t, podList.Items[0].Spec.Containers, 2) - } - - if c.secure { - logger.Log(t, "checking that the connection is not successful because there's no intention") - if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), "http://static-server") - } else { - k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), "http://localhost:1234") - } - - logger.Log(t, "creating intention") - _, err := consulClient.Connect().IntentionUpsert(&api.Intention{ - SourceName: staticClientName, - DestinationName: staticServerName, - Action: api.IntentionActionAllow, - }, nil) - require.NoError(t, err) - } - - logger.Log(t, "checking that connection is successful") - if cfg.EnableTransparentProxy { - // todo: add an assertion that the traffic is going through the proxy - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://static-server") - } else { - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://localhost:1234") - } - - // Test that kubernetes readiness status is synced to Consul. - // Create the file so that the readiness probe of the static-server pod fails. - logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") - - // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry - // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. - // We are expecting a "connection reset by peer" error because in a case of health checks, - // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply - // from server, which is the case when a connection is unsuccessful due to intentions in other tests. - logger.Log(t, "checking that connection is unsuccessful") - if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server port 80: Connection refused"}, "http://static-server") - } else { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") - } + ConnectInjectConnectivityCheck(t, ctx, cfg, c.secure, c.autoEncrypt, false) }) } diff --git a/charts/consul/test/acceptance/tests/connect/main_test.go b/acceptance/tests/connect/main_test.go similarity index 63% rename from charts/consul/test/acceptance/tests/connect/main_test.go rename to acceptance/tests/connect/main_test.go index f57bf14e07..a2b5925bed 100644 --- a/charts/consul/test/acceptance/tests/connect/main_test.go +++ b/acceptance/tests/connect/main_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testsuite.Suite diff --git a/charts/consul/test/acceptance/tests/consul-dns/consul_dns_test.go b/acceptance/tests/consul-dns/consul_dns_test.go similarity index 92% rename from charts/consul/test/acceptance/tests/consul-dns/consul_dns_test.go rename to acceptance/tests/consul-dns/consul_dns_test.go index 3814bf7672..126b97df81 100644 --- a/charts/consul/test/acceptance/tests/consul-dns/consul_dns_test.go +++ b/acceptance/tests/consul-dns/consul_dns_test.go @@ -6,9 +6,9 @@ import ( "strconv" "testing" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/charts/consul/test/acceptance/tests/consul-dns/main_test.go b/acceptance/tests/consul-dns/main_test.go similarity index 63% rename from charts/consul/test/acceptance/tests/consul-dns/main_test.go rename to acceptance/tests/consul-dns/main_test.go index 2c5096e90f..848f30ad8f 100644 --- a/charts/consul/test/acceptance/tests/consul-dns/main_test.go +++ b/acceptance/tests/consul-dns/main_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testsuite.Suite diff --git a/charts/consul/test/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go similarity index 98% rename from charts/consul/test/acceptance/tests/controller/controller_namespaces_test.go rename to acceptance/tests/controller/controller_namespaces_test.go index 157d7e5fc6..2299a860a7 100644 --- a/charts/consul/test/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -7,10 +7,10 @@ import ( "testing" "time" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" diff --git a/charts/consul/test/acceptance/tests/controller/controller_test.go b/acceptance/tests/controller/controller_test.go similarity index 98% rename from charts/consul/test/acceptance/tests/controller/controller_test.go rename to acceptance/tests/controller/controller_test.go index ba22f3c61c..ffc0b2e68b 100644 --- a/charts/consul/test/acceptance/tests/controller/controller_test.go +++ b/acceptance/tests/controller/controller_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" diff --git a/charts/consul/test/acceptance/tests/controller/main_test.go b/acceptance/tests/controller/main_test.go similarity index 64% rename from charts/consul/test/acceptance/tests/controller/main_test.go rename to acceptance/tests/controller/main_test.go index ebdd540513..115627fb85 100644 --- a/charts/consul/test/acceptance/tests/controller/main_test.go +++ b/acceptance/tests/controller/main_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - testSuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testSuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testSuite.Suite diff --git a/charts/consul/test/acceptance/tests/example/example_test.go b/acceptance/tests/example/example_test.go similarity index 89% rename from charts/consul/test/acceptance/tests/example/example_test.go rename to acceptance/tests/example/example_test.go index 8f23ceab8a..4be7c3db7d 100644 --- a/charts/consul/test/acceptance/tests/example/example_test.go +++ b/acceptance/tests/example/example_test.go @@ -5,9 +5,9 @@ import ( "context" "testing" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/charts/consul/test/acceptance/tests/example/main_test.go b/acceptance/tests/example/main_test.go similarity index 89% rename from charts/consul/test/acceptance/tests/example/main_test.go rename to acceptance/tests/example/main_test.go index 8c6b31da89..323f421d32 100644 --- a/charts/consul/test/acceptance/tests/example/main_test.go +++ b/acceptance/tests/example/main_test.go @@ -4,7 +4,7 @@ package example import ( "testing" - testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testsuite.Suite diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/mesh-gateway/kustomization.yaml b/acceptance/tests/fixtures/bases/mesh-gateway/kustomization.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/mesh-gateway/kustomization.yaml rename to acceptance/tests/fixtures/bases/mesh-gateway/kustomization.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/mesh-gateway/proxydefaults.yaml b/acceptance/tests/fixtures/bases/mesh-gateway/proxydefaults.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/mesh-gateway/proxydefaults.yaml rename to acceptance/tests/fixtures/bases/mesh-gateway/proxydefaults.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-client/anyuid-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-client/anyuid-scc-rolebinding.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-client/anyuid-scc-rolebinding.yaml rename to acceptance/tests/fixtures/bases/static-client/anyuid-scc-rolebinding.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-client/deployment.yaml b/acceptance/tests/fixtures/bases/static-client/deployment.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-client/deployment.yaml rename to acceptance/tests/fixtures/bases/static-client/deployment.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-client/kustomization.yaml b/acceptance/tests/fixtures/bases/static-client/kustomization.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-client/kustomization.yaml rename to acceptance/tests/fixtures/bases/static-client/kustomization.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-client/privileged-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-client/privileged-scc-rolebinding.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-client/privileged-scc-rolebinding.yaml rename to acceptance/tests/fixtures/bases/static-client/privileged-scc-rolebinding.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-client/psp-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-client/psp-rolebinding.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-client/psp-rolebinding.yaml rename to acceptance/tests/fixtures/bases/static-client/psp-rolebinding.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-client/service.yaml b/acceptance/tests/fixtures/bases/static-client/service.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-client/service.yaml rename to acceptance/tests/fixtures/bases/static-client/service.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-client/serviceaccount.yaml b/acceptance/tests/fixtures/bases/static-client/serviceaccount.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-client/serviceaccount.yaml rename to acceptance/tests/fixtures/bases/static-client/serviceaccount.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-metrics-app/deployment.yaml b/acceptance/tests/fixtures/bases/static-metrics-app/deployment.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-metrics-app/deployment.yaml rename to acceptance/tests/fixtures/bases/static-metrics-app/deployment.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-metrics-app/kustomization.yaml b/acceptance/tests/fixtures/bases/static-metrics-app/kustomization.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-metrics-app/kustomization.yaml rename to acceptance/tests/fixtures/bases/static-metrics-app/kustomization.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-metrics-app/service.yaml b/acceptance/tests/fixtures/bases/static-metrics-app/service.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-metrics-app/service.yaml rename to acceptance/tests/fixtures/bases/static-metrics-app/service.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-server/anyuid-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server/anyuid-scc-rolebinding.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-server/anyuid-scc-rolebinding.yaml rename to acceptance/tests/fixtures/bases/static-server/anyuid-scc-rolebinding.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-server/deployment.yaml b/acceptance/tests/fixtures/bases/static-server/deployment.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-server/deployment.yaml rename to acceptance/tests/fixtures/bases/static-server/deployment.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-server/kustomization.yaml b/acceptance/tests/fixtures/bases/static-server/kustomization.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-server/kustomization.yaml rename to acceptance/tests/fixtures/bases/static-server/kustomization.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-server/privileged-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server/privileged-scc-rolebinding.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-server/privileged-scc-rolebinding.yaml rename to acceptance/tests/fixtures/bases/static-server/privileged-scc-rolebinding.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-server/psp-rolebinding.yaml b/acceptance/tests/fixtures/bases/static-server/psp-rolebinding.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-server/psp-rolebinding.yaml rename to acceptance/tests/fixtures/bases/static-server/psp-rolebinding.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-server/service.yaml b/acceptance/tests/fixtures/bases/static-server/service.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-server/service.yaml rename to acceptance/tests/fixtures/bases/static-server/service.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/bases/static-server/serviceaccount.yaml b/acceptance/tests/fixtures/bases/static-server/serviceaccount.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/bases/static-server/serviceaccount.yaml rename to acceptance/tests/fixtures/bases/static-server/serviceaccount.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml rename to acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-inject/patch.yaml b/acceptance/tests/fixtures/cases/static-client-inject/patch.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-client-inject/patch.yaml rename to acceptance/tests/fixtures/cases/static-client-inject/patch.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml rename to acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-multi-dc/patch.yaml b/acceptance/tests/fixtures/cases/static-client-multi-dc/patch.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-client-multi-dc/patch.yaml rename to acceptance/tests/fixtures/cases/static-client-multi-dc/patch.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml rename to acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-namespaces/patch.yaml b/acceptance/tests/fixtures/cases/static-client-namespaces/patch.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-client-namespaces/patch.yaml rename to acceptance/tests/fixtures/cases/static-client-namespaces/patch.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml rename to acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-tproxy/patch.yaml b/acceptance/tests/fixtures/cases/static-client-tproxy/patch.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-client-tproxy/patch.yaml rename to acceptance/tests/fixtures/cases/static-client-tproxy/patch.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml b/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml rename to acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-server-inject/patch.yaml b/acceptance/tests/fixtures/cases/static-server-inject/patch.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-server-inject/patch.yaml rename to acceptance/tests/fixtures/cases/static-server-inject/patch.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/crds/ingressgateway.yaml b/acceptance/tests/fixtures/crds/ingressgateway.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/crds/ingressgateway.yaml rename to acceptance/tests/fixtures/crds/ingressgateway.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/crds/mesh.yaml b/acceptance/tests/fixtures/crds/mesh.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/crds/mesh.yaml rename to acceptance/tests/fixtures/crds/mesh.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/crds/proxydefaults.yaml b/acceptance/tests/fixtures/crds/proxydefaults.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/crds/proxydefaults.yaml rename to acceptance/tests/fixtures/crds/proxydefaults.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/crds/servicedefaults.yaml b/acceptance/tests/fixtures/crds/servicedefaults.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/crds/servicedefaults.yaml rename to acceptance/tests/fixtures/crds/servicedefaults.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/crds/serviceintentions.yaml b/acceptance/tests/fixtures/crds/serviceintentions.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/crds/serviceintentions.yaml rename to acceptance/tests/fixtures/crds/serviceintentions.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/crds/serviceresolver.yaml b/acceptance/tests/fixtures/crds/serviceresolver.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/crds/serviceresolver.yaml rename to acceptance/tests/fixtures/crds/serviceresolver.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/crds/servicerouter.yaml b/acceptance/tests/fixtures/crds/servicerouter.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/crds/servicerouter.yaml rename to acceptance/tests/fixtures/crds/servicerouter.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/crds/servicesplitter.yaml b/acceptance/tests/fixtures/crds/servicesplitter.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/crds/servicesplitter.yaml rename to acceptance/tests/fixtures/crds/servicesplitter.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/crds/terminatinggateway.yaml b/acceptance/tests/fixtures/crds/terminatinggateway.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/crds/terminatinggateway.yaml rename to acceptance/tests/fixtures/crds/terminatinggateway.yaml diff --git a/charts/consul/test/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go b/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go similarity index 96% rename from charts/consul/test/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go rename to acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go index 8a3610a812..baa4e8bddb 100644 --- a/charts/consul/test/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go +++ b/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go @@ -6,10 +6,10 @@ import ( "testing" terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" ) diff --git a/charts/consul/test/acceptance/tests/ingress-gateway/ingress_gateway_test.go b/acceptance/tests/ingress-gateway/ingress_gateway_test.go similarity index 91% rename from charts/consul/test/acceptance/tests/ingress-gateway/ingress_gateway_test.go rename to acceptance/tests/ingress-gateway/ingress_gateway_test.go index e360f0efd3..823291e5da 100644 --- a/charts/consul/test/acceptance/tests/ingress-gateway/ingress_gateway_test.go +++ b/acceptance/tests/ingress-gateway/ingress_gateway_test.go @@ -5,10 +5,10 @@ import ( "strconv" "testing" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" ) diff --git a/charts/consul/test/acceptance/tests/ingress-gateway/main_test.go b/acceptance/tests/ingress-gateway/main_test.go similarity index 64% rename from charts/consul/test/acceptance/tests/ingress-gateway/main_test.go rename to acceptance/tests/ingress-gateway/main_test.go index 2a208fbf0e..bd927f96cb 100644 --- a/charts/consul/test/acceptance/tests/ingress-gateway/main_test.go +++ b/acceptance/tests/ingress-gateway/main_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testsuite.Suite diff --git a/charts/consul/test/acceptance/tests/mesh-gateway/main_test.go b/acceptance/tests/mesh-gateway/main_test.go similarity index 78% rename from charts/consul/test/acceptance/tests/mesh-gateway/main_test.go rename to acceptance/tests/mesh-gateway/main_test.go index d29d17a1d0..fb8935441e 100644 --- a/charts/consul/test/acceptance/tests/mesh-gateway/main_test.go +++ b/acceptance/tests/mesh-gateway/main_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testsuite.Suite diff --git a/charts/consul/test/acceptance/tests/mesh-gateway/mesh_gateway_test.go b/acceptance/tests/mesh-gateway/mesh_gateway_test.go similarity index 96% rename from charts/consul/test/acceptance/tests/mesh-gateway/mesh_gateway_test.go rename to acceptance/tests/mesh-gateway/mesh_gateway_test.go index 521cc1573a..fd72db25d0 100644 --- a/charts/consul/test/acceptance/tests/mesh-gateway/mesh_gateway_test.go +++ b/acceptance/tests/mesh-gateway/mesh_gateway_test.go @@ -6,11 +6,11 @@ import ( "testing" "time" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/environment" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" diff --git a/charts/consul/test/acceptance/tests/metrics/main_test.go b/acceptance/tests/metrics/main_test.go similarity index 63% rename from charts/consul/test/acceptance/tests/metrics/main_test.go rename to acceptance/tests/metrics/main_test.go index b4e970d990..8717c7c4b5 100644 --- a/charts/consul/test/acceptance/tests/metrics/main_test.go +++ b/acceptance/tests/metrics/main_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testsuite.Suite diff --git a/charts/consul/test/acceptance/tests/metrics/metrics_test.go b/acceptance/tests/metrics/metrics_test.go similarity index 93% rename from charts/consul/test/acceptance/tests/metrics/metrics_test.go rename to acceptance/tests/metrics/metrics_test.go index 44bec20f8b..25e480c8d3 100644 --- a/charts/consul/test/acceptance/tests/metrics/metrics_test.go +++ b/acceptance/tests/metrics/metrics_test.go @@ -5,11 +5,11 @@ import ( "fmt" "testing" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/environment" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) diff --git a/charts/consul/test/acceptance/tests/sync/main_test.go b/acceptance/tests/sync/main_test.go similarity index 63% rename from charts/consul/test/acceptance/tests/sync/main_test.go rename to acceptance/tests/sync/main_test.go index 75326d15f7..80c394e561 100644 --- a/charts/consul/test/acceptance/tests/sync/main_test.go +++ b/acceptance/tests/sync/main_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testsuite.Suite diff --git a/charts/consul/test/acceptance/tests/sync/sync_catalog_namespaces_test.go b/acceptance/tests/sync/sync_catalog_namespaces_test.go similarity index 92% rename from charts/consul/test/acceptance/tests/sync/sync_catalog_namespaces_test.go rename to acceptance/tests/sync/sync_catalog_namespaces_test.go index 40e316412b..2352fedc6a 100644 --- a/charts/consul/test/acceptance/tests/sync/sync_catalog_namespaces_test.go +++ b/acceptance/tests/sync/sync_catalog_namespaces_test.go @@ -6,10 +6,10 @@ import ( "time" terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" diff --git a/charts/consul/test/acceptance/tests/sync/sync_catalog_test.go b/acceptance/tests/sync/sync_catalog_test.go similarity index 88% rename from charts/consul/test/acceptance/tests/sync/sync_catalog_test.go rename to acceptance/tests/sync/sync_catalog_test.go index a8d45596df..dcfa361487 100644 --- a/charts/consul/test/acceptance/tests/sync/sync_catalog_test.go +++ b/acceptance/tests/sync/sync_catalog_test.go @@ -5,10 +5,10 @@ import ( "testing" "time" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" ) diff --git a/charts/consul/test/acceptance/tests/terminating-gateway/main_test.go b/acceptance/tests/terminating-gateway/main_test.go similarity index 65% rename from charts/consul/test/acceptance/tests/terminating-gateway/main_test.go rename to acceptance/tests/terminating-gateway/main_test.go index 341d70dc7e..477e125f94 100644 --- a/charts/consul/test/acceptance/tests/terminating-gateway/main_test.go +++ b/acceptance/tests/terminating-gateway/main_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testsuite.Suite diff --git a/charts/consul/test/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go b/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go similarity index 96% rename from charts/consul/test/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go rename to acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go index b6dfff9ce7..061d85e662 100644 --- a/charts/consul/test/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go +++ b/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go @@ -6,10 +6,10 @@ import ( "testing" terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" ) diff --git a/charts/consul/test/acceptance/tests/terminating-gateway/terminating_gateway_test.go b/acceptance/tests/terminating-gateway/terminating_gateway_test.go similarity index 95% rename from charts/consul/test/acceptance/tests/terminating-gateway/terminating_gateway_test.go rename to acceptance/tests/terminating-gateway/terminating_gateway_test.go index c1ec1e748c..19a7c274cd 100644 --- a/charts/consul/test/acceptance/tests/terminating-gateway/terminating_gateway_test.go +++ b/acceptance/tests/terminating-gateway/terminating_gateway_test.go @@ -7,10 +7,10 @@ import ( "testing" terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" ) From c3ec95287d8b7a5b98dbcad0d1a05710bdf60c44 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:05:47 -0700 Subject: [PATCH 057/418] Use go run when running CLI acceptance tests This ensures the version of the CLI being run has the templates from the current directory. Previously the tests would use the consul-k8s binary in your PATH which might have been compiled a long time ago and not have the latest local changes to the charts. --- acceptance/framework/config/config.go | 1 + acceptance/framework/consul/cli_cluster.go | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/acceptance/framework/config/config.go b/acceptance/framework/config/config.go index 500a10001d..a998587291 100644 --- a/acceptance/framework/config/config.go +++ b/acceptance/framework/config/config.go @@ -14,6 +14,7 @@ import ( // Note: this will need to be changed if this file is moved. const ( HelmChartPath = "../../../charts/consul" + CLIPath = "../../../cli" LicenseSecretName = "license" LicenseSecretKey = "key" ) diff --git a/acceptance/framework/consul/cli_cluster.go b/acceptance/framework/consul/cli_cluster.go index 7d07cb4da3..e291805c44 100644 --- a/acceptance/framework/consul/cli_cluster.go +++ b/acceptance/framework/consul/cli_cluster.go @@ -132,7 +132,11 @@ func (h *CLICluster) Create(t *testing.T) { args = append(args, "-timeout", "15m") args = append(args, "-auto-approve") - cmd := exec.Command("consul-k8s", args...) + // Use `go run` so that the CLI is recompiled and therefore uses the local + // charts directory rather than the directory from whenever it was last + // compiled. + cmd := exec.Command("go", append([]string{"run", "."}, args...)...) + cmd.Dir = config.CLIPath out, err := cmd.Output() if err != nil { h.logger.Logf(t, "error running command [ consul-k8s %s ]: %s", args, err.Error()) @@ -159,7 +163,11 @@ func (h *CLICluster) Destroy(t *testing.T) { } args = append(args, "-auto-approve", "-wipe-data") - cmd := exec.Command("consul-k8s", args...) + // Use `go run` so that the CLI is recompiled and therefore uses the local + // charts directory rather than the directory from whenever it was last + // compiled. + cmd := exec.Command("go", append([]string{"run", "."}, args...)...) + cmd.Dir = config.CLIPath out, err := cmd.Output() if err != nil { h.logger.Logf(t, "error running command [ consul-k8s %s ]: %s", args, err.Error()) From 7eda9334064a8ec51913fc109ae34b7cbb6fcfdc Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 7 Oct 2021 16:07:02 -0700 Subject: [PATCH 058/418] Update builds to not compile consul-k8s Since the acceptance tests now use go run --- .circleci/config.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 981c0dc0b9..abc38dc5ff 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -78,11 +78,6 @@ commands: - when: condition: << parameters.failfast >> steps: - - run: - name: Build CLI binary - working_directory: *cli-path - command: | - go build -o << parameters.go-path >>/bin/consul-k8s - run: name: Run acceptance tests working_directory: *acceptance-test-path From eb862436c39344e54a4c4ad3b247246f596dc384 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Thu, 7 Oct 2021 16:07:42 -0700 Subject: [PATCH 059/418] Embed Helm chart templates in CLI (#757) --- charts/embed_chart.go | 16 +++++ charts/go.mod | 3 + cli/cmd/common/fixtures/consul/Chart.yaml | 1 + .../fixtures/consul/templates/_helpers.tpl | 1 + .../common/fixtures/consul/templates/foo.yaml | 1 + cli/cmd/common/fixtures/consul/values.yaml | 1 + cli/cmd/common/utils.go | 61 +++++++++++++++++++ cli/cmd/common/utils_test.go | 39 ++++++++++++ cli/cmd/install/install.go | 10 +-- cli/go.mod | 7 +++ 10 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 charts/embed_chart.go create mode 100644 charts/go.mod create mode 100644 cli/cmd/common/fixtures/consul/Chart.yaml create mode 100644 cli/cmd/common/fixtures/consul/templates/_helpers.tpl create mode 100644 cli/cmd/common/fixtures/consul/templates/foo.yaml create mode 100644 cli/cmd/common/fixtures/consul/values.yaml create mode 100644 cli/cmd/common/utils_test.go diff --git a/charts/embed_chart.go b/charts/embed_chart.go new file mode 100644 index 0000000000..6393508ebb --- /dev/null +++ b/charts/embed_chart.go @@ -0,0 +1,16 @@ +package charts + +import "embed" + +// ConsulHelmChart embeds the Consul Helm Chart files into an exported variable from this package. Changes to the chart +// files referenced below will be reflected in the embedded templates in the CLI at CLI compile time. +// +// This is currently only meant to be used by the consul-k8s CLI within this repository. Importing this package from the +// CLI allows us to embed the templates at compilation time. Since this is in a monorepo, we can directly reference this +// charts module as relative to the CLI module (with a replace directive), which allows us to not need to bump the +// charts module dependency manually or as part of a Makefile. +// +// The embed directive does not include files with underscores unless explicitly listed, which is why _helpers.tpl is +// explicitly embedded. +//go:embed consul/Chart.yaml consul/values.yaml consul/templates consul/templates/_helpers.tpl +var ConsulHelmChart embed.FS diff --git a/charts/go.mod b/charts/go.mod new file mode 100644 index 0000000000..b5195323c1 --- /dev/null +++ b/charts/go.mod @@ -0,0 +1,3 @@ +module github.com/hashicorp/consul-k8s/charts + +go 1.16 diff --git a/cli/cmd/common/fixtures/consul/Chart.yaml b/cli/cmd/common/fixtures/consul/Chart.yaml new file mode 100644 index 0000000000..54c6e609d9 --- /dev/null +++ b/cli/cmd/common/fixtures/consul/Chart.yaml @@ -0,0 +1 @@ +chart \ No newline at end of file diff --git a/cli/cmd/common/fixtures/consul/templates/_helpers.tpl b/cli/cmd/common/fixtures/consul/templates/_helpers.tpl new file mode 100644 index 0000000000..bdf8746bdb --- /dev/null +++ b/cli/cmd/common/fixtures/consul/templates/_helpers.tpl @@ -0,0 +1 @@ +helpers \ No newline at end of file diff --git a/cli/cmd/common/fixtures/consul/templates/foo.yaml b/cli/cmd/common/fixtures/consul/templates/foo.yaml new file mode 100644 index 0000000000..1910281566 --- /dev/null +++ b/cli/cmd/common/fixtures/consul/templates/foo.yaml @@ -0,0 +1 @@ +foo \ No newline at end of file diff --git a/cli/cmd/common/fixtures/consul/values.yaml b/cli/cmd/common/fixtures/consul/values.yaml new file mode 100644 index 0000000000..972ac6208d --- /dev/null +++ b/cli/cmd/common/fixtures/consul/values.yaml @@ -0,0 +1 @@ +values \ No newline at end of file diff --git a/cli/cmd/common/utils.go b/cli/cmd/common/utils.go index 5c044a0e03..b02abfabf9 100644 --- a/cli/cmd/common/utils.go +++ b/cli/cmd/common/utils.go @@ -1,11 +1,14 @@ package common import ( + "embed" "fmt" "os" + "path/filepath" "strings" "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart/loader" helmCLI "helm.sh/helm/v3/pkg/cli" "k8s.io/cli-runtime/pkg/genericclioptions" ) @@ -13,8 +16,66 @@ import ( const ( DefaultReleaseName = "consul" DefaultReleaseNamespace = "consul" + chartFileName = "Chart.yaml" + valuesFileName = "values.yaml" + templatesDirName = "templates" + TopLevelChartDirName = "consul" ) +// ReadChartFiles reads the chart files from the embedded file system, and loads their contents into +// []*loader.BufferedFile. This is a format that the Helm Go SDK functions can read from to create a chart to install +// from. The names of these files are important, as there are case statements in the Helm Go SDK looking for files named +// "Chart.yaml" or "templates/.yaml", which is why even though the embedded file system has them named +// "consul/Chart.yaml" we have to strip the "consul" prefix out, which is done by the call to the helper method readFile. +func ReadChartFiles(chart embed.FS, chartDirName string) ([]*loader.BufferedFile, error) { + var chartFiles []*loader.BufferedFile + + // Load Chart.yaml and values.yaml first. + for _, f := range []string{chartFileName, valuesFileName} { + file, err := readFile(chart, filepath.Join(chartDirName, f), chartDirName) + if err != nil { + return nil, err + } + chartFiles = append(chartFiles, file) + } + + // Now load everything under templates/. + dirs, err := chart.ReadDir(filepath.Join(chartDirName, templatesDirName)) + if err != nil { + return nil, err + } + for _, f := range dirs { + if f.IsDir() { + // We only need to include files in the templates directory. + continue + } + + file, err := readFile(chart, filepath.Join(chartDirName, templatesDirName, f.Name()), chartDirName) + if err != nil { + return nil, err + } + chartFiles = append(chartFiles, file) + } + + return chartFiles, nil +} + +func readFile(chart embed.FS, f string, pathPrefix string) (*loader.BufferedFile, error) { + bytes, err := chart.ReadFile(f) + if err != nil { + return nil, err + } + // Remove the path prefix. + rel, err := filepath.Rel(pathPrefix, f) + if err != nil { + return nil, err + } + return &loader.BufferedFile{ + Name: rel, + Data: bytes, + }, nil +} + // Abort returns true if the raw input string is not equal to "y" or "yes". func Abort(raw string) bool { confirmation := strings.TrimSuffix(raw, "\n") diff --git a/cli/cmd/common/utils_test.go b/cli/cmd/common/utils_test.go new file mode 100644 index 0000000000..fc9bf5292c --- /dev/null +++ b/cli/cmd/common/utils_test.go @@ -0,0 +1,39 @@ +package common + +import ( + "embed" + "testing" + + "github.com/stretchr/testify/require" +) + +//go:embed fixtures/consul/* fixtures/consul/templates/_helpers.tpl +var testChart embed.FS + +func TestReadChartFiles(t *testing.T) { + files, err := ReadChartFiles(testChart, "fixtures/consul") + require.NoError(t, err) + var foundChart, foundValues, foundTemplate, foundHelper bool + for _, f := range files { + if f.Name == "Chart.yaml" { + require.Equal(t, "chart", string(f.Data)) + foundChart = true + } + if f.Name == "values.yaml" { + require.Equal(t, "values", string(f.Data)) + foundValues = true + } + if f.Name == "templates/foo.yaml" { + require.Equal(t, "foo", string(f.Data)) + foundTemplate = true + } + if f.Name == "templates/_helpers.tpl" { + require.Equal(t, "helpers", string(f.Data)) + foundHelper = true + } + } + require.True(t, foundChart) + require.True(t, foundValues) + require.True(t, foundTemplate) + require.True(t, foundHelper) +} diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index 9e1d406ed8..bef831802f 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -8,6 +8,7 @@ import ( "sync" "time" + consulChart "github.com/hashicorp/consul-k8s/charts" "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" @@ -304,19 +305,18 @@ func (c *Command) Run(args []string) int { install.ReleaseName = common.DefaultReleaseName install.Namespace = c.flagNamespace install.CreateNamespace = true - install.ChartPathOptions.RepoURL = helmRepository install.Wait = c.flagWait install.Timeout = c.timeoutDuration - // Locate the chart, install it in some cache locally. - chartPath, err := install.ChartPathOptions.LocateChart("consul", settings) + // Read the embedded chart files into []*loader.BufferedFile. + chartFiles, err := common.ReadChartFiles(consulChart.ConsulHelmChart, common.TopLevelChartDirName) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 } - // Actually load the chart into memory. - chart, err := loader.Load(chartPath) + // Create a *chart.Chart object from the files to run the installation from. + chart, err := loader.LoadFiles(chartFiles) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 diff --git a/cli/go.mod b/cli/go.mod index 38ed649c60..470bc78c42 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -7,6 +7,7 @@ require ( github.com/cenkalti/backoff v2.2.1+incompatible github.com/fatih/color v1.9.0 github.com/golang/protobuf v1.5.2 // indirect + github.com/hashicorp/consul-k8s/charts v0.0.0-00010101000000-000000000000 github.com/hashicorp/go-hclog v0.16.2 github.com/hashicorp/go-multierror v1.1.0 // indirect github.com/kr/text v0.2.0 @@ -27,3 +28,9 @@ require ( rsc.io/letsencrypt v0.0.3 // indirect sigs.k8s.io/yaml v1.2.0 ) + +// This replace directive is to avoid having to manually bump the version of the charts module upon changes to the Helm +// chart. When the CLI compiles, all changes to the local charts directory are picked up automatically. This directive +// works because of the monorepo setup, where the charts module and CLI module are in the same repository. Otherwise, +// this won't work. +replace github.com/hashicorp/consul-k8s/charts => ../charts From 3b16065789c19f9ff4a272c1d3013e651e33c60d Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Fri, 8 Oct 2021 19:02:28 -0700 Subject: [PATCH 060/418] CLI CI: Run unit tests and linter in CI (#770) --- .circleci/config.yml | 38 +++++++++++++++++++++++++ .github/workflows/golangci-lint-cli.yml | 20 +++++++++++++ cli/cmd/common/flag/flag.go | 34 ---------------------- cli/cmd/common/terminal/basic.go | 4 +-- cli/cmd/common/utils.go | 5 +--- cli/cmd/install/install.go | 12 ++++---- cli/cmd/install/install_test.go | 2 -- cli/cmd/install/presets.go | 2 +- cli/cmd/uninstall/uninstall_test.go | 2 -- cli/main.go | 10 ++++--- 10 files changed, 73 insertions(+), 56 deletions(-) create mode 100644 .github/workflows/golangci-lint-cli.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index abc38dc5ff..4558ba49fc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -291,6 +291,40 @@ jobs: working_directory: *control-plane-path command: make ci.dev-docker + unit-cli: + executor: go + steps: + - checkout + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-k8s-cli-modcache-v1-{{ checksum "cli/go.mod" }} + + - run: + name: go mod download + working_directory: *cli-path + command: go mod download + + # Save go module cache if the go.mod file has changed + - save_cache: + key: consul-k8s-cli-modcache-v1-{{ checksum "cli/go.mod" }} + paths: + - "/go/pkg/mod" + + - run: mkdir -p $TEST_RESULTS + + - run: + name: Run tests + working_directory: *cli-path + command: | + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 + + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + go-fmt-and-vet-acceptance: executor: go steps: @@ -885,6 +919,8 @@ workflows: requires: - go-fmt-and-vet-control-plane - lint-control-plane + # Unit test CLI + - unit-cli # Unit tests for go modules in helm and bats tests for templates - unit-acceptance-framework: requires: @@ -926,11 +962,13 @@ workflows: - dev-upload-docker - unit-test-helm-templates - unit-acceptance-framework + - unit-cli - acceptance-tproxy: requires: - dev-upload-docker - unit-test-helm-templates - unit-acceptance-framework + - unit-cli nightly-acceptance-tests: triggers: - schedule: diff --git a/.github/workflows/golangci-lint-cli.yml b/.github/workflows/golangci-lint-cli.yml new file mode 100644 index 0000000000..f4c395b23c --- /dev/null +++ b/.github/workflows/golangci-lint-cli.yml @@ -0,0 +1,20 @@ +name: golangci-lint-acceptance +on: + push: + tags: + - v* + branches: + - main + pull_request: +jobs: + golangci: + name: lint-cli + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: golangci-lint-cli + uses: golangci/golangci-lint-action@v2 + with: + version: v1.41.1 + # Optional: working directory, useful for monorepos + working-directory: cli diff --git a/cli/cmd/common/flag/flag.go b/cli/cmd/common/flag/flag.go index c89869e322..a0ccf2b239 100644 --- a/cli/cmd/common/flag/flag.go +++ b/cli/cmd/common/flag/flag.go @@ -1,11 +1,8 @@ package flag import ( - "os" "regexp" - "strconv" "strings" - "time" "github.com/kr/text" ) @@ -30,37 +27,6 @@ type FlagVisibility interface { Hidden() bool } -// helpers - -func envDefault(key, def string) string { - if v, exist := os.LookupEnv(key); exist { - return v - } - return def -} - -func envBoolDefault(key string, def bool) bool { - if v, exist := os.LookupEnv(key); exist { - b, err := strconv.ParseBool(v) - if err != nil { - panic(err) - } - return b - } - return def -} - -func envDurationDefault(key string, def time.Duration) time.Duration { - if v, exist := os.LookupEnv(key); exist { - d, err := time.ParseDuration(v) - if err != nil { - panic(err) - } - return d - } - return def -} - // wrapAtLengthWithPadding wraps the given text at the maxLineLength, taking // into account any provided left padding. func wrapAtLengthWithPadding(s string, pad int) string { diff --git a/cli/cmd/common/terminal/basic.go b/cli/cmd/common/terminal/basic.go index 99491fabcc..37562d7598 100644 --- a/cli/cmd/common/terminal/basic.go +++ b/cli/cmd/common/terminal/basic.go @@ -133,8 +133,8 @@ func (ui *basicUI) NamedValues(rows []NamedValue, opts ...Option) { } } - tr.Flush() - colorInfo.Fprintln(cfg.Writer, buf.String()) + _ = tr.Flush() + _, _ = colorInfo.Fprintln(cfg.Writer, buf.String()) } // OutputWriters implements UI diff --git a/cli/cmd/common/utils.go b/cli/cmd/common/utils.go index b02abfabf9..a6bafdbc00 100644 --- a/cli/cmd/common/utils.go +++ b/cli/cmd/common/utils.go @@ -79,10 +79,7 @@ func readFile(chart embed.FS, f string, pathPrefix string) (*loader.BufferedFile // Abort returns true if the raw input string is not equal to "y" or "yes". func Abort(raw string) bool { confirmation := strings.TrimSuffix(raw, "\n") - if !(strings.ToLower(confirmation) == "y" || strings.ToLower(confirmation) == "yes") { - return true - } - return false + return !(strings.ToLower(confirmation) == "y" || strings.ToLower(confirmation) == "yes") } // InitActionConfig initializes a Helm Go SDK action configuration. This function currently uses a hack to override the diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index bef831802f..9b3f02e0e0 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -46,8 +46,6 @@ const ( flagNameWait = "wait" defaultWait = true - - helmRepository = "https://helm.releases.hashicorp.com" ) type Command struct { @@ -472,14 +470,14 @@ func (c *Command) validateFlags(args []string) error { return errors.New("should have no non-flag arguments") } if len(c.flagValueFiles) != 0 && c.flagPreset != defaultPreset { - return errors.New(fmt.Sprintf("Cannot set both -%s and -%s", flagNameConfigFile, flagNamePreset)) + return fmt.Errorf("Cannot set both -%s and -%s", flagNameConfigFile, flagNamePreset) } if _, ok := presets[c.flagPreset]; c.flagPreset != defaultPreset && !ok { - return errors.New(fmt.Sprintf("'%s' is not a valid preset", c.flagPreset)) + return fmt.Errorf("'%s' is not a valid preset", c.flagPreset) } if !validLabel(c.flagNamespace) { - return errors.New(fmt.Sprintf("'%s' is an invalid namespace. Namespaces follow the RFC 1123 label convention and must "+ - "consist of a lower case alphanumeric character or '-' and must start/end with an alphanumeric.", c.flagNamespace)) + return fmt.Errorf("'%s' is an invalid namespace. Namespaces follow the RFC 1123 label convention and must "+ + "consist of a lower case alphanumeric character or '-' and must start/end with an alphanumeric", c.flagNamespace) } duration, err := time.ParseDuration(c.flagTimeout) if err != nil { @@ -489,7 +487,7 @@ func (c *Command) validateFlags(args []string) error { if len(c.flagValueFiles) != 0 { for _, filename := range c.flagValueFiles { if _, err := os.Stat(filename); err != nil && os.IsNotExist(err) { - return errors.New(fmt.Sprintf("File '%s' does not exist.", filename)) + return fmt.Errorf("File '%s' does not exist.", filename) } } } diff --git a/cli/cmd/install/install_test.go b/cli/cmd/install/install_test.go index b299b84f5f..0680cc032d 100644 --- a/cli/cmd/install/install_test.go +++ b/cli/cmd/install/install_test.go @@ -176,10 +176,8 @@ func getInitializedCommand(t *testing.T) *Command { Level: hclog.Info, Output: os.Stdout, }) - ctx, _ := context.WithCancel(context.Background()) baseCommand := &common.BaseCommand{ - Ctx: ctx, Log: log, } diff --git a/cli/cmd/install/presets.go b/cli/cmd/install/presets.go index 5aa61874df..4a3d2523ef 100644 --- a/cli/cmd/install/presets.go +++ b/cli/cmd/install/presets.go @@ -46,6 +46,6 @@ global: // convert is a helper function that converts a YAML string to a map. func convert(s string) map[string]interface{} { var m map[string]interface{} - yaml.Unmarshal([]byte(s), &m) + _ = yaml.Unmarshal([]byte(s), &m) return m } diff --git a/cli/cmd/uninstall/uninstall_test.go b/cli/cmd/uninstall/uninstall_test.go index 8473cd6e61..95696b481c 100644 --- a/cli/cmd/uninstall/uninstall_test.go +++ b/cli/cmd/uninstall/uninstall_test.go @@ -182,10 +182,8 @@ func getInitializedCommand(t *testing.T) *Command { Level: hclog.Info, Output: os.Stdout, }) - ctx, _ := context.WithCancel(context.Background()) baseCommand := &common.BaseCommand{ - Ctx: ctx, Log: log, } diff --git a/cli/main.go b/cli/main.go index 0c3705f0df..c979ec625a 100644 --- a/cli/main.go +++ b/cli/main.go @@ -26,15 +26,17 @@ func main() { basecmd, commands := initializeCommands(ctx, log) c.Commands = commands - defer basecmd.Close() + defer func() { + _ = basecmd.Close() + }() - ch := make(chan os.Signal) - signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL) + ch := make(chan os.Signal, 1) + signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) go func() { <-ch // Any cleanups, such as cancelling contexts cancel() - basecmd.Close() + _ = basecmd.Close() os.Exit(1) }() From 4f9852caf354673baff3dbe0318a143ddb16447a Mon Sep 17 00:00:00 2001 From: David Yu Date: Mon, 11 Oct 2021 10:50:14 -0700 Subject: [PATCH 061/418] issue template: revising question to provide more context (#774) * issue template: revising question to provide more context Our question template gets a lot of hits but in most cases the type of issue that is labeled a question is technically related to our issue label. Copying some relevant questions over. --- .github/ISSUE_TEMPLATE/question.md | 82 +++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 686b2c22fb..40e55daeaf 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -9,10 +9,88 @@ Please search the existing issues for relevant questions, and use the reaction f #### Question Please provide as many details as you can, including but not limited to -- Helm command you're running -- consul-k8s-control-plane command you're running +- CLI commands you are issuing (consul-k8s, consul-k8s-control-plane, helm) - Any helm values you've configured - Your current understanding, and what you're trying to figure out More details will help us answer questions more accurately and with less delay :) +### CLI Commands (consul-k8s, consul-k8s-control-plane, helm) + + + +### Helm Configuration + + + +### Logs + + + +### Current understanding and Expected behavior + + + +### Environment details + + + +### Additional Context + + From cacb9243e10632936083fefd33aab016632302fc Mon Sep 17 00:00:00 2001 From: David Yu Date: Mon, 11 Oct 2021 13:40:12 -0700 Subject: [PATCH 062/418] issue template: more details about question and move suggestions to comments (#777) * issue template: more details about question and move suggestions to comment --- .github/ISSUE_TEMPLATE/question.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 40e55daeaf..b2c5614384 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,19 +1,24 @@ --- name: Question -about: If you have a question. +about: You'd like to clarify your understanding about a particular area within Consul K8s. There are situations when an issue or feature request does not really classify the type of help you are requesting from the Consul K8s team. We'd like to help and engage the community through Github! labels: question --- -Please search the existing issues for relevant questions, and use the reaction feature (https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to add upvotes to pre-existing questions. + + #### Question -Please provide as many details as you can, including but not limited to -- CLI commands you are issuing (consul-k8s, consul-k8s-control-plane, helm) -- Any helm values you've configured -- Your current understanding, and what you're trying to figure out + ### CLI Commands (consul-k8s, consul-k8s-control-plane, helm) From 9e17236c2f177797d996eedfbfe5604328addf9c Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 11 Oct 2021 14:51:52 -0600 Subject: [PATCH 063/418] aws-acceptance-test-cleanup: Release elastic IPs and delete VPC dependencies (#767) * Release elastic IPs of NAT gws * Don't look at deleted nat gateways when confirming they are destroyed because they can show up in the describe-nat-gateways output for about an 1hr after being deleted. * Delete VPC dependencies --- .circleci/config.yml | 2 +- hack/aws-acceptance-test-cleanup/main.go | 159 ++++++++++++++++++++--- 2 files changed, 144 insertions(+), 17 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4558ba49fc..b2d4f810a2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -580,7 +580,7 @@ jobs: cleanup-eks-resources: docker: - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.9.0 + - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 steps: - checkout - run: diff --git a/hack/aws-acceptance-test-cleanup/main.go b/hack/aws-acceptance-test-cleanup/main.go index fb998a5fd0..45198b8ea5 100644 --- a/hack/aws-acceptance-test-cleanup/main.go +++ b/hack/aws-acceptance-test-cleanup/main.go @@ -219,12 +219,25 @@ func realMain(ctx context.Context) error { } if err := destroyBackoff(ctx, "NAT gateway", *gateway.NatGatewayId, func() error { + // We only care about Nat gateways whose state is not "deleted." + // Deleted Nat gateways will show in the output for about 1hr + // (https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html#nat-gateway-deleting), + // but we can proceed with deleting other resources once its state is deleted. currNatGateways, err := ec2Client.DescribeNatGatewaysWithContext(ctx, &ec2.DescribeNatGatewaysInput{ Filter: []*ec2.Filter{ { Name: aws.String("vpc-id"), Values: []*string{vpcID}, }, + { + Name: aws.String("state"), + Values: []*string{ + aws.String(ec2.NatGatewayStatePending), + aws.String(ec2.NatGatewayStateFailed), + aws.String(ec2.NatGatewayStateDeleting), + aws.String(ec2.NatGatewayStateAvailable), + }, + }, }, }) if err != nil { @@ -238,6 +251,18 @@ func realMain(ctx context.Context) error { return err } fmt.Printf("NAT gateway: Destroyed [id=%s]\n", *gateway.NatGatewayId) + + // Release Elastic IP associated with the NAT gateway (if any). + for _, address := range gateway.NatGatewayAddresses { + if address.AllocationId != nil { + fmt.Printf("NAT gateway: Releasing Elastic IP... [id=%s]\n", *address.AllocationId) + _, err := ec2Client.ReleaseAddressWithContext(ctx, &ec2.ReleaseAddressInput{AllocationId: address.AllocationId}) + if err != nil { + return err + } + fmt.Printf("NAT gateway: Elastic IP released [id=%s]\n", *address.AllocationId) + } + } } // Delete ELBs (usually left from mesh gateway tests). @@ -276,6 +301,124 @@ func realMain(ctx context.Context) error { fmt.Printf("ELB: Destroyed [id=%s]\n", *elbDescrip.LoadBalancerName) } + // Delete internet gateways. + igws, err := ec2Client.DescribeInternetGatewaysWithContext(ctx, &ec2.DescribeInternetGatewaysInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("attachment.vpc-id"), + Values: []*string{vpcID}, + }, + }, + }) + for _, igw := range igws.InternetGateways { + fmt.Printf("Internet gateway: Detaching from VPC... [id=%s]\n", *igw.InternetGatewayId) + _, err := ec2Client.DetachInternetGatewayWithContext(ctx, &ec2.DetachInternetGatewayInput{ + InternetGatewayId: igw.InternetGatewayId, + VpcId: vpcID, + }) + if err != nil { + return err + } + fmt.Printf("Internet gateway: Detached [id=%s]\n", *igw.InternetGatewayId) + + fmt.Printf("Internet gateway: Destroying... [id=%s]\n", *igw.InternetGatewayId) + _, err = ec2Client.DeleteInternetGatewayWithContext(ctx, &ec2.DeleteInternetGatewayInput{ + InternetGatewayId: igw.InternetGatewayId, + }) + if err != nil { + return err + } + fmt.Printf("Internet gateway: Destroyed [id=%s]\n", *igw.InternetGatewayId) + } + + // Delete subnets. + subnets, err := ec2Client.DescribeSubnetsWithContext(ctx, &ec2.DescribeSubnetsInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("vpc-id"), + Values: []*string{vpcID}, + }, + }, + }) + for _, subnet := range subnets.Subnets { + fmt.Printf("Subnet: Destroying... [id=%s]\n", *subnet.SubnetId) + _, err := ec2Client.DeleteSubnetWithContext(ctx, &ec2.DeleteSubnetInput{ + SubnetId: subnet.SubnetId, + }) + if err != nil { + return err + } + fmt.Printf("Subnet: Destroyed [id=%s]\n", *subnet.SubnetId) + } + + // Delete route tables. + routeTables, err := ec2Client.DescribeRouteTablesWithContext(ctx, &ec2.DescribeRouteTablesInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("vpc-id"), + Values: []*string{vpcID}, + }, + }, + }) + for _, routeTable := range routeTables.RouteTables { + // Find out if this is the main route table. + var mainRouteTable bool + for _, association := range routeTable.Associations { + if association.Main != nil && *association.Main { + mainRouteTable = true + break + } + } + + if mainRouteTable { + fmt.Printf("Route table: Skipping the main route table [id=%s]\n", *routeTable.RouteTableId) + } else { + fmt.Printf("Route table: Destroying... [id=%s]\n", *routeTable.RouteTableId) + _, err := ec2Client.DeleteRouteTableWithContext(ctx, &ec2.DeleteRouteTableInput{ + RouteTableId: routeTable.RouteTableId, + }) + if err != nil { + return err + } + fmt.Printf("Route table: Destroyed [id=%s]\n", *routeTable.RouteTableId) + } + } + + // Delete security groups. + sgs, err := ec2Client.DescribeSecurityGroupsWithContext(ctx, &ec2.DescribeSecurityGroupsInput{ + Filters: []*ec2.Filter{ + { + Name: aws.String("vpc-id"), + Values: []*string{vpcID}, + }, + }, + }) + for _, sg := range sgs.SecurityGroups { + revokeSGInput := &ec2.RevokeSecurityGroupIngressInput{GroupId: sg.GroupId} + revokeSGInput.SetIpPermissions(sg.IpPermissions) + fmt.Printf("Security group: Removing security group rules... [id=%s]\n", *sg.GroupId) + _, err := ec2Client.RevokeSecurityGroupIngressWithContext(ctx, revokeSGInput) + if err != nil { + return err + } + fmt.Printf("Security group: Removed security group rules [id=%s]\n", *sg.GroupId) + } + + for _, sg := range sgs.SecurityGroups { + if sg.GroupName != nil && *sg.GroupName == "default" { + fmt.Printf("Security group: Skipping default security group [id=%s]\n", *sg.GroupId) + continue + } + fmt.Printf("Security group: Destroying... [id=%s]\n", *sg.GroupId) + _, err = ec2Client.DeleteSecurityGroupWithContext(ctx, &ec2.DeleteSecurityGroupInput{ + GroupId: sg.GroupId, + }) + if err != nil { + return err + } + fmt.Printf("Security group: Destroyed [id=%s]\n", *sg.GroupId) + } + // Delete VPC. Sometimes there's a race condition where AWS thinks // the VPC still has dependencies but they've already been deleted so // we may need to retry a couple times. @@ -296,22 +439,6 @@ func realMain(ctx context.Context) error { return errors.New("reached max retry count deleting VPC") } - // Now that the destroy request went through we still need to wait for - // the deletion to complete. - if err := destroyBackoff(ctx, "VPC", *vpcID, func() error { - currVPCs, err := ec2Client.DescribeVpcsWithContext(ctx, &ec2.DescribeVpcsInput{ - VpcIds: []*string{vpcID}, - }) - if err != nil { - return err - } - if len(currVPCs.Vpcs) > 0 { - return errNotDestroyed - } - return nil - }); err != nil { - return err - } fmt.Printf("VPC: Destroyed [id=%s]\n", *vpcID) } From 3dc48eb086bcd48646dea5efc848ba80c0634d2c Mon Sep 17 00:00:00 2001 From: David Yu Date: Mon, 11 Oct 2021 13:55:24 -0700 Subject: [PATCH 064/418] issue template: reducing about to less than 200 characters (#778) --- .github/ISSUE_TEMPLATE/question.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index b2c5614384..e25acb2416 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,6 +1,6 @@ --- name: Question -about: You'd like to clarify your understanding about a particular area within Consul K8s. There are situations when an issue or feature request does not really classify the type of help you are requesting from the Consul K8s team. We'd like to help and engage the community through Github! +about: You'd like to clarify your understanding about a particular area within Consul K8s. We'd like to help and engage the community through Github! labels: question --- From 242a9d25b36b1da9efbc65a957cb75ad764a275b Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Thu, 14 Oct 2021 12:52:54 -0700 Subject: [PATCH 065/418] cli: bump golang.org/x/sys dependency (#781) See https://github.com/golang/go/issues/46763. The CLI would error at runtime after being compiled with go 1.17, unless the x/sys dependency is bumped. --- cli/go.mod | 1 + cli/go.sum | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/go.mod b/cli/go.mod index 470bc78c42..cbb00dadc1 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -19,6 +19,7 @@ require ( github.com/posener/complete v1.1.1 github.com/stretchr/testify v1.7.0 go.starlark.net v0.0.0-20200707032745-474f21a9602d // indirect + golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect google.golang.org/grpc v1.33.1 // indirect helm.sh/helm/v3 v3.6.1 k8s.io/api v0.21.2 diff --git a/cli/go.sum b/cli/go.sum index 7ccb6c8963..bd14d14daa 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -957,8 +957,9 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8= +golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= From a92c0acd8e7d66412a6f4228488aee1f4ec8bbf8 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 14 Oct 2021 16:42:08 -0400 Subject: [PATCH 066/418] Remove warning about repo merge in README (#782) --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index cc5b1985c2..0a83bc50ab 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,5 @@ # Consul + Kubernetes (consul-k8s) -> :warning: **Please note**: This repository has recently been merged with [consul-helm](https://www.consul.io/docs/platform/k8s/index.html). For more information on this change, please see [PR #1051](https://github.com/hashicorp/consul-helm/issues/1051). - ---- - **We're looking for feedback on how folks are using Consul on Kubernetes. Please fill out our brief [survey](https://hashicorp.sjc1.qualtrics.com/jfe/form/SV_4MANbw1BUku7YhL)!** ## Overview From 56cbbb00f0c368775ca4368b60de7c61b2e227d2 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Thu, 14 Oct 2021 15:50:05 -0500 Subject: [PATCH 067/418] update contributing guide (#783) --- .golangci.yml | 2 +- CONTRIBUTING.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.golangci.yml b/.golangci.yml index 3b0fa6c309..d6f534e8be 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,7 +2,7 @@ linters: # enables all defaults + the below, `golangci-lint linters` to see the list of active linters. enable: - gofmt - # TODO: re-enable things as we have master cleaned up vs the defaults + # TODO: re-enable things as we have main cleaned up vs the defaults #- stylecheck #- goconst #- prealloc diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b2628d1e23..7c8281c6c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,6 +52,14 @@ To create a docker image with your local changes: $ make dev-docker ``` +### Running linters locally +[`golangci-lint`](https://golangci-lint.run/) is used in CI to enforce coding and style standards and help catch bugs ahead of time. +The configuration that CI runs is stored in `.golangci.yml` at the top level of the repository. +Please ensure your code passes by running `golangci-lint run` at the top level of the repository and addressing +any issues prior to submitting a PR. + +Version 1.41.1 or higher of [`golangci-lint`](https://github.com/golangci/golangci-lint/releases/tag/v1.41.1) is currently required. + ### Rebasing contributions against main PRs in this repo are merged using the [`rebase`](https://git-scm.com/docs/git-rebase) method. This keeps From 00082a0d69282358b7fd3d46293bde312494c08a Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Fri, 15 Oct 2021 13:22:47 -0400 Subject: [PATCH 068/418] Add command to `consul-k8s-control-plane`: `gossip-encryption-autogenerate` (#772) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add the initial gossip-encryption-autogen command stub * Move synopsis and help to the bottom of the command file * Add logging flags to init * Clean up error and logging messages * Add secret struct and some basic tests for it * Only require secret name to be set * Add test for flag validation * Generate a 32 byte secret value * Add kubernetes client to command * Write the secret to Kubernetes * Re-order flags * Add required namespace flag logic * Test for namespace flag and log flag errors * Delete secret * Secret creation and storage brought into command * Safe exit if secret already exists * Add context to the command * Rename k8s to k8sFlags * Add some nice tests * Inline functions * Move init to the tippy-top * Use Sprintf instead of Errorf...Error() * Move initialization of err closer to useage * Remove client check in secret exists check * Remove unneeded else * Rename SafeFail to EarlyTerminationWithSuccessCode * Add a message on success * Test secret generation from the outside * Add changelog entry * Update CHANGELOG.md Co-authored-by: Kyle Schochenmaier * Grammar fix in changelog * Update comments and synopsis for clarity * Clarify the does secret exists method * Rename doesK8sSecretExist to doesKubernetesSecretExist * Some polish to make it sing 😘 🤌 * Update control-plane/subcommand/gossip-encryption-autogenerate/command.go Co-authored-by: Nitya Dhanushkodi Co-authored-by: Kyle Schochenmaier Co-authored-by: Nitya Dhanushkodi --- CHANGELOG.md | 2 + control-plane/commands.go | 5 + .../gossip-encryption-autogenerate/command.go | 211 ++++++++++++++++++ .../command_test.go | 103 +++++++++ 4 files changed, 321 insertions(+) create mode 100644 control-plane/subcommand/gossip-encryption-autogenerate/command.go create mode 100644 control-plane/subcommand/gossip-encryption-autogenerate/command_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index ec5596255b..b1ed8c762b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## UNRELEASED FEATURES: +* Control Plane + * Add `gossip-encryption-autogenerate` subcommand to generate a random 32 byte Kubernetes secret to be used as a gossip encryption key. [[GH-772](https://github.com/hashicorp/consul-k8s/pull/772)] * Helm Chart * Add automatic generation of gossip encryption with `global.gossipEncryption.autoGenerate=true`. [[GH-738](https://github.com/hashicorp/consul-k8s/pull/738)] * Add support for configuring resources for mesh gateway `service-init` container. [[GH-758](https://github.com/hashicorp/consul-k8s/pull/758)] diff --git a/control-plane/commands.go b/control-plane/commands.go index 465ccbdd50..db43863642 100644 --- a/control-plane/commands.go +++ b/control-plane/commands.go @@ -10,6 +10,7 @@ import ( cmdCreateFederationSecret "github.com/hashicorp/consul-k8s/control-plane/subcommand/create-federation-secret" cmdDeleteCompletedJob "github.com/hashicorp/consul-k8s/control-plane/subcommand/delete-completed-job" cmdGetConsulClientCA "github.com/hashicorp/consul-k8s/control-plane/subcommand/get-consul-client-ca" + cmdGossipEncryptionAutogenerate "github.com/hashicorp/consul-k8s/control-plane/subcommand/gossip-encryption-autogenerate" cmdInjectConnect "github.com/hashicorp/consul-k8s/control-plane/subcommand/inject-connect" cmdPartitionInit "github.com/hashicorp/consul-k8s/control-plane/subcommand/partition-init" cmdServerACLInit "github.com/hashicorp/consul-k8s/control-plane/subcommand/server-acl-init" @@ -88,6 +89,10 @@ func init() { "tls-init": func() (cli.Command, error) { return &cmdTLSInit.Command{UI: ui}, nil }, + + "gossip-encryption-autogenerate": func() (cli.Command, error) { + return &cmdGossipEncryptionAutogenerate.Command{UI: ui}, nil + }, } } diff --git a/control-plane/subcommand/gossip-encryption-autogenerate/command.go b/control-plane/subcommand/gossip-encryption-autogenerate/command.go new file mode 100644 index 0000000000..0383bc8f08 --- /dev/null +++ b/control-plane/subcommand/gossip-encryption-autogenerate/command.go @@ -0,0 +1,211 @@ +package gossipencryptionautogenerate + +import ( + "context" + "crypto/rand" + "encoding/base64" + "flag" + "fmt" + "sync" + + "github.com/hashicorp/consul-k8s/control-plane/subcommand" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" + "github.com/hashicorp/go-hclog" + "github.com/mitchellh/cli" + v1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +type Command struct { + UI cli.Ui + + flags *flag.FlagSet + k8s *flags.K8SFlags + + // These flags determine where the Kubernetes secret will be stored. + flagNamespace string + flagSecretName string + flagSecretKey string + + flagLogLevel string + flagLogJSON bool + + k8sClient kubernetes.Interface + + log hclog.Logger + once sync.Once + ctx context.Context + help string +} + +// init is run once to set up usage documentation for flags. +func (c *Command) init() { + c.flags = flag.NewFlagSet("", flag.ContinueOnError) + + c.flags.StringVar(&c.flagLogLevel, "log-level", "info", + "Log verbosity level. Supported values (in order of detail) are \"trace\", "+ + "\"debug\", \"info\", \"warn\", and \"error\".") + c.flags.BoolVar(&c.flagLogJSON, "log-json", false, "Enable or disable JSON output format for logging.") + c.flags.StringVar(&c.flagNamespace, "namespace", "", "Name of Kubernetes namespace where Consul and consul-k8s components are deployed.") + c.flags.StringVar(&c.flagSecretName, "secret-name", "", "Name of the secret to create.") + c.flags.StringVar(&c.flagSecretKey, "secret-key", "key", "Name of the secret key to create.") + + c.k8s = &flags.K8SFlags{} + flags.Merge(c.flags, c.k8s.Flags()) + + c.help = flags.Usage(help, c.flags) +} + +// Run parses input and creates a gossip secret in Kubernetes if none exists at the given namespace and secret name. +func (c *Command) Run(args []string) int { + c.once.Do(c.init) + + if err := c.flags.Parse(args); err != nil { + c.UI.Error(fmt.Sprintf("Failed to parse args: %v", err)) + return 1 + } + + if err := c.validateFlags(); err != nil { + c.UI.Error(fmt.Sprintf("Failed to validate flags: %v", err)) + return 1 + } + + var err error + c.log, err = common.Logger(c.flagLogLevel, c.flagLogJSON) + if err != nil { + c.UI.Error(err.Error()) + return 1 + } + + if c.ctx == nil { + c.ctx = context.Background() + } + + if c.k8sClient == nil { + if err = c.createKubernetesClient(); err != nil { + c.UI.Error(fmt.Sprintf("Failed to create Kubernetes client: %v", err)) + return 1 + } + } + + if exists, err := c.doesKubernetesSecretExist(); err != nil { + c.UI.Error(fmt.Sprintf("Failed to check if Kubernetes secret exists: %v", err)) + return 1 + } else if exists { + // Safe exit if secret already exists. + c.UI.Info(fmt.Sprintf("A Kubernetes secret with the name `%s` already exists.", c.flagSecretName)) + return 0 + } + + gossipSecret, err := generateGossipSecret() + if err != nil { + c.UI.Error(fmt.Sprintf("Failed to generate gossip secret: %v", err)) + return 1 + } + + // Create the Kubernetes secret object. + kubernetesSecret := v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: c.flagSecretName, + Namespace: c.flagNamespace, + }, + Data: map[string][]byte{ + c.flagSecretKey: []byte(gossipSecret), + }, + } + + // Write the secret to Kubernetes. + _, err = c.k8sClient.CoreV1().Secrets(c.flagNamespace).Create(c.ctx, &kubernetesSecret, metav1.CreateOptions{}) + if err != nil { + c.UI.Error(fmt.Sprintf("Failed to create Kubernetes secret: %v", err)) + return 1 + } + + c.UI.Info(fmt.Sprintf("Successfully created Kubernetes secret `%s` in namespace `%s`.", c.flagSecretName, c.flagNamespace)) + return 0 +} + +// Help returns the command's help text. +func (c *Command) Help() string { + c.once.Do(c.init) + return c.help +} + +// Synopsis returns a one-line synopsis of the command. +func (c *Command) Synopsis() string { + return synopsis +} + +// validateFlags ensures that all required flags are set. +func (c *Command) validateFlags() error { + if c.flagNamespace == "" { + return fmt.Errorf("-namespace must be set") + } + + if c.flagSecretName == "" { + return fmt.Errorf("-secret-name must be set") + } + + return nil +} + +// createKubernetesClient creates a Kubernetes client on the command object. +func (c *Command) createKubernetesClient() error { + config, err := subcommand.K8SConfig(c.k8s.KubeConfig()) + if err != nil { + return fmt.Errorf("failed to create Kubernetes config: %v", err) + } + + c.k8sClient, err = kubernetes.NewForConfig(config) + if err != nil { + return fmt.Errorf("error initializing Kubernetes client: %s", err) + } + + return nil +} + +// doesKubernetesSecretExist checks if a secret with the given name exists in the given namespace. +func (c *Command) doesKubernetesSecretExist() (bool, error) { + _, err := c.k8sClient.CoreV1().Secrets(c.flagNamespace).Get(c.ctx, c.flagSecretName, metav1.GetOptions{}) + + // If the secret does not exist, the error will be a NotFound error. + if err != nil && apierrors.IsNotFound(err) { + return false, nil + } + + // If the error is not a NotFound error, return the error. + if err != nil && !apierrors.IsNotFound(err) { + return false, fmt.Errorf("failed to get Kubernetes secret: %v", err) + } + + // The secret exists. + return true, nil +} + +// generateGossipSecret generates a random 32 byte secret returned as a base64 encoded string. +func generateGossipSecret() (string, error) { + // This code was copied from Consul's Keygen command: + // https://github.com/hashicorp/consul/blob/d652cc86e3d0322102c2b5e9026c6a60f36c17a5/command/keygen/keygen.go + + key := make([]byte, 32) + n, err := rand.Reader.Read(key) + + if err != nil { + return "", fmt.Errorf("error reading random data: %s", err) + } + if n != 32 { + return "", fmt.Errorf("couldn't read enough entropy") + } + + return base64.StdEncoding.EncodeToString(key), nil +} + +const synopsis = "Generate and store a secret for gossip encryption." +const help = ` +Usage: consul-k8s-control-plane gossip-encryption-autogenerate [options] + + Bootstraps the installation with a secret for gossip encryption. +` diff --git a/control-plane/subcommand/gossip-encryption-autogenerate/command_test.go b/control-plane/subcommand/gossip-encryption-autogenerate/command_test.go new file mode 100644 index 0000000000..91d7101232 --- /dev/null +++ b/control-plane/subcommand/gossip-encryption-autogenerate/command_test.go @@ -0,0 +1,103 @@ +package gossipencryptionautogenerate + +import ( + "context" + "encoding/base64" + "fmt" + "testing" + + "github.com/mitchellh/cli" + "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" +) + +func TestRun_FlagValidation(t *testing.T) { + t.Parallel() + cases := []struct { + flags []string + expErr string + }{ + { + flags: []string{}, + expErr: "-namespace must be set", + }, + { + flags: []string{"-namespace", "default"}, + expErr: "-secret-name must be set", + }, + { + flags: []string{"-namespace", "default", "-secret-name", "my-secret", "-log-level", "oak"}, + expErr: "unknown log level", + }, + } + + for _, c := range cases { + t.Run(c.expErr, func(t *testing.T) { + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + } + code := cmd.Run(c.flags) + require.Equal(t, 1, code) + require.Contains(t, ui.ErrorWriter.String(), c.expErr) + }) + } +} + +func TestRun_EarlyTerminationWithSuccessCodeIfSecretExists(t *testing.T) { + namespace := "default" + secretName := "my-secret" + secretKey := "my-secret-key" + + ui := cli.NewMockUi() + k8s := fake.NewSimpleClientset() + + cmd := Command{UI: ui, k8sClient: k8s} + + // Create a secret. + secret := v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretName, + Namespace: namespace, + }, + Data: map[string][]byte{ + secretKey: []byte(secretKey), + }, + } + _, err := k8s.CoreV1().Secrets(namespace).Create(context.Background(), &secret, metav1.CreateOptions{}) + require.NoError(t, err) + + // Run the command. + flags := []string{"-namespace", namespace, "-secret-name", secretName, "-secret-key", secretKey} + code := cmd.Run(flags) + + require.Equal(t, 0, code) + require.Contains(t, ui.OutputWriter.String(), fmt.Sprintf("A Kubernetes secret with the name `%s` already exists.", secretName)) +} + +func TestRun_SecretIsGeneratedIfNoneExists(t *testing.T) { + namespace := "default" + secretName := "my-secret" + secretKey := "my-secret-key" + + ui := cli.NewMockUi() + k8s := fake.NewSimpleClientset() + + cmd := Command{UI: ui, k8sClient: k8s} + + // Run the command. + flags := []string{"-namespace", namespace, "-secret-name", secretName, "-secret-key", secretKey} + code := cmd.Run(flags) + + require.Equal(t, 0, code) + require.Contains(t, ui.OutputWriter.String(), fmt.Sprintf("Successfully created Kubernetes secret `%s` in namespace `%s`.", secretName, namespace)) + + // Check the secret was created. + secret, err := k8s.CoreV1().Secrets(namespace).Get(context.Background(), secretName, metav1.GetOptions{}) + require.NoError(t, err) + gossipSecret, err := base64.StdEncoding.DecodeString(string(secret.Data[secretKey])) + require.NoError(t, err) + require.Len(t, gossipSecret, 32) +} From bd3f2a7ca8eaea8d042c663f8f3cd1fc00f4fb2e Mon Sep 17 00:00:00 2001 From: David Yu Date: Fri, 15 Oct 2021 10:54:07 -0700 Subject: [PATCH 069/418] cli: bump version to 0.35.0 (#784) * cli: bump version to 0.35.0 * removing dev to align with Helm chart version --- cli/version/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/version/version.go b/cli/version/version.go index 6194e7ee7c..fc82a0063a 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.34.1" + Version = "0.35.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 14ce7399cd435379429fe66fb507095ad4d8816f Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 15 Oct 2021 13:18:39 -0700 Subject: [PATCH 070/418] Add ACL support (#766) * Add ACL support - Update server-acl-init job to create tokens that are partition aware when Admin Partitions are enabled. - server-acl-init creates a partition-token that is used by partition-init and server-acl-init in non-default-partitions. - Update partition-init to use provided partition-token when ACLs are enabled. - Update license-policy to be acl:write when created in a partition. * Add connect style acceptance tests to test namespace and connect within partitions * Add changelog and update consul image --- CHANGELOG.md | 99 +++ acceptance/go.mod | 2 +- acceptance/go.sum | 5 +- .../kustomization.yaml | 0 .../cases/static-client-partition/patch.yaml | 0 .../tests/partitions/main_test.go | 2 +- .../tests/partitions/partitions_test.go | 445 +++++++++++ .../consul/templates/partition-init-job.yaml | 13 +- .../consul/templates/server-acl-init-job.yaml | 5 +- .../tests/partitions/partitions_test.go | 146 ---- charts/consul/test/unit/client-daemonset.bats | 4 +- .../consul/test/unit/partition-init-job.bats | 18 +- .../consul/test/unit/server-acl-init-job.bats | 39 + .../subcommand/partition-init/command.go | 4 +- .../subcommand/server-acl-init/command.go | 58 +- .../server-acl-init/command_ent_test.go | 236 +++--- .../subcommand/server-acl-init/rules.go | 201 +++-- .../subcommand/server-acl-init/rules_test.go | 734 ++++++++++++------ 18 files changed, 1432 insertions(+), 579 deletions(-) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-client-partition/kustomization.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/fixtures/cases/static-client-partition/patch.yaml (100%) rename {charts/consul/test/acceptance => acceptance}/tests/partitions/main_test.go (77%) create mode 100644 acceptance/tests/partitions/partitions_test.go delete mode 100644 charts/consul/test/acceptance/tests/partitions/partitions_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index b1ed8c762b..7eedfd277b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,105 @@ IMPROVEMENTS: * Upgrade Docker image Alpine version from 3.13 to 3.14. [[GH-737](https://github.com/hashicorp/consul-k8s/pull/737)] * Helm Chart * Enable adding extra containers to server and client Pods. [[GH-749](https://github.com/hashicorp/consul-k8s/pull/749)] + * ACL support for Admin Partitions. **(Consul Enterprise only)** + **BETA** [[GH-766](https://github.com/hashicorp/consul-k8s/pull/766)] + * This feature now enabled ACL support for Admin Partitions. The server-acl-init job now creates a Partition token. This token +can be used to bootstrap new partitions as well as manage ACLs in the non-default partitions. + * Partition to partition networking is disabled if ACLs are enabled. + +To enabled ACLs on the server cluster use the following config: +```yaml +global: + enableConsulNamespaces: true + tls: + enabled: true + image: hashicorp/consul-enterprise:1.11.0-ent-beta1 + adminPartitions: + enabled: true + acls: + manageSystemACLs: true +server: + exposeGossipAndRPCPorts: true + enterpriseLicense: + secretName: license + secretKey: key + replicas: 1 +connectInject: + enabled: true + transparentProxy: + defaultEnabled: false + consulNamespaces: + mirroringK8S: true +controller: + enabled: true +``` + +Identify the LoadBalancer External IP of the `partition-service` +```bash +kubectl get svc consul-consul-partition-service -o json | jq -r '.status.loadBalancer.ingress[0].ip' +``` + +Migrate the TLS CA credentials from the server cluster to the workload clusters +```bash +kubectl get secret consul-consul-ca-key --context "server-context" -o json | kubectl apply --context "workload-context" -f - +kubectl get secret consul-consul-ca-cert --context "server-context" -o json | kubectl apply --context "workload-context" -f - +``` + +Migrate the Partition token from the server cluster to the workload clusters +```bash +kubectl get secret consul-consul-partitions-acl-token --context "server-context" -o json | kubectl apply --context "workload-context" -f - +``` + +Identify the Kubernetes AuthMethod URL of the workload cluster to use as the `k8sAuthMethodHost`: +```bash +kubectl config view -o "jsonpath={.clusters[?(@.name=='workload-cluster-name')].cluster.server}" +``` + +Configure the workload cluster using the following: + +```yaml +global: + enabled: false + enableConsulNamespaces: true + image: hashicorp/consul-enterprise:1.11.0-ent-beta1 + adminPartitions: + enabled: true + name: "partition-name" + tls: + enabled: true + caCert: + secretName: consul-consul-ca-cert + secretKey: tls.crt + caKey: + secretName: consul-consul-ca-key + secretKey: tls.key + acls: + manageSystemACLs: true + bootstrapToken: + secretName: consul-consul-partitions-acl-token + secretKey: token +server: + enterpriseLicense: + secretName: license + secretKey: key +externalServers: + enabled: true + hosts: [ "loadbalancer IP" ] + tlsServerName: server.dc1.consul + k8sAuthMethodHost: "authmethod-host IP" +client: + enabled: true + exposeGossipPorts: true + join: [ "loadbalancer IP" ] +connectInject: + enabled: true + consulNamespaces: + mirroringK8S: true +controller: + enabled: true +``` +This should create clusters that have Admin Partitions deployed on them with ACLs enabled. + * CLI * Add `version` command. [[GH-741](https://github.com/hashicorp/consul-k8s/pull/741)] diff --git a/acceptance/go.mod b/acceptance/go.mod index 040d14ee87..5e017ccec6 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/gruntwork-io/terratest v0.31.2 - github.com/hashicorp/consul/api v1.9.0 + github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf github.com/hashicorp/consul/sdk v0.8.0 github.com/stretchr/testify v1.5.1 gopkg.in/yaml.v2 v2.2.8 diff --git a/acceptance/go.sum b/acceptance/go.sum index f91e3dc13c..ab20eec364 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -225,8 +225,9 @@ github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arn github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= -github.com/hashicorp/consul/api v1.9.0 h1:T6dKIWcaihG2c21YUi0BMAHbJanVXiYuz+mPgqxY3N4= -github.com/hashicorp/consul/api v1.9.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf h1:fouyN8SkrE4py09XaOru4PCM9zunem39CjOrMJMrKsc= +github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= +github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml rename to acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml diff --git a/charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/patch.yaml b/acceptance/tests/fixtures/cases/static-client-partition/patch.yaml similarity index 100% rename from charts/consul/test/acceptance/tests/fixtures/cases/static-client-partition/patch.yaml rename to acceptance/tests/fixtures/cases/static-client-partition/patch.yaml diff --git a/charts/consul/test/acceptance/tests/partitions/main_test.go b/acceptance/tests/partitions/main_test.go similarity index 77% rename from charts/consul/test/acceptance/tests/partitions/main_test.go rename to acceptance/tests/partitions/main_test.go index c26f293f10..b2758a572c 100644 --- a/charts/consul/test/acceptance/tests/partitions/main_test.go +++ b/acceptance/tests/partitions/main_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - testsuite "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/suite" + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" ) var suite testsuite.Suite diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go new file mode 100644 index 0000000000..0e48ddaa4d --- /dev/null +++ b/acceptance/tests/partitions/partitions_test.go @@ -0,0 +1,445 @@ +package partitions + +import ( + "context" + "fmt" + "strconv" + "testing" + + terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil/retry" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const staticClientName = "static-client" +const staticServerName = "static-server" +const staticServerNamespace = "ns1" +const staticClientNamespace = "ns2" + +// Test that Connect works in a default installation. +// i.e. without ACLs because TLS is required for setting up Admin Partitions. +func TestPartitions(t *testing.T) { + env := suite.Environment() + cfg := suite.Config() + + if !cfg.EnableEnterprise { + t.Skipf("skipping this test because -enable-enterprise is not set") + } + + if !cfg.UseKind { + t.Skipf("skipping this test because Admin Partition tests are only supported in Kind for now") + } + + if cfg.EnableTransparentProxy { + t.Skipf("skipping this test because -enable-transparent-proxy is true") + } + + cases := []struct { + name string + destinationNamespace string + mirrorK8S bool + secure bool + }{ + { + "default namespace", + "default", + false, + false, + }, + { + "default namespace; secure", + "default", + false, + true, + }, + { + "single destination namespace", + staticServerNamespace, + false, + false, + }, + { + "single destination namespace; secure", + staticServerNamespace, + false, + true, + }, + { + "mirror k8s namespaces", + staticServerNamespace, + true, + false, + }, + { + "mirror k8s namespaces; secure", + staticServerNamespace, + true, + true, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + serverClusterContext := env.DefaultContext(t) + clientClusterContext := env.Context(t, environment.SecondaryContextName) + + ctx := context.Background() + + serverHelmValues := map[string]string{ + "global.datacenter": "dc1", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta1", + + "global.adminPartitions.enabled": "true", + "global.enableConsulNamespaces": "true", + "global.tls.enabled": "true", + "global.tls.httpsOnly": strconv.FormatBool(c.secure), + "global.tls.enableAutoEncrypt": strconv.FormatBool(c.secure), + + "server.exposeGossipAndRPCPorts": "true", + + "connectInject.enabled": "true", + // When mirroringK8S is set, this setting is ignored. + "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, + "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.mirrorK8S), + "connectInject.transparentProxy.defaultEnabled": "false", + + "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), + } + + if cfg.UseKind { + serverHelmValues["global.adminPartitions.service.type"] = "NodePort" + serverHelmValues["global.adminPartitions.service.nodePort.https"] = "30000" + } + + releaseName := helpers.RandomName() + + // Install the consul cluster with servers in the default kubernetes context. + serverConsulCluster := consul.NewHelmCluster(t, serverHelmValues, serverClusterContext, cfg, releaseName) + serverConsulCluster.Create(t) + + // Get the TLS CA certificate and key secret from the server cluster and apply it to client cluster. + tlsCert := fmt.Sprintf("%s-consul-ca-cert", releaseName) + tlsKey := fmt.Sprintf("%s-consul-ca-key", releaseName) + + logger.Logf(t, "retrieving ca cert secret %s from the server cluster and applying to the client cluster", tlsCert) + caCertSecret, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, tlsCert, metav1.GetOptions{}) + caCertSecret.ResourceVersion = "" + require.NoError(t, err) + _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, caCertSecret, metav1.CreateOptions{}) + require.NoError(t, err) + + if !c.secure { + // When running in the insecure mode, auto-encrypt is disabled which requires both + // the CA cert and CA key to be available in the clients cluster. + logger.Logf(t, "retrieving ca key secret %s from the server cluster and applying to the client cluster", tlsKey) + caKeySecret, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, tlsKey, metav1.GetOptions{}) + caKeySecret.ResourceVersion = "" + require.NoError(t, err) + _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, caKeySecret, metav1.CreateOptions{}) + require.NoError(t, err) + } + + partitionToken := fmt.Sprintf("%s-consul-partitions-acl-token", releaseName) + if c.secure { + logger.Logf(t, "retrieving partition token secret %s from the server cluster and applying to the client cluster", tlsKey) + token, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionToken, metav1.GetOptions{}) + token.ResourceVersion = "" + require.NoError(t, err) + _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, token, metav1.CreateOptions{}) + require.NoError(t, err) + } + + var partitionSvcIP string + if !cfg.UseKind { + // Get the IP of the partition service to configure the external server address in the values file for the workload cluster. + partitionServiceName := fmt.Sprintf("%s-partition-secret", releaseName) + logger.Logf(t, "retrieving partition service to determine external IP for servers") + partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionServiceName, metav1.GetOptions{}) + require.NoError(t, err) + partitionSvcIP = partitionsSvc.Status.LoadBalancer.Ingress[0].IP + } else { + nodeList, err := serverClusterContext.KubernetesClient(t).CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + // Get the address of the (only) node from the Kind cluster. + partitionSvcIP = nodeList.Items[0].Status.Addresses[0].Address + } + + // The Kubernetes AuthMethod IP for Kind is read from the endpoint for the Kubernetes service. On other clouds, + // this can be identified by reading the cluster config. + kubernetesEndpoint, err := clientClusterContext.KubernetesClient(t).CoreV1().Endpoints("default").Get(ctx, "kubernetes", metav1.GetOptions{}) + require.NoError(t, err) + k8sAuthMethodHost := fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) + + // Create client cluster. + clientHelmValues := map[string]string{ + "global.datacenter": "dc1", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta1", + "global.enabled": "false", + + "global.tls.enabled": "true", + "global.tls.httpsOnly": strconv.FormatBool(c.secure), + "global.tls.enableAutoEncrypt": strconv.FormatBool(c.secure), + + "server.exposeGossipAndRPCPorts": "true", + + "connectInject.enabled": "true", + // When mirroringK8S is set, this setting is ignored. + "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, + "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.mirrorK8S), + "connectInject.transparentProxy.defaultEnabled": "false", + + "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), + + "global.adminPartitions.enabled": "true", + "global.adminPartitions.name": "secondary", + "global.enableConsulNamespaces": "true", + + "global.tls.caCert.secretName": tlsCert, + "global.tls.caCert.secretKey": "tls.crt", + + "externalServers.enabled": "true", + "externalServers.hosts[0]": partitionSvcIP, + "externalServers.tlsServerName": "server.dc1.consul", + "externalServers.k8sAuthMethodHost": k8sAuthMethodHost, + + "client.enabled": "true", + "client.exposeGossipPorts": "true", + "client.join[0]": partitionSvcIP, + } + + if c.secure { + // setup partition token if ACLs enabled. + clientHelmValues["global.acls.bootstrapToken.secretName"] = partitionToken + clientHelmValues["global.acls.bootstrapToken.secretKey"] = "token" + } else { + // provide CA key when auto-encrypt is disabled. + clientHelmValues["global.tls.caKey.secretName"] = tlsKey + clientHelmValues["global.tls.caKey.secretKey"] = "tls.key" + } + + if cfg.UseKind { + clientHelmValues["externalServers.httpsPort"] = "30000" + } + + // Install the consul cluster without servers in the client cluster kubernetes context. + clientConsulCluster := consul.NewHelmCluster(t, clientHelmValues, clientClusterContext, cfg, releaseName) + clientConsulCluster.Create(t) + + agentPodList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(clientClusterContext.KubectlOptions(t).Namespace).List(ctx, metav1.ListOptions{LabelSelector: "app=consul,component=client"}) + require.NoError(t, err) + require.Len(t, agentPodList.Items, 1) + + output, err := k8s.RunKubectlAndGetOutputE(t, clientClusterContext.KubectlOptions(t), "logs", agentPodList.Items[0].Name, "-n", clientClusterContext.KubectlOptions(t).Namespace) + require.NoError(t, err) + require.Contains(t, output, "Partition: 'secondary'") + + serverClusterStaticServerOpts := &terratestk8s.KubectlOptions{ + ContextName: serverClusterContext.KubectlOptions(t).ContextName, + ConfigPath: serverClusterContext.KubectlOptions(t).ConfigPath, + Namespace: staticServerNamespace, + } + serverClusterStaticClientOpts := &terratestk8s.KubectlOptions{ + ContextName: serverClusterContext.KubectlOptions(t).ContextName, + ConfigPath: serverClusterContext.KubectlOptions(t).ConfigPath, + Namespace: staticClientNamespace, + } + clientClusterStaticServerOpts := &terratestk8s.KubectlOptions{ + ContextName: clientClusterContext.KubectlOptions(t).ContextName, + ConfigPath: clientClusterContext.KubectlOptions(t).ConfigPath, + Namespace: staticServerNamespace, + } + clientClusterStaticClientOpts := &terratestk8s.KubectlOptions{ + ContextName: clientClusterContext.KubectlOptions(t).ContextName, + ConfigPath: clientClusterContext.KubectlOptions(t).ConfigPath, + Namespace: staticClientNamespace, + } + + logger.Logf(t, "creating namespaces %s and %s in servers cluster", staticServerNamespace, staticClientNamespace) + k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace) + }) + + k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "create", "ns", staticClientNamespace) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + // Note: this deletion will take longer in cases when the static-client deployment + // hasn't yet fully terminated. + k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "delete", "ns", staticClientNamespace) + }) + + logger.Logf(t, "creating namespaces %s and %s in clients cluster", staticServerNamespace, staticClientNamespace) + k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace) + }) + + k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "create", "ns", staticClientNamespace) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + // Note: this deletion will take longer in cases when the static-client deployment + // hasn't yet fully terminated. + k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "delete", "ns", staticClientNamespace) + }) + + consulClient := serverConsulCluster.SetupConsulClient(t, c.secure) + + serverQueryServerOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: "default"} + clientQueryServerOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: "default"} + + serverQueryClientOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: "secondary"} + clientQueryClientOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: "secondary"} + + if !c.mirrorK8S { + serverQueryServerOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: "default"} + clientQueryServerOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: "default"} + serverQueryClientOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: "secondary"} + clientQueryClientOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: "secondary"} + } + + // Check that the ACL token is deleted. + if c.secure { + // We need to register the cleanup function before we create the deployments + // because golang will execute them in reverse order i.e. the last registered + // cleanup function will be executed first. + t.Cleanup(func() { + if c.secure { + retry.Run(t, func(r *retry.R) { + tokens, _, err := consulClient.ACL().TokenList(serverQueryServerOpts) + require.NoError(r, err) + for _, token := range tokens { + require.NotContains(r, token.Description, staticServerName) + } + + tokens, _, err = consulClient.ACL().TokenList(clientQueryServerOpts) + require.NoError(r, err) + for _, token := range tokens { + require.NotContains(r, token.Description, staticClientName) + } + tokens, _, err = consulClient.ACL().TokenList(serverQueryClientOpts) + require.NoError(r, err) + for _, token := range tokens { + require.NotContains(r, token.Description, staticServerName) + } + + tokens, _, err = consulClient.ACL().TokenList(clientQueryClientOpts) + require.NoError(r, err) + for _, token := range tokens { + require.NotContains(r, token.Description, staticClientName) + } + }) + } + }) + } + + logger.Log(t, "creating static-server and static-client deployments in server cluster") + k8s.DeployKustomize(t, serverClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if c.destinationNamespace == "default" { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + } else { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + } + logger.Log(t, "creating static-server and static-client deployments in client cluster") + k8s.DeployKustomize(t, clientClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if c.destinationNamespace == "default" { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + } else { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + } + // Check that both static-server and static-client have been injected and now have 2 containers in server cluster. + for _, labelSelector := range []string{"app=static-server", "app=static-client"} { + podList, err := serverClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 2) + } + + // Check that both static-server and static-client have been injected and now have 2 containers in client cluster. + for _, labelSelector := range []string{"app=static-server", "app=static-client"} { + podList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 2) + } + + // Make sure that services are registered in the correct namespace. + // If mirroring is enabled, we expect services to be registered in the + // Consul namespace with the same name as their source + // Kubernetes namespace. + // If a single destination namespace is set, we expect all services + // to be registered in that destination Consul namespace. + // Server cluster. + services, _, err := consulClient.Catalog().Service(staticServerName, "", serverQueryServerOpts) + require.NoError(t, err) + require.Len(t, services, 1) + + services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryServerOpts) + require.NoError(t, err) + require.Len(t, services, 1) + + // Client cluster. + services, _, err = consulClient.Catalog().Service(staticServerName, "", serverQueryClientOpts) + require.NoError(t, err) + require.Len(t, services, 1) + + services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryClientOpts) + require.NoError(t, err) + require.Len(t, services, 1) + + if c.secure { + logger.Log(t, "checking that the connection is not successful because there's no intention") + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") + + intention := &api.Intention{ + SourceName: staticClientName, + SourceNS: staticClientNamespace, + DestinationName: staticServerName, + DestinationNS: staticServerNamespace, + Action: api.IntentionActionAllow, + } + + // Set the destination namespace to be the same + // unless mirrorK8S is true. + if !c.mirrorK8S { + intention.SourceNS = c.destinationNamespace + intention.DestinationNS = c.destinationNamespace + } + + logger.Log(t, "creating intention") + _, err := consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: "default"}) + require.NoError(t, err) + _, err = consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: "secondary"}) + require.NoError(t, err) + } + + logger.Log(t, "checking that connection is successful") + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") + + // Test that kubernetes readiness status is synced to Consul. + // Create the file so that the readiness probe of the static-server pod fails. + logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") + k8s.RunKubectl(t, serverClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, clientClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + + // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry + // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. + // We are expecting a "connection reset by peer" error because in a case of health checks, + // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply + // from server, which is the case when a connection is unsuccessful due to intentions in other tests. + logger.Log(t, "checking that connection is unsuccessful") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + }) + } +} diff --git a/charts/consul/templates/partition-init-job.yaml b/charts/consul/templates/partition-init-job.yaml index b9d438c436..10772cd75d 100644 --- a/charts/consul/templates/partition-init-job.yaml +++ b/charts/consul/templates/partition-init-job.yaml @@ -42,19 +42,26 @@ spec: path: tls.crt {{- end }} containers: - - name: post-install-job + - name: partition-init-job image: {{ .Values.global.imageK8S }} env: - name: NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - {{- if .Values.global.tls.enabled }} + {{- if (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey) }} + - name: CONSUL_HTTP_TOKEN + valueFrom: + secretKeyRef: + name: {{ .Values.global.acls.bootstrapToken.secretName }} + key: {{ .Values.global.acls.bootstrapToken.secretKey }} + {{- end }} + {{- if .Values.global.tls.enabled }} volumeMounts: - name: consul-ca-cert mountPath: /consul/tls/ca readOnly: true - {{- end }} + {{- end }} command: - "/bin/sh" - "-ec" diff --git a/charts/consul/templates/server-acl-init-job.yaml b/charts/consul/templates/server-acl-init-job.yaml index 752774064a..07b9ab8e6b 100644 --- a/charts/consul/templates/server-acl-init-job.yaml +++ b/charts/consul/templates/server-acl-init-job.yaml @@ -134,7 +134,10 @@ spec: -sync-consul-node-name={{ .Values.syncCatalog.consulNodeName }} \ {{- end }} {{- end }} - + {{- if .Values.global.adminPartitions.enabled }} + -enable-partitions=true \ + -partition={{ .Values.global.adminPartitions.name }} \ + {{- end }} {{- if (or (and (ne (.Values.dns.enabled | toString) "-") .Values.dns.enabled) (and (eq (.Values.dns.enabled | toString) "-") .Values.global.enabled)) }} -allow-dns=true \ {{- end }} diff --git a/charts/consul/test/acceptance/tests/partitions/partitions_test.go b/charts/consul/test/acceptance/tests/partitions/partitions_test.go deleted file mode 100644 index bb6c1553eb..0000000000 --- a/charts/consul/test/acceptance/tests/partitions/partitions_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package partitions - -import ( - "context" - "fmt" - "testing" - - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/consul" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/environment" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/k8s" - "github.com/hashicorp/consul-k8s/charts/consul/test/acceptance/framework/logger" - "github.com/stretchr/testify/require" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// Test that Connect works in a default installation. -// i.e. without ACLs because TLS is required for setting up Admin Partitions. -func TestPartitions(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - - if !cfg.EnableEnterprise { - t.Skipf("skipping this test because -enable-enterprise is not set") - } - - if !cfg.UseKind { - t.Skipf("skipping this test because Admin Partition tests are only supported in Kind for now") - } - - primaryContext := env.DefaultContext(t) - secondaryContext := env.Context(t, environment.SecondaryContextName) - - ctx := context.Background() - - primaryHelmValues := map[string]string{ - "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-alpha", - - "global.adminPartitions.enabled": "true", - "global.enableConsulNamespaces": "true", - "global.tls.enabled": "true", - - "server.exposeGossipAndRPCPorts": "true", - - "connectInject.enabled": "true", - } - - if cfg.UseKind { - primaryHelmValues["global.adminPartitions.service.type"] = "NodePort" - primaryHelmValues["global.adminPartitions.service.nodePort.https"] = "30000" - } - - releaseName := helpers.RandomName() - - // Install the consul cluster with servers in the default kubernetes context. - primaryConsulCluster := consul.NewHelmCluster(t, primaryHelmValues, primaryContext, cfg, releaseName) - primaryConsulCluster.Create(t) - - // Get the TLS CA certificate and key secret from the primary cluster and apply it to secondary cluster - tlsCert := fmt.Sprintf("%s-consul-ca-cert", releaseName) - logger.Logf(t, "retrieving ca cert secret %s from the primary cluster and applying to the secondary", tlsCert) - caCertSecret, err := primaryContext.KubernetesClient(t).CoreV1().Secrets(primaryContext.KubectlOptions(t).Namespace).Get(ctx, tlsCert, metav1.GetOptions{}) - caCertSecret.ResourceVersion = "" - require.NoError(t, err) - _, err = secondaryContext.KubernetesClient(t).CoreV1().Secrets(secondaryContext.KubectlOptions(t).Namespace).Create(ctx, caCertSecret, metav1.CreateOptions{}) - require.NoError(t, err) - - tlsKey := fmt.Sprintf("%s-consul-ca-key", releaseName) - logger.Logf(t, "retrieving ca key secret %s from the primary cluster and applying to the secondary", tlsKey) - caKeySecret, err := primaryContext.KubernetesClient(t).CoreV1().Secrets(primaryContext.KubectlOptions(t).Namespace).Get(ctx, tlsKey, metav1.GetOptions{}) - caKeySecret.ResourceVersion = "" - require.NoError(t, err) - _, err = secondaryContext.KubernetesClient(t).CoreV1().Secrets(secondaryContext.KubectlOptions(t).Namespace).Create(ctx, caKeySecret, metav1.CreateOptions{}) - require.NoError(t, err) - - var partitionSvcIP string - if !cfg.UseKind { - // Get the IP of the partition service to configure the external server address in the values file for the workload cluster. - partitionServiceName := fmt.Sprintf("%s-partition-secret", releaseName) - logger.Logf(t, "retrieving partition service to determine external IP for servers") - partitionsSvc, err := primaryContext.KubernetesClient(t).CoreV1().Services(primaryContext.KubectlOptions(t).Namespace).Get(ctx, partitionServiceName, metav1.GetOptions{}) - require.NoError(t, err) - partitionSvcIP = partitionsSvc.Status.LoadBalancer.Ingress[0].IP - } else { - nodeList, err := primaryContext.KubernetesClient(t).CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) - require.NoError(t, err) - // Get the address of the (only) node from the Kind cluster. - partitionSvcIP = nodeList.Items[0].Status.Addresses[0].Address - } - - // Create secondary cluster - secondaryHelmValues := map[string]string{ - "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-alpha", - "global.enabled": "false", - - "global.adminPartitions.enabled": "true", - "global.adminPartitions.name": "secondary", - "global.enableConsulNamespaces": "true", - - "global.tls.enabled": "true", - "global.tls.caCert.secretName": tlsCert, - "global.tls.caCert.secretKey": "tls.crt", - "global.tls.caKey.secretName": tlsKey, - "global.tls.caKey.secretKey": "tls.key", - - "externalServers.enabled": "true", - "externalServers.hosts[0]": partitionSvcIP, - "externalServers.tlsServerName": "server.dc1.consul", - - "client.enabled": "true", - "client.exposeGossipPorts": "true", - "client.join[0]": partitionSvcIP, - - "connectInject.enabled": "true", - } - - if cfg.UseKind { - secondaryHelmValues["externalServers.httpsPort"] = "30000" - } - - // Install the consul cluster without servers in the secondary kubernetes context. - secondaryConsulCluster := consul.NewHelmCluster(t, secondaryHelmValues, secondaryContext, cfg, releaseName) - secondaryConsulCluster.Create(t) - - agentPodList, err := secondaryContext.KubernetesClient(t).CoreV1().Pods(secondaryContext.KubectlOptions(t).Namespace).List(ctx, metav1.ListOptions{LabelSelector: "app=consul,component=client"}) - require.NoError(t, err) - require.Len(t, agentPodList.Items, 1) - - output, err := k8s.RunKubectlAndGetOutputE(t, secondaryContext.KubectlOptions(t), "logs", agentPodList.Items[0].Name, "-n", secondaryContext.KubectlOptions(t).Namespace) - require.NoError(t, err) - require.Contains(t, output, "Partition: 'secondary'") - - // TODO: These can be enabled once mesh gateways are used for communication between services. Currently we cant setup a flat pod network on Kind. - // Check that we can connect services over the mesh gateways - - //logger.Log(t, "creating static-server in workload cluster") - //k8s.DeployKustomize(t, secondaryContext.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - - //logger.Log(t, "creating static-client in server cluster") - //k8s.DeployKustomize(t, primaryContext.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partition") - - //logger.Log(t, "checking that connection is successful") - //k8s.CheckStaticServerConnectionSuccessful(t, primaryContext.KubectlOptions(t), "http://localhost:1234") -} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index e0560c8c60..64a9d0e4c0 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1407,7 +1407,7 @@ rollingUpdate: #-------------------------------------------------------------------- # partitions -@test "client/DaemonSet: -partitions can be set by global.adminPartition.enabled" { +@test "client/DaemonSet: -partitions can be set by global.adminPartitions.enabled" { cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ @@ -1417,7 +1417,7 @@ rollingUpdate: [ "${actual}" = "true" ] } -@test "client/DaemonSet: -partitions can be overridden by global.adminPartition.name" { +@test "client/DaemonSet: -partitions can be overridden by global.adminPartitions.name" { cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ diff --git a/charts/consul/test/unit/partition-init-job.bats b/charts/consul/test/unit/partition-init-job.bats index ac6d5ccd27..addf34266e 100644 --- a/charts/consul/test/unit/partition-init-job.bats +++ b/charts/consul/test/unit/partition-init-job.bats @@ -93,4 +93,20 @@ load _helpers # check that the volume uses the provided secret key actual=$(echo $ca_cert_volume | jq -r '.secret.items[0].key' | tee /dev/stderr) [ "${actual}" = "key" ] -} \ No newline at end of file +} + +#-------------------------------------------------------------------- +# global.acls.bootstrapToken + +@test "partitionInit/Job: HTTP_TOKEN is set when global.acls.bootstrapToken is provided" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.enabled=false' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.acls.bootstrapToken.secretName=partition-token' \ + --set 'global.acls.bootstrapToken.secretKey=token' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[].name] | any(contains("CONSUL_HTTP_TOKEN"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/test/unit/server-acl-init-job.bats b/charts/consul/test/unit/server-acl-init-job.bats index 4fd6867d17..a0ae9a34c5 100644 --- a/charts/consul/test/unit/server-acl-init-job.bats +++ b/charts/consul/test/unit/server-acl-init-job.bats @@ -995,6 +995,45 @@ load _helpers [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# admin partitions + +@test "serverACLInit/Job: admin partitions disabled by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) + + local actual=$(echo $object | + yq 'any(contains("enable-partitions"))' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(echo $object | + yq 'any(contains("partition"))' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "serverACLInit/Job: admin partitions enabled when admin partitions are enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) + + local actual=$(echo $object | + yq 'any(contains("enable-partitions"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq 'any(contains("partition"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + #-------------------------------------------------------------------- # global.acls.createReplicationToken diff --git a/control-plane/subcommand/partition-init/command.go b/control-plane/subcommand/partition-init/command.go index bdbb4df21d..4b75f9634f 100644 --- a/control-plane/subcommand/partition-init/command.go +++ b/control-plane/subcommand/partition-init/command.go @@ -23,6 +23,7 @@ type Command struct { flags *flag.FlagSet k8s *k8sflags.K8SFlags + http *flags.HTTPFlags flagPartitionName string @@ -65,7 +66,6 @@ func (c *Command) init() { "The server name to set as the SNI header when sending HTTPS requests to Consul.") c.flags.BoolVar(&c.flagUseHTTPS, "use-https", false, "Toggle for using HTTPS for all API calls to Consul.") - c.flags.DurationVar(&c.flagTimeout, "timeout", 10*time.Minute, "How long we'll try to bootstrap Partitions for before timing out, e.g. 1ms, 2s, 3m") c.flags.StringVar(&c.flagLogLevel, "log-level", "info", @@ -75,7 +75,9 @@ func (c *Command) init() { "Enable or disable JSON output format for logging.") c.k8s = &k8sflags.K8SFlags{} + c.http = &flags.HTTPFlags{} flags.Merge(c.flags, c.k8s.Flags()) + flags.Merge(c.flags, c.http.Flags()) c.help = flags.Usage(help, c.flags) // Default retry to 1s. This is exposed for setting in tests. diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index b69b66edbb..7a9f2b40e2 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -56,18 +56,22 @@ type Command struct { flagIngressGatewayNames []string flagTerminatingGatewayNames []string - // Flags to configure Consul connection + // Flags to configure Consul connection. flagServerAddresses []string flagServerPort uint flagConsulCACert string flagConsulTLSServerName string flagUseHTTPS bool - // Flags for ACL replication + // Flags for ACL replication. flagCreateACLReplicationToken bool flagACLReplicationTokenFile string - // Flags to support namespaces + // Flags to support partitions. + flagEnablePartitions bool // true if Admin Partitions are enabled + flagPartitionName string // name of the Admin Partition + + // Flags to support namespaces. flagEnableNamespaces bool // Use namespacing on all components flagConsulSyncDestinationNamespace string // Consul namespace to register all catalog sync services into if not mirroring flagEnableSyncK8SNSMirroring bool // Enables mirroring of k8s namespaces into Consul for catalog sync @@ -76,7 +80,7 @@ type Command struct { flagEnableInjectK8SNSMirroring bool // Enables mirroring of k8s namespaces into Consul for Connect inject flagInjectK8SNSMirroringPrefix string // Prefix added to Consul namespaces created when mirroring injected services - // Flag to support a custom bootstrap token + // Flag to support a custom bootstrap token. flagBootstrapTokenFile string flagLogLevel string @@ -169,6 +173,11 @@ func (c *Command) init() { c.flags.BoolVar(&c.flagUseHTTPS, "use-https", false, "Toggle for using HTTPS for all API calls to Consul.") + c.flags.BoolVar(&c.flagEnablePartitions, "enable-partitions", false, + "[Enterprise Only] Enables Admin Partitions [Enterprise only feature]") + c.flags.StringVar(&c.flagPartitionName, "partition", "", + "[Enterprise Only] Name of the Admin Partition") + c.flags.BoolVar(&c.flagEnableNamespaces, "enable-namespaces", false, "[Enterprise Only] Enables namespaces, in either a single Consul namespace or mirrored [Enterprise only feature]") c.flags.StringVar(&c.flagConsulSyncDestinationNamespace, "consul-sync-destination-namespace", consulDefaultNamespace, @@ -349,7 +358,7 @@ func (c *Command) Run(args []string) int { // For all of the next operations we'll need a Consul client. serverAddr := fmt.Sprintf("%s:%d", serverAddresses[0], c.flagServerPort) - consulClient, err := consul.NewClient(&api.Config{ + clientConfig := &api.Config{ Address: serverAddr, Scheme: scheme, Token: bootstrapToken, @@ -357,7 +366,12 @@ func (c *Command) Run(args []string) int { Address: c.flagConsulTLSServerName, CAFile: c.flagConsulCACert, }, - }) + } + if c.flagEnablePartitions { + clientConfig.Partition = c.flagPartitionName + } + + consulClient, err := consul.NewClient(clientConfig) if err != nil { c.log.Error(fmt.Sprintf("Error creating Consul client for addr %q: %s", serverAddr, err)) return 1 @@ -382,6 +396,15 @@ func (c *Command) Run(args []string) int { } } + if c.flagEnablePartitions && c.flagPartitionName == consulDefaultPartition && isPrimary { + // Partition token must be local because only the Primary datacenter can have Admin Partitions. + err := c.createLocalACL("partitions", partitionRules, consulDC, isPrimary, consulClient) + if err != nil { + c.log.Error(err.Error()) + return 1 + } + } + // If namespaces are enabled, to allow cross-Consul-namespace permissions // for services from k8s, the Consul `default` namespace needs a policy // allowing service discovery in all namespaces. Each namespace that is @@ -389,12 +412,17 @@ func (c *Command) Run(args []string) int { // connect inject) needs to reference this policy on namespace creation // to finish the cross namespace permission setup. if c.flagEnableNamespaces { + crossNamespaceRule, err := c.crossNamespaceRule() + if err != nil { + c.log.Error("Error templating cross namespace rules", "err", err) + return 1 + } policyTmpl := api.ACLPolicy{ Name: "cross-namespace-policy", Description: "Policy to allow permissions to cross Consul namespaces for k8s services", - Rules: crossNamespaceRules, + Rules: crossNamespaceRule, } - err := c.untilSucceeds(fmt.Sprintf("creating %s policy", policyTmpl.Name), + err = c.untilSucceeds(fmt.Sprintf("creating %s policy", policyTmpl.Name), func() error { return c.createOrUpdateACLPolicy(policyTmpl, consulClient) }) @@ -497,7 +525,12 @@ func (c *Command) Run(args []string) int { } if c.flagCreateEntLicenseToken { - err := c.createLocalACL("enterprise-license", entLicenseRules, consulDC, isPrimary, consulClient) + var err error + if c.flagEnablePartitions { + err = c.createLocalACL("enterprise-license", entPartitionLicenseRules, consulDC, isPrimary, consulClient) + } else { + err = c.createLocalACL("enterprise-license", entLicenseRules, consulDC, isPrimary, consulClient) + } if err != nil { c.log.Error(err.Error()) return 1 @@ -827,10 +860,17 @@ func (c *Command) validateFlags() error { ) } + if c.flagEnablePartitions && c.flagPartitionName == "" { + return errors.New("-partition must be set if -enable-partitions is true") + } + if !c.flagEnablePartitions && c.flagPartitionName != "" { + return fmt.Errorf("-enable-partitions must be 'true' if setting -partition to %s", c.flagPartitionName) + } return nil } const consulDefaultNamespace = "default" +const consulDefaultPartition = "default" const synopsis = "Initialize ACLs on Consul servers and other components." const help = ` Usage: consul-k8s-control-plane server-acl-init [options] diff --git a/control-plane/subcommand/server-acl-init/command_ent_test.go b/control-plane/subcommand/server-acl-init/command_ent_test.go index 57270644b6..26842e8d6b 100644 --- a/control-plane/subcommand/server-acl-init/command_ent_test.go +++ b/control-plane/subcommand/server-acl-init/command_ent_test.go @@ -19,7 +19,6 @@ import ( // and there's a single consul destination namespace. func TestRun_ConnectInject_SingleDestinationNamespace(t *testing.T) { t.Parallel() - consulDestNamespaces := []string{"default", "destination"} for _, consulDestNamespace := range consulDestNamespaces { t.Run(consulDestNamespace, func(tt *testing.T) { @@ -40,6 +39,8 @@ func TestRun_ConnectInject_SingleDestinationNamespace(t *testing.T) { "-resource-prefix=" + resourcePrefix, "-k8s-namespace=" + ns, "-create-inject-token", + "-enable-partitions", + "-partition=default", "-enable-namespaces", "-consul-inject-destination-namespace", consulDestNamespace, "-acl-binding-rule-selector=serviceaccount.name!=default", @@ -160,6 +161,8 @@ func TestRun_ConnectInject_NamespaceMirroring(t *testing.T) { "-resource-prefix=" + resourcePrefix, "-k8s-namespace=" + ns, "-create-inject-token", + "-enable-partitions", + "-partition=default", "-enable-namespaces", "-enable-inject-k8s-namespace-mirroring", "-inject-k8s-namespace-mirroring-prefix", c.MirroringPrefix, @@ -203,7 +206,7 @@ func TestRun_ConnectInject_NamespaceMirroring(t *testing.T) { } } -// Test that ACL policies get updated if namespaces config changes. +// Test that ACL policies get updated if namespaces/partition config changes. func TestRun_ACLPolicyUpdates(t *testing.T) { t.Parallel() @@ -234,9 +237,11 @@ func TestRun_ACLPolicyUpdates(t *testing.T) { "-terminating-gateway-name=anothergw", "-create-controller-token", } - // Our second run, we're going to update from namespaces disabled to - // namespaces enabled with a single destination ns. + // Our second run, we're going to update from partitions and namespaces disabled to + // namespaces enabled with a single destination ns and partitions enabled. secondRunArgs := append(firstRunArgs, + "-enable-partitions", + "-partition=default", "-enable-namespaces", "-consul-sync-destination-namespace=sync", "-consul-inject-destination-namespace=dest") @@ -322,6 +327,7 @@ func TestRun_ACLPolicyUpdates(t *testing.T) { "gw-terminating-gateway-token", "anothergw-terminating-gateway-token", "controller-token", + "partitions-token", } policies, _, err = consul.ACL().PolicyList(nil) require.NoError(err) @@ -348,10 +354,13 @@ func TestRun_ACLPolicyUpdates(t *testing.T) { case "connect-inject-token": // The connect inject token doesn't have namespace config, // but does change to operator:write from an empty string. - require.Contains(actRules, "operator = \"write\"") + require.Contains(actRules, "policy = \"write\"") case "client-snapshot-agent-token", "enterprise-license-token": // The snapshot agent and enterprise license tokens shouldn't change. require.NotContains(actRules, "namespace") + require.Contains(actRules, "acl = \"write\"") + case "partitions-token": + require.Contains(actRules, "operator = \"write\"") default: // Assert that the policies have the word namespace in them. This // tests that they were updated. The actual contents are tested @@ -528,6 +537,8 @@ func TestRun_ConnectInject_Updates(t *testing.T) { "-server-port=" + strings.Split(testAgent.HTTPAddr, ":")[1], "-resource-prefix=" + resourcePrefix, "-k8s-namespace=" + ns, + "-enable-partitions", + "-partition=default", "-create-inject-token", } @@ -693,6 +704,13 @@ func TestRun_TokensWithNamespacesEnabled(t *testing.T) { SecretNames: []string{resourcePrefix + "-controller-acl-token"}, LocalToken: false, }, + "partitions token": { + TokenFlags: []string{"-enable-partitions", "-partition=default"}, + PolicyNames: []string{"partitions-token"}, + PolicyDCs: []string{"dc1"}, + SecretNames: []string{resourcePrefix + "-partitions-acl-token"}, + LocalToken: true, + }, } for testName, c := range cases { t.Run(testName, func(t *testing.T) { @@ -713,6 +731,8 @@ func TestRun_TokensWithNamespacesEnabled(t *testing.T) { "-server-port", strings.Split(testSvr.HTTPAddr, ":")[1], "-resource-prefix=" + resourcePrefix, "-k8s-namespace=" + ns, + "-enable-partitions", + "-partition=default", "-enable-namespaces", }, c.TokenFlags...) @@ -779,37 +799,43 @@ func TestRun_GatewayNamespaceParsing(t *testing.T) { "gateway-ingress-gateway-token", "another-gateway-ingress-gateway-token"}, ExpectedPolicies: []string{` -namespace "default" { - service "ingress" { - policy = "write" - } - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" +partition "default" { + namespace "default" { + service "ingress" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } } }`, ` -namespace "default" { - service "gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" +partition "default" { + namespace "default" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } } }`, ` -namespace "default" { - service "another-gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" +partition "default" { + namespace "default" { + service "another-gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } } }`}, }, @@ -822,37 +848,43 @@ namespace "default" { "gateway-ingress-gateway-token", "another-gateway-ingress-gateway-token"}, ExpectedPolicies: []string{` -namespace "default" { - service "ingress" { - policy = "write" - } - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" +partition "default" { + namespace "default" { + service "ingress" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } } }`, ` -namespace "namespace1" { - service "gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" +partition "default" { + namespace "namespace1" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } } }`, ` -namespace "namespace2" { - service "another-gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" +partition "default" { + namespace "namespace2" { + service "another-gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } } }`}, }, @@ -865,28 +897,34 @@ namespace "namespace2" { "gateway-terminating-gateway-token", "another-gateway-terminating-gateway-token"}, ExpectedPolicies: []string{` -namespace "default" { - service "terminating" { - policy = "write" - } - node_prefix "" { - policy = "read" +partition "default" { + namespace "default" { + service "terminating" { + policy = "write" + } + node_prefix "" { + policy = "read" + } } }`, ` -namespace "default" { - service "gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" +partition "default" { + namespace "default" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } } }`, ` -namespace "default" { - service "another-gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" +partition "default" { + namespace "default" { + service "another-gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } } }`}, }, @@ -899,28 +937,34 @@ namespace "default" { "gateway-terminating-gateway-token", "another-gateway-terminating-gateway-token"}, ExpectedPolicies: []string{` -namespace "default" { - service "terminating" { - policy = "write" - } - node_prefix "" { - policy = "read" +partition "default" { + namespace "default" { + service "terminating" { + policy = "write" + } + node_prefix "" { + policy = "read" + } } }`, ` -namespace "namespace1" { - service "gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" +partition "default" { + namespace "namespace1" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } } }`, ` -namespace "namespace2" { - service "another-gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" +partition "default" { + namespace "namespace2" { + service "another-gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } } }`}, }, @@ -944,6 +988,8 @@ namespace "namespace2" { "-server-port", strings.Split(testSvr.HTTPAddr, ":")[1], "-resource-prefix=" + resourcePrefix, "-enable-namespaces=true", + "-enable-partitions", + "-partition=default", }, c.TokenFlags...) responseCode := cmd.Run(cmdArgs) diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index 1b8a64b704..ec1a474a6f 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -7,6 +7,8 @@ import ( ) type rulesData struct { + EnablePartitions bool + PartitionName string EnableNamespaces bool SyncConsulDestNS string SyncEnableNSMirroring bool @@ -35,28 +37,55 @@ service "consul-snapshot" { }` const entLicenseRules = `operator = "write"` +const entPartitionLicenseRules = `acl = "write"` -const crossNamespaceRules = `namespace_prefix "" { - service_prefix "" { - policy = "read" +const partitionRules = `operator = "write" +agent_prefix "" { + policy = "read" +} +partition_prefix "" { + namespace_prefix "" { + acl = "write" } - node_prefix "" { - policy = "read" +}` + +func (c *Command) crossNamespaceRule() (string, error) { + crossNamespaceRulesTpl := `{{- if .EnablePartitions }} +partition "{{ .PartitionName }}" { +{{- end }} + namespace_prefix "" { + service_prefix "" { + policy = "read" + } + node_prefix "" { + policy = "read" + } } -} ` +{{- if .EnablePartitions }} +} +{{- end }}` + + return c.renderRules(crossNamespaceRulesTpl) +} func (c *Command) agentRules() (string, error) { agentRulesTpl := ` +{{- if .EnablePartitions }} +partition "{{ .PartitionName }}" { +{{- end }} node_prefix "" { policy = "write" } {{- if .EnableNamespaces }} -namespace_prefix "" { + namespace_prefix "" { {{- end }} - service_prefix "" { - policy = "read" - } + service_prefix "" { + policy = "read" + } {{- if .EnableNamespaces }} + } +{{- end }} +{{- if .EnablePartitions }} } {{- end }} ` @@ -80,16 +109,22 @@ func (c *Command) anonymousTokenRules() (string, error) { // ACL token. Thus the anonymous policy must // allow reading all services. anonTokenRulesTpl := ` +{{- if .EnablePartitions }} +partition_prefix "" { +{{- end }} {{- if .EnableNamespaces }} -namespace_prefix "" { + namespace_prefix "" { {{- end }} - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" - } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } {{- if .EnableNamespaces }} + } +{{- end }} +{{- if .EnablePartitions }} } {{- end }} ` @@ -133,19 +168,25 @@ namespace_prefix "" { func (c *Command) ingressGatewayRules(name, namespace string) (string, error) { ingressGatewayRulesTpl := ` +{{- if .EnablePartitions }} +partition "{{ .PartitionName }}" { +{{- end }} {{- if .EnableNamespaces }} -namespace "{{ .GatewayNamespace }}" { + namespace "{{ .GatewayNamespace }}" { {{- end }} - service "{{ .GatewayName }}" { - policy = "write" - } - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" - } + service "{{ .GatewayName }}" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } {{- if .EnableNamespaces }} + } +{{- end }} +{{- if .EnablePartitions }} } {{- end }} ` @@ -159,16 +200,22 @@ namespace "{{ .GatewayNamespace }}" { // of the initial implementation func (c *Command) terminatingGatewayRules(name, namespace string) (string, error) { terminatingGatewayRulesTpl := ` +{{- if .EnablePartitions }} +partition "{{ .PartitionName }}" { +{{- end }} {{- if .EnableNamespaces }} -namespace "{{ .GatewayNamespace }}" { + namespace "{{ .GatewayNamespace }}" { {{- end }} - service "{{ .GatewayName }}" { - policy = "write" - } - node_prefix "" { - policy = "read" - } + service "{{ .GatewayName }}" { + policy = "write" + } + node_prefix "" { + policy = "read" + } {{- if .EnableNamespaces }} + } +{{- end }} +{{- if .EnablePartitions }} } {{- end }} ` @@ -207,22 +254,33 @@ func (c *Command) injectRules() (string, error) { // The Connect injector needs permissions to create namespaces when namespaces are enabled. // It must also create/update service health checks via the endpoints controller. // When ACLs are enabled, the endpoints controller needs "acl:write" permissions - // to delete ACL tokens created via "consul login". + // to delete ACL tokens created via "consul login". policy = "write" is required when + // creating namespaces within a partition. injectRulesTpl := ` +{{- if .EnablePartitions }} +partition "{{ .PartitionName }}" { +{{- else }} {{- if .EnableNamespaces }} -operator = "write" + operator = "write" {{- end }} -node_prefix "" { - policy = "write" -} -{{- if .EnableNamespaces }} -namespace_prefix "" { {{- end }} - acl = "write" - service_prefix "" { + node_prefix "" { policy = "write" } {{- if .EnableNamespaces }} + namespace_prefix "" { +{{- end }} +{{- if .EnablePartitions }} + policy = "write" +{{- end }} + acl = "write" + service_prefix "" { + policy = "write" + } +{{- if .EnableNamespaces }} + } +{{- end }} +{{- if .EnablePartitions }} } {{- end }}` return c.renderRules(injectRulesTpl) @@ -237,43 +295,62 @@ func (c *Command) aclReplicationRules() (string, error) { // datacenters during federation since in order to start ACL replication, // we need a token with both replication and agent permissions. aclReplicationRulesTpl := ` -operator = "write" -agent_prefix "" { - policy = "read" -} -node_prefix "" { - policy = "write" -} -{{- if .EnableNamespaces }} -namespace_prefix "" { +{{- if .EnablePartitions }} +partition "default" { {{- end }} - acl = "write" - service_prefix "" { + operator = "write" + agent_prefix "" { policy = "read" - intentions = "read" } + node_prefix "" { + policy = "write" + } +{{- if .EnableNamespaces }} + namespace_prefix "" { +{{- end }} + acl = "write" + service_prefix "" { + policy = "read" + intentions = "read" + } {{- if .EnableNamespaces }} + } +{{- end }} +{{- if .EnablePartitions }} } {{- end }} ` return c.renderRules(aclReplicationRulesTpl) } +// policy = "write" is required when creating namespaces within a partition. func (c *Command) controllerRules() (string, error) { controllerRules := ` -operator = "write" +{{- if .EnablePartitions }} +partition "{{ .PartitionName }}" { + mesh = "write" + acl = "write" +{{- else }} + operator = "write" +{{- end }} {{- if .EnableNamespaces }} {{- if .InjectEnableNSMirroring }} -namespace_prefix "{{ .InjectNSMirroringPrefix }}" { + namespace_prefix "{{ .InjectNSMirroringPrefix }}" { {{- else }} -namespace "{{ .InjectConsulDestNS }}" { + namespace "{{ .InjectConsulDestNS }}" { {{- end }} {{- end }} - service_prefix "" { +{{- if .EnablePartitions }} policy = "write" - intentions = "write" - } +{{- end }} + service_prefix "" { + policy = "write" + intentions = "write" + } {{- if .EnableNamespaces }} + } +{{- end }} +{{- if .EnablePartitions }} } {{- end }} ` @@ -282,6 +359,8 @@ namespace "{{ .InjectConsulDestNS }}" { func (c *Command) rulesData() rulesData { return rulesData{ + EnablePartitions: c.flagEnablePartitions, + PartitionName: c.flagPartitionName, EnableNamespaces: c.flagEnableNamespaces, SyncConsulDestNS: c.flagConsulSyncDestinationNamespace, SyncEnableNSMirroring: c.flagEnableSyncK8SNSMirroring, diff --git a/control-plane/subcommand/server-acl-init/rules_test.go b/control-plane/subcommand/server-acl-init/rules_test.go index 1160236eef..9914f23585 100644 --- a/control-plane/subcommand/server-acl-init/rules_test.go +++ b/control-plane/subcommand/server-acl-init/rules_test.go @@ -10,28 +10,48 @@ import ( func TestAgentRules(t *testing.T) { cases := []struct { Name string + EnablePartitions bool + PartitionName string EnableNamespaces bool Expected string }{ { - "Namespaces are disabled", - false, - `node_prefix "" { + Name: "Namespaces and Partitions are disabled", + Expected: ` + node_prefix "" { policy = "write" } - service_prefix "" { - policy = "read" + service_prefix "" { + policy = "read" + }`, + }, + { + Name: "Namespaces are enabled, Partitions are disabled", + EnableNamespaces: true, + Expected: ` + node_prefix "" { + policy = "write" + } + namespace_prefix "" { + service_prefix "" { + policy = "read" + } }`, }, { - "Namespaces are enabled", - true, - `node_prefix "" { + Name: "Namespaces and Partitions are enabled", + EnablePartitions: true, + PartitionName: "part-1", + EnableNamespaces: true, + Expected: ` +partition "part-1" { + node_prefix "" { policy = "write" } -namespace_prefix "" { - service_prefix "" { - policy = "read" + namespace_prefix "" { + service_prefix "" { + policy = "read" + } } }`, }, @@ -39,16 +59,16 @@ namespace_prefix "" { for _, tt := range cases { t.Run(tt.Name, func(t *testing.T) { - require := require.New(t) - cmd := Command{ + flagEnablePartitions: tt.EnablePartitions, + flagPartitionName: tt.PartitionName, flagEnableNamespaces: tt.EnableNamespaces, } agentRules, err := cmd.agentRules() - require.NoError(err) - require.Equal(tt.Expected, agentRules) + require.NoError(t, err) + require.Equal(t, tt.Expected, agentRules) }) } } @@ -56,30 +76,48 @@ namespace_prefix "" { func TestAnonymousTokenRules(t *testing.T) { cases := []struct { Name string + EnablePartitions bool + PartitionName string EnableNamespaces bool Expected string }{ { - "Namespaces are disabled", - false, - ` - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" + Name: "Namespaces and Partitions are disabled", + Expected: ` + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + }`, + }, + { + Name: "Namespaces are enabled, Partitions are disabled", + EnableNamespaces: true, + Expected: ` + namespace_prefix "" { + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } }`, }, { - "Namespaces are enabled", - true, - ` -namespace_prefix "" { - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" + Name: "Namespaces and Partitions are enabled", + EnablePartitions: true, + PartitionName: "part-2", + EnableNamespaces: true, + Expected: ` +partition_prefix "" { + namespace_prefix "" { + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } } }`, }, @@ -87,16 +125,16 @@ namespace_prefix "" { for _, tt := range cases { t.Run(tt.Name, func(t *testing.T) { - require := require.New(t) - cmd := Command{ + flagEnablePartitions: tt.EnablePartitions, + flagPartitionName: tt.PartitionName, flagEnableNamespaces: tt.EnableNamespaces, } rules, err := cmd.anonymousTokenRules() - require.NoError(err) - require.Equal(tt.Expected, rules) + require.NoError(t, err) + require.Equal(t, tt.Expected, rules) }) } } @@ -108,9 +146,8 @@ func TestMeshGatewayRules(t *testing.T) { Expected string }{ { - "Namespaces are disabled", - false, - `agent_prefix "" { + Name: "Namespaces are disabled", + Expected: `agent_prefix "" { policy = "read" } service "mesh-gateway" { @@ -124,9 +161,9 @@ func TestMeshGatewayRules(t *testing.T) { }`, }, { - "Namespaces are enabled", - true, - `agent_prefix "" { + Name: "Namespaces are enabled", + EnableNamespaces: true, + Expected: `agent_prefix "" { policy = "read" } namespace "default" { @@ -147,16 +184,14 @@ namespace_prefix "" { for _, tt := range cases { t.Run(tt.Name, func(t *testing.T) { - require := require.New(t) - cmd := Command{ flagEnableNamespaces: tt.EnableNamespaces, } meshGatewayRules, err := cmd.meshGatewayRules() - require.NoError(err) - require.Equal(tt.Expected, meshGatewayRules) + require.NoError(t, err) + require.Equal(t, tt.Expected, meshGatewayRules) }) } } @@ -166,58 +201,102 @@ func TestIngressGatewayRules(t *testing.T) { Name string GatewayName string GatewayNamespace string + EnablePartitions bool + PartitionName string EnableNamespaces bool Expected string }{ { - "Namespaces are disabled", - "ingress-gateway", - "", - false, - ` - service "ingress-gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" + Name: "Namespaces and Partitions are disabled", + GatewayName: "ingress-gateway", + Expected: ` + service "ingress-gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + }`, + }, + { + Name: "Namespaces are enabled, Partitions are disabled", + GatewayName: "gateway", + GatewayNamespace: "default", + EnableNamespaces: true, + Expected: ` + namespace "default" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } }`, }, { - "Namespaces are enabled", - "gateway", - "default", - true, - ` -namespace "default" { - service "gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" + Name: "Namespaces are enabled, non-default namespace, Partitions are disabled", + GatewayName: "gateway", + GatewayNamespace: "non-default", + EnableNamespaces: true, + Expected: ` + namespace "non-default" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } + }`, + }, + { + Name: "Namespaces and Partitions are enabled", + GatewayName: "gateway", + GatewayNamespace: "default", + EnableNamespaces: true, + EnablePartitions: true, + PartitionName: "part-1", + Expected: ` +partition "part-1" { + namespace "default" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } } }`, }, { - "Namespaces are enabled, non-default namespace", - "gateway", - "non-default", - true, - ` -namespace "non-default" { - service "gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" - } - service_prefix "" { - policy = "read" + Name: "Namespaces and Partitions are enabled, non-default namespace", + GatewayName: "gateway", + GatewayNamespace: "non-default", + EnableNamespaces: true, + EnablePartitions: true, + PartitionName: "default", + Expected: ` +partition "default" { + namespace "non-default" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + service_prefix "" { + policy = "read" + } } }`, }, @@ -225,16 +304,16 @@ namespace "non-default" { for _, tt := range cases { t.Run(tt.Name, func(t *testing.T) { - require := require.New(t) - cmd := Command{ + flagEnablePartitions: tt.EnablePartitions, + flagPartitionName: tt.PartitionName, flagEnableNamespaces: tt.EnableNamespaces, } ingressGatewayRules, err := cmd.ingressGatewayRules(tt.GatewayName, tt.GatewayNamespace) - require.NoError(err) - require.Equal(tt.Expected, ingressGatewayRules) + require.NoError(t, err) + require.Equal(t, tt.Expected, ingressGatewayRules) }) } } @@ -245,48 +324,86 @@ func TestTerminatingGatewayRules(t *testing.T) { GatewayName string GatewayNamespace string EnableNamespaces bool + EnablePartitions bool + PartitionName string Expected string }{ { - "Namespaces are disabled", - "terminating-gateway", - "", - false, - ` - service "terminating-gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" + Name: "Namespaces and Partitions are disabled", + GatewayName: "terminating-gateway", + Expected: ` + service "terminating-gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + }`, + }, + { + Name: "Namespaces are enabled, Partitions are disabled", + GatewayName: "gateway", + GatewayNamespace: "default", + EnableNamespaces: true, + Expected: ` + namespace "default" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } }`, }, { - "Namespaces are enabled", - "gateway", - "default", - true, - ` -namespace "default" { - service "gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" + Name: "Namespaces are enabled, non-default namespace, Partitions are disabled", + GatewayName: "gateway", + GatewayNamespace: "non-default", + EnableNamespaces: true, + Expected: ` + namespace "non-default" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } + }`, + }, + { + Name: "Namespaces and Partitions are enabled", + GatewayName: "gateway", + GatewayNamespace: "default", + EnableNamespaces: true, + EnablePartitions: true, + PartitionName: "part-1", + Expected: ` +partition "part-1" { + namespace "default" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } } }`, }, { - "Namespaces are enabled, non-default namespace", - "gateway", - "non-default", - true, - ` -namespace "non-default" { - service "gateway" { - policy = "write" - } - node_prefix "" { - policy = "read" + Name: "Namespaces and Partitions are enabled, non-default namespace", + GatewayName: "gateway", + GatewayNamespace: "non-default", + EnableNamespaces: true, + EnablePartitions: true, + PartitionName: "default", + Expected: ` +partition "default" { + namespace "non-default" { + service "gateway" { + policy = "write" + } + node_prefix "" { + policy = "read" + } } }`, }, @@ -294,16 +411,16 @@ namespace "non-default" { for _, tt := range cases { t.Run(tt.Name, func(t *testing.T) { - require := require.New(t) - cmd := Command{ + flagEnablePartitions: tt.EnablePartitions, + flagPartitionName: tt.PartitionName, flagEnableNamespaces: tt.EnableNamespaces, } terminatingGatewayRules, err := cmd.terminatingGatewayRules(tt.GatewayName, tt.GatewayNamespace) - require.NoError(err) - require.Equal(tt.Expected, terminatingGatewayRules) + require.NoError(t, err) + require.Equal(t, tt.Expected, terminatingGatewayRules) }) } } @@ -319,13 +436,12 @@ func TestSyncRules(t *testing.T) { Expected string }{ { - "Namespaces are disabled", - false, - "sync-namespace", - true, - "prefix-", - "k8s-sync", - `node "k8s-sync" { + Name: "Namespaces are disabled", + ConsulSyncDestinationNamespace: "sync-namespace", + EnableSyncK8SNSMirroring: true, + SyncK8SNSMirroringPrefix: "prefix-", + SyncConsulNodeName: "k8s-sync", + Expected: `node "k8s-sync" { policy = "write" } node_prefix "" { @@ -336,13 +452,12 @@ func TestSyncRules(t *testing.T) { }`, }, { - "Namespaces are disabled, non-default node name", - false, - "sync-namespace", - true, - "prefix-", - "new-node-name", - `node "new-node-name" { + Name: "Namespaces are disabled, non-default node name", + ConsulSyncDestinationNamespace: "sync-namespace", + EnableSyncK8SNSMirroring: true, + SyncK8SNSMirroringPrefix: "prefix-", + SyncConsulNodeName: "new-node-name", + Expected: `node "new-node-name" { policy = "write" } node_prefix "" { @@ -353,13 +468,12 @@ func TestSyncRules(t *testing.T) { }`, }, { - "Namespaces are enabled, mirroring disabled", - true, - "sync-namespace", - false, - "prefix-", - "k8s-sync", - `node "k8s-sync" { + Name: "Namespaces are enabled, mirroring disabled", + EnableNamespaces: true, + ConsulSyncDestinationNamespace: "sync-namespace", + SyncK8SNSMirroringPrefix: "prefix-", + SyncConsulNodeName: "k8s-sync", + Expected: `node "k8s-sync" { policy = "write" } operator = "write" @@ -373,13 +487,12 @@ namespace "sync-namespace" { }`, }, { - "Namespaces are enabled, mirroring disabled, non-default node name", - true, - "sync-namespace", - false, - "prefix-", - "new-node-name", - `node "new-node-name" { + Name: "Namespaces are enabled, mirroring disabled, non-default node name", + EnableNamespaces: true, + ConsulSyncDestinationNamespace: "sync-namespace", + SyncK8SNSMirroringPrefix: "prefix-", + SyncConsulNodeName: "new-node-name", + Expected: `node "new-node-name" { policy = "write" } operator = "write" @@ -393,13 +506,12 @@ namespace "sync-namespace" { }`, }, { - "Namespaces are enabled, mirroring enabled, prefix empty", - true, - "sync-namespace", - true, - "", - "k8s-sync", - `node "k8s-sync" { + Name: "Namespaces are enabled, mirroring enabled, prefix empty", + EnableNamespaces: true, + ConsulSyncDestinationNamespace: "sync-namespace", + EnableSyncK8SNSMirroring: true, + SyncConsulNodeName: "k8s-sync", + Expected: `node "k8s-sync" { policy = "write" } operator = "write" @@ -413,13 +525,12 @@ namespace_prefix "" { }`, }, { - "Namespaces are enabled, mirroring enabled, prefix empty, non-default node name", - true, - "sync-namespace", - true, - "", - "new-node-name", - `node "new-node-name" { + Name: "Namespaces are enabled, mirroring enabled, prefix empty, non-default node name", + EnableNamespaces: true, + ConsulSyncDestinationNamespace: "sync-namespace", + EnableSyncK8SNSMirroring: true, + SyncConsulNodeName: "new-node-name", + Expected: `node "new-node-name" { policy = "write" } operator = "write" @@ -433,13 +544,13 @@ namespace_prefix "" { }`, }, { - "Namespaces are enabled, mirroring enabled, prefix defined", - true, - "sync-namespace", - true, - "prefix-", - "k8s-sync", - `node "k8s-sync" { + Name: "Namespaces are enabled, mirroring enabled, prefix defined", + EnableNamespaces: true, + ConsulSyncDestinationNamespace: "sync-namespace", + EnableSyncK8SNSMirroring: true, + SyncK8SNSMirroringPrefix: "prefix-", + SyncConsulNodeName: "k8s-sync", + Expected: `node "k8s-sync" { policy = "write" } operator = "write" @@ -453,13 +564,13 @@ namespace_prefix "prefix-" { }`, }, { - "Namespaces are enabled, mirroring enabled, prefix defined, non-default node name", - true, - "sync-namespace", - true, - "prefix-", - "new-node-name", - `node "new-node-name" { + Name: "Namespaces are enabled, mirroring enabled, prefix defined, non-default node name", + EnableNamespaces: true, + ConsulSyncDestinationNamespace: "sync-namespace", + EnableSyncK8SNSMirroring: true, + SyncK8SNSMirroringPrefix: "prefix-", + SyncConsulNodeName: "new-node-name", + Expected: `node "new-node-name" { policy = "write" } operator = "write" @@ -476,8 +587,6 @@ namespace_prefix "prefix-" { for _, tt := range cases { t.Run(tt.Name, func(t *testing.T) { - require := require.New(t) - cmd := Command{ flagEnableNamespaces: tt.EnableNamespaces, flagConsulSyncDestinationNamespace: tt.ConsulSyncDestinationNamespace, @@ -488,8 +597,8 @@ namespace_prefix "prefix-" { syncRules, err := cmd.syncRules() - require.NoError(err) - require.Equal(tt.Expected, syncRules) + require.NoError(t, err) + require.Equal(t, tt.Expected, syncRules) }) } } @@ -498,48 +607,71 @@ namespace_prefix "prefix-" { func TestInjectRules(t *testing.T) { cases := []struct { EnableNamespaces bool + EnablePartitions bool + PartitionName string Expected string }{ { EnableNamespaces: false, + EnablePartitions: false, Expected: ` -node_prefix "" { - policy = "write" -} - acl = "write" - service_prefix "" { + node_prefix "" { + policy = "write" + } + acl = "write" + service_prefix "" { + policy = "write" + }`, + }, + { + EnableNamespaces: true, + EnablePartitions: false, + Expected: ` + operator = "write" + node_prefix "" { policy = "write" + } + namespace_prefix "" { + acl = "write" + service_prefix "" { + policy = "write" + } }`, }, { EnableNamespaces: true, + EnablePartitions: true, + PartitionName: "part-1", Expected: ` -operator = "write" -node_prefix "" { - policy = "write" -} -namespace_prefix "" { - acl = "write" - service_prefix "" { +partition "part-1" { + node_prefix "" { + policy = "write" + } + namespace_prefix "" { policy = "write" + acl = "write" + service_prefix "" { + policy = "write" + } } }`, }, } for _, tt := range cases { - caseName := fmt.Sprintf("ns=%t", tt.EnableNamespaces) + caseName := fmt.Sprintf("ns=%t, partition=%t", tt.EnableNamespaces, tt.EnablePartitions) t.Run(caseName, func(t *testing.T) { - require := require.New(t) cmd := Command{ + flagEnablePartitions: tt.EnablePartitions, + flagPartitionName: tt.PartitionName, flagEnableNamespaces: tt.EnableNamespaces, } injectorRules, err := cmd.injectRules() - require.NoError(err) - require.Equal(tt.Expected, injectorRules) + require.NoError(t, err) + require.Equal(t, tt.Expected, injectorRules) }) } } @@ -548,39 +680,65 @@ func TestReplicationTokenRules(t *testing.T) { cases := []struct { Name string EnableNamespaces bool + EnablePartitions bool + PartitionName string Expected string }{ { - "Namespaces are disabled", - false, - `operator = "write" -agent_prefix "" { - policy = "read" -} -node_prefix "" { - policy = "write" -} - acl = "write" - service_prefix "" { + Name: "Namespaces and Partitions are disabled", + Expected: ` + operator = "write" + agent_prefix "" { policy = "read" - intentions = "read" + } + node_prefix "" { + policy = "write" + } + acl = "write" + service_prefix "" { + policy = "read" + intentions = "read" + }`, + }, + { + Name: "Namespaces are enabled, Partitions are disabled", + EnableNamespaces: true, + Expected: ` + operator = "write" + agent_prefix "" { + policy = "read" + } + node_prefix "" { + policy = "write" + } + namespace_prefix "" { + acl = "write" + service_prefix "" { + policy = "read" + intentions = "read" + } }`, }, { - "Namespaces are enabled", - true, - `operator = "write" -agent_prefix "" { - policy = "read" -} -node_prefix "" { - policy = "write" -} -namespace_prefix "" { - acl = "write" - service_prefix "" { + Name: "Namespaces and Partitions are enabled, default partition", + EnableNamespaces: true, + EnablePartitions: true, + PartitionName: "default", + Expected: ` +partition "default" { + operator = "write" + agent_prefix "" { policy = "read" - intentions = "read" + } + node_prefix "" { + policy = "write" + } + namespace_prefix "" { + acl = "write" + service_prefix "" { + policy = "read" + intentions = "read" + } } }`, }, @@ -588,13 +746,14 @@ namespace_prefix "" { for _, tt := range cases { t.Run(tt.Name, func(t *testing.T) { - require := require.New(t) cmd := Command{ + flagEnablePartitions: tt.EnablePartitions, + flagPartitionName: tt.PartitionName, flagEnableNamespaces: tt.EnableNamespaces, } replicationTokenRules, err := cmd.aclReplicationRules() - require.NoError(err) - require.Equal(tt.Expected, replicationTokenRules) + require.NoError(t, err) + require.Equal(t, tt.Expected, replicationTokenRules) }) } } @@ -602,6 +761,8 @@ namespace_prefix "" { func TestControllerRules(t *testing.T) { cases := []struct { Name string + EnablePartitions bool + PartitionName string EnableNamespaces bool DestConsulNS string Mirroring bool @@ -609,48 +770,109 @@ func TestControllerRules(t *testing.T) { Expected string }{ { - Name: "namespaces=disabled", - EnableNamespaces: false, - Expected: `operator = "write" - service_prefix "" { - policy = "write" - intentions = "write" + Name: "namespaces=disabled, partitions=disabled", + Expected: ` + operator = "write" + service_prefix "" { + policy = "write" + intentions = "write" + }`, + }, + { + Name: "namespaces=enabled, consulDestNS=consul, partitions=disabled", + EnableNamespaces: true, + DestConsulNS: "consul", + Expected: ` + operator = "write" + namespace "consul" { + service_prefix "" { + policy = "write" + intentions = "write" + } }`, }, { - Name: "namespaces=enabled, consulDestNS=consul", + Name: "namespaces=enabled, mirroring=true, partitions=disabled", + EnableNamespaces: true, + Mirroring: true, + Expected: ` + operator = "write" + namespace_prefix "" { + service_prefix "" { + policy = "write" + intentions = "write" + } + }`, + }, + { + Name: "namespaces=enabled, mirroring=true, mirroringPrefix=prefix-, partitions=disabled", + EnableNamespaces: true, + Mirroring: true, + MirroringPrefix: "prefix-", + Expected: ` + operator = "write" + namespace_prefix "prefix-" { + service_prefix "" { + policy = "write" + intentions = "write" + } + }`, + }, + { + Name: "namespaces=enabled, consulDestNS=consul, partitions=enabled", + EnablePartitions: true, + PartitionName: "part-1", EnableNamespaces: true, DestConsulNS: "consul", - Expected: `operator = "write" -namespace "consul" { - service_prefix "" { + Expected: ` +partition "part-1" { + mesh = "write" + acl = "write" + namespace "consul" { policy = "write" - intentions = "write" + service_prefix "" { + policy = "write" + intentions = "write" + } } }`, }, { - Name: "namespaces=enabled, mirroring=true", + Name: "namespaces=enabled, mirroring=true, partitions=enabled", + EnablePartitions: true, + PartitionName: "part-1", EnableNamespaces: true, Mirroring: true, - Expected: `operator = "write" -namespace_prefix "" { - service_prefix "" { + Expected: ` +partition "part-1" { + mesh = "write" + acl = "write" + namespace_prefix "" { policy = "write" - intentions = "write" + service_prefix "" { + policy = "write" + intentions = "write" + } } }`, }, { - Name: "namespaces=enabled, mirroring=true, mirroringPrefix=prefix-", + Name: "namespaces=enabled, mirroring=true, mirroringPrefix=prefix-, partitions=enabled", + EnablePartitions: true, + PartitionName: "part-1", EnableNamespaces: true, Mirroring: true, MirroringPrefix: "prefix-", - Expected: `operator = "write" -namespace_prefix "prefix-" { - service_prefix "" { + Expected: ` +partition "part-1" { + mesh = "write" + acl = "write" + namespace_prefix "prefix-" { policy = "write" - intentions = "write" + service_prefix "" { + policy = "write" + intentions = "write" + } } }`, }, @@ -658,19 +880,19 @@ namespace_prefix "prefix-" { for _, tt := range cases { t.Run(tt.Name, func(t *testing.T) { - require := require.New(t) - cmd := Command{ flagEnableNamespaces: tt.EnableNamespaces, flagConsulInjectDestinationNamespace: tt.DestConsulNS, flagEnableInjectK8SNSMirroring: tt.Mirroring, flagInjectK8SNSMirroringPrefix: tt.MirroringPrefix, + flagEnablePartitions: tt.EnablePartitions, + flagPartitionName: tt.PartitionName, } rules, err := cmd.controllerRules() - require.NoError(err) - require.Equal(tt.Expected, rules) + require.NoError(t, err) + require.Equal(t, tt.Expected, rules) }) } } From 6fccb5cedbac988a18b0dfb1a5b946e8fbde5307 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 15 Oct 2021 13:58:18 -0700 Subject: [PATCH 071/418] Address Luke's comment on the Admin Partitions ACL PR (#785) --- control-plane/subcommand/server-acl-init/command.go | 8 ++++---- control-plane/subcommand/server-acl-init/rules.go | 8 +++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index 7a9f2b40e2..9e7bd3d355 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -174,7 +174,7 @@ func (c *Command) init() { "Toggle for using HTTPS for all API calls to Consul.") c.flags.BoolVar(&c.flagEnablePartitions, "enable-partitions", false, - "[Enterprise Only] Enables Admin Partitions [Enterprise only feature]") + "[Enterprise Only] Enables Admin Partitions") c.flags.StringVar(&c.flagPartitionName, "partition", "", "[Enterprise Only] Name of the Admin Partition") @@ -397,7 +397,7 @@ func (c *Command) Run(args []string) int { } if c.flagEnablePartitions && c.flagPartitionName == consulDefaultPartition && isPrimary { - // Partition token must be local because only the Primary datacenter can have Admin Partitions. + // Partition token is local because only the Primary datacenter can have Admin Partitions. err := c.createLocalACL("partitions", partitionRules, consulDC, isPrimary, consulClient) if err != nil { c.log.Error(err.Error()) @@ -412,7 +412,7 @@ func (c *Command) Run(args []string) int { // connect inject) needs to reference this policy on namespace creation // to finish the cross namespace permission setup. if c.flagEnableNamespaces { - crossNamespaceRule, err := c.crossNamespaceRule() + crossNamespaceRule, err := c.crossNamespaceRules() if err != nil { c.log.Error("Error templating cross namespace rules", "err", err) return 1 @@ -864,7 +864,7 @@ func (c *Command) validateFlags() error { return errors.New("-partition must be set if -enable-partitions is true") } if !c.flagEnablePartitions && c.flagPartitionName != "" { - return fmt.Errorf("-enable-partitions must be 'true' if setting -partition to %s", c.flagPartitionName) + return errors.New("-enable-partitions must be 'true' if -partition is set") } return nil } diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index ec1a474a6f..c6f5cdf29c 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -36,9 +36,15 @@ service "consul-snapshot" { policy = "write" }` +// The enterprise license rules are acl="write" inside partitions as operator="write" +// is unsupported in partitions. const entLicenseRules = `operator = "write"` const entPartitionLicenseRules = `acl = "write"` +// The partition token is utilized by the partition-init job and server-acl-init in +// non-default partitions. This token requires permissions to create partitions, read the +// agent endpoint during startup and have the ability to create an auth-method within a namespace +// for any partition. const partitionRules = `operator = "write" agent_prefix "" { policy = "read" @@ -49,7 +55,7 @@ partition_prefix "" { } }` -func (c *Command) crossNamespaceRule() (string, error) { +func (c *Command) crossNamespaceRules() (string, error) { crossNamespaceRulesTpl := `{{- if .EnablePartitions }} partition "{{ .PartitionName }}" { {{- end }} From 50d6ae79d554e3e27e86e52198f9b861eafe5ade Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Fri, 15 Oct 2021 16:57:01 -0700 Subject: [PATCH 072/418] Changelog for uninstall command (#786) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eedfd277b..ff8a56b833 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -113,6 +113,7 @@ This should create clusters that have Admin Partitions deployed on them with ACL * CLI * Add `version` command. [[GH-741](https://github.com/hashicorp/consul-k8s/pull/741)] + * Add `uninstall` command. [[GH-725](https://github.com/hashicorp/consul-k8s/pull/725)] ## 0.34.1 (September 17, 2021) From 82e820d7a7cfcd1b72399b1baea15e5a63a4d5e1 Mon Sep 17 00:00:00 2001 From: David Yu Date: Mon, 18 Oct 2021 09:08:42 -0700 Subject: [PATCH 073/418] CONTRIBUTING.md: adding TOC (#787) Adding a TOC since it was getting harder to read --- CONTRIBUTING.md | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c8281c6c6..766798d32e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,30 @@ -# Contributing +# Contributing to Consul on Kubernetes + +# Table of Contents +1. [Contributing 101](#contributing-101) + 1. [Running Linters Locally](#running-linters-locally) + 2. [Rebasing Contributions against main](#rebasing-contributions-against-main) +3. [Creating a new CRD](#creating-a-new-crd) + 1. [The Structs](#the-structs) + 2. [Spec Methods](#spec-methods) + 3. [Spec Tests](#spec-tests) + 4. [Controller](#controller) + 5. [Webhook](#webhook) + 6. [Update command.go](#update-commandgo) + 7. [Generating YAML](#generating-yaml) + 8. [Updating consul-helm](#updating-consul-helm) + 9. [Testing a new CRD](#testing-a-new-crd) + 10. [Update Consul K8s accpetance tests](#update-consul-k8s-acceptance-tests) +5. [The the Helm chart](#testing-the-helm-chart) +6. [Running the tests](#running-the-tests) + 1. [Writing Unit tests](#writing-unit-tests) + 2. [Writing Acceptance tests](#writing-acceptance-tests) +8. [Helm Reference Docs](#helm-reference-docs) + + +--- + +## Contributing 101 To build and install the control plane binary `consul-k8s` locally, Go version 1.11.4+ is required because this repository uses go modules and go 1.11.4 introduced changes to checksumming of modules to correct a symlink problem. You will also need to install the Docker engine: @@ -72,6 +98,8 @@ automatic rebasing when the PR is accepted into the code. However, if there are a warning on the PR that reads "This branch cannot be rebased due to conflicts"), you will need to manually rebase the branch on main, fixing any conflicts along the way before the code can be merged. +--- + ## Creating a new CRD ### The Structs @@ -387,15 +415,16 @@ rebase the branch on main, fixing any conflicts along the way before the code ca } ``` -### Update consul-helm Acceptance Tests +### Update consul-k8s Acceptance Tests 1. Add a test resource to `test/acceptance/tests/fixtures/crds/ingressgateway.yaml`. Ideally it requires no other resources. For example, I used a `tcp` service so it didn't require a `ServiceDefaults` resource to set its protocol to something else. 1. Update `charts/consul/test/acceptance/tests/controller/controller_test.go` and `charts/consul/test/acceptance/tests/controller/controller_namespaces_test.go`. 1. Test locally, then submit a PR that uses your Docker image as `global.imageK8S`. +--- -## Testing Helm Chart +## Testing the Helm Chart The Helm chart ships with both unit and acceptance tests. The unit tests don't require any active Kubernetes cluster and complete @@ -419,6 +448,8 @@ The acceptance tests require a Kubernetes cluster with a configured `kubectl`. ```bash brew install golang ``` + +--- ### Running The Tests @@ -762,6 +793,8 @@ Here are some things to consider before adding a test: For example, we don't expect acceptance tests to include all the permutations of the consul-k8s commands and their respective flags. Something like that should be tested in the consul-k8s repository. +--- + ## Helm Reference Docs The helm reference docs (https://www.consul.io/docs/k8s/helm) are automatically From 829719236653e886a9d33568e2ddc87a7d36376a Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Mon, 18 Oct 2021 09:26:22 -0700 Subject: [PATCH 074/418] Remove TOC header --- CONTRIBUTING.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 766798d32e..31a46a4712 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,5 @@ # Contributing to Consul on Kubernetes -# Table of Contents 1. [Contributing 101](#contributing-101) 1. [Running Linters Locally](#running-linters-locally) 2. [Rebasing Contributions against main](#rebasing-contributions-against-main) @@ -15,15 +14,13 @@ 8. [Updating consul-helm](#updating-consul-helm) 9. [Testing a new CRD](#testing-a-new-crd) 10. [Update Consul K8s accpetance tests](#update-consul-k8s-acceptance-tests) -5. [The the Helm chart](#testing-the-helm-chart) +5. [Testing the Helm chart](#testing-the-helm-chart) 6. [Running the tests](#running-the-tests) 1. [Writing Unit tests](#writing-unit-tests) 2. [Writing Acceptance tests](#writing-acceptance-tests) 8. [Helm Reference Docs](#helm-reference-docs) ---- - ## Contributing 101 To build and install the control plane binary `consul-k8s` locally, Go version 1.11.4+ is required because this repository uses go modules and go 1.11.4 introduced changes to checksumming of modules to correct a symlink problem. From 617ea9286c7fd32412f3e42b563313e479dbb226 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Mon, 18 Oct 2021 13:31:13 -0400 Subject: [PATCH 075/418] Add docs --- CHANGELOG.md | 94 +----------------------------- docs/admin-partitions-with-acls.md | 94 ++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 93 deletions(-) create mode 100644 docs/admin-partitions-with-acls.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ff8a56b833..6a85efe235 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,99 +17,7 @@ IMPROVEMENTS: * This feature now enabled ACL support for Admin Partitions. The server-acl-init job now creates a Partition token. This token can be used to bootstrap new partitions as well as manage ACLs in the non-default partitions. * Partition to partition networking is disabled if ACLs are enabled. - -To enabled ACLs on the server cluster use the following config: -```yaml -global: - enableConsulNamespaces: true - tls: - enabled: true - image: hashicorp/consul-enterprise:1.11.0-ent-beta1 - adminPartitions: - enabled: true - acls: - manageSystemACLs: true -server: - exposeGossipAndRPCPorts: true - enterpriseLicense: - secretName: license - secretKey: key - replicas: 1 -connectInject: - enabled: true - transparentProxy: - defaultEnabled: false - consulNamespaces: - mirroringK8S: true -controller: - enabled: true -``` - -Identify the LoadBalancer External IP of the `partition-service` -```bash -kubectl get svc consul-consul-partition-service -o json | jq -r '.status.loadBalancer.ingress[0].ip' -``` - -Migrate the TLS CA credentials from the server cluster to the workload clusters -```bash -kubectl get secret consul-consul-ca-key --context "server-context" -o json | kubectl apply --context "workload-context" -f - -kubectl get secret consul-consul-ca-cert --context "server-context" -o json | kubectl apply --context "workload-context" -f - -``` - -Migrate the Partition token from the server cluster to the workload clusters -```bash -kubectl get secret consul-consul-partitions-acl-token --context "server-context" -o json | kubectl apply --context "workload-context" -f - -``` - -Identify the Kubernetes AuthMethod URL of the workload cluster to use as the `k8sAuthMethodHost`: -```bash -kubectl config view -o "jsonpath={.clusters[?(@.name=='workload-cluster-name')].cluster.server}" -``` - -Configure the workload cluster using the following: - -```yaml -global: - enabled: false - enableConsulNamespaces: true - image: hashicorp/consul-enterprise:1.11.0-ent-beta1 - adminPartitions: - enabled: true - name: "partition-name" - tls: - enabled: true - caCert: - secretName: consul-consul-ca-cert - secretKey: tls.crt - caKey: - secretName: consul-consul-ca-key - secretKey: tls.key - acls: - manageSystemACLs: true - bootstrapToken: - secretName: consul-consul-partitions-acl-token - secretKey: token -server: - enterpriseLicense: - secretName: license - secretKey: key -externalServers: - enabled: true - hosts: [ "loadbalancer IP" ] - tlsServerName: server.dc1.consul - k8sAuthMethodHost: "authmethod-host IP" -client: - enabled: true - exposeGossipPorts: true - join: [ "loadbalancer IP" ] -connectInject: - enabled: true - consulNamespaces: - mirroringK8S: true -controller: - enabled: true -``` -This should create clusters that have Admin Partitions deployed on them with ACLs enabled. + * Documentation for the installation can be found [here](https://github.com/hashicorp/consul-k8s/blob/main/docs/admin-partitions-with-acls.md). * CLI * Add `version` command. [[GH-741](https://github.com/hashicorp/consul-k8s/pull/741)] diff --git a/docs/admin-partitions-with-acls.md b/docs/admin-partitions-with-acls.md new file mode 100644 index 0000000000..6ff5be54f1 --- /dev/null +++ b/docs/admin-partitions-with-acls.md @@ -0,0 +1,94 @@ +## Installing Admin Partitions with ACLs enabled + +To enable ACLs on the server cluster use the following config: +```yaml +global: + enableConsulNamespaces: true + tls: + enabled: true + image: hashicorp/consul-enterprise:1.11.0-ent-beta1 + adminPartitions: + enabled: true + acls: + manageSystemACLs: true +server: + exposeGossipAndRPCPorts: true + enterpriseLicense: + secretName: license + secretKey: key + replicas: 1 +connectInject: + enabled: true + transparentProxy: + defaultEnabled: false + consulNamespaces: + mirroringK8S: true +controller: + enabled: true +``` + +Identify the LoadBalancer External IP of the `partition-service` +```bash +kubectl get svc consul-consul-partition-service -o json | jq -r '.status.loadBalancer.ingress[0].ip' +``` + +Migrate the TLS CA credentials from the server cluster to the workload clusters +```bash +kubectl get secret consul-consul-ca-key --context "server-context" -o json | kubectl apply --context "workload-context" -f - +kubectl get secret consul-consul-ca-cert --context "server-context" -o json | kubectl apply --context "workload-context" -f - +``` + +Migrate the Partition token from the server cluster to the workload clusters +```bash +kubectl get secret consul-consul-partitions-acl-token --context "server-context" -o json | kubectl apply --context "workload-context" -f - +``` + +Identify the Kubernetes AuthMethod URL of the workload cluster to use as the `k8sAuthMethodHost`: +```bash +kubectl config view -o "jsonpath={.clusters[?(@.name=='workload-cluster-name')].cluster.server}" +``` + +Configure the workload cluster using the following: + +```yaml +global: + enabled: false + enableConsulNamespaces: true + image: hashicorp/consul-enterprise:1.11.0-ent-beta1 + adminPartitions: + enabled: true + name: "partition-name" + tls: + enabled: true + caCert: + secretName: consul-consul-ca-cert + secretKey: tls.crt + caKey: + secretName: consul-consul-ca-key + secretKey: tls.key + acls: + manageSystemACLs: true + bootstrapToken: + secretName: consul-consul-partitions-acl-token + secretKey: token +server: + enterpriseLicense: + secretName: license + secretKey: key +externalServers: + enabled: true + hosts: [ "loadbalancer IP" ] + tlsServerName: server.dc1.consul + k8sAuthMethodHost: "authmethod-host IP" +client: + enabled: true + exposeGossipPorts: true + join: [ "loadbalancer IP" ] +connectInject: + enabled: true + consulNamespaces: + mirroringK8S: true +controller: + enabled: true +``` +This should create clusters that have Admin Partitions deployed on them with ACLs enabled. From 7089f162d94a966efce8e16325e636fa85b23cdb Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Sun, 17 Oct 2021 22:07:57 -0700 Subject: [PATCH 076/418] Change CRD retry-backoff Previously, if a custom resource failed to sync with Consul, we used the default retry backoff. This was an exponential backoff starting at 5ms and maxing out at 1000s (16m). This backoff was a poor UX for our common error case where one config entry cannot be applied due to a prerequisite, for example an ingress gateway entry cannot be applied until the protocol is set to http. The usual workflow to resolve this would be to look up the error, figure out the correct ServiceDefaults/ProxyDefaults, and then apply that resource. Once applied, the user needs to wait fo the ingress gateway (in this example) resource to be retried. With the default backoff config, because the user will have taken on the order of minutes to figure out the correct config, the exponential backoff will now be upwards of five minutes. The user will have to wait for a long time for the ingress gateway resource to be retried. This PR changes the backoff to start out at 200ms and max out at 5s. This fits our use-case better because the user will have to wait at max 5ms, usually if there's an error, retrying within 5ms does nothing, so waiting 200ms to start is fine, and finally, Consul servers can accept tens of thousands of writes per second so even if there are a ton of resources retrying every 5s, it won't be an issue. --- CHANGELOG.md | 4 +-- .../controller/configentry_controller.go | 35 +++++++++++++++++++ .../controller/ingressgateway_controller.go | 4 +-- control-plane/controller/mesh_controller.go | 4 +-- .../controller/proxydefaults_controller.go | 4 +-- .../controller/servicedefaults_controller.go | 4 +-- .../serviceintentions_controller.go | 4 +-- .../controller/serviceresolver_controller.go | 4 +-- .../controller/servicerouter_controller.go | 4 +-- .../controller/servicesplitter_controller.go | 4 +-- .../terminatinggateway_controller.go | 4 +-- control-plane/go.mod | 1 + 12 files changed, 47 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a85efe235..73ed979a77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,15 +10,15 @@ FEATURES: IMPROVEMENTS: * Control Plane * Upgrade Docker image Alpine version from 3.13 to 3.14. [[GH-737](https://github.com/hashicorp/consul-k8s/pull/737)] + * CRDs: tune failure backoff so invalid config entries are re-synced more quickly. [[GH-788](https://github.com/hashicorp/consul-k8s/pull/788)] * Helm Chart * Enable adding extra containers to server and client Pods. [[GH-749](https://github.com/hashicorp/consul-k8s/pull/749)] * ACL support for Admin Partitions. **(Consul Enterprise only)** **BETA** [[GH-766](https://github.com/hashicorp/consul-k8s/pull/766)] * This feature now enabled ACL support for Admin Partitions. The server-acl-init job now creates a Partition token. This token -can be used to bootstrap new partitions as well as manage ACLs in the non-default partitions. + can be used to bootstrap new partitions as well as manage ACLs in the non-default partitions. * Partition to partition networking is disabled if ACLs are enabled. * Documentation for the installation can be found [here](https://github.com/hashicorp/consul-k8s/blob/main/docs/admin-partitions-with-acls.md). - * CLI * Add `version` command. [[GH-741](https://github.com/hashicorp/consul-k8s/pull/741)] * Add `uninstall` command. [[GH-725](https://github.com/hashicorp/consul-k8s/pull/725)] diff --git a/control-plane/controller/configentry_controller.go b/control-plane/controller/configentry_controller.go index 995c8138ed..d45340b151 100644 --- a/control-plane/controller/configentry_controller.go +++ b/control-plane/controller/configentry_controller.go @@ -11,12 +11,16 @@ import ( "github.com/hashicorp/consul-k8s/control-plane/api/common" "github.com/hashicorp/consul-k8s/control-plane/namespaces" capi "github.com/hashicorp/consul/api" + "golang.org/x/time/rate" 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" 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" ) const ( @@ -246,6 +250,37 @@ func (r *ConfigEntryController) ReconcileEntry(ctx context.Context, crdCtrl Cont 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 config entry is applied that requires + // a protocol like http or grpc. Often the user will apply a new config + // entry 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 config entry 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 its 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 *ConfigEntryController) consulNamespace(configEntry capi.ConfigEntry, namespace string, globalResource bool) string { // ServiceIntentions have the appropriate Consul Namespace set on them as the value // is defaulted by the webhook. These are then set on the ServiceIntentions config entry diff --git a/control-plane/controller/ingressgateway_controller.go b/control-plane/controller/ingressgateway_controller.go index aedb2ff697..7e656b3d29 100644 --- a/control-plane/controller/ingressgateway_controller.go +++ b/control-plane/controller/ingressgateway_controller.go @@ -36,7 +36,5 @@ func (r *IngressGatewayController) UpdateStatus(ctx context.Context, obj client. } func (r *IngressGatewayController) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&consulv1alpha1.IngressGateway{}). - Complete(r) + return setupWithManager(mgr, &consulv1alpha1.IngressGateway{}, r) } diff --git a/control-plane/controller/mesh_controller.go b/control-plane/controller/mesh_controller.go index 4b4e1257bc..61652d23fe 100644 --- a/control-plane/controller/mesh_controller.go +++ b/control-plane/controller/mesh_controller.go @@ -36,7 +36,5 @@ func (r *MeshController) UpdateStatus(ctx context.Context, obj client.Object, op } func (r *MeshController) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&consulv1alpha1.Mesh{}). - Complete(r) + return setupWithManager(mgr, &consulv1alpha1.Mesh{}, r) } diff --git a/control-plane/controller/proxydefaults_controller.go b/control-plane/controller/proxydefaults_controller.go index 0b4a11c001..658806d340 100644 --- a/control-plane/controller/proxydefaults_controller.go +++ b/control-plane/controller/proxydefaults_controller.go @@ -36,7 +36,5 @@ func (r *ProxyDefaultsController) UpdateStatus(ctx context.Context, obj client.O } func (r *ProxyDefaultsController) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&consulv1alpha1.ProxyDefaults{}). - Complete(r) + return setupWithManager(mgr, &consulv1alpha1.ProxyDefaults{}, r) } diff --git a/control-plane/controller/servicedefaults_controller.go b/control-plane/controller/servicedefaults_controller.go index f71afed09c..7dd73914e4 100644 --- a/control-plane/controller/servicedefaults_controller.go +++ b/control-plane/controller/servicedefaults_controller.go @@ -36,7 +36,5 @@ func (r *ServiceDefaultsController) UpdateStatus(ctx context.Context, obj client } func (r *ServiceDefaultsController) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&consulv1alpha1.ServiceDefaults{}). - Complete(r) + return setupWithManager(mgr, &consulv1alpha1.ServiceDefaults{}, r) } diff --git a/control-plane/controller/serviceintentions_controller.go b/control-plane/controller/serviceintentions_controller.go index b6db47dfd0..1ee1db037c 100644 --- a/control-plane/controller/serviceintentions_controller.go +++ b/control-plane/controller/serviceintentions_controller.go @@ -36,7 +36,5 @@ func (r *ServiceIntentionsController) UpdateStatus(ctx context.Context, obj clie } func (r *ServiceIntentionsController) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&consulv1alpha1.ServiceIntentions{}). - Complete(r) + return setupWithManager(mgr, &consulv1alpha1.ServiceIntentions{}, r) } diff --git a/control-plane/controller/serviceresolver_controller.go b/control-plane/controller/serviceresolver_controller.go index 96f068441c..3e01e680ea 100644 --- a/control-plane/controller/serviceresolver_controller.go +++ b/control-plane/controller/serviceresolver_controller.go @@ -36,7 +36,5 @@ func (r *ServiceResolverController) UpdateStatus(ctx context.Context, obj client } func (r *ServiceResolverController) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&consulv1alpha1.ServiceResolver{}). - Complete(r) + return setupWithManager(mgr, &consulv1alpha1.ServiceResolver{}, r) } diff --git a/control-plane/controller/servicerouter_controller.go b/control-plane/controller/servicerouter_controller.go index e32c3d175a..7db983dec2 100644 --- a/control-plane/controller/servicerouter_controller.go +++ b/control-plane/controller/servicerouter_controller.go @@ -36,7 +36,5 @@ func (r *ServiceRouterController) UpdateStatus(ctx context.Context, obj client.O } func (r *ServiceRouterController) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&consulv1alpha1.ServiceRouter{}). - Complete(r) + return setupWithManager(mgr, &consulv1alpha1.ServiceRouter{}, r) } diff --git a/control-plane/controller/servicesplitter_controller.go b/control-plane/controller/servicesplitter_controller.go index 537fbef969..a8b6267c70 100644 --- a/control-plane/controller/servicesplitter_controller.go +++ b/control-plane/controller/servicesplitter_controller.go @@ -36,7 +36,5 @@ func (r *ServiceSplitterController) UpdateStatus(ctx context.Context, obj client } func (r *ServiceSplitterController) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&consulv1alpha1.ServiceSplitter{}). - Complete(r) + return setupWithManager(mgr, &consulv1alpha1.ServiceSplitter{}, r) } diff --git a/control-plane/controller/terminatinggateway_controller.go b/control-plane/controller/terminatinggateway_controller.go index 43b4b3a0df..a8db2d851e 100644 --- a/control-plane/controller/terminatinggateway_controller.go +++ b/control-plane/controller/terminatinggateway_controller.go @@ -36,7 +36,5 @@ func (r *TerminatingGatewayController) UpdateStatus(ctx context.Context, obj cli } func (r *TerminatingGatewayController) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - For(&consulv1alpha1.TerminatingGateway{}). - Complete(r) + return setupWithManager(mgr, &consulv1alpha1.TerminatingGateway{}, r) } diff --git a/control-plane/go.mod b/control-plane/go.mod index cf90cff87d..35fce971ae 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -31,6 +31,7 @@ require ( github.com/stretchr/testify v1.7.0 go.uber.org/zap v1.17.0 golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 // indirect + golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/tools v0.1.2 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 k8s.io/api v0.21.1 From d153c34afbe30b3b7be278c6eef02db83450fc41 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Mon, 18 Oct 2021 14:55:14 -0500 Subject: [PATCH 077/418] Release time (#792) * Release time --- .circleci/config.yml | 4 ++-- charts/consul/Chart.yaml | 8 ++++---- charts/consul/values.yaml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b2d4f810a2..a592052168 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,8 +9,8 @@ executors: - image: docker.mirror.hashicorp.services/circleci/golang:1.16 environment: TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.11.0-alpha # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.11.0+ent-alpha # Consul's enterprise version to use in tests + CONSUL_VERSION: 1.11.0-beta1 # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.0+ent-beta1 # Consul's enterprise version to use in tests control-plane-path : &control-plane-path control-plane cli-path : &cli-path cli diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index b76187558a..78502183ff 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: consul -version: 0.34.1 -appVersion: 1.10.2 +version: 0.35.0 +appVersion: 1.10.3 kubeVersion: ">=1.17.0-0" description: Official HashiCorp Consul Chart home: https://www.consul.io @@ -13,9 +13,9 @@ annotations: artifacthub.io/prerelease: false artifacthub.io/images: | - name: consul - image: hashicorp/consul:1.10.2 + image: hashicorp/consul:1.10.3 - name: consul-k8s-control-plane - image: hashicorp/consul-k8s-control-plane:0.34.1 + image: hashicorp/consul-k8s-control-plane:0.35.0 - name: envoy image: envoyproxy/envoy-alpine:v1.18.4 artifacthub.io/license: MPL-2.0 diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 49defa4f03..a64c09fc7f 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -85,7 +85,7 @@ global: # image: "hashicorp/consul-enterprise:1.10.0-ent" # ``` # @default: hashicorp/consul: - image: "hashicorp/consul:1.10.2" + image: "hashicorp/consul:1.10.3" # Array of objects containing image pull secret names that will be applied to each service account. # This can be used to reference image pull secrets if using a custom consul or consul-k8s-control-plane Docker image. @@ -105,7 +105,7 @@ global: # image that is used for functionality such as catalog sync. # This can be overridden per component. # @default: hashicorp/consul-k8s-control-plane: - imageK8S: "hashicorp/consul-k8s-control-plane:0.34.1" + imageK8S: "hashicorp/consul-k8s-control-plane:0.35.0" # The name of the datacenter that the agents should # register as. This can't be changed once the Consul cluster is up and running From de72393353f06e15f636ede9ffc12a7bd8b1b4ab Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 18 Oct 2021 18:13:40 -0600 Subject: [PATCH 078/418] Fix unit tests to work with consul 1.11 (#794) Previously, WaitForLeader would work because it relied on legacy ACLs not erroring out before WAN joining the cluster. But this is not longer the case, and so we need to WAN join first and wait for ACL replication to finish before calling WaitForLeader. --- control-plane/subcommand/server-acl-init/command_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index 1a3d81ab2d..a70a2383c6 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -2103,7 +2103,6 @@ func replicatedSetup(t *testing.T, bootToken string) (*fake.Clientset, *api.Clie } }) require.NoError(t, err) - secondarySvr.WaitForLeader(t) // Our consul client will use the secondary dc. clientToken := bootToken @@ -2127,6 +2126,8 @@ func replicatedSetup(t *testing.T, bootToken string) (*fake.Clientset, *api.Clie err = consul.Agent().Join(secondarySvr.WANAddr, true) require.NoError(t, err) + secondarySvr.WaitForLeader(t) + // Overwrite consul client, pointing it to the secondary DC consul, err = api.NewClient(&api.Config{ Address: secondarySvr.HTTPAddr, From b875de2d35fe7bf329ea3314e63d4b6239987b20 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Tue, 19 Oct 2021 18:04:53 +0000 Subject: [PATCH 079/418] Release v0.35.0 --- CHANGELOG.md | 2 +- control-plane/version/version.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73ed979a77..ad17d71782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.35.0 (October 19, 2021) FEATURES: * Control Plane diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 6194e7ee7c..fc82a0063a 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.34.1" + Version = "0.35.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 74aa67934ae460f19fe7e1d5bf4ab62f5ce0977e Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Tue, 19 Oct 2021 18:20:54 +0000 Subject: [PATCH 080/418] Putting source back into Dev Mode --- CHANGELOG.md | 2 ++ control-plane/version/version.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad17d71782..737dc57523 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## UNRELEASED + ## 0.35.0 (October 19, 2021) FEATURES: diff --git a/control-plane/version/version.go b/control-plane/version/version.go index fc82a0063a..9ccf557a41 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 9a3c7980b3a8359520a9841159d7dbd1475cb2bd Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 19 Oct 2021 15:40:36 -0400 Subject: [PATCH 081/418] Update the arch label to match releases --- control-plane/build-support/docker/Release.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control-plane/build-support/docker/Release.dockerfile b/control-plane/build-support/docker/Release.dockerfile index d07f3d994e..fec607a7c1 100644 --- a/control-plane/build-support/docker/Release.dockerfile +++ b/control-plane/build-support/docker/Release.dockerfile @@ -50,7 +50,7 @@ RUN set -eux && \ apkArch="$(apk --print-arch)" && \ case "${apkArch}" in \ aarch64) ARCH='arm64' ;; \ - armhf) ARCH='armhfv6' ;; \ + armhf) ARCH='arm' ;; \ x86) ARCH='386' ;; \ x86_64) ARCH='amd64' ;; \ *) echo >&2 "error: unsupported architecture: ${apkArch} (see ${HASHICORP_RELEASES}/${NAME}/${VERSION}/)" && exit 1 ;; \ From 68a0520478ee749ef2d44dc04d95a333590dd2ac Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 20 Oct 2021 17:36:17 -0400 Subject: [PATCH 082/418] Use Gossip Autogenerate Command (#789) * Add `get` perm to role * Use `imageK8S` and run command from job * Use release namespace * Use .Release.Namespace in job definition * Update CHANGELOG --- CHANGELOG.md | 4 +++ .../gossip-encryption-autogenerate-job.yaml | 26 +++++-------------- .../gossip-encryption-autogenerate-role.yaml | 1 + 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 737dc57523..6927e3433b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## UNRELEASED +IMPROVEMENTS: +* Helm Chart + * Automatic retry for `gossip-encryption-autogenerate-job` on failure [[GH-789](https://github.com/hashicorp/consul-k8s/pull/789)] + ## 0.35.0 (October 19, 2021) FEATURES: diff --git a/charts/consul/templates/gossip-encryption-autogenerate-job.yaml b/charts/consul/templates/gossip-encryption-autogenerate-job.yaml index ae5c0674d1..3811f36703 100644 --- a/charts/consul/templates/gossip-encryption-autogenerate-job.yaml +++ b/charts/consul/templates/gossip-encryption-autogenerate-job.yaml @@ -38,29 +38,17 @@ spec: fsGroup: 1000 containers: - name: gossip-encryption-autogen - image: "{{ .Values.global.image }}" - env: - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - # We're using POST requests below to create secrets via Kubernetes API. - # Note that in the subsequent runs of the job, POST requests will - # return a 409 because these secrets would already exist; - # we are ignoring these response codes. + image: "{{ .Values.global.imageK8S }}" command: - "/bin/sh" - "-ec" - | - secretName={{ template "consul.fullname" . }}-gossip-encryption-key - secretKey=key - keyValue=$(consul keygen | base64) - curl -s -X POST --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt \ - https://${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}/api/v1/namespaces/${NAMESPACE}/secrets \ - -H "Authorization: Bearer $( cat /var/run/secrets/kubernetes.io/serviceaccount/token )" \ - -H "Content-Type: application/json" \ - -H "Accept: application/json" \ - -d "{ \"kind\": \"Secret\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"${secretName}\", \"namespace\": \"${NAMESPACE}\" }, \"type\": \"Opaque\", \"data\": { \"${secretKey}\": \"${keyValue}\" }}" > /dev/null + consul-k8s-control-plane gossip-encryption-autogenerate \ + -namespace={{ .Release.Namespace }} \ + -secret-name={{ template "consul.fullname" . }}-gossip-encryption-key \ + -secret-key="key" \ + -log-level={{ .Values.global.logLevel }} \ + -log-json={{ .Values.global.logJSON }} resources: requests: memory: "50Mi" diff --git a/charts/consul/templates/gossip-encryption-autogenerate-role.yaml b/charts/consul/templates/gossip-encryption-autogenerate-role.yaml index 5f9d354f38..ee5afac0ba 100644 --- a/charts/consul/templates/gossip-encryption-autogenerate-role.yaml +++ b/charts/consul/templates/gossip-encryption-autogenerate-role.yaml @@ -18,6 +18,7 @@ rules: - secrets verbs: - create + - get {{- if .Values.global.enablePodSecurityPolicies }} - apiGroups: ["policy"] resources: From 92a5a4f90a18eed8f0bc1fadcec487eec32c54f9 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Wed, 20 Oct 2021 21:16:07 -0500 Subject: [PATCH 083/418] test --- acceptance/framework/vault/vault_cluster.go | 312 ++++++++++++++++++++ acceptance/go.mod | 3 +- acceptance/go.sum | 208 +++++++++++-- acceptance/tests/vault/main_test.go | 15 + acceptance/tests/vault/vault_test.go | 133 +++++++++ 5 files changed, 650 insertions(+), 21 deletions(-) create mode 100644 acceptance/framework/vault/vault_cluster.go create mode 100644 acceptance/tests/vault/main_test.go create mode 100644 acceptance/tests/vault/vault_test.go diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go new file mode 100644 index 0000000000..e582eabf34 --- /dev/null +++ b/acceptance/framework/vault/vault_cluster.go @@ -0,0 +1,312 @@ +package vault + +import ( + "context" + "encoding/json" + "fmt" + corev1 "k8s.io/api/core/v1" + "strings" + "testing" + "time" + + "github.com/gruntwork-io/terratest/modules/helm" + terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" + terratestLogger "github.com/gruntwork-io/terratest/modules/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/config" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/consul/sdk/testutil/retry" + "k8s.io/apimachinery/pkg/api/errors" + // https://github.com/hashicorp/vault-examples/tree/main/go + vapi "github.com/hashicorp/vault/api" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +// Cluster represents a consul cluster object +type Cluster interface { + Create(t *testing.T) + Bootstrap(t *testing.T, ctx environment.TestContext) + Destroy(t *testing.T) + SetupVaultClient(t *testing.T) *vapi.Client + VaultClient(t *testing.T) *vapi.Client +} + +const ( + vaultNS = "default" +) + +// VaultCluster +type VaultCluster struct { + ctx environment.TestContext + namespace string + + vaultHelmOptions *helm.Options + vaultReleaseName string + vaultClient *vapi.Client + rootToken string + + kubectlOptions *terratestk8s.KubectlOptions + values map[string]string + + kubernetesClient kubernetes.Interface + kubeConfig string + kubeContext string + + noCleanupOnFailure bool + debugDirectory string + logger terratestLogger.TestLogger +} + +// NewHelmCluster installs Vault into Kubernetes using Helm. +func NewHelmCluster( + t *testing.T, + helmValues map[string]string, + ctx environment.TestContext, + cfg *config.TestConfig, + releaseName string, +) Cluster { + + logger := terratestLogger.New(logger.TestLogger{}) + + kopts := ctx.KubectlOptions(t) + kopts.Namespace = vaultNS + + vaultHelmOpts := &helm.Options{ + SetValues: defaultVaultValues(), + KubectlOptions: kopts, + Logger: logger, + } + + return &VaultCluster{ + ctx: ctx, + vaultHelmOptions: vaultHelmOpts, + kubectlOptions: kopts, + namespace: cfg.KubeNamespace, + values: helmValues, + kubernetesClient: ctx.KubernetesClient(t), + kubeConfig: cfg.Kubeconfig, + kubeContext: cfg.KubeContext, + noCleanupOnFailure: cfg.NoCleanupOnFailure, + debugDirectory: cfg.DebugDirectory, + logger: logger, + vaultReleaseName: releaseName, + } +} + +func (v *VaultCluster) VaultClient(t *testing.T) *vapi.Client { return v.vaultClient } + +// checkForPriorInstallations checks if there is an existing Helm release +// for this Helm chart already installed. If there is, it fails the tests. +func (v *VaultCluster) checkForPriorVaultInstallations(t *testing.T) { + t.Helper() + + var helmListOutput string + // Check if there's an existing cluster and fail if there is one. + // We may need to retry since this is the first command run once the Kube + // cluster is created and sometimes the API server returns errors. + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 3}, t, func(r *retry.R) { + var err error + // NOTE: It's okay to pass in `t` to RunHelmCommandAndGetOutputE despite being in a retry + // because we're using RunHelmCommandAndGetOutputE (not RunHelmCommandAndGetOutput) so the `t` won't + // get used to fail the test, just for logging. + helmListOutput, err = helm.RunHelmCommandAndGetOutputE(t, v.vaultHelmOptions, "list", "--output", "json") + require.NoError(r, err) + }) + + var installedReleases []map[string]string + + err := json.Unmarshal([]byte(helmListOutput), &installedReleases) + require.NoError(t, err, "unmarshalling %q", helmListOutput) + + for _, r := range installedReleases { + require.NotContains(t, r["chart"], "vault", fmt.Sprintf("detected an existing installation of Vault %s, release name: %s", r["chart"], r["name"])) + } + /* + // TODO: Copied this from Consul Cluster implementation, is this necessary for vault? + // Wait for all pods in the "default" namespace to exit. A previous + // release may not be listed by Helm but its pods may still be terminating. + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { + consulPods, err := v.kubernetesClient.CoreV1().Pods(v.vaultHelmOptions.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) + require.NoError(r, err) + if len(consulPods.Items) > 0 { + var podNames []string + for _, p := range consulPods.Items { + podNames = append(podNames, p.Name) + } + r.Errorf("pods from previous installation still running: %s", strings.Join(podNames, ", ")) + } + }) + */ +} + +// Setup Vault Client returns a Vault Client. +// TODO: We need to support Vault with TLS enabled. +func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { + t.Helper() + + config := vapi.DefaultConfig() + localPort := terratestk8s.GetAvailablePort(t) + remotePort := 8200 // use non-secure by default + + serverPod := fmt.Sprintf("%s-vault-0", v.vaultReleaseName) + tunnel := terratestk8s.NewTunnelWithLogger( + v.vaultHelmOptions.KubectlOptions, + terratestk8s.ResourceTypePod, + serverPod, + localPort, + remotePort, + v.logger) + + // Retry creating the port forward since it can fail occasionally. + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 3}, t, func(r *retry.R) { + // NOTE: It's okay to pass in `t` to ForwardPortE despite being in a retry + // because we're using ForwardPortE (not ForwardPort) so the `t` won't + // get used to fail the test, just for logging. + require.NoError(r, tunnel.ForwardPortE(t)) + }) + + t.Cleanup(func() { + tunnel.Close() + }) + + config.Address = fmt.Sprintf("http://127.0.0.1:%d", localPort) + consulClient, err := vapi.NewClient(config) + require.NoError(t, err) + + return consulClient +} + +// Bootstrap runs Init, Unseals the Vault installation +// and then does the setup of Auth Methods and Enables Secrets Engines. +func (v *VaultCluster) Bootstrap(t *testing.T, ctx environment.TestContext) { + + v.vaultClient = v.SetupVaultClient(t) + + // Init the Vault Cluster and store the rootToken. + initResp, err := v.vaultClient.Sys().Init(&vapi.InitRequest{ + // Init the cluster and only request a single Secret to be used for Unsealing. + SecretShares: 1, + SecretThreshold: 1, + StoredShares: 1, + RecoveryShares: 0, + RecoveryThreshold: 0, + }) + if err != nil { + t.Fatal("unable to init Vault cluster", "err", err) + } + // Store the RootToken and set the client to use it so it can Unseal and finish bootstrapping. + v.rootToken = initResp.RootToken + v.vaultClient.SetToken(v.rootToken) + + // Unseal the Vault Cluster using the Unseal Keys from Init(). + sealResp, err := v.vaultClient.Sys().Unseal(initResp.KeysB64[0]) + if err != nil { + t.Fatal("unable to unseal Vault cluster", "err", err) + } + require.Equal(t, false, sealResp.Sealed) + + // Enable the KV-V2 Secrets engine + err = v.vaultClient.Sys().Mount("consul", &vapi.MountInput{ + Type: "kv-v2", + Config: vapi.MountConfigInput{}, + }) + if err != nil { + t.Fatal("unable to mount kv-v2 secrets engine", "err", err) + } + // TODO: Enable the PKI Secrets Engine + + // Enable Kube Auth. + err = v.vaultClient.Sys().EnableAuthWithOptions("kubernetes", &vapi.EnableAuthOptions{ + Type: "kubernetes", + Config: vapi.MountConfigInput{}, + }) + if err != nil { + t.Fatal("unable to enable kube auth", "err", err) + } + // We need to kubectl exec this one on the vault server: + // This is taken from https://learn.hashicorp.com/tutorials/vault/kubernetes-google-cloud-gke?in=vault/kubernetes#configure-kubernetes-authentication + cmdString := fmt.Sprintf("VAULT_TOKEN=%s vault write auth/kubernetes/config token_reviewer_jwt=\"$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\" kubernetes_host=\"https://${KUBERNETES_PORT_443_TCP_ADDR}:443\" kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", v.rootToken) + + v.logger.Logf(t, "updating vault kube auth config") + // TODO: figure out if this sleep can be done differently. + time.Sleep(time.Second * 30) + k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "-i", fmt.Sprintf("%s-vault-0", v.vaultReleaseName), "--", "sh", "-c", cmdString) + + // Create an access policy for Secrets Management, so we can create them later + /* + // TODO: Do we need this policy, because we will have to have root token (or some other priv'd) in our client + // TODO: already in order to create policies and roles. + devpolicyRule := `{ "policy": "path "consul/data/*" { capabilities = ["create", "update", "read"] } }` + err = v.vaultClient.Sys().PutPolicy("dev-root-policy", devpolicyRule) + if err != nil { + t.Fatal("unable to create secret mgmt policy", "err", err) + } + */ +} + +// Create installs Vault via Helm. +func (v *VaultCluster) Create(t *testing.T) { + t.Helper() + + // Make sure we delete the cluster if we receive an interrupt signal and + // register cleanup so that we delete the cluster when test finishes. + helpers.Cleanup(t, v.noCleanupOnFailure, func() { + v.Destroy(t) + }) + + // Fail if there are any existing installations of the Helm chart. + v.checkForPriorVaultInstallations(t) + + // step 1: install Vault + helm.Install(t, v.vaultHelmOptions, "hashicorp/vault", v.vaultReleaseName) + // Wait for the injector pod to become Ready. + helpers.WaitForAllPodsToBeReady(t, v.kubernetesClient, v.vaultHelmOptions.KubectlOptions.Namespace, fmt.Sprintf("app.kubernetes.io/name=vault-agent-injector")) + // Wait for the Server Pod to be online, it will not be Ready because it has not been Init+Unseal'd yet, this is done + // in the Bootstrap method. + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 30}, t, func(r *retry.R) { + pod, err := v.kubernetesClient.CoreV1().Pods(v.vaultHelmOptions.KubectlOptions.Namespace).Get(context.Background(), fmt.Sprintf("%s-vault-0", v.vaultReleaseName), metav1.GetOptions{}) + require.NoError(r, err) + require.Equal(r, pod.Status.Phase, corev1.PodRunning) + }) + +} + +func (v *VaultCluster) Destroy(t *testing.T) { + t.Helper() + + k8s.WritePodsDebugInfoIfFailed(t, v.kubectlOptions, v.debugDirectory, "release="+v.vaultReleaseName) + + // Ignore the error returned by the helm delete here so that we can + // always idempotently clean up resources in the cluster. + _ = helm.DeleteE(t, v.vaultHelmOptions, v.vaultReleaseName, false) + // Delete PVCs. + err := v.kubernetesClient.CoreV1().PersistentVolumeClaims(v.vaultHelmOptions.KubectlOptions.Namespace).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: fmt.Sprintf("app.kubernetes.io/instance==data-%s-vault-0", v.vaultReleaseName)}) + require.NoError(t, err) + + // Delete any secrets that have v.releaseName in their name. + secrets, err := v.kubernetesClient.CoreV1().Secrets(v.vaultHelmOptions.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + for _, secret := range secrets.Items { + if strings.Contains(secret.Name, v.vaultReleaseName) { + err := v.kubernetesClient.CoreV1().Secrets(v.vaultHelmOptions.KubectlOptions.Namespace).Delete(context.Background(), secret.Name, metav1.DeleteOptions{}) + if !errors.IsNotFound(err) { + require.NoError(t, err) + } + } + } +} + +func defaultVaultValues() map[string]string { + values := map[string]string{ + "server.replicas": "1", + "server.bootstrapExpect": "1", + //"ui.enabled": "true", + "injector.enabled": "true", + "global.enabled": "true", + } + return values +} diff --git a/acceptance/go.mod b/acceptance/go.mod index 5e017ccec6..0802e05d35 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -6,7 +6,8 @@ require ( github.com/gruntwork-io/terratest v0.31.2 github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf github.com/hashicorp/consul/sdk v0.8.0 - github.com/stretchr/testify v1.5.1 + github.com/hashicorp/vault/api v1.2.0 + github.com/stretchr/testify v1.7.0 gopkg.in/yaml.v2 v2.2.8 k8s.io/api v0.19.3 k8s.io/apimachinery v0.19.3 diff --git a/acceptance/go.sum b/acceptance/go.sum index ab20eec364..38c12fdd82 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -1,3 +1,4 @@ +bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -48,38 +49,65 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= +github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= +github.com/armon/go-metrics v0.3.3 h1:a9F4rlj7EWWrbj7BYw8J8+x+ZZkJeqzNyRk8hdPF+ro= +github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.27.1 h1:MXnqY6SlWySaZAqNnXThOvjRFdiiOuKtC6i7baFdNdU= +github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.30.27 h1:9gPjZWVDSoQrBO2AvqrWObS6KAZByfEJxQoCYo4ZfK0= +github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= +github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/containerd v1.3.4/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/containerd/continuity v0.0.0-20200709052629-daa8e1ccc0bc/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo= +github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI= +github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= +github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= +github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= @@ -95,6 +123,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -107,6 +136,7 @@ github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20200319182547-c7ad2b866182/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -124,7 +154,9 @@ github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy0 github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= @@ -132,18 +164,28 @@ github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= +github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= +github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 h1:skJKxRtNmevLqnayafdLe2AsenqRupVmzZSqrvb5caU= github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8= +github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= @@ -158,9 +200,14 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8 github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -186,14 +233,18 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -215,6 +266,7 @@ github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyyc github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -230,31 +282,57 @@ github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf/go.mod h1: github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc= +github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= 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-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE= +github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= +github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= +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= +github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 h1:78ki3QBevHwYrVxnyVeaEz+7WtifHhauYF23es/0KlI= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 h1:nd0HIW15E6FG1MsnArYaHfuw9C2zgzM8LxkG5Ty/788= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= @@ -262,6 +340,14 @@ github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5 h1:EBWvyu9tcRszt3Bxp3KNssBMP1KuHWyO51lz9+786iM= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f/go.mod h1:euTFbi2YJgwcju3imEt919lhJKF68nN1cQPq3aA+kBE= +github.com/hashicorp/vault/api v1.2.0 h1:ysGFc6XRGbv05NsWPzuO5VTv68Lj8jtwATxRLFOpP9s= +github.com/hashicorp/vault/api v1.2.0/go.mod h1:dAjw0T5shMnrfH7Q/Mst+LrcTKvStZBVs1PICEDpUqY= +github.com/hashicorp/vault/sdk v0.1.14-0.20200519221530-14615acda45f/go.mod h1:WX57W2PwkrOPQ6rVQk+dy5/htHIaB4aBM70EwKThu10= +github.com/hashicorp/vault/sdk v0.2.1 h1:S4O6Iv/dyKlE9AUTXGa7VOvZmsCvg36toPKgV4f2P4M= +github.com/hashicorp/vault/sdk v0.2.1/go.mod h1:WfUiO1vYzfBkz1TmoE4ZGU7HD0T0Cl/rZwaxjBkgN4U= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -270,14 +356,16 @@ github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= +github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -290,12 +378,14 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -321,14 +411,24 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= +github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -341,6 +441,8 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -352,14 +454,24 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= +github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= +github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -372,13 +484,21 @@ github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prY github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= @@ -389,12 +509,16 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= @@ -402,10 +526,12 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -419,10 +545,13 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= @@ -437,13 +566,17 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -451,6 +584,7 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -468,6 +602,8 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -480,6 +616,7 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -496,9 +633,12 @@ golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -521,19 +661,23 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -543,11 +687,15 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -557,8 +705,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -575,6 +724,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -582,10 +732,12 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200113040837-eac381796e91 h1:OOkytthzFBKHY5EfEgLUabprb0LtJVkQtNxAQ02+UE4= golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -615,15 +767,21 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98 google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -632,8 +790,10 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -644,11 +804,15 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= @@ -656,9 +820,13 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/acceptance/tests/vault/main_test.go b/acceptance/tests/vault/main_test.go new file mode 100644 index 0000000000..1d3a5a5842 --- /dev/null +++ b/acceptance/tests/vault/main_test.go @@ -0,0 +1,15 @@ +package vault + +import ( + "os" + "testing" + + testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" +) + +var suite testsuite.Suite + +func TestMain(m *testing.M) { + suite = testsuite.NewSuite(m) + os.Exit(suite.Run()) +} diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go new file mode 100644 index 0000000000..4ee68fbb1f --- /dev/null +++ b/acceptance/tests/vault/vault_test.go @@ -0,0 +1,133 @@ +package vault + +import ( + "testing" + + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/vault" + "github.com/stretchr/testify/require" +) + +// Installs Vault, bootstraps it with the kube auth method +// and then validates that the KV2 secrets engine is online +// and the Kube Auth Method is enabled. +func TestVault_Bootstrap(t *testing.T) { + cfg := suite.Config() + ctx := suite.Environment().DefaultContext(t) + + vaultReleaseName := helpers.RandomName() + vaultCluster := vault.NewHelmCluster(t, nil, ctx, cfg, vaultReleaseName) + vaultCluster.Create(t) + vaultCluster.Bootstrap(t, ctx) + logger.Log(t, "Finished Bootstrap") + + vaultClient := vaultCluster.VaultClient(t) + + // Write to the KV2 engine succeeds + logger.Log(t, "Creating a KV2 Secret") + params := map[string]interface{}{ + "data": map[string]interface{}{ + "test": "ABCD1234", + }, + } + _, err := vaultClient.Logical().Write("consul/data/secret/test", params) + require.NoError(t, err) + + // Auth Methods exists + authList, err := vaultClient.Sys().ListAuth() + require.NoError(t, err) + logger.Log(t, "Auth List: ", authList) + require.NotNil(t, authList["kubernetes/"]) +} + +/* +// Installs Vault, bootstraps it with secrets, policies, and kube auth method +// then creates a gossip encryption secret and uses this to bootstrap Consul +func TestVaultConsulGossipEncryptionKeyIntegration(t *testing.T) { + cfg := suite.Config() + ctx := suite.Environment().DefaultContext(t) + + vaultReleaseName := helpers.RandomName() + logger.Log(t, "Entering NewHelmCluster") + vaultCluster := vault.NewHelmCluster(t, nil, ctx, cfg, vaultReleaseName) + logger.Log(t, "Entering Create") + vaultCluster.Create(t) + // Vault is now installed in the cluster + + logger.Log(t, "Entering Bootstrap") + vaultCluster.Bootstrap(t, ctx) + logger.Log(t, "Finished Bootstrap") + + vaultClient := vaultCluster.VaultClient(t) + + logger.Log(t, "Creating the policies and secrets") + + var err error + // Create the Vault Policy for the gossip key + logger.Log(t, "Creating the gossip policy") + rules := ` +path "consul/data/secret/gossip" { + capabilities = ["read"] +}` + err = vaultClient.Sys().PutPolicy("consul-gossip", rules) + require.NoError(t, err) + + // create the auth roles for consul-server + consul-client + logger.Log(t, "Creating the gossip auth roles") + params := map[string]interface{}{ + "bound_service_account_names": "consul-consul-client", + "bound_service_account_namespaces": "default", + "policies": "consul-gossip", + "ttl": "24h", + } + _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-client", params) + require.NoError(t, err) + + params = map[string]interface{}{ + "bound_service_account_names": "consul-consul-server", + "bound_service_account_namespaces": "default", + "policies": "consul-gossip", + "ttl": "24h", + } + _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-server", params) + require.NoError(t, err) + + // Create the gossip key + logger.Log(t, "Creating the gossip secret") + params = map[string]interface{}{ + "data": map[string]interface{}{ + "gossip": "3R7oLrdpkk2V0Y7yHLizyxXeS2RtaVuy07DkU15Lhws=", + }, + } + _, err = vaultClient.Logical().Write("consul/data/secret/gossip", params) + require.NoError(t, err) + + time.Sleep(time.Second * 30) + + consulHelmValues := map[string]string{ + "server.enabled": "true", + "server.replicas": "1", + "global.imageK8S": "kschoche/consul-k8s-hashiconf", + + "connectInject.enabled": "true", + + "secretsBackend.vault.enabled": "true", + "secretsBackend.vault.consulServerRole": "consul-server", + "secretsBackend.vault.consulclientRole": "consul-client", + + "global.tls.enabled": "true", + "global.gossipEncryption.secretName": "consul/data/secret/gossip", + "global.gossipEncryption.secretKey": ".Data.data.gossip", + } + // TODO: consul-release name needs to be integrated into all of the secret names and policies above + consulReleaseName := "consul" //helpers.RandomName() + logger.Log(t, "Installing Consul") + consulCluster := consul.NewHelmCluster(t, consulHelmValues, ctx, cfg, consulReleaseName) + + consulCluster.Create(t) + + time.Sleep(time.Second * 600) + +} +*/ From 8171ec55ef60ca50289ce2cd751cf02afe28f080 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Wed, 20 Oct 2021 21:23:21 -0500 Subject: [PATCH 084/418] test --- acceptance/framework/vault/vault_cluster.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index e582eabf34..b5731bcb9b 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -264,7 +264,7 @@ func (v *VaultCluster) Create(t *testing.T) { // step 1: install Vault helm.Install(t, v.vaultHelmOptions, "hashicorp/vault", v.vaultReleaseName) // Wait for the injector pod to become Ready. - helpers.WaitForAllPodsToBeReady(t, v.kubernetesClient, v.vaultHelmOptions.KubectlOptions.Namespace, fmt.Sprintf("app.kubernetes.io/name=vault-agent-injector")) + helpers.WaitForAllPodsToBeReady(t, v.kubernetesClient, v.vaultHelmOptions.KubectlOptions.Namespace, "app.kubernetes.io/name=vault-agent-injector") // Wait for the Server Pod to be online, it will not be Ready because it has not been Init+Unseal'd yet, this is done // in the Bootstrap method. retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 30}, t, func(r *retry.R) { From 3ba20ec8ec4480dd1e77d12bcdd0769d4ac7199d Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Wed, 20 Oct 2021 22:07:32 -0500 Subject: [PATCH 085/418] change something --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index a592052168..cd6a53cda0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -50,6 +50,7 @@ commands: wget https://get.helm.sh/helm-v3.7.0-linux-amd64.tar.gz tar -zxvf helm-v3.7.0-linux-amd64.tar.gz sudo mv linux-amd64/helm /usr/local/bin/helm + /usr/local/bin/helm repo add hashicorp https://helm.releases.hashicorp.com create-kind-clusters: parameters: From 3a0f5a3c4e34a9f9cc60fad7e00a4eafca123d35 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Thu, 21 Oct 2021 10:54:48 -0500 Subject: [PATCH 086/418] clean this up --- acceptance/framework/vault/vault_cluster.go | 71 +++++++-------- acceptance/tests/vault/vault_test.go | 99 +-------------------- 2 files changed, 37 insertions(+), 133 deletions(-) diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index b5731bcb9b..7f02ee1dbe 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" "fmt" - corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" "strings" "testing" "time" @@ -18,20 +18,31 @@ import ( "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/sdk/testutil/retry" - "k8s.io/apimachinery/pkg/api/errors" - // https://github.com/hashicorp/vault-examples/tree/main/go vapi "github.com/hashicorp/vault/api" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) -// Cluster represents a consul cluster object +// Cluster represents a vault cluster object, it is modeled off of the consul_cluster implementation and will +// provide thea ability to rapidly install and bootrstap a vault cluster so that end-to-end testing may be done. type Cluster interface { + // Create will install a vault cluster via helm using the default config defined at the end of this file. Create(t *testing.T) + + // Bootstrap will execute the Init(), Unseal() process and bootstrap the vault cluster by enabling the KV2 secret + // engine and also enabling the Kube Auth Method. Bootstrap(t *testing.T, ctx environment.TestContext) + + // Destroy will do a helm uninstall of the Vault installation and then delete the data PVC used by Vault. Destroy(t *testing.T) + + // SetupVaultClient will setup the port-forwarding to the Vault server so that we can create a vault client connection. + // This is run as part of Bootstrap. SetupVaultClient(t *testing.T) *vapi.Client + + // VaultClient returns the client that was built as part of SetupVaultClient. VaultClient(t *testing.T) *vapi.Client } @@ -97,6 +108,7 @@ func NewHelmCluster( } } +// VaultClient returns the vault client. func (v *VaultCluster) VaultClient(t *testing.T) *vapi.Client { return v.vaultClient } // checkForPriorInstallations checks if there is an existing Helm release @@ -125,22 +137,19 @@ func (v *VaultCluster) checkForPriorVaultInstallations(t *testing.T) { for _, r := range installedReleases { require.NotContains(t, r["chart"], "vault", fmt.Sprintf("detected an existing installation of Vault %s, release name: %s", r["chart"], r["name"])) } - /* - // TODO: Copied this from Consul Cluster implementation, is this necessary for vault? - // Wait for all pods in the "default" namespace to exit. A previous - // release may not be listed by Helm but its pods may still be terminating. - retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { - consulPods, err := v.kubernetesClient.CoreV1().Pods(v.vaultHelmOptions.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) - require.NoError(r, err) - if len(consulPods.Items) > 0 { - var podNames []string - for _, p := range consulPods.Items { - podNames = append(podNames, p.Name) - } - r.Errorf("pods from previous installation still running: %s", strings.Join(podNames, ", ")) + // Wait for all pods in the "default" namespace to exit. A previous + // release may not be listed by Helm but its pods may still be terminating. + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { + vaultPods, err := v.kubernetesClient.CoreV1().Pods(v.vaultHelmOptions.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) + require.NoError(r, err) + if len(vaultPods.Items) > 0 { + var podNames []string + for _, p := range vaultPods.Items { + podNames = append(podNames, p.Name) } - }) - */ + r.Errorf("pods from previous installation still running: %s", strings.Join(podNames, ", ")) + } + }) } // Setup Vault Client returns a Vault Client. @@ -174,10 +183,9 @@ func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { }) config.Address = fmt.Sprintf("http://127.0.0.1:%d", localPort) - consulClient, err := vapi.NewClient(config) + vaultClient, err := vapi.NewClient(config) require.NoError(t, err) - - return consulClient + return vaultClient } // Bootstrap runs Init, Unseals the Vault installation @@ -217,7 +225,7 @@ func (v *VaultCluster) Bootstrap(t *testing.T, ctx environment.TestContext) { if err != nil { t.Fatal("unable to mount kv-v2 secrets engine", "err", err) } - // TODO: Enable the PKI Secrets Engine + // TODO: add the PKI Secrets Engine when we have a need for it. // Enable Kube Auth. err = v.vaultClient.Sys().EnableAuthWithOptions("kubernetes", &vapi.EnableAuthOptions{ @@ -232,20 +240,7 @@ func (v *VaultCluster) Bootstrap(t *testing.T, ctx environment.TestContext) { cmdString := fmt.Sprintf("VAULT_TOKEN=%s vault write auth/kubernetes/config token_reviewer_jwt=\"$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\" kubernetes_host=\"https://${KUBERNETES_PORT_443_TCP_ADDR}:443\" kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", v.rootToken) v.logger.Logf(t, "updating vault kube auth config") - // TODO: figure out if this sleep can be done differently. - time.Sleep(time.Second * 30) k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "-i", fmt.Sprintf("%s-vault-0", v.vaultReleaseName), "--", "sh", "-c", cmdString) - - // Create an access policy for Secrets Management, so we can create them later - /* - // TODO: Do we need this policy, because we will have to have root token (or some other priv'd) in our client - // TODO: already in order to create policies and roles. - devpolicyRule := `{ "policy": "path "consul/data/*" { capabilities = ["create", "update", "read"] } }` - err = v.vaultClient.Sys().PutPolicy("dev-root-policy", devpolicyRule) - if err != nil { - t.Fatal("unable to create secret mgmt policy", "err", err) - } - */ } // Create installs Vault via Helm. @@ -284,10 +279,10 @@ func (v *VaultCluster) Destroy(t *testing.T) { // always idempotently clean up resources in the cluster. _ = helm.DeleteE(t, v.vaultHelmOptions, v.vaultReleaseName, false) // Delete PVCs. - err := v.kubernetesClient.CoreV1().PersistentVolumeClaims(v.vaultHelmOptions.KubectlOptions.Namespace).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: fmt.Sprintf("app.kubernetes.io/instance==data-%s-vault-0", v.vaultReleaseName)}) + err := v.kubernetesClient.CoreV1().PersistentVolumeClaims(v.vaultHelmOptions.KubectlOptions.Namespace).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: fmt.Sprintf("app.kubernetes.io/instance=%s", v.vaultReleaseName)}) require.NoError(t, err) - // Delete any secrets that have v.releaseName in their name. + // Delete any secrets that have v.releaseName in their name, this is only needed to delete the Helm release secret. secrets, err := v.kubernetesClient.CoreV1().Secrets(v.vaultHelmOptions.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) require.NoError(t, err) for _, secret := range secrets.Items { diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 4ee68fbb1f..a6d7ce4154 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -12,7 +12,7 @@ import ( // Installs Vault, bootstraps it with the kube auth method // and then validates that the KV2 secrets engine is online // and the Kube Auth Method is enabled. -func TestVault_Bootstrap(t *testing.T) { +func TestVault_CreateAndBootstrap(t *testing.T) { cfg := suite.Config() ctx := suite.Environment().DefaultContext(t) @@ -24,110 +24,19 @@ func TestVault_Bootstrap(t *testing.T) { vaultClient := vaultCluster.VaultClient(t) - // Write to the KV2 engine succeeds + // Write to the KV2 engine succeeds. logger.Log(t, "Creating a KV2 Secret") params := map[string]interface{}{ "data": map[string]interface{}{ - "test": "ABCD1234", + "foo": "bar", }, } _, err := vaultClient.Logical().Write("consul/data/secret/test", params) require.NoError(t, err) - // Auth Methods exists + // Validate that the Auth Methods exist. authList, err := vaultClient.Sys().ListAuth() require.NoError(t, err) logger.Log(t, "Auth List: ", authList) require.NotNil(t, authList["kubernetes/"]) } - -/* -// Installs Vault, bootstraps it with secrets, policies, and kube auth method -// then creates a gossip encryption secret and uses this to bootstrap Consul -func TestVaultConsulGossipEncryptionKeyIntegration(t *testing.T) { - cfg := suite.Config() - ctx := suite.Environment().DefaultContext(t) - - vaultReleaseName := helpers.RandomName() - logger.Log(t, "Entering NewHelmCluster") - vaultCluster := vault.NewHelmCluster(t, nil, ctx, cfg, vaultReleaseName) - logger.Log(t, "Entering Create") - vaultCluster.Create(t) - // Vault is now installed in the cluster - - logger.Log(t, "Entering Bootstrap") - vaultCluster.Bootstrap(t, ctx) - logger.Log(t, "Finished Bootstrap") - - vaultClient := vaultCluster.VaultClient(t) - - logger.Log(t, "Creating the policies and secrets") - - var err error - // Create the Vault Policy for the gossip key - logger.Log(t, "Creating the gossip policy") - rules := ` -path "consul/data/secret/gossip" { - capabilities = ["read"] -}` - err = vaultClient.Sys().PutPolicy("consul-gossip", rules) - require.NoError(t, err) - - // create the auth roles for consul-server + consul-client - logger.Log(t, "Creating the gossip auth roles") - params := map[string]interface{}{ - "bound_service_account_names": "consul-consul-client", - "bound_service_account_namespaces": "default", - "policies": "consul-gossip", - "ttl": "24h", - } - _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-client", params) - require.NoError(t, err) - - params = map[string]interface{}{ - "bound_service_account_names": "consul-consul-server", - "bound_service_account_namespaces": "default", - "policies": "consul-gossip", - "ttl": "24h", - } - _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-server", params) - require.NoError(t, err) - - // Create the gossip key - logger.Log(t, "Creating the gossip secret") - params = map[string]interface{}{ - "data": map[string]interface{}{ - "gossip": "3R7oLrdpkk2V0Y7yHLizyxXeS2RtaVuy07DkU15Lhws=", - }, - } - _, err = vaultClient.Logical().Write("consul/data/secret/gossip", params) - require.NoError(t, err) - - time.Sleep(time.Second * 30) - - consulHelmValues := map[string]string{ - "server.enabled": "true", - "server.replicas": "1", - "global.imageK8S": "kschoche/consul-k8s-hashiconf", - - "connectInject.enabled": "true", - - "secretsBackend.vault.enabled": "true", - "secretsBackend.vault.consulServerRole": "consul-server", - "secretsBackend.vault.consulclientRole": "consul-client", - - "global.tls.enabled": "true", - "global.gossipEncryption.secretName": "consul/data/secret/gossip", - "global.gossipEncryption.secretKey": ".Data.data.gossip", - } - // TODO: consul-release name needs to be integrated into all of the secret names and policies above - consulReleaseName := "consul" //helpers.RandomName() - logger.Log(t, "Installing Consul") - consulCluster := consul.NewHelmCluster(t, consulHelmValues, ctx, cfg, consulReleaseName) - - consulCluster.Create(t) - - time.Sleep(time.Second * 600) - -} -*/ From 08daf431f5ba3fb1b957e4f53eed9c654180fdd3 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Thu, 21 Oct 2021 11:50:58 -0500 Subject: [PATCH 087/418] remove interface and make bootstrap part of Create --- acceptance/framework/vault/vault_cluster.go | 39 +++++++++++---------- acceptance/tests/vault/vault_test.go | 9 +++-- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index 7f02ee1dbe..2460edc515 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "k8s.io/apimachinery/pkg/api/errors" "strings" "testing" "time" @@ -21,21 +20,24 @@ import ( vapi "github.com/hashicorp/vault/api" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) -// Cluster represents a vault cluster object, it is modeled off of the consul_cluster implementation and will -// provide thea ability to rapidly install and bootrstap a vault cluster so that end-to-end testing may be done. -type Cluster interface { - // Create will install a vault cluster via helm using the default config defined at the end of this file. - Create(t *testing.T) +/* + // High level description of the functions implemented for the VaultCluster object: + + // Create will install a vault cluster via helm using the default config defined at the end of this file. It will + // then also call bootstrap() to setup the vault cluster for testing. + Create(t *testing.T, ctx environment.TestContext) - // Bootstrap will execute the Init(), Unseal() process and bootstrap the vault cluster by enabling the KV2 secret + // bootstrap will execute the Init(), Unseal() process and bootstrap the vault cluster by enabling the KV2 secret // engine and also enabling the Kube Auth Method. - Bootstrap(t *testing.T, ctx environment.TestContext) + bootstrap(t *testing.T, ctx environment.TestContext) - // Destroy will do a helm uninstall of the Vault installation and then delete the data PVC used by Vault. + // Destroy will do a helm uninstall of the Vault installation and then delete the data PVC used by Vault and the + // helm secrets. Destroy(t *testing.T) // SetupVaultClient will setup the port-forwarding to the Vault server so that we can create a vault client connection. @@ -44,7 +46,7 @@ type Cluster interface { // VaultClient returns the client that was built as part of SetupVaultClient. VaultClient(t *testing.T) *vapi.Client -} +*/ const ( vaultNS = "default" @@ -72,14 +74,14 @@ type VaultCluster struct { logger terratestLogger.TestLogger } -// NewHelmCluster installs Vault into Kubernetes using Helm. -func NewHelmCluster( +// NewVaultCluster creates a VaultCluster which will be used to install Vault using Helm. +func NewVaultCluster( t *testing.T, helmValues map[string]string, ctx environment.TestContext, cfg *config.TestConfig, releaseName string, -) Cluster { +) *VaultCluster { logger := terratestLogger.New(logger.TestLogger{}) @@ -188,9 +190,9 @@ func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { return vaultClient } -// Bootstrap runs Init, Unseals the Vault installation +// bootstrap runs Init, Unseals the Vault installation // and then does the setup of Auth Methods and Enables Secrets Engines. -func (v *VaultCluster) Bootstrap(t *testing.T, ctx environment.TestContext) { +func (v *VaultCluster) bootstrap(t *testing.T, ctx environment.TestContext) { v.vaultClient = v.SetupVaultClient(t) @@ -243,8 +245,8 @@ func (v *VaultCluster) Bootstrap(t *testing.T, ctx environment.TestContext) { k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "-i", fmt.Sprintf("%s-vault-0", v.vaultReleaseName), "--", "sh", "-c", cmdString) } -// Create installs Vault via Helm. -func (v *VaultCluster) Create(t *testing.T) { +// Create installs Vault via Helm and then calls bootstrap to initialize it. +func (v *VaultCluster) Create(t *testing.T, ctx environment.TestContext) { t.Helper() // Make sure we delete the cluster if we receive an interrupt signal and @@ -267,7 +269,8 @@ func (v *VaultCluster) Create(t *testing.T) { require.NoError(r, err) require.Equal(r, pod.Status.Phase, corev1.PodRunning) }) - + // Now call bootstrap() + v.bootstrap(t, ctx) } func (v *VaultCluster) Destroy(t *testing.T) { diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index a6d7ce4154..6d58c7365c 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -12,15 +12,14 @@ import ( // Installs Vault, bootstraps it with the kube auth method // and then validates that the KV2 secrets engine is online // and the Kube Auth Method is enabled. -func TestVault_CreateAndBootstrap(t *testing.T) { +func TestVault_Create(t *testing.T) { cfg := suite.Config() ctx := suite.Environment().DefaultContext(t) vaultReleaseName := helpers.RandomName() - vaultCluster := vault.NewHelmCluster(t, nil, ctx, cfg, vaultReleaseName) - vaultCluster.Create(t) - vaultCluster.Bootstrap(t, ctx) - logger.Log(t, "Finished Bootstrap") + vaultCluster := vault.NewVaultCluster(t, nil, ctx, cfg, vaultReleaseName) + vaultCluster.Create(t, ctx) + logger.Log(t, "Finished Installing and Bootstrapping") vaultClient := vaultCluster.VaultClient(t) From 039542f583cece545c9181119d66a68666dd7030 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Thu, 21 Oct 2021 13:10:32 -0600 Subject: [PATCH 088/418] Enable trace logs for Consul in acceptance tests (#800) --- acceptance/framework/consul/consul_cluster.go | 4 ++++ acceptance/framework/consul/consul_cluster_test.go | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/acceptance/framework/consul/consul_cluster.go b/acceptance/framework/consul/consul_cluster.go index b1e8f8d9e2..d34024b865 100644 --- a/acceptance/framework/consul/consul_cluster.go +++ b/acceptance/framework/consul/consul_cluster.go @@ -509,6 +509,10 @@ func defaultValues() map[string]string { // which could result in tests passing due to that token having privileges to read services // (false positive). "dns.enabled": "false", + + // Enable trace logs for servers and clients. + "server.extraConfig": `"{\"log_level\": \"TRACE\"}"`, + "client.extraConfig": `"{\"log_level\": \"TRACE\"}"`, } return values } diff --git a/acceptance/framework/consul/consul_cluster_test.go b/acceptance/framework/consul/consul_cluster_test.go index f427969ef3..1a9ac604db 100644 --- a/acceptance/framework/consul/consul_cluster_test.go +++ b/acceptance/framework/consul/consul_cluster_test.go @@ -30,6 +30,8 @@ func TestNewHelmCluster(t *testing.T) { "connectInject.logLevel": "debug", "connectInject.transparentProxy.defaultEnabled": "false", "dns.enabled": "false", + "server.extraConfig": `"{\"log_level\": \"TRACE\"}"`, + "client.extraConfig": `"{\"log_level\": \"TRACE\"}"`, }, }, { @@ -42,6 +44,8 @@ func TestNewHelmCluster(t *testing.T) { "connectInject.logLevel": "debug", "connectInject.transparentProxy.defaultEnabled": "true", "dns.enabled": "true", + "server.extraConfig": `"{\"foo\": \"bar\"}"`, + "client.extraConfig": `"{\"foo\": \"bar\"}"`, "feature.enabled": "true", }, want: map[string]string{ @@ -52,6 +56,8 @@ func TestNewHelmCluster(t *testing.T) { "connectInject.logLevel": "debug", "connectInject.transparentProxy.defaultEnabled": "true", "dns.enabled": "true", + "server.extraConfig": `"{\"foo\": \"bar\"}"`, + "client.extraConfig": `"{\"foo\": \"bar\"}"`, "feature.enabled": "true", }, }, From a185c0acfc3ded69238cc73f651fe07adc8ebc71 Mon Sep 17 00:00:00 2001 From: Saad Jamal <85898851+sadjamz@users.noreply.github.com> Date: Mon, 25 Oct 2021 16:09:29 -0700 Subject: [PATCH 089/418] cli: status command (#768) Finished status command, resolved git issues. Co-authored-by: Nitya Dhanushkodi --- CHANGELOG.md | 2 + cli/cmd/common/utils.go | 34 ++++ cli/cmd/install/install.go | 47 +----- cli/cmd/status/status.go | 287 +++++++++++++++++++++++++++++++++ cli/cmd/status/status_test.go | 186 +++++++++++++++++++++ cli/cmd/uninstall/uninstall.go | 46 ++---- cli/commands.go | 6 + 7 files changed, 532 insertions(+), 76 deletions(-) create mode 100644 cli/cmd/status/status.go create mode 100644 cli/cmd/status/status_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 6927e3433b..aa4e981474 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ IMPROVEMENTS: * Helm Chart * Automatic retry for `gossip-encryption-autogenerate-job` on failure [[GH-789](https://github.com/hashicorp/consul-k8s/pull/789)] +* CLI + * Add `status` command. [[GH-768](https://github.com/hashicorp/consul-k8s/pull/768)] ## 0.35.0 (October 19, 2021) diff --git a/cli/cmd/common/utils.go b/cli/cmd/common/utils.go index a6bafdbc00..f7c0b7eb34 100644 --- a/cli/cmd/common/utils.go +++ b/cli/cmd/common/utils.go @@ -2,6 +2,7 @@ package common import ( "embed" + "errors" "fmt" "os" "path/filepath" @@ -95,3 +96,36 @@ func InitActionConfig(actionConfig *action.Configuration, namespace string, sett } return actionConfig, nil } + +// CheckForPreviousInstallations uses the helm Go SDK to find helm releases in all namespaces where the chart name is +// "consul", and returns the release name and namespace if found, or an error if not found. +func CheckForInstallations(settings *helmCLI.EnvSettings, uiLogger action.DebugLog) (string, string, error) { + // Need a specific action config to call helm list, where namespace is NOT specified. + listConfig := new(action.Configuration) + if err := listConfig.Init(settings.RESTClientGetter(), "", + os.Getenv("HELM_DRIVER"), uiLogger); err != nil { + return "", "", fmt.Errorf("couldn't initialize helm config: %s", err) + } + + lister := action.NewList(listConfig) + lister.AllNamespaces = true + lister.StateMask = action.ListAll + res, err := lister.Run() + if err != nil { + return "", "", fmt.Errorf("couldn't check for installations: %s", err) + } + + for _, rel := range res { + if rel.Chart.Metadata.Name == "consul" { + return rel.Name, rel.Namespace, nil + } + } + return "", "", errors.New("couldn't find consul installation") +} + +func CloseWithError(c *BaseCommand) { + if err := c.Close(); err != nil { + c.Log.Error(err.Error()) + os.Exit(1) + } +} diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index 9b3f02e0e0..dbb481c0ea 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -169,12 +169,7 @@ func (c *Command) Run(args []string) int { // The logger is initialized in main with the name cli. Here, we reset the name to install so log lines would be prefixed with install. c.Log.ResetNamed("install") - defer func() { - if err := c.Close(); err != nil { - c.Log.Error(err.Error()) - os.Exit(1) - } - }() + defer common.CloseWithError(c.BaseCommand) if err := c.validateFlags(args); err != nil { c.UI.Output(err.Error()) @@ -218,9 +213,14 @@ func (c *Command) Run(args []string) int { c.UI.Output("Pre-Install Checks", terminal.WithHeaderStyle()) - if err := c.checkForPreviousInstallations(settings, uiLogger); err != nil { - c.UI.Output(err.Error(), terminal.WithErrorStyle()) + // Note the logic here, common's CheckForPreviousInstallations function returns an error if + // the release is not found, which in the install command is what we need for a successful install. + if name, ns, err := common.CheckForInstallations(settings, uiLogger); err == nil { + c.UI.Output(fmt.Sprintf("existing Consul installation found (name=%s, namespace=%s) - run "+ + "consul-k8s uninstall if you wish to re-install", name, ns), terminal.WithErrorStyle()) return 1 + } else { + c.UI.Output("No existing installations found.") } // Ensure there's no previous PVCs lying around. @@ -341,37 +341,6 @@ func (c *Command) Synopsis() string { return "Install Consul on Kubernetes." } -// checkForPreviousInstallations uses the helm Go SDK to find helm releases in all namespaces where the chart name is -// "consul", and returns an error if there is an existing installation. -// Note that this function is tricky to test because mocking out the action.Configuration struct requires a -// RegistryClient field that is from an internal helm package, so we are not unit testing it. -func (c *Command) checkForPreviousInstallations(settings *helmCLI.EnvSettings, uiLogger action.DebugLog) error { - // Need a specific action config to call helm list, where namespace is NOT specified. - listConfig := new(action.Configuration) - if err := listConfig.Init(settings.RESTClientGetter(), "", - os.Getenv("HELM_DRIVER"), uiLogger); err != nil { - return fmt.Errorf("couldn't initialize helm config: %s", err) - } - - lister := action.NewList(listConfig) - lister.AllNamespaces = true - res, err := lister.Run() - if err != nil { - return fmt.Errorf("couldn't check for installations: %s", err) - } - - for _, rel := range res { - if rel.Chart.Metadata.Name == "consul" { - // TODO: In the future the user will be prompted with our own uninstall command. - return fmt.Errorf("existing Consul installation found (name=%s, namespace=%s) - run helm "+ - "delete %s -n %s if you wish to re-install", - rel.Name, rel.Namespace, rel.Name, rel.Namespace) - } - } - c.UI.Output("No existing installations found", terminal.WithSuccessStyle()) - return nil -} - // checkForPreviousPVCs checks for existing PVCs with a name containing "consul-server" and returns an error and lists // the PVCs it finds matches. func (c *Command) checkForPreviousPVCs() error { diff --git a/cli/cmd/status/status.go b/cli/cmd/status/status.go new file mode 100644 index 0000000000..6d8e636b31 --- /dev/null +++ b/cli/cmd/status/status.go @@ -0,0 +1,287 @@ +package status + +import ( + "errors" + "fmt" + "strconv" + "sync" + + "helm.sh/helm/v3/pkg/release" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" + "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + "helm.sh/helm/v3/pkg/action" + helmCLI "helm.sh/helm/v3/pkg/cli" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/yaml" +) + +type Command struct { + *common.BaseCommand + + kubernetes kubernetes.Interface + + set *flag.Sets + + flagKubeConfig string + flagKubeContext string + + once sync.Once + help string +} + +func (c *Command) init() { + c.set = flag.NewSets() + + f := c.set.NewSet("Global Options") + f.StringVar(&flag.StringVar{ + Name: "kubeconfig", + Aliases: []string{"c"}, + Target: &c.flagKubeConfig, + Default: "", + Usage: "Path to kubeconfig file.", + }) + f.StringVar(&flag.StringVar{ + Name: "context", + Target: &c.flagKubeContext, + Default: "", + Usage: "Kubernetes context to use.", + }) + + c.help = c.set.Help() + + // c.Init() calls the embedded BaseCommand's initialization function. + c.Init() +} + +func (c *Command) Run(args []string) int { + c.once.Do(c.init) + + // The logger is initialized in main with the name cli. Here, we reset the name to status so log lines would be prefixed with status. + c.Log.ResetNamed("status") + + defer common.CloseWithError(c.BaseCommand) + + if err := c.set.Parse(args); err != nil { + c.UI.Output(err.Error()) + return 1 + } + + if err := c.validateFlags(args); err != nil { + c.UI.Output(err.Error()) + return 1 + } + + // helmCLI.New() will create a settings object which is used by the Helm Go SDK calls. + settings := helmCLI.New() + if c.flagKubeConfig != "" { + settings.KubeConfig = c.flagKubeConfig + } + if c.flagKubeContext != "" { + settings.KubeContext = c.flagKubeContext + } + + if err := c.setupKubeClient(settings); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // Setup logger to stream Helm library logs. + var uiLogger = func(s string, args ...interface{}) { + logMsg := fmt.Sprintf(s, args...) + c.UI.Output(logMsg, terminal.WithLibraryStyle()) + } + + c.UI.Output("Consul-K8s Status Summary", terminal.WithHeaderStyle()) + + releaseName, namespace, err := common.CheckForInstallations(settings, uiLogger) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if err := c.checkHelmInstallation(settings, uiLogger, releaseName, namespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if s, err := c.checkConsulServers(namespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } else { + c.UI.Output(s, terminal.WithSuccessStyle()) + } + + if s, err := c.checkConsulClients(namespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } else { + c.UI.Output(s, terminal.WithSuccessStyle()) + } + + return 0 +} + +// validateFlags is a helper function that performs checks on the user's provided flags. +func (c *Command) validateFlags(args []string) error { + if len(c.set.Args()) > 0 { + return errors.New("should have no non-flag arguments") + } + return nil +} + +// checkHelmInstallation uses the helm Go SDK to depict the status of a named release. This function then prints +// the version of the release, it's status (unknown, deployed, uninstalled, ...), and the overwritten values. +func (c *Command) checkHelmInstallation(settings *helmCLI.EnvSettings, uiLogger action.DebugLog, releaseName, namespace string) error { + // Need a specific action config to call helm status, where namespace comes from the previous call to list. + statusConfig := new(action.Configuration) + statusConfig, err := common.InitActionConfig(statusConfig, namespace, settings, uiLogger) + if err != nil { + return err + } + + statuser := action.NewStatus(statusConfig) + rel, err := statuser.Run(releaseName) + if err != nil { + return fmt.Errorf("couldn't check for installations: %s", err) + } + + timezone, _ := rel.Info.LastDeployed.Zone() + + tbl := terminal.NewTable([]string{"Name", "Namespace", "Status", "ChartVersion", "AppVersion", "Revision", "Last Updated"}...) + trow := []terminal.TableEntry{ + { + Value: releaseName, + }, + { + Value: namespace, + }, + { + Value: string(rel.Info.Status), + }, + { + Value: rel.Chart.Metadata.Version, + }, + { + Value: rel.Chart.Metadata.AppVersion, + }, + { + Value: strconv.Itoa(rel.Version), + }, + { + Value: rel.Info.LastDeployed.Format("2006/01/02 15:04:05") + " " + timezone, + }, + } + tbl.Rows = [][]terminal.TableEntry{} + tbl.Rows = append(tbl.Rows, trow) + + c.UI.Table(tbl) + + valuesYaml, err := yaml.Marshal(rel.Config) + c.UI.Output("Config:", terminal.WithHeaderStyle()) + if err != nil { + c.UI.Output("%+v", err, terminal.WithInfoStyle()) + } else if len(rel.Config) == 0 { + c.UI.Output(string(valuesYaml), terminal.WithInfoStyle()) + } else { + c.UI.Output(string(valuesYaml), terminal.WithInfoStyle()) + } + + // Check the status of the hooks. + if len(rel.Hooks) > 1 { + c.UI.Output("Status Of Helm Hooks:", terminal.WithHeaderStyle()) + + for _, hook := range rel.Hooks { + // Remember that we only report the status of pre-install or pre-upgrade hooks. + if validEvent(hook.Events) { + c.UI.Output("%s %s: %s", hook.Name, hook.Kind, hook.LastRun.Phase.String()) + } + } + fmt.Println("") + } + + return nil +} + +// validEvent is a helper function that checks if the given hook's events are pre-install or pre-upgrade. +// Only pre-install and pre-upgrade hooks are expected to have run when using the status command against +// a running installation. +func validEvent(events []release.HookEvent) bool { + for _, event := range events { + if event.String() == "pre-install" || event.String() == "pre-upgrade" { + return true + } + } + return false +} + +// checkConsulServers uses the Kubernetes list function to report if the consul servers are healthy. +func (c *Command) checkConsulServers(namespace string) (string, error) { + servers, err := c.kubernetes.AppsV1().StatefulSets(namespace).List(c.Ctx, + metav1.ListOptions{LabelSelector: "app=consul,chart=consul-helm,component=server"}) + if err != nil { + return "", err + } else if len(servers.Items) == 0 { + return "", errors.New("no server stateful set found") + } else if len(servers.Items) > 1 { + return "", errors.New("found multiple server stateful sets") + } + + desiredReplicas := int(*servers.Items[0].Spec.Replicas) + readyReplicas := int(servers.Items[0].Status.ReadyReplicas) + if readyReplicas < desiredReplicas { + return "", fmt.Errorf("%d/%d Consul servers unhealthy", desiredReplicas-readyReplicas, desiredReplicas) + } + return fmt.Sprintf("Consul servers healthy (%d/%d)", readyReplicas, desiredReplicas), nil +} + +// checkConsulClients uses the Kubernetes list function to report if the consul clients are healthy. +func (c *Command) checkConsulClients(namespace string) (string, error) { + clients, err := c.kubernetes.AppsV1().DaemonSets(namespace).List(c.Ctx, + metav1.ListOptions{LabelSelector: "app=consul,chart=consul-helm"}) + if err != nil { + return "", err + } else if len(clients.Items) == 0 { + return "", errors.New("no client daemon set found") + } else if len(clients.Items) > 1 { + return "", errors.New("found multiple client daemon sets") + } + desiredReplicas := int(clients.Items[0].Status.DesiredNumberScheduled) + readyReplicas := int(clients.Items[0].Status.NumberReady) + if readyReplicas < desiredReplicas { + return "", fmt.Errorf("%d/%d Consul clients unhealthy", desiredReplicas-readyReplicas, desiredReplicas) + } + return fmt.Sprintf("Consul clients healthy (%d/%d)", readyReplicas, desiredReplicas), nil +} + +// setupKubeClient to use for non Helm SDK calls to the Kubernetes API The Helm SDK will use +// settings.RESTClientGetter for its calls as well, so this will use a consistent method to +// target the right cluster for both Helm SDK and non Helm SDK calls. +func (c *Command) setupKubeClient(settings *helmCLI.EnvSettings) error { + if c.kubernetes == nil { + restConfig, err := settings.RESTClientGetter().ToRESTConfig() + if err != nil { + c.UI.Output("Retrieving Kubernetes auth: %v", err, terminal.WithErrorStyle()) + return err + } + c.kubernetes, err = kubernetes.NewForConfig(restConfig) + if err != nil { + c.UI.Output("Initializing Kubernetes client: %v", err, terminal.WithErrorStyle()) + return err + } + } + + return nil +} + +func (c *Command) Help() string { + c.once.Do(c.init) + s := "Usage: consul-k8s status" + "\n\n" + "Get the status of the current Consul installation." + "\n" + return s +} + +func (c *Command) Synopsis() string { + return "Status of Consul-K8s installation." +} diff --git a/cli/cmd/status/status_test.go b/cli/cmd/status/status_test.go new file mode 100644 index 0000000000..e369555143 --- /dev/null +++ b/cli/cmd/status/status_test.go @@ -0,0 +1,186 @@ +package status + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/require" + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" +) + +// TestCheckConsulServers creates a fake stateful set and tests the checkConsulServers function. +func TestCheckConsulServers(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + + // First check that no stateful sets causes an error. + _, err := c.checkConsulServers("default") + require.Error(t, err) + require.Contains(t, err.Error(), "no server stateful set found") + + // Next create a stateful set with 3 desired replicas and 3 ready replicas. + var replicas int32 = 3 + + ss := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-server-test1", + Namespace: "default", + Labels: map[string]string{"app": "consul", "chart": "consul-helm", "component": "server"}, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &replicas, + }, + Status: appsv1.StatefulSetStatus{ + Replicas: replicas, + ReadyReplicas: replicas, + }, + } + + c.kubernetes.AppsV1().StatefulSets("default").Create(context.Background(), ss, metav1.CreateOptions{}) + + // Now we run the checkConsulServers() function and it should succeed. + s, err := c.checkConsulServers("default") + require.NoError(t, err) + require.Equal(t, "Consul servers healthy (3/3)", s) + + // If you then create another stateful set it should error. + ss2 := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-server-test2", + Namespace: "default", + Labels: map[string]string{"app": "consul", "chart": "consul-helm", "component": "server"}, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &replicas, + }, + Status: appsv1.StatefulSetStatus{ + Replicas: replicas, + ReadyReplicas: replicas, + }, + } + c.kubernetes.AppsV1().StatefulSets("default").Create(context.Background(), ss2, metav1.CreateOptions{}) + + _, err = c.checkConsulServers("default") + require.Error(t, err) + require.Contains(t, err.Error(), "found multiple server stateful sets") + + // Clear out the client and now run a test where the stateful set isn't ready. + c.kubernetes = fake.NewSimpleClientset() + + ss3 := &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-server-test3", + Namespace: "default", + Labels: map[string]string{"app": "consul", "chart": "consul-helm", "component": "server"}, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &replicas, + }, + Status: appsv1.StatefulSetStatus{ + Replicas: replicas, + ReadyReplicas: replicas - 1, // Let's just set one of the servers to unhealthy + }, + } + c.kubernetes.AppsV1().StatefulSets("default").Create(context.Background(), ss3, metav1.CreateOptions{}) + + _, err = c.checkConsulServers("default") + require.Error(t, err) + require.Contains(t, err.Error(), fmt.Sprintf("%d/%d Consul servers unhealthy", 1, replicas)) +} + +// TestCheckConsulClients is very similar to TestCheckConsulServers() in structure. +func TestCheckConsulClients(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + + // No client daemon set should cause an error. + _, err := c.checkConsulClients("default") + require.Error(t, err) + require.Contains(t, err.Error(), "no client daemon set found") + + // Next create a daemon set. + var desired int32 = 3 + + ds := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-client-test1", + Namespace: "default", + Labels: map[string]string{"app": "consul", "chart": "consul-helm"}, + }, + Status: appsv1.DaemonSetStatus{ + DesiredNumberScheduled: desired, + NumberReady: desired, + }, + } + + c.kubernetes.AppsV1().DaemonSets("default").Create(context.Background(), ds, metav1.CreateOptions{}) + + // Now run checkConsulClients() and make sure it succeeds. + s, err := c.checkConsulClients("default") + require.NoError(t, err) + require.Equal(t, "Consul clients healthy (3/3)", s) + + // Creating another daemon set should cause an error. + ds2 := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-client-test2", + Namespace: "default", + Labels: map[string]string{"app": "consul", "chart": "consul-helm"}, + }, + Status: appsv1.DaemonSetStatus{ + DesiredNumberScheduled: desired, + NumberReady: desired, + }, + } + c.kubernetes.AppsV1().DaemonSets("default").Create(context.Background(), ds2, metav1.CreateOptions{}) + + _, err = c.checkConsulClients("default") + require.Error(t, err) + require.Contains(t, err.Error(), "found multiple client daemon sets") + + // Clear out the client and run a test with fewer than desired daemon sets ready. + c.kubernetes = fake.NewSimpleClientset() + + ds3 := &appsv1.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-client-test2", + Namespace: "default", + Labels: map[string]string{"app": "consul", "chart": "consul-helm"}, + }, + Status: appsv1.DaemonSetStatus{ + DesiredNumberScheduled: desired, + NumberReady: desired - 1, + }, + } + c.kubernetes.AppsV1().DaemonSets("default").Create(context.Background(), ds3, metav1.CreateOptions{}) + + _, err = c.checkConsulClients("default") + require.Error(t, err) + require.Contains(t, err.Error(), fmt.Sprintf("%d/%d Consul clients unhealthy", 1, desired)) +} + +// getInitializedCommand sets up a command struct for tests. +func getInitializedCommand(t *testing.T) *Command { + t.Helper() + log := hclog.New(&hclog.LoggerOptions{ + Name: "cli", + Level: hclog.Info, + Output: os.Stdout, + }) + + baseCommand := &common.BaseCommand{ + Log: log, + } + + c := &Command{ + BaseCommand: baseCommand, + } + c.init() + return c +} diff --git a/cli/cmd/uninstall/uninstall.go b/cli/cmd/uninstall/uninstall.go index 2e1d870c00..5bb6c69e61 100644 --- a/cli/cmd/uninstall/uninstall.go +++ b/cli/cmd/uninstall/uninstall.go @@ -183,13 +183,10 @@ func (c *Command) Run(args []string) int { return 1 } - found, foundReleaseName, foundReleaseNamespace, err := c.findExistingInstallation(actionConfig) + found, foundReleaseName, foundReleaseNamespace, err := c.findExistingInstallation(settings, uiLogger) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 - } - if !found { - c.UI.Output("No existing Consul installations.", terminal.WithSuccessStyle()) } else { c.UI.Output("Existing Consul installation found.", terminal.WithSuccessStyle()) c.UI.Output("Consul Uninstall Summary", terminal.WithHeaderStyle()) @@ -315,41 +312,16 @@ func (c *Command) Synopsis() string { return "Uninstall Consul deployment." } -func (c *Command) findExistingInstallation(actionConfig *action.Configuration) (bool, string, string, error) { - lister := action.NewList(actionConfig) - // lister.All will search for helm installations in all states, such as deployed, pending, uninstalling, etc. - lister.All = true - if c.flagNamespace == defaultAllNamespaces { - lister.AllNamespaces = true - } - res, err := lister.Run() +func (c *Command) findExistingInstallation(settings *helmCLI.EnvSettings, uiLogger action.DebugLog) (bool, string, string, error) { + releaseName, namespace, err := common.CheckForInstallations(settings, uiLogger) if err != nil { - return false, "", "", fmt.Errorf("error finding existing installations: %s", err) - } - - found := false - foundReleaseName := "" - foundReleaseNamespace := "" - for _, rel := range res { - if rel.Chart.Metadata.Name == "consul" { - if c.flagNamespace != defaultAllNamespaces && c.flagNamespace == rel.Namespace { - // If we found a chart named "consul" and -namespace was specified, we only found the release if the - // release namespace matches the -namespace flag. - found = true - foundReleaseName = rel.Name - foundReleaseNamespace = rel.Namespace - break - } - if c.flagNamespace == defaultAllNamespaces { - found = true - foundReleaseName = rel.Name - foundReleaseNamespace = rel.Namespace - break - } - } + return false, "", "", err + } else if (c.flagNamespace != defaultAllNamespaces && c.flagNamespace == namespace) || + (c.flagNamespace == defaultAllNamespaces) { + return true, releaseName, namespace, nil + } else { + return false, "", "", fmt.Errorf("could not find consul installation in namespace %s", c.flagNamespace) } - - return found, foundReleaseName, foundReleaseNamespace, nil } // deletePVCs deletes any pvcs that have the label release={{foundReleaseName}} and waits for them to be deleted. diff --git a/cli/commands.go b/cli/commands.go index 3fc4a7d936..50da5806d4 100644 --- a/cli/commands.go +++ b/cli/commands.go @@ -5,6 +5,7 @@ import ( "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/consul-k8s/cli/cmd/install" + "github.com/hashicorp/consul-k8s/cli/cmd/status" "github.com/hashicorp/consul-k8s/cli/cmd/uninstall" cmdversion "github.com/hashicorp/consul-k8s/cli/cmd/version" "github.com/hashicorp/consul-k8s/cli/version" @@ -30,6 +31,11 @@ func initializeCommands(ctx context.Context, log hclog.Logger) (*common.BaseComm BaseCommand: baseCommand, }, nil }, + "status": func() (cli.Command, error) { + return &status.Command{ + BaseCommand: baseCommand, + }, nil + }, "version": func() (cli.Command, error) { return &cmdversion.Command{ BaseCommand: baseCommand, From a7ad878b2fa950f364cec6874b218bf0c371ed6a Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Tue, 26 Oct 2021 12:01:04 -0500 Subject: [PATCH 090/418] clean up the framework a bit --- acceptance/framework/consul/consul_cluster.go | 46 +------------- acceptance/framework/helpers/helpers.go | 48 +++++++++++++++ acceptance/framework/vault/vault_cluster.go | 61 +++---------------- 3 files changed, 59 insertions(+), 96 deletions(-) diff --git a/acceptance/framework/consul/consul_cluster.go b/acceptance/framework/consul/consul_cluster.go index b1e8f8d9e2..d99551994f 100644 --- a/acceptance/framework/consul/consul_cluster.go +++ b/acceptance/framework/consul/consul_cluster.go @@ -2,7 +2,6 @@ package consul import ( "context" - "encoding/json" "fmt" "strings" "testing" @@ -115,7 +114,7 @@ func (h *HelmCluster) Create(t *testing.T) { }) // Fail if there are any existing installations of the Helm chart. - h.checkForPriorInstallations(t) + helpers.CheckForPriorInstallations(t, h.kubernetesClient, h.helmOptions, "consul") helm.Install(t, h.helmOptions, config.HelmChartPath, h.releaseName) @@ -281,49 +280,6 @@ func (h *HelmCluster) SetupConsulClient(t *testing.T, secure bool) *api.Client { return consulClient } -// checkForPriorInstallations checks if there is an existing Helm release -// for this Helm chart already installed. If there is, it fails the tests. -func (h *HelmCluster) checkForPriorInstallations(t *testing.T) { - t.Helper() - - var helmListOutput string - // Check if there's an existing cluster and fail if there is one. - // We may need to retry since this is the first command run once the Kube - // cluster is created and sometimes the API server returns errors. - retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 3}, t, func(r *retry.R) { - var err error - // NOTE: It's okay to pass in `t` to RunHelmCommandAndGetOutputE despite being in a retry - // because we're using RunHelmCommandAndGetOutputE (not RunHelmCommandAndGetOutput) so the `t` won't - // get used to fail the test, just for logging. - helmListOutput, err = helm.RunHelmCommandAndGetOutputE(t, h.helmOptions, "list", "--output", "json") - require.NoError(r, err) - }) - - var installedReleases []map[string]string - - err := json.Unmarshal([]byte(helmListOutput), &installedReleases) - require.NoError(t, err, "unmarshalling %q", helmListOutput) - - for _, r := range installedReleases { - require.NotContains(t, r["chart"], "consul", fmt.Sprintf("detected an existing installation of Consul %s, release name: %s", r["chart"], r["name"])) - } - - // Wait for all pods in the "default" namespace to exit. A previous - // release may not be listed by Helm but its pods may still be terminating. - retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { - consulPods, err := h.kubernetesClient.CoreV1().Pods(h.helmOptions.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) - require.NoError(r, err) - if len(consulPods.Items) > 0 { - var podNames []string - for _, p := range consulPods.Items { - podNames = append(podNames, p.Name) - } - r.Errorf("pods from previous installation still running: %s", strings.Join(podNames, ", ")) - } - }) - -} - // configurePodSecurityPolicies creates a simple pod security policy, a cluster role to allow access to the PSP, // and a role binding that binds the default service account in the helm installation namespace to the cluster role. // We bind the default service account for tests that are spinning up pods without a service account set so that diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index e4a2c02c91..f1c4494b80 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -2,7 +2,9 @@ package helpers import ( "context" + "encoding/json" "fmt" + "github.com/gruntwork-io/terratest/modules/helm" "os" "os/signal" "strings" @@ -25,6 +27,52 @@ func RandomName() string { return fmt.Sprintf("test-%s", strings.ToLower(random.UniqueId())) } +// CheckForPriorInstallations checks if there is an existing Helm release +// for this Helm chart already installed. If there is, it fails the tests. +func CheckForPriorInstallations(t *testing.T, client kubernetes.Interface, options *helm.Options, chartName string) { + t.Helper() + + var helmListOutput string + // Check if there's an existing cluster and fail if there is one. + // We may need to retry since this is the first command run once the Kube + // cluster is created and sometimes the API server returns errors. + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 3}, t, func(r *retry.R) { + var err error + // NOTE: It's okay to pass in `t` to RunHelmCommandAndGetOutputE despite being in a retry + // because we're using RunHelmCommandAndGetOutputE (not RunHelmCommandAndGetOutput) so the `t` won't + // get used to fail the test, just for logging. + helmListOutput, err = helm.RunHelmCommandAndGetOutputE(t, options, "list", "--output", "json") + require.NoError(r, err) + }) + + var installedReleases []map[string]string + + err := json.Unmarshal([]byte(helmListOutput), &installedReleases) + require.NoError(t, err, "unmarshalling %q", helmListOutput) + + for _, r := range installedReleases { + require.NotContains(t, r["chart"], chartName, fmt.Sprintf("detected an existing installation of %s %s, release name: %s", chartName, r["chart"], r["name"])) + } + + // Wait for all pods in the "default" namespace to exit. A previous + // release may not be listed by Helm but its pods may still be terminating. + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { + pods, err := client.CoreV1().Pods(options.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) + require.NoError(r, err) + if len(pods.Items) > 0 { + var podNames []string + for _, p := range pods.Items { + if strings.Contains(p.Name, chartName) { + podNames = append(podNames, p.Name) + } + } + if len(podNames) > 0 { + r.Errorf("pods from previous installation still running: %s", strings.Join(podNames, ", ")) + } + } + }) +} + // WaitForAllPodsToBeReady waits until all pods with the provided podLabelSelector // are in the ready status. It checks every 5 seconds for a total of 20 tries. // If there is at least one container in a pod that isn't ready after that, diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index 2460edc515..45dab57dca 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -2,7 +2,6 @@ package vault import ( "context" - "encoding/json" "fmt" "strings" "testing" @@ -113,47 +112,6 @@ func NewVaultCluster( // VaultClient returns the vault client. func (v *VaultCluster) VaultClient(t *testing.T) *vapi.Client { return v.vaultClient } -// checkForPriorInstallations checks if there is an existing Helm release -// for this Helm chart already installed. If there is, it fails the tests. -func (v *VaultCluster) checkForPriorVaultInstallations(t *testing.T) { - t.Helper() - - var helmListOutput string - // Check if there's an existing cluster and fail if there is one. - // We may need to retry since this is the first command run once the Kube - // cluster is created and sometimes the API server returns errors. - retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 3}, t, func(r *retry.R) { - var err error - // NOTE: It's okay to pass in `t` to RunHelmCommandAndGetOutputE despite being in a retry - // because we're using RunHelmCommandAndGetOutputE (not RunHelmCommandAndGetOutput) so the `t` won't - // get used to fail the test, just for logging. - helmListOutput, err = helm.RunHelmCommandAndGetOutputE(t, v.vaultHelmOptions, "list", "--output", "json") - require.NoError(r, err) - }) - - var installedReleases []map[string]string - - err := json.Unmarshal([]byte(helmListOutput), &installedReleases) - require.NoError(t, err, "unmarshalling %q", helmListOutput) - - for _, r := range installedReleases { - require.NotContains(t, r["chart"], "vault", fmt.Sprintf("detected an existing installation of Vault %s, release name: %s", r["chart"], r["name"])) - } - // Wait for all pods in the "default" namespace to exit. A previous - // release may not be listed by Helm but its pods may still be terminating. - retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { - vaultPods, err := v.kubernetesClient.CoreV1().Pods(v.vaultHelmOptions.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) - require.NoError(r, err) - if len(vaultPods.Items) > 0 { - var podNames []string - for _, p := range vaultPods.Items { - podNames = append(podNames, p.Name) - } - r.Errorf("pods from previous installation still running: %s", strings.Join(podNames, ", ")) - } - }) -} - // Setup Vault Client returns a Vault Client. // TODO: We need to support Vault with TLS enabled. func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { @@ -256,14 +214,14 @@ func (v *VaultCluster) Create(t *testing.T, ctx environment.TestContext) { }) // Fail if there are any existing installations of the Helm chart. - v.checkForPriorVaultInstallations(t) + helpers.CheckForPriorInstallations(t, v.kubernetesClient, v.vaultHelmOptions, "vault") - // step 1: install Vault + // Install Vault. helm.Install(t, v.vaultHelmOptions, "hashicorp/vault", v.vaultReleaseName) - // Wait for the injector pod to become Ready. + // Wait for the injector pod to become Ready, but not the server. helpers.WaitForAllPodsToBeReady(t, v.kubernetesClient, v.vaultHelmOptions.KubectlOptions.Namespace, "app.kubernetes.io/name=vault-agent-injector") - // Wait for the Server Pod to be online, it will not be Ready because it has not been Init+Unseal'd yet, this is done - // in the Bootstrap method. + // Wait for the server pod to be PodRunning, it will not be Ready because it has not been Init+Unseal'd yet. + // The vault server has health checks bound to unseal status, and Unseal is done as part of bootstrap (below). retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 30}, t, func(r *retry.R) { pod, err := v.kubernetesClient.CoreV1().Pods(v.vaultHelmOptions.KubectlOptions.Namespace).Get(context.Background(), fmt.Sprintf("%s-vault-0", v.vaultReleaseName), metav1.GetOptions{}) require.NoError(r, err) @@ -273,6 +231,7 @@ func (v *VaultCluster) Create(t *testing.T, ctx environment.TestContext) { v.bootstrap(t, ctx) } +// Destroy issues an helm delete and deletes the PVC + any helm secrets related to the release that are leftover. func (v *VaultCluster) Destroy(t *testing.T) { t.Helper() @@ -281,11 +240,12 @@ func (v *VaultCluster) Destroy(t *testing.T) { // Ignore the error returned by the helm delete here so that we can // always idempotently clean up resources in the cluster. _ = helm.DeleteE(t, v.vaultHelmOptions, v.vaultReleaseName, false) - // Delete PVCs. + + // Delete PVCs, these are the only parts that need to be cleaned up in Vault installs. err := v.kubernetesClient.CoreV1().PersistentVolumeClaims(v.vaultHelmOptions.KubectlOptions.Namespace).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: fmt.Sprintf("app.kubernetes.io/instance=%s", v.vaultReleaseName)}) require.NoError(t, err) - // Delete any secrets that have v.releaseName in their name, this is only needed to delete the Helm release secret. + // Delete any secrets that have v.releaseName in their name, this is only needed to delete the Helm release secret if it is still around. secrets, err := v.kubernetesClient.CoreV1().Secrets(v.vaultHelmOptions.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) require.NoError(t, err) for _, secret := range secrets.Items { @@ -299,12 +259,11 @@ func (v *VaultCluster) Destroy(t *testing.T) { } func defaultVaultValues() map[string]string { - values := map[string]string{ + return map[string]string{ "server.replicas": "1", "server.bootstrapExpect": "1", //"ui.enabled": "true", "injector.enabled": "true", "global.enabled": "true", } - return values } From de510170f4c1bde29d5dc2b1d8b59fbc5f9f3ba8 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 26 Oct 2021 14:23:09 -0700 Subject: [PATCH 091/418] Default to excluding system ns's from injection (#726) * Default to excluding system ns's from injection kube-system is excluded because it's unlikely users will want to provision Connect pods in that namespace and also because we don't want to block pods being provisioned there if our webhook injector is down. local-path-storage is excluded because this ns is used by kind to provision PVCs and if ACLs are enabled then the install gets into a deadlock where: - PVC can't be provisioned because Kind needs to create a Pod - Pod can't be created because injector webhook needs to be up - injector webhook can't come up until its got an ACL token - ACL token can't be provisioned because Consul server isn't up - Consul server can't be started because it doesn't have a PVC NOTE: This matching is only supported in Kube 1.21+ where they've added these labels to namespaces automatically now. --- CHANGELOG.md | 5 +++++ acceptance/framework/config/config.go | 5 ----- charts/consul/values.yaml | 11 ++++++++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa4e981474..aa92e03d2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,12 @@ ## UNRELEASED +BREAKING CHANGES: +* Helm Chart + * The `kube-system` and `local-path-storage` namespaces are now _excluded_ from connect injection by default on Kubernetes versions >= 1.21. If you wish to enable injection on those namespaces, set `connectInject.namespaceSelector` to `null`. [[GH-726](https://github.com/hashicorp/consul-k8s/pull/726)] IMPROVEMENTS: * Helm Chart * Automatic retry for `gossip-encryption-autogenerate-job` on failure [[GH-789](https://github.com/hashicorp/consul-k8s/pull/789)] + * `kube-system` and `local-path-storage` namespaces are now excluded from connect injection by default on Kubernetes versions >= 1.21. This prevents deadlock issues when `kube-system` components go down and allows Kind to work without changing the failure policy of the mutating webhook. [[GH-726](https://github.com/hashicorp/consul-k8s/pull/726)] * CLI * Add `status` command. [[GH-768](https://github.com/hashicorp/consul-k8s/pull/768)] @@ -38,6 +42,7 @@ BUG FIXES: * Fix consul-k8s image version in values file. [[GH-732](https://github.com/hashicorp/consul-k8s/pull/732)] ## 0.34.0 (September 17, 2021) + FEATURES: * CLI * The `consul-k8s` CLI enables users to deploy and operate Consul on Kubernetes. diff --git a/acceptance/framework/config/config.go b/acceptance/framework/config/config.go index a998587291..28803faa20 100644 --- a/acceptance/framework/config/config.go +++ b/acceptance/framework/config/config.go @@ -55,11 +55,6 @@ type TestConfig struct { func (t *TestConfig) HelmValuesFromConfig() (map[string]string, error) { helmValues := map[string]string{} - // If Kind is being used they use a pod to provision the underlying PV which will hang if we - // use "Fail" for the webhook failurePolicy. - if t.UseKind { - setIfNotEmpty(helmValues, "connectInject.failurePolicy", "Ignore") - } // Set the enterprise image first if enterprise tests are enabled. // It can be overwritten by the -consul-image flag later. if t.EnableEnterprise { diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index a64c09fc7f..44b81cc327 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -1625,6 +1625,11 @@ connectInject: # See https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#matching-requests-namespaceselector # for more details. # + # By default, we exclude the kube-system namespace since usually users won't + # want those pods injected and also the local-path-storage namespace so that + # Kind (Kubernetes In Docker) can provision Pods used to create PVCs. + # Note that this exclusion is only supported in Kubernetes v1.21.1+. + # # Example: # # ```yaml @@ -1633,7 +1638,11 @@ connectInject: # namespace-label: label-value # ``` # @type: string - namespaceSelector: null + namespaceSelector: | + matchExpressions: + - key: "kubernetes.io/metadata.name" + operator: "NotIn" + values: ["kube-system","local-path-storage"] # List of k8s namespaces to allow Connect sidecar # injection in. If a k8s namespace is not included or is listed in `k8sDenyNamespaces`, From e7c2ad3a445c23c453c11703a3e8085d8476f547 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 27 Oct 2021 10:14:13 -0400 Subject: [PATCH 092/418] Add support for PartitionExports (#802) * Add support for PartitionExports - This PR does not include acceptance tests. The desired acceptance tests will be determined based on the expected behavior of PartitionExports when partitions are disabled. - Similarly, controller tests have not been added as our existing controller tests only account for namespace. The behavior with partitions has not been resolved. * CHANGELOG --- CHANGELOG.md | 2 + acceptance/go.mod | 2 +- acceptance/go.sum | 2 + .../tests/fixtures/crds/partitionexports.yaml | 10 + .../templates/controller-clusterrole.yaml | 2 + .../templates/crd-partitionexports.yaml | 137 +++++++ .../test/unit/crd-partitionexports.bats | 24 ++ control-plane/PROJECT | 37 +- control-plane/api/common/common.go | 2 + .../api/v1alpha1/partitionexports_types.go | 186 ++++++++++ .../v1alpha1/partitionexports_types_test.go | 335 ++++++++++++++++++ .../api/v1alpha1/partitionexports_webhook.go | 70 ++++ .../v1alpha1/partitionexports_webhook_test.go | 106 ++++++ .../api/v1alpha1/zz_generated.deepcopy.go | 116 ++++++ ...consul.hashicorp.com_partitionexports.yaml | 130 +++++++ control-plane/config/crd/kustomization.yaml | 3 + .../patches/webhook_in_partitionexports.yaml | 17 + .../rbac/partitionexport_editor_role.yaml | 24 ++ .../rbac/partitionexport_viewer_role.yaml | 20 ++ control-plane/config/rbac/role.yaml | 20 ++ .../consul_v1alpha1_partitionexport.yaml | 7 + control-plane/config/webhook/manifests.yaml | 21 ++ .../configentry_controller_ent_test.go | 2 +- .../controller/partitionexports_controller.go | 40 +++ control-plane/go.mod | 19 +- control-plane/go.sum | 227 +++++++----- .../subcommand/controller/command.go | 18 + 27 files changed, 1450 insertions(+), 129 deletions(-) create mode 100644 acceptance/tests/fixtures/crds/partitionexports.yaml create mode 100644 charts/consul/templates/crd-partitionexports.yaml create mode 100644 charts/consul/test/unit/crd-partitionexports.bats create mode 100644 control-plane/api/v1alpha1/partitionexports_types.go create mode 100644 control-plane/api/v1alpha1/partitionexports_types_test.go create mode 100644 control-plane/api/v1alpha1/partitionexports_webhook.go create mode 100644 control-plane/api/v1alpha1/partitionexports_webhook_test.go create mode 100644 control-plane/config/crd/bases/consul.hashicorp.com_partitionexports.yaml create mode 100644 control-plane/config/crd/patches/webhook_in_partitionexports.yaml create mode 100644 control-plane/config/rbac/partitionexport_editor_role.yaml create mode 100644 control-plane/config/rbac/partitionexport_viewer_role.yaml create mode 100644 control-plane/config/samples/consul_v1alpha1_partitionexport.yaml create mode 100644 control-plane/controller/partitionexports_controller.go diff --git a/CHANGELOG.md b/CHANGELOG.md index aa92e03d2b..a224794a64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,11 @@ IMPROVEMENTS: FEATURES: * Control Plane * Add `gossip-encryption-autogenerate` subcommand to generate a random 32 byte Kubernetes secret to be used as a gossip encryption key. [[GH-772](https://github.com/hashicorp/consul-k8s/pull/772)] + * Add support for `partition-exports` config entry. [[GH-802](https://github.com/hashicorp/consul-k8s/pull/802)], [[GH-803](https://github.com/hashicorp/consul-k8s/pull/803)] * Helm Chart * Add automatic generation of gossip encryption with `global.gossipEncryption.autoGenerate=true`. [[GH-738](https://github.com/hashicorp/consul-k8s/pull/738)] * Add support for configuring resources for mesh gateway `service-init` container. [[GH-758](https://github.com/hashicorp/consul-k8s/pull/758)] + * Add support for `PartitionExports` CRD. [[GH-802](https://github.com/hashicorp/consul-k8s/pull/802)], [[GH-803](https://github.com/hashicorp/consul-k8s/pull/803)] IMPROVEMENTS: * Control Plane diff --git a/acceptance/go.mod b/acceptance/go.mod index 5e017ccec6..2ac3c700b0 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/gruntwork-io/terratest v0.31.2 - github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf + github.com/hashicorp/consul/api v1.10.1-0.20211020192418-04cd2c983e9c github.com/hashicorp/consul/sdk v0.8.0 github.com/stretchr/testify v1.5.1 gopkg.in/yaml.v2 v2.2.8 diff --git a/acceptance/go.sum b/acceptance/go.sum index ab20eec364..9008c7aaf4 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -227,6 +227,8 @@ github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+Xb github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf h1:fouyN8SkrE4py09XaOru4PCM9zunem39CjOrMJMrKsc= github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= +github.com/hashicorp/consul/api v1.10.1-0.20211020192418-04cd2c983e9c h1:7eKUSC17HDH0+lHsI/fiPe5y8hMarXJdECqG7KiGkNA= +github.com/hashicorp/consul/api v1.10.1-0.20211020192418-04cd2c983e9c/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= diff --git a/acceptance/tests/fixtures/crds/partitionexports.yaml b/acceptance/tests/fixtures/crds/partitionexports.yaml new file mode 100644 index 0000000000..d6159310cf --- /dev/null +++ b/acceptance/tests/fixtures/crds/partitionexports.yaml @@ -0,0 +1,10 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: PartitionExports +metadata: + name: exports +spec: + services: + - name: frontend + namespace: frontend + consumers: + - partition: other \ No newline at end of file diff --git a/charts/consul/templates/controller-clusterrole.yaml b/charts/consul/templates/controller-clusterrole.yaml index b113366cd2..993768811c 100644 --- a/charts/consul/templates/controller-clusterrole.yaml +++ b/charts/consul/templates/controller-clusterrole.yaml @@ -17,6 +17,7 @@ rules: - serviceresolvers - proxydefaults - meshes + - partitionexports - servicerouters - servicesplitters - serviceintentions @@ -37,6 +38,7 @@ rules: - serviceresolvers/status - proxydefaults/status - meshes/status + - partitionexports/status - servicerouters/status - servicesplitters/status - serviceintentions/status diff --git a/charts/consul/templates/crd-partitionexports.yaml b/charts/consul/templates/crd-partitionexports.yaml new file mode 100644 index 0000000000..a39dcaad0a --- /dev/null +++ b/charts/consul/templates/crd-partitionexports.yaml @@ -0,0 +1,137 @@ +{{- if .Values.controller.enabled }} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.0 + creationTimestamp: null + name: partitionexports.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: PartitionExports + listKind: PartitionExportsList + plural: partitionexports + singular: partitionexports + 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: PartitionExports is the Schema for the partitionexports 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: PartitionExportsSpec defines the desired state of PartitionExports + properties: + services: + description: Services is a list of services to be exported and the + list of partitions to expose them to. + items: + description: ExportedService manages the exporting of a service + in the local partition to other partitions. + properties: + consumers: + description: Consumers is a list of downstream consumers of + the service to be exported. + items: + description: ServiceConsumer represents a downstream consumer + of the service to be exported. + properties: + partition: + description: Partition is the admin partition to export + the service to. + type: string + type: object + type: array + name: + description: Name is the name of the service to be exported. + type: string + namespace: + description: Namespace is the namespace to export the service + from. + 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/test/unit/crd-partitionexports.bats b/charts/consul/test/unit/crd-partitionexports.bats new file mode 100644 index 0000000000..35463eea29 --- /dev/null +++ b/charts/consul/test/unit/crd-partitionexports.bats @@ -0,0 +1,24 @@ +#!/usr/bin/env bats + +load _helpers + +@test "partitionExports/CustomerResourceDefinition: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/crd-partitionexports.yaml \ + . +} + +@test "partitionExports/CustomerResourceDefinition: enabled with controller.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/crd-partitionexports.yaml \ + --set 'controller.enabled=true' \ + . | tee /dev/stderr | + # The generated CRDs have "---" at the top which results in two objects + # being detected by yq, the first of which is null. We must therefore use + # yq -s so that length operates on both objects at once rather than + # individually, which would output false\ntrue and fail the test. + yq -s 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/control-plane/PROJECT b/control-plane/PROJECT index 9df8efbbe7..9e26de1f52 100644 --- a/control-plane/PROJECT +++ b/control-plane/PROJECT @@ -1,63 +1,62 @@ domain: hashicorp.com -layout: go.kubebuilder.io/v2 +layout: +- go.kubebuilder.io/v2 +plugins: + go.operator-sdk.io/v2-alpha: {} repo: github.com/hashicorp/consul-k8s resources: -- - controller: true +- controller: true domain: hashicorp.com group: consul kind: IngressGateway path: github.com/hashicorp/consul-k8s/api/v1alpha1 version: v1alpha1 -- - controller: true +- controller: true domain: hashicorp.com group: consul kind: ProxyDefaults path: github.com/hashicorp/consul-k8s/api/v1alpha1 version: v1alpha1 -- - controller: true +- controller: true domain: hashicorp.com group: consul kind: ServiceIntentions path: github.com/hashicorp/consul-k8s/api/v1alpha1 version: v1alpha1 -- - controller: true +- controller: true domain: hashicorp.com group: consul kind: ServiceDefaults path: github.com/hashicorp/consul-k8s/api/v1alpha1 version: v1alpha1 -- - controller: true +- controller: true domain: hashicorp.com group: consul kind: ServiceResolver path: github.com/hashicorp/consul-k8s/api/v1alpha1 version: v1alpha1 -- - controller: true +- controller: true domain: hashicorp.com group: consul kind: ServiceRouter path: github.com/hashicorp/consul-k8s/api/v1alpha1 version: v1alpha1 -- - controller: true +- controller: true domain: hashicorp.com group: consul kind: ServiceSplitter path: github.com/hashicorp/consul-k8s/api/v1alpha1 version: v1alpha1 -- - controller: true +- controller: true domain: hashicorp.com group: consul kind: TerminatingGateway path: github.com/hashicorp/consul-k8s/api/v1alpha1 version: v1alpha1 +- controller: true + domain: hashicorp.com + group: consul + kind: PartitionExport + path: github.com/hashicorp/consul-k8s/api/v1alpha1 + version: v1alpha1 version: "3" -plugins: - go.operator-sdk.io/v2-alpha: {} diff --git a/control-plane/api/common/common.go b/control-plane/api/common/common.go index 3d0ae3f6e7..a44f527472 100644 --- a/control-plane/api/common/common.go +++ b/control-plane/api/common/common.go @@ -8,12 +8,14 @@ const ( ServiceRouter string = "servicerouter" ServiceSplitter string = "servicesplitter" ServiceIntentions string = "serviceintentions" + PartitionExports string = "partitionexports" IngressGateway string = "ingressgateway" TerminatingGateway string = "terminatinggateway" Global string = "global" Mesh string = "mesh" DefaultConsulNamespace string = "default" + DefaultConsulPartition string = "default" WildcardNamespace string = "*" SourceKey string = "external-source" diff --git a/control-plane/api/v1alpha1/partitionexports_types.go b/control-plane/api/v1alpha1/partitionexports_types.go new file mode 100644 index 0000000000..9c20377807 --- /dev/null +++ b/control-plane/api/v1alpha1/partitionexports_types.go @@ -0,0 +1,186 @@ +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" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const PartitionExportsKubeKind = "partitionexports" + +func init() { + SchemeBuilder.Register(&PartitionExports{}, &PartitionExportsList{}) +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status + +// PartitionExports is the Schema for the partitionexports 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" +type PartitionExports struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec PartitionExportsSpec `json:"spec,omitempty"` + Status `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// PartitionExportsList contains a list of PartitionExports +type PartitionExportsList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []PartitionExports `json:"items"` +} + +// PartitionExportsSpec defines the desired state of PartitionExports +type PartitionExportsSpec struct { + // Services is a list of services to be exported and the list of partitions + // to expose them to. + Services []ExportedService `json:"services,omitempty"` +} + +// ExportedService manages the exporting of a service in the local partition to +// other partitions. +type ExportedService struct { + // Name is the name of the service to be exported. + Name string `json:"name,omitempty"` + + // Namespace is the namespace to export the service from. + Namespace string `json:"namespace,omitempty"` + + // Consumers is a list of downstream consumers of the service to be exported. + Consumers []ServiceConsumer `json:"consumers,omitempty"` +} + +// ServiceConsumer represents a downstream consumer of the service to be exported. +type ServiceConsumer struct { + // Partition is the admin partition to export the service to. + Partition string `json:"partition,omitempty"` +} + +func (in *PartitionExports) GetObjectMeta() metav1.ObjectMeta { + return in.ObjectMeta +} + +func (in *PartitionExports) AddFinalizer(name string) { + in.ObjectMeta.Finalizers = append(in.Finalizers(), name) +} + +func (in *PartitionExports) RemoveFinalizer(name string) { + var newFinalizers []string + for _, oldF := range in.Finalizers() { + if oldF != name { + newFinalizers = append(newFinalizers, oldF) + } + } + in.ObjectMeta.Finalizers = newFinalizers +} + +func (in *PartitionExports) Finalizers() []string { + return in.ObjectMeta.Finalizers +} + +func (in *PartitionExports) ConsulKind() string { + return capi.PartitionExports +} + +func (in *PartitionExports) ConsulGlobalResource() bool { + return true +} + +func (in *PartitionExports) ConsulMirroringNS() string { + return common.DefaultConsulNamespace +} + +func (in *PartitionExports) KubeKind() string { + return PartitionExportsKubeKind +} + +func (in *PartitionExports) ConsulName() string { + return in.ObjectMeta.Name +} + +func (in *PartitionExports) KubernetesName() string { + return in.ObjectMeta.Name +} + +func (in *PartitionExports) SetSyncedCondition(status corev1.ConditionStatus, reason, message string) { + in.Status.Conditions = Conditions{ + { + Type: ConditionSynced, + Status: status, + LastTransitionTime: metav1.Now(), + Reason: reason, + Message: message, + }, + } +} + +func (in *PartitionExports) SetLastSyncedTime(time *metav1.Time) { + in.Status.LastSyncedTime = time +} + +func (in *PartitionExports) 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 *PartitionExports) SyncedConditionStatus() corev1.ConditionStatus { + cond := in.Status.GetCondition(ConditionSynced) + if cond == nil { + return corev1.ConditionUnknown + } + return cond.Status +} + +func (in *PartitionExports) ToConsul(datacenter string) api.ConfigEntry { + var services []capi.ExportedService + for _, service := range in.Spec.Services { + services = append(services, service.toConsul()) + } + return &capi.PartitionExportsConfigEntry{ + Name: in.Name, + Services: services, + Meta: meta(datacenter), + } +} + +func (in *ExportedService) toConsul() capi.ExportedService { + var consumers []capi.ServiceConsumer + for _, consumer := range in.Consumers { + consumers = append(consumers, capi.ServiceConsumer{Partition: consumer.Partition}) + } + return capi.ExportedService{ + Name: in.Name, + Namespace: in.Namespace, + Consumers: consumers, + } +} + +func (in *PartitionExports) MatchesConsul(candidate api.ConfigEntry) bool { + configEntry, ok := candidate.(*capi.PartitionExportsConfigEntry) + if !ok { + return false + } + // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.PartitionExportsConfigEntry{}, "Partition", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) + +} + +func (in *PartitionExports) Validate(_ bool) error { + return nil +} + +func (in *PartitionExports) DefaultNamespaceFields(_ bool, _ string, _ bool, _ string) { +} diff --git a/control-plane/api/v1alpha1/partitionexports_types_test.go b/control-plane/api/v1alpha1/partitionexports_types_test.go new file mode 100644 index 0000000000..dc0898da66 --- /dev/null +++ b/control-plane/api/v1alpha1/partitionexports_types_test.go @@ -0,0 +1,335 @@ +package v1alpha1 + +import ( + "testing" + "time" + + "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" +) + +// Test MatchesConsul for cases that should return true. +func TestPartitionExports_MatchesConsul(t *testing.T) { + cases := map[string]struct { + Ours PartitionExports + Theirs capi.ConfigEntry + Matches bool + }{ + "empty fields matches": { + Ours: PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.DefaultConsulPartition, + }, + Spec: PartitionExportsSpec{}, + }, + Theirs: &capi.PartitionExportsConfigEntry{ + Name: common.DefaultConsulPartition, + CreateIndex: 1, + ModifyIndex: 2, + Meta: map[string]string{ + common.SourceKey: common.SourceValue, + common.DatacenterKey: "datacenter", + }, + }, + Matches: true, + }, + "all fields set matches": { + Ours: PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.DefaultConsulPartition, + }, + Spec: PartitionExportsSpec{ + Services: []ExportedService{ + { + Name: "service-frontend", + Namespace: "frontend", + Consumers: []ServiceConsumer{ + { + Partition: "second", + }, + { + Partition: "third", + }, + }, + }, + { + Name: "service-backend", + Namespace: "backend", + Consumers: []ServiceConsumer{ + { + Partition: "fourth", + }, + { + Partition: "fifth", + }, + }, + }, + }, + }, + }, + Theirs: &capi.PartitionExportsConfigEntry{ + Name: common.DefaultConsulPartition, + Services: []capi.ExportedService{ + { + Name: "service-frontend", + Namespace: "frontend", + Consumers: []capi.ServiceConsumer{ + { + Partition: "second", + }, + { + Partition: "third", + }, + }, + }, + { + Name: "service-backend", + Namespace: "backend", + Consumers: []capi.ServiceConsumer{ + { + Partition: "fourth", + }, + { + Partition: "fifth", + }, + }, + }, + }, + Meta: map[string]string{ + common.SourceKey: common.SourceValue, + common.DatacenterKey: "datacenter", + }, + CreateIndex: 1, + ModifyIndex: 2, + }, + Matches: true, + }, + "mismatched types does not match": { + Ours: PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.DefaultConsulPartition, + }, + Spec: PartitionExportsSpec{}, + }, + Theirs: &capi.ServiceConfigEntry{ + Name: common.DefaultConsulPartition, + Kind: capi.PartitionExports, + }, + Matches: false, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + require.Equal(t, c.Matches, c.Ours.MatchesConsul(c.Theirs)) + }) + } +} + +func TestPartitionExports_ToConsul(t *testing.T) { + cases := map[string]struct { + Ours PartitionExports + Exp *capi.PartitionExportsConfigEntry + }{ + "empty fields": { + Ours: PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.DefaultConsulPartition, + }, + Spec: PartitionExportsSpec{}, + }, + Exp: &capi.PartitionExportsConfigEntry{ + Name: common.DefaultConsulPartition, + Meta: map[string]string{ + common.SourceKey: common.SourceValue, + common.DatacenterKey: "datacenter", + }, + }, + }, + "every field set": { + Ours: PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.DefaultConsulPartition, + }, + Spec: PartitionExportsSpec{ + Services: []ExportedService{ + { + Name: "service-frontend", + Namespace: "frontend", + Consumers: []ServiceConsumer{ + { + Partition: "second", + }, + { + Partition: "third", + }, + }, + }, + { + Name: "service-backend", + Namespace: "backend", + Consumers: []ServiceConsumer{ + { + Partition: "fourth", + }, + { + Partition: "fifth", + }, + }, + }, + }, + }, + }, + Exp: &capi.PartitionExportsConfigEntry{ + Name: common.DefaultConsulPartition, + Services: []capi.ExportedService{ + { + Name: "service-frontend", + Namespace: "frontend", + Consumers: []capi.ServiceConsumer{ + { + Partition: "second", + }, + { + Partition: "third", + }, + }, + }, + { + Name: "service-backend", + Namespace: "backend", + Consumers: []capi.ServiceConsumer{ + { + Partition: "fourth", + }, + { + Partition: "fifth", + }, + }, + }, + }, + Meta: map[string]string{ + common.SourceKey: common.SourceValue, + common.DatacenterKey: "datacenter", + }, + }, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + act := c.Ours.ToConsul("datacenter") + partitionExports, ok := act.(*capi.PartitionExportsConfigEntry) + require.True(t, ok, "could not cast") + require.Equal(t, c.Exp, partitionExports) + }) + } +} + +func TestPartitionExports_AddFinalizer(t *testing.T) { + partitionExports := &PartitionExports{} + partitionExports.AddFinalizer("finalizer") + require.Equal(t, []string{"finalizer"}, partitionExports.ObjectMeta.Finalizers) +} + +func TestPartitionExports_RemoveFinalizer(t *testing.T) { + partitionExports := &PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Finalizers: []string{"f1", "f2"}, + }, + } + partitionExports.RemoveFinalizer("f1") + require.Equal(t, []string{"f2"}, partitionExports.ObjectMeta.Finalizers) +} + +func TestPartitionExports_SetSyncedCondition(t *testing.T) { + partitionExports := &PartitionExports{} + partitionExports.SetSyncedCondition(corev1.ConditionTrue, "reason", "message") + + require.Equal(t, corev1.ConditionTrue, partitionExports.Status.Conditions[0].Status) + require.Equal(t, "reason", partitionExports.Status.Conditions[0].Reason) + require.Equal(t, "message", partitionExports.Status.Conditions[0].Message) + now := metav1.Now() + require.True(t, partitionExports.Status.Conditions[0].LastTransitionTime.Before(&now)) +} + +func TestPartitionExports_SetLastSyncedTime(t *testing.T) { + partitionExports := &PartitionExports{} + syncedTime := metav1.NewTime(time.Now()) + partitionExports.SetLastSyncedTime(&syncedTime) + + require.Equal(t, &syncedTime, partitionExports.Status.LastSyncedTime) +} + +func TestPartitionExports_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) { + partitionExports := &PartitionExports{ + Status: Status{ + Conditions: []Condition{{ + Type: ConditionSynced, + Status: status, + }}, + }, + } + + require.Equal(t, status, partitionExports.SyncedConditionStatus()) + }) + } +} + +func TestPartitionExports_GetConditionWhenStatusNil(t *testing.T) { + require.Nil(t, (&PartitionExports{}).GetCondition(ConditionSynced)) +} + +func TestPartitionExports_SyncedConditionStatusWhenStatusNil(t *testing.T) { + require.Equal(t, corev1.ConditionUnknown, (&PartitionExports{}).SyncedConditionStatus()) +} + +func TestPartitionExports_SyncedConditionWhenStatusNil(t *testing.T) { + status, reason, message := (&PartitionExports{}).SyncedCondition() + require.Equal(t, corev1.ConditionUnknown, status) + require.Equal(t, "", reason) + require.Equal(t, "", message) +} + +func TestPartitionExports_ConsulKind(t *testing.T) { + require.Equal(t, capi.PartitionExports, (&PartitionExports{}).ConsulKind()) +} + +func TestPartitionExports_KubeKind(t *testing.T) { + require.Equal(t, "partitionexports", (&PartitionExports{}).KubeKind()) +} + +func TestPartitionExports_ConsulName(t *testing.T) { + require.Equal(t, "foo", (&PartitionExports{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) +} + +func TestPartitionExports_KubernetesName(t *testing.T) { + require.Equal(t, "foo", (&PartitionExports{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) +} + +func TestPartitionExports_ConsulNamespace(t *testing.T) { + require.Equal(t, common.DefaultConsulNamespace, (&PartitionExports{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"}}).ConsulMirroringNS()) +} + +func TestPartitionExports_ConsulGlobalResource(t *testing.T) { + require.True(t, (&PartitionExports{}).ConsulGlobalResource()) +} + +func TestPartitionExports_ObjectMeta(t *testing.T) { + meta := metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + } + partitionExports := &PartitionExports{ + ObjectMeta: meta, + } + require.Equal(t, meta, partitionExports.GetObjectMeta()) +} diff --git a/control-plane/api/v1alpha1/partitionexports_webhook.go b/control-plane/api/v1alpha1/partitionexports_webhook.go new file mode 100644 index 0000000000..6dc2e6c2a6 --- /dev/null +++ b/control-plane/api/v1alpha1/partitionexports_webhook.go @@ -0,0 +1,70 @@ +package v1alpha1 + +import ( + "context" + "fmt" + "net/http" + + "github.com/go-logr/logr" + capi "github.com/hashicorp/consul/api" + admissionv1 "k8s.io/api/admission/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +// +kubebuilder:object:generate=false + +type PartitionExportsWebhook struct { + client.Client + ConsulClient *capi.Client + Logger logr.Logger + decoder *admission.Decoder + EnableConsulNamespaces bool + EnableNSMirroring bool + PartitionName string +} + +// 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-partitionexports,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=partitionexports,versions=v1alpha1,name=mutate-partitionexports.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 + +func (v *PartitionExportsWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { + var exports PartitionExports + var exportsList PartitionExportsList + err := v.decoder.Decode(req, &exports) + if err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + + if req.Operation == admissionv1.Create { + v.Logger.Info("validate create", "name", exports.KubernetesName()) + + if exports.KubernetesName() != v.PartitionName { + return admission.Errored(http.StatusBadRequest, + fmt.Errorf(`%s resource name must be the same name as the partition, "%s"`, + exports.KubeKind(), v.PartitionName)) + } + + if err := v.Client.List(ctx, &exportsList); err != nil { + return admission.Errored(http.StatusInternalServerError, err) + } + + if len(exportsList.Items) > 0 { + return admission.Errored(http.StatusBadRequest, + fmt.Errorf("%s resource already defined - only one partitionexports entry is supported per Kubernetes cluster", + exports.KubeKind())) + } + } + + return admission.Allowed(fmt.Sprintf("valid %s request", exports.KubeKind())) +} + +func (v *PartitionExportsWebhook) InjectDecoder(d *admission.Decoder) error { + v.decoder = d + return nil +} diff --git a/control-plane/api/v1alpha1/partitionexports_webhook_test.go b/control-plane/api/v1alpha1/partitionexports_webhook_test.go new file mode 100644 index 0000000000..5ee4bc2ce6 --- /dev/null +++ b/control-plane/api/v1alpha1/partitionexports_webhook_test.go @@ -0,0 +1,106 @@ +package v1alpha1 + +import ( + "context" + "encoding/json" + "testing" + + logrtest "github.com/go-logr/logr/testing" + "github.com/stretchr/testify/require" + admissionv1 "k8s.io/api/admission/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/webhook/admission" +) + +func TestValidatePartitionExports(t *testing.T) { + otherNS := "other" + otherPartition := "other" + + cases := map[string]struct { + existingResources []runtime.Object + newResource *PartitionExports + expAllow bool + expErrMessage string + }{ + "no duplicates, valid": { + existingResources: nil, + newResource: &PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: otherPartition, + }, + Spec: PartitionExportsSpec{}, + }, + expAllow: true, + }, + "partitionexports exists": { + existingResources: []runtime.Object{&PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: otherPartition, + }, + }}, + newResource: &PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: otherPartition, + }, + Spec: PartitionExportsSpec{ + Services: []ExportedService{ + { + Name: "service", + Namespace: "service-ns", + Consumers: []ServiceConsumer{{Partition: "other"}}, + }, + }, + }, + }, + expAllow: false, + expErrMessage: "partitionexports resource already defined - only one partitionexports entry is supported per Kubernetes cluster", + }, + "name not exports": { + existingResources: []runtime.Object{}, + newResource: &PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: "local", + }, + }, + expAllow: false, + expErrMessage: "partitionexports resource name must be the same name as the partition, \"other\"", + }, + } + 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) + s := runtime.NewScheme() + s.AddKnownTypes(GroupVersion, &PartitionExports{}, &PartitionExportsList{}) + client := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(c.existingResources...).Build() + decoder, err := admission.NewDecoder(s) + require.NoError(t, err) + + validator := &PartitionExportsWebhook{ + Client: client, + ConsulClient: nil, + Logger: logrtest.TestLogger{T: t}, + PartitionName: otherPartition, + decoder: decoder, + } + response := validator.Handle(ctx, admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Name: c.newResource.KubernetesName(), + Namespace: otherNS, + Operation: admissionv1.Create, + Object: runtime.RawExtension{ + Raw: marshalledRequestObject, + }, + }, + }) + + require.Equal(t, c.expAllow, response.Allowed) + if c.expErrMessage != "" { + require.Equal(t, c.expErrMessage, response.AdmissionResponse.Result.Message) + } + }) + } +} diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index 77b6b2d4e2..04288255f1 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -77,6 +77,26 @@ func (in *Destination) DeepCopy() *Destination { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExportedService) DeepCopyInto(out *ExportedService) { + *out = *in + if in.Consumers != nil { + in, out := &in.Consumers, &out.Consumers + *out = make([]ServiceConsumer, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExportedService. +func (in *ExportedService) DeepCopy() *ExportedService { + if in == nil { + return nil + } + out := new(ExportedService) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Expose) DeepCopyInto(out *Expose) { *out = *in @@ -527,6 +547,87 @@ func (in *MeshSpec) DeepCopy() *MeshSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PartitionExports) DeepCopyInto(out *PartitionExports) { + *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 PartitionExports. +func (in *PartitionExports) DeepCopy() *PartitionExports { + if in == nil { + return nil + } + out := new(PartitionExports) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PartitionExports) 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 *PartitionExportsList) DeepCopyInto(out *PartitionExportsList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]PartitionExports, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PartitionExportsList. +func (in *PartitionExportsList) DeepCopy() *PartitionExportsList { + if in == nil { + return nil + } + out := new(PartitionExportsList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *PartitionExportsList) 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 *PartitionExportsSpec) DeepCopyInto(out *PartitionExportsSpec) { + *out = *in + if in.Services != nil { + in, out := &in.Services, &out.Services + *out = make([]ExportedService, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PartitionExportsSpec. +func (in *PartitionExportsSpec) DeepCopy() *PartitionExportsSpec { + if in == nil { + return nil + } + out := new(PartitionExportsSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PassiveHealthCheck) DeepCopyInto(out *PassiveHealthCheck) { *out = *in @@ -649,6 +750,21 @@ 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 *ServiceConsumer) DeepCopyInto(out *ServiceConsumer) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceConsumer. +func (in *ServiceConsumer) DeepCopy() *ServiceConsumer { + if in == nil { + return nil + } + out := new(ServiceConsumer) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceDefaults) DeepCopyInto(out *ServiceDefaults) { *out = *in diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_partitionexports.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_partitionexports.yaml new file mode 100644 index 0000000000..8e31c6ade8 --- /dev/null +++ b/control-plane/config/crd/bases/consul.hashicorp.com_partitionexports.yaml @@ -0,0 +1,130 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.0 + creationTimestamp: null + name: partitionexports.consul.hashicorp.com +spec: + group: consul.hashicorp.com + names: + kind: PartitionExports + listKind: PartitionExportsList + plural: partitionexports + singular: partitionexports + 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: PartitionExports is the Schema for the partitionexports 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: PartitionExportsSpec defines the desired state of PartitionExports + properties: + services: + description: Services is a list of services to be exported and the + list of partitions to expose them to. + items: + description: ExportedService manages the exporting of a service + in the local partition to other partitions. + properties: + consumers: + description: Consumers is a list of downstream consumers of + the service to be exported. + items: + description: ServiceConsumer represents a downstream consumer + of the service to be exported. + properties: + partition: + description: Partition is the admin partition to export + the service to. + type: string + type: object + type: array + name: + description: Name is the name of the service to be exported. + type: string + namespace: + description: Namespace is the namespace to export the service + from. + 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/kustomization.yaml b/control-plane/config/crd/kustomization.yaml index ca5496003f..1c9666aac6 100644 --- a/control-plane/config/crd/kustomization.yaml +++ b/control-plane/config/crd/kustomization.yaml @@ -10,6 +10,7 @@ resources: - bases/consul.hashicorp.com_ingressgateways.yaml - bases/consul.hashicorp.com_terminatinggateways.yaml - bases/consul.hashicorp.com_meshes.yaml +- bases/consul.hashicorp.com_partitionexports.yaml # +kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -23,6 +24,7 @@ patchesStrategicMerge: - patches/webhook_in_ingressgateways.yaml - patches/webhook_in_terminatinggateways.yaml #- patches/webhook_in_meshes.yaml +#- patches/webhook_in_partitionexports.yaml # +kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. @@ -35,6 +37,7 @@ patchesStrategicMerge: #- patches/cainjection_in_ingressgateways.yaml #- patches/cainjection_in_terminatinggateways.yaml #- patches/cainjection_in_meshes.yaml +#- patches/cainjection_in_partitionexports.yaml # +kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/control-plane/config/crd/patches/webhook_in_partitionexports.yaml b/control-plane/config/crd/patches/webhook_in_partitionexports.yaml new file mode 100644 index 0000000000..3084d0409c --- /dev/null +++ b/control-plane/config/crd/patches/webhook_in_partitionexports.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: partitionexports.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/partitionexport_editor_role.yaml b/control-plane/config/rbac/partitionexport_editor_role.yaml new file mode 100644 index 0000000000..45b9d4c5c0 --- /dev/null +++ b/control-plane/config/rbac/partitionexport_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit partitionexports. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: partitionexport-editor-role +rules: +- apiGroups: + - consul.hashicorp.com + resources: + - partitionexports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - consul.hashicorp.com + resources: + - partitionexports/status + verbs: + - get diff --git a/control-plane/config/rbac/partitionexport_viewer_role.yaml b/control-plane/config/rbac/partitionexport_viewer_role.yaml new file mode 100644 index 0000000000..ce62786b98 --- /dev/null +++ b/control-plane/config/rbac/partitionexport_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view partitionexports. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: partitionexport-viewer-role +rules: +- apiGroups: + - consul.hashicorp.com + resources: + - partitionexports + verbs: + - get + - list + - watch +- apiGroups: + - consul.hashicorp.com + resources: + - partitionexports/status + verbs: + - get diff --git a/control-plane/config/rbac/role.yaml b/control-plane/config/rbac/role.yaml index 734e80da0f..f1a46e72d3 100644 --- a/control-plane/config/rbac/role.yaml +++ b/control-plane/config/rbac/role.yaml @@ -46,6 +46,26 @@ rules: - get - patch - update +- apiGroups: + - consul.hashicorp.com + resources: + - partitionexports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - consul.hashicorp.com + resources: + - partitionexports/status + verbs: + - get + - patch + - update - apiGroups: - consul.hashicorp.com resources: diff --git a/control-plane/config/samples/consul_v1alpha1_partitionexport.yaml b/control-plane/config/samples/consul_v1alpha1_partitionexport.yaml new file mode 100644 index 0000000000..fa34ecf043 --- /dev/null +++ b/control-plane/config/samples/consul_v1alpha1_partitionexport.yaml @@ -0,0 +1,7 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: PartitionExport +metadata: + name: exports +spec: + # Add fields here + foo: bar diff --git a/control-plane/config/webhook/manifests.yaml b/control-plane/config/webhook/manifests.yaml index 21d6cf6dec..8264b31887 100644 --- a/control-plane/config/webhook/manifests.yaml +++ b/control-plane/config/webhook/manifests.yaml @@ -48,6 +48,27 @@ webhooks: resources: - mesh sideEffects: None +- admissionReviewVersions: + - v1beta1 + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-v1alpha1-partitionexports + failurePolicy: Fail + name: mutate-partitionexports.consul.hashicorp.com + rules: + - apiGroups: + - consul.hashicorp.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - partitionexports + sideEffects: None - admissionReviewVersions: - v1beta1 - v1 diff --git a/control-plane/controller/configentry_controller_ent_test.go b/control-plane/controller/configentry_controller_ent_test.go index 8291276d02..09b8d4c06d 100644 --- a/control-plane/controller/configentry_controller_ent_test.go +++ b/control-plane/controller/configentry_controller_ent_test.go @@ -120,7 +120,7 @@ func TestConfigEntryController_createsConfigEntry_consulNamespaces(tt *testing.T ConsulKind: capi.ProxyDefaults, KubeResource: &v1alpha1.ProxyDefaults{ ObjectMeta: metav1.ObjectMeta{ - Name: "global", + Name: common.Global, Namespace: c.SourceKubeNS, }, Spec: v1alpha1.ProxyDefaultsSpec{ diff --git a/control-plane/controller/partitionexports_controller.go b/control-plane/controller/partitionexports_controller.go new file mode 100644 index 0000000000..fd1034a81b --- /dev/null +++ b/control-plane/controller/partitionexports_controller.go @@ -0,0 +1,40 @@ +package controller + +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" + + consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" +) + +// PartitionExportsController reconciles a PartitionExports object +type PartitionExportsController struct { + client.Client + Log logr.Logger + Scheme *runtime.Scheme + ConfigEntryController *ConfigEntryController +} + +// +kubebuilder:rbac:groups=consul.hashicorp.com,resources=partitionexports,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=consul.hashicorp.com,resources=partitionexports/status,verbs=get;update;patch + +func (r *PartitionExportsController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + return r.ConfigEntryController.ReconcileEntry(ctx, r, req, &consulv1alpha1.PartitionExports{}) +} + +func (r *PartitionExportsController) Logger(name types.NamespacedName) logr.Logger { + return r.Log.WithValues("request", name) +} + +func (r *PartitionExportsController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + return r.Status().Update(ctx, obj, opts...) +} + +func (r *PartitionExportsController) SetupWithManager(mgr ctrl.Manager) error { + return setupWithManager(mgr, &consulv1alpha1.PartitionExports{}, r) +} diff --git a/control-plane/go.mod b/control-plane/go.mod index 35fce971ae..044d9f347c 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/go-cmp v0.5.6 github.com/google/go-querystring v1.0.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf + github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f @@ -28,17 +28,16 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-testing-interface v1.14.0 // indirect github.com/mitchellh/mapstructure v1.4.1 + github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.7.0 - go.uber.org/zap v1.17.0 - golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 // indirect - golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba - golang.org/x/tools v0.1.2 // indirect + go.uber.org/zap v1.19.0 + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac gomodules.xyz/jsonpatch/v2 v2.2.0 - k8s.io/api v0.21.1 - k8s.io/apimachinery v0.21.1 - k8s.io/client-go v0.21.1 - k8s.io/klog/v2 v2.8.0 - sigs.k8s.io/controller-runtime v0.9.0 + k8s.io/api v0.22.2 + k8s.io/apimachinery v0.22.2 + k8s.io/client-go v0.22.2 + k8s.io/klog/v2 v2.9.0 + sigs.k8s.io/controller-runtime v0.10.2 ) go 1.16 diff --git a/control-plane/go.sum b/control-plane/go.sum index dffc93655e..e80510e6c9 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -25,17 +25,18 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v44.0.0+incompatible h1:e82Yv2HNpS0kuyeCrV29OPKvEiqfs2/uJHic3/3iKdg= github.com/Azure/azure-sdk-for-go v44.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= -github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE= -github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= -github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/azure/auth v0.5.0 h1:nSMjYIe24eBYasAIxt859TxyXef/IqoH+8/g4+LmcVs= github.com/Azure/go-autorest/autorest/azure/auth v0.5.0/go.mod h1:QRTvSZQpxqm8mSErhnbI+tANIBAKP7B+UIE2z4ypUO0= github.com/Azure/go-autorest/autorest/azure/cli v0.4.0 h1:Ml+UCrnlKD+cJmSzrZ/RDcDw86NjkRUpnFh7V5JUhzU= @@ -53,8 +54,9 @@ github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcP github.com/Azure/go-autorest/autorest/validation v0.3.0 h1:3I9AAI63HfcLtphd9g39ruUwRI+Ca+z/f36KHPFRUss= github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= @@ -75,6 +77,7 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -86,6 +89,9 @@ github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgI github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.25.41 h1:/hj7nZ0586wFqpwjNpzWiUTwtaMgxAZNZKHay80MdXw= github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -97,6 +103,8 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= @@ -107,8 +115,12 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -116,13 +128,11 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -143,27 +153,32 @@ github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -182,32 +197,31 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -228,17 +242,18 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= @@ -258,7 +273,6 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -268,26 +282,24 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf h1:fouyN8SkrE4py09XaOru4PCM9zunem39CjOrMJMrKsc= -github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= +github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c h1:7hQzN7YHI2XscCNqPVW5pORQSwJWdFgObnwXNFdEJI8= +github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -324,9 +336,8 @@ github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2I github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= @@ -355,12 +366,13 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f h1:ENpDacvnr8faw5ugQmEF1QYk+f/Y9lXFvuYmRxykago= github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -381,7 +393,6 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -393,21 +404,19 @@ github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czP github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= @@ -432,7 +441,7 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -452,21 +461,21 @@ github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20180130162743-b8a9be070da4/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= -github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c h1:vwpFWvAO8DeIZfFeqASzZfsxuWPno9ncAebBEP0N3uE= github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -508,13 +517,13 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 h1:Wdi9nwnhFNAlseAOekn6B5G/+GMtks9UKbvRU/CMM/o= github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/zerolog v1.4.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -532,24 +541,24 @@ github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjM github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d h1:bVQRCxQvfjNUeRqaY/uT0tFuvuFY0ulgnczuR684Xic= github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -571,12 +580,11 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible h1:8uRvJleFpqLsO77WaAh2UrasMOzd8MxXrNj20e7El+Q= github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo= github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -585,15 +593,31 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -603,8 +627,9 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -641,8 +666,9 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -651,7 +677,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -672,7 +697,6 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -685,11 +709,13 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -725,10 +751,8 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -750,21 +774,23 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210611083646-a4fc73990273 h1:faDu4veV+8pcThn4fewv6TVlNCezafGoC1gM/mxQLbQ= -golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo= +golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= @@ -775,15 +801,15 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -798,7 +824,6 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -827,7 +852,6 @@ golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -873,19 +897,27 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4 google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= -google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -906,7 +938,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= @@ -922,6 +953,7 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -941,20 +973,20 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= -k8s.io/api v0.21.1 h1:94bbZ5NTjdINJEdzOkpS4vdPhkb1VFpTYC9zh43f75c= -k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s= -k8s.io/apiextensions-apiserver v0.21.1 h1:AA+cnsb6w7SZ1vD32Z+zdgfXdXY8X9uGX5bN6EoPEIo= -k8s.io/apiextensions-apiserver v0.21.1/go.mod h1:KESQFCGjqVcVsZ9g0xX5bacMjyX5emuWcS2arzdEouA= +k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= +k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= +k8s.io/apiextensions-apiserver v0.22.2 h1:zK7qI8Ery7j2CaN23UCFaC1hj7dMiI87n01+nKuewd4= +k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apimachinery v0.21.1 h1:Q6XuHGlj2xc+hlMCvqyYfbv3H7SRGn2c8NycxJquDVs= -k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= -k8s.io/apiserver v0.21.1/go.mod h1:nLLYZvMWn35glJ4/FZRhzLG/3MPxAaZTgV4FJZdr+tY= +k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= +k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= -k8s.io/client-go v0.21.1 h1:bhblWYLZKUu+pm50plvQF8WpY6TXdRRtcS/K9WauOj4= -k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs= -k8s.io/code-generator v0.21.1/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= -k8s.io/component-base v0.21.1 h1:iLpj2btXbR326s/xNQWmPNGu0gaYSjzn7IN/5i28nQw= -k8s.io/component-base v0.21.1/go.mod h1:NgzFZ2qu4m1juby4TnrmpR8adRk6ka62YdH5DkIIyKA= +k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= +k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= +k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= +k8s.io/component-base v0.22.2 h1:vNIvE0AIrLhjX8drH0BgCNJcR4QZxMXcJzBsDplDx9M= +k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= @@ -964,26 +996,25 @@ k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= -k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210527160623-6fdb442a123b h1:MSqsVQ3pZvPGTqCjptfimO2WjG7A9un2zcpiHkA6M/s= -k8s.io/utils v0.0.0-20210527160623-6fdb442a123b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/controller-runtime v0.9.0 h1:ZIZ/dtpboPSbZYY7uUz2OzrkaBTOThx2yekLtpGB+zY= -sigs.k8s.io/controller-runtime v0.9.0/go.mod h1:TgkfvrhhEw3PlI0BRL/5xM+89y3/yc0ZDfdbTl84si8= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/controller-runtime v0.10.2 h1:jW8qiY+yMnnPx6O9hu63tgcwaKzd1yLYui+mpvClOOc= +sigs.k8s.io/controller-runtime v0.10.2/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/control-plane/subcommand/controller/command.go b/control-plane/subcommand/controller/command.go index 0e7a84a540..e1640de4c8 100644 --- a/control-plane/subcommand/controller/command.go +++ b/control-plane/subcommand/controller/command.go @@ -183,6 +183,15 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", common.Mesh) return 1 } + if err = (&controller.PartitionExportsController{ + ConfigEntryController: configEntryReconciler, + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controller").WithName(common.PartitionExports), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", common.PartitionExports) + return 1 + } if err = (&controller.ServiceRouterController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), @@ -272,6 +281,15 @@ func (c *Command) Run(args []string) int { EnableConsulNamespaces: c.flagEnableNamespaces, EnableNSMirroring: c.flagEnableNSMirroring, }}) + mgr.GetWebhookServer().Register("/mutate-v1alpha1-partitionexports", + &webhook.Admission{Handler: &v1alpha1.PartitionExportsWebhook{ + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.PartitionExports), + EnableConsulNamespaces: c.flagEnableNamespaces, + EnableNSMirroring: c.flagEnableNSMirroring, + PartitionName: c.httpFlags.Partition(), + }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicerouter", &webhook.Admission{Handler: &v1alpha1.ServiceRouterWebhook{ Client: mgr.GetClient(), From fe39eda7ebeb7e8a157206e076ad797d07837977 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 27 Oct 2021 10:23:59 -0400 Subject: [PATCH 093/418] Consul meta (#803) * Use type ConsulMeta for defaultNamespaces in config entry interface * Update Validate to recieve ConsulMeta * Update validations for Config Entries with Partition awareness - Add acceptance test and controller test for PartitionExports. * Skipping tests for partition-exports controller as the images the tests run against dont yet support partition-exports. * Apply suggestions from code review * Update control-plane/controller/partitionexports_controller_ent_test.go --- acceptance/go.mod | 2 +- acceptance/go.sum | 7 +- .../controller/controller_namespaces_test.go | 35 +- .../tests/fixtures/crds/partitionexports.yaml | 2 +- control-plane/api/common/configentry.go | 33 +- .../api/common/configentry_webhook.go | 15 +- .../api/common/configentry_webhook_test.go | 16 +- .../api/v1alpha1/ingressgateway_types.go | 11 +- .../api/v1alpha1/ingressgateway_types_test.go | 59 +-- .../api/v1alpha1/ingressgateway_webhook.go | 32 +- control-plane/api/v1alpha1/mesh_types.go | 4 +- control-plane/api/v1alpha1/mesh_webhook.go | 8 +- .../api/v1alpha1/partitionexports_types.go | 40 +- .../api/v1alpha1/partitionexports_webhook.go | 21 +- .../v1alpha1/partitionexports_webhook_test.go | 110 ++++- .../api/v1alpha1/proxydefaults_types.go | 4 +- .../api/v1alpha1/proxydefaults_types_test.go | 2 +- .../api/v1alpha1/proxydefaults_webhook.go | 11 +- .../api/v1alpha1/servicedefaults_types.go | 18 +- .../v1alpha1/servicedefaults_types_test.go | 85 ++-- .../api/v1alpha1/servicedefaults_webhook.go | 32 +- .../api/v1alpha1/serviceintentions_types.go | 24 +- .../v1alpha1/serviceintentions_types_test.go | 190 ++++++-- .../api/v1alpha1/serviceintentions_webhook.go | 17 +- .../serviceintentions_webhook_test.go | 43 +- .../api/v1alpha1/serviceresolver_types.go | 7 +- .../v1alpha1/serviceresolver_types_test.go | 2 +- .../api/v1alpha1/serviceresolver_webhook.go | 32 +- .../api/v1alpha1/servicerouter_types.go | 11 +- .../api/v1alpha1/servicerouter_types_test.go | 59 +-- .../api/v1alpha1/servicerouter_webhook.go | 32 +- .../api/v1alpha1/servicesplitter_types.go | 6 +- .../v1alpha1/servicesplitter_types_test.go | 2 +- .../api/v1alpha1/servicesplitter_webhook.go | 32 +- .../api/v1alpha1/terminatinggateway_types.go | 11 +- .../v1alpha1/terminatinggateway_types_test.go | 59 +-- .../v1alpha1/terminatinggateway_webhook.go | 32 +- control-plane/config/rbac/role.yaml | 20 + control-plane/config/webhook/manifests.yaml | 21 + .../partitionexports_controller_ent_test.go | 425 ++++++++++++++++++ .../subcommand/controller/command.go | 114 ++--- 41 files changed, 1184 insertions(+), 502 deletions(-) create mode 100644 control-plane/controller/partitionexports_controller_ent_test.go diff --git a/acceptance/go.mod b/acceptance/go.mod index 2ac3c700b0..0113dd8adb 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/gruntwork-io/terratest v0.31.2 - github.com/hashicorp/consul/api v1.10.1-0.20211020192418-04cd2c983e9c + github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c github.com/hashicorp/consul/sdk v0.8.0 github.com/stretchr/testify v1.5.1 gopkg.in/yaml.v2 v2.2.8 diff --git a/acceptance/go.sum b/acceptance/go.sum index 9008c7aaf4..67d784e957 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -225,11 +225,8 @@ github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arn github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= -github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf h1:fouyN8SkrE4py09XaOru4PCM9zunem39CjOrMJMrKsc= -github.com/hashicorp/consul/api v1.10.1-0.20210915232521-e0a7900f52bf/go.mod h1:sDjTOq0yUyv5G4h+BqSea7Fn6BU+XbolEz1952UB+mk= -github.com/hashicorp/consul/api v1.10.1-0.20211020192418-04cd2c983e9c h1:7eKUSC17HDH0+lHsI/fiPe5y8hMarXJdECqG7KiGkNA= -github.com/hashicorp/consul/api v1.10.1-0.20211020192418-04cd2c983e9c/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/sdk v0.7.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= +github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c h1:7hQzN7YHI2XscCNqPVW5pORQSwJWdFgObnwXNFdEJI8= +github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= diff --git a/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go index 2299a860a7..00affb3f19 100644 --- a/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -74,9 +74,12 @@ func TestControllerNamespaces(t *testing.T) { ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ - "global.enableConsulNamespaces": "true", - "controller.enabled": "true", - "connectInject.enabled": "true", + "global.image": "ashwinvenkatesh/consul@sha256:7426f47fa7065e38a2488042be66325aa37cda17a3bc15e58178104ff4619c1b", + + "global.enableConsulNamespaces": "true", + "global.adminPartitions.enabled": "true", + "controller.enabled": "true", + "connectInject.enabled": "true", // When mirroringK8S is set, this setting is ignored. "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, @@ -153,6 +156,13 @@ func TestControllerNamespaces(t *testing.T) { require.True(r, ok, "could not cast to ProxyConfigEntry") require.Equal(r, api.MeshGatewayModeLocal, proxyDefaultEntry.MeshGateway.Mode) + // partition-exports + entry, _, err = consulClient.ConfigEntries().Get(api.PartitionExports, "default", defaultOpts) + require.NoError(r, err) + partitionExportsEntry, ok := entry.(*api.PartitionExportsConfigEntry) + require.True(r, ok, "could not cast to PartitionExportsConfigEntry") + require.Equal(r, "frontend", partitionExportsEntry.Services[0].Name) + // mesh entry, _, err = consulClient.ConfigEntries().Get(api.MeshConfig, "mesh", defaultOpts) require.NoError(r, err) @@ -220,6 +230,10 @@ func TestControllerNamespaces(t *testing.T) { patchMeshGatewayMode := "remote" k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "proxydefaults", "global", "-p", fmt.Sprintf(`{"spec":{"meshGateway":{"mode": "%s"}}}`, patchMeshGatewayMode), "--type=merge") + logger.Log(t, "patching partition-exports custom resource") + patchServiceName := "backend" + k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "partitionexports", "default", "-p", fmt.Sprintf(`{"spec":{"services":[{"name": "%s", "namespace": "front", "consumers":[{"partition": "foo"}]}]}}`, patchServiceName), "--type=merge") + logger.Log(t, "patching mesh custom resource") k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "mesh", "mesh", "-p", fmt.Sprintf(`{"spec":{"transparentProxy":{"meshDestinationsOnly": %t}}}`, false), "--type=merge") @@ -264,6 +278,13 @@ func TestControllerNamespaces(t *testing.T) { require.True(r, ok, "could not cast to ProxyConfigEntry") require.Equal(r, api.MeshGatewayModeRemote, proxyDefaultsEntry.MeshGateway.Mode) + // partition-exports + entry, _, err = consulClient.ConfigEntries().Get(api.PartitionExports, "default", defaultOpts) + require.NoError(r, err) + partitionExportsEntry, ok := entry.(*api.PartitionExportsConfigEntry) + require.True(r, ok, "could not cast to PartitionExportsConfigEntry") + require.Equal(r, "backend", partitionExportsEntry.Services[0].Name) + // mesh entry, _, err = consulClient.ConfigEntries().Get(api.MeshConfig, "mesh", defaultOpts) require.NoError(r, err) @@ -321,6 +342,9 @@ func TestControllerNamespaces(t *testing.T) { logger.Log(t, "deleting proxy-defaults custom resource") k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "proxydefaults", "global") + logger.Log(t, "deleting partition-exports custom resource") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "partitionexports", "default") + logger.Log(t, "deleting mesh custom resource") k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "mesh", "mesh") @@ -356,6 +380,11 @@ func TestControllerNamespaces(t *testing.T) { require.Error(r, err) require.Contains(r, err.Error(), "404 (Config entry not found") + // partition-exports + _, _, err = consulClient.ConfigEntries().Get(api.PartitionExports, "default", defaultOpts) + require.Error(r, err) + require.Contains(r, err.Error(), "404 (Config entry not found") + // mesh _, _, err = consulClient.ConfigEntries().Get(api.MeshConfig, "mesh", defaultOpts) require.Error(r, err) diff --git a/acceptance/tests/fixtures/crds/partitionexports.yaml b/acceptance/tests/fixtures/crds/partitionexports.yaml index d6159310cf..cbcf65c389 100644 --- a/acceptance/tests/fixtures/crds/partitionexports.yaml +++ b/acceptance/tests/fixtures/crds/partitionexports.yaml @@ -1,7 +1,7 @@ apiVersion: consul.hashicorp.com/v1alpha1 kind: PartitionExports metadata: - name: exports + name: default spec: services: - name: frontend diff --git a/control-plane/api/common/configentry.go b/control-plane/api/common/configentry.go index eefd52635f..2d83ce05b0 100644 --- a/control-plane/api/common/configentry.go +++ b/control-plane/api/common/configentry.go @@ -58,13 +58,42 @@ type ConfigEntryResource interface { // DeepCopyObject should be implemented by the generated code. DeepCopyObject() runtime.Object // Validate returns an error if the resource is invalid. - Validate(namespacesEnabled bool) error + Validate(consulMeta ConsulMeta) error // DefaultNamespaceFields sets Consul namespace fields on the config entry // spec to their default values if namespaces are enabled. - DefaultNamespaceFields(consulNamespacesEnabled bool, destinationNamespace string, mirroring bool, prefix string) + DefaultNamespaceFields(consulMeta ConsulMeta) // ConfigEntryResource has to implement metav1.Object so that structs // that implement it effectively implement client.Object which is // the interface supported by controller-runtime reconcile-able resources. metav1.Object } + +// ConsulMeta contains metadata which represents installation specific +// information about Consul. +type ConsulMeta struct { + // PartitionsEnabled indicates that a user is running Consul Enterprise + // with version 1.11+ which supports Admin Partitions. + PartitionsEnabled bool + // Partition is the name of the Admin Partition in Consul that the config + // entry will be created in. + Partition string + + // NamespacesEnabled indicates that a user is running Consul Enterprise + // with version 1.7+ which supports namespaces. + NamespacesEnabled bool + // DestinationNamespace is the namespace in Consul that the config entry created + // in k8s will get mapped into. If the Consul namespace does not already exist, it will + // be created. + DestinationNamespace string + // Mirroring causes Consul namespaces to be created to match the + // k8s namespace of any config entry custom resource. Config entries will + // be created in the matching Consul namespace. + Mirroring bool + // Prefix works in conjunction with Mirroring. + // It is the prefix added to the Consul namespace to map to a specific. + // k8s namespace. For example, if `mirroringK8SPrefix` is set to "k8s-", a + // service in the k8s `staging` namespace will be registered into the + // `k8s-staging` Consul namespace. + Prefix string +} diff --git a/control-plane/api/common/configentry_webhook.go b/control-plane/api/common/configentry_webhook.go index fe62b29754..4028a5e3cb 100644 --- a/control-plane/api/common/configentry_webhook.go +++ b/control-plane/api/common/configentry_webhook.go @@ -29,12 +29,9 @@ func ValidateConfigEntry( logger logr.Logger, configEntryLister ConfigEntryLister, cfgEntry ConfigEntryResource, - enableConsulNamespaces bool, - nsMirroring bool, - consulDestinationNamespace string, - nsMirroringPrefix string) admission.Response { + consulMeta ConsulMeta) admission.Response { - defaultingPatches, err := DefaultingPatches(cfgEntry, enableConsulNamespaces, nsMirroring, consulDestinationNamespace, nsMirroringPrefix) + defaultingPatches, err := DefaultingPatches(cfgEntry, consulMeta) if err != nil { return admission.Errored(http.StatusInternalServerError, err) } @@ -43,7 +40,7 @@ func ValidateConfigEntry( // 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 := !(enableConsulNamespaces && nsMirroring) + singleConsulDestNS := !(consulMeta.NamespacesEnabled && consulMeta.Mirroring) if req.Operation == admissionv1.Create && singleConsulDestNS { logger.Info("validate create", "name", cfgEntry.KubernetesName()) @@ -61,7 +58,7 @@ func ValidateConfigEntry( } } } - if err := cfgEntry.Validate(enableConsulNamespaces); err != nil { + if err := cfgEntry.Validate(consulMeta); err != nil { return admission.Errored(http.StatusBadRequest, err) } return admission.Patched(fmt.Sprintf("valid %s request", cfgEntry.KubeKind()), defaultingPatches...) @@ -69,12 +66,12 @@ func ValidateConfigEntry( // DefaultingPatches returns the patches needed to set fields to their // defaults. -func DefaultingPatches(cfgEntry ConfigEntryResource, enableConsulNamespaces bool, nsMirroring bool, consulDestinationNamespace string, nsMirroringPrefix string) ([]jsonpatch.Operation, error) { +func DefaultingPatches(cfgEntry ConfigEntryResource, consulMeta ConsulMeta) ([]jsonpatch.Operation, error) { beforeDefaulting, err := json.Marshal(cfgEntry) if err != nil { return nil, fmt.Errorf("marshalling input: %s", err) } - cfgEntry.DefaultNamespaceFields(enableConsulNamespaces, consulDestinationNamespace, nsMirroring, nsMirroringPrefix) + cfgEntry.DefaultNamespaceFields(consulMeta) afterDefaulting, err := json.Marshal(cfgEntry) if err != nil { return nil, fmt.Errorf("marshalling after defaulting: %s", err) diff --git a/control-plane/api/common/configentry_webhook_test.go b/control-plane/api/common/configentry_webhook_test.go index 258f4886de..cf79efea85 100644 --- a/control-plane/api/common/configentry_webhook_test.go +++ b/control-plane/api/common/configentry_webhook_test.go @@ -115,10 +115,12 @@ func TestValidateConfigEntry(t *testing.T) { logrtest.TestLogger{T: t}, lister, c.newResource, - c.enableNamespaces, - c.nsMirroring, - c.consulDestinationNS, - c.nsMirroringPrefix) + ConsulMeta{ + NamespacesEnabled: c.enableNamespaces, + DestinationNamespace: c.consulDestinationNS, + Mirroring: c.nsMirroring, + Prefix: c.nsMirroringPrefix, + }) require.Equal(t, c.expAllow, response.Allowed) if c.expErrMessage != "" { require.Equal(t, c.expErrMessage, response.AdmissionResponse.Result.Message) @@ -134,7 +136,7 @@ func TestDefaultingPatches(t *testing.T) { } // This test validates that DefaultingPatches invokes DefaultNamespaceFields on the Config Entry. - patches, err := DefaultingPatches(cfgEntry, false, false, "", "") + patches, err := DefaultingPatches(cfgEntry, ConsulMeta{}) require.NoError(t, err) require.Equal(t, []jsonpatch.Operation{ @@ -320,14 +322,14 @@ func (in *mockConfigEntry) ToConsul(string) capi.ConfigEntry { return &capi.ServiceConfigEntry{} } -func (in *mockConfigEntry) Validate(bool) error { +func (in *mockConfigEntry) Validate(_ ConsulMeta) error { if !in.Valid { return errors.New("invalid") } return nil } -func (in *mockConfigEntry) DefaultNamespaceFields(consulNamespacesEnabled bool, destinationNamespace string, mirroring bool, prefix string) { +func (in *mockConfigEntry) DefaultNamespaceFields(_ ConsulMeta) { in.MockNamespace = "bar" } diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index 4dbe4cc03a..d4b6b6dfd2 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -6,6 +6,7 @@ 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-k8s/control-plane/namespaces" capi "github.com/hashicorp/consul/api" corev1 "k8s.io/api/core/v1" @@ -213,7 +214,7 @@ func (in *IngressGateway) MatchesConsul(candidate capi.ConfigEntry) bool { return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.IngressGatewayConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } -func (in *IngressGateway) Validate(namespacesEnabled bool) error { +func (in *IngressGateway) Validate(consulMeta common.ConsulMeta) error { var errs field.ErrorList path := field.NewPath("spec") @@ -221,7 +222,7 @@ func (in *IngressGateway) Validate(namespacesEnabled bool) error { errs = append(errs, v.validate(path.Child("listeners").Index(i))...) } - errs = append(errs, in.validateNamespaces(namespacesEnabled)...) + errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) if len(errs) > 0 { return apierrors.NewInvalid( @@ -232,14 +233,14 @@ func (in *IngressGateway) Validate(namespacesEnabled bool) error { } // DefaultNamespaceFields sets the namespace field on spec.listeners[].services to their default values if namespaces are enabled. -func (in *IngressGateway) DefaultNamespaceFields(consulNamespacesEnabled bool, destinationNamespace string, mirroring bool, prefix string) { +func (in *IngressGateway) DefaultNamespaceFields(consulMeta common.ConsulMeta) { // If namespaces are enabled we want to set the namespace fields to their // defaults. If namespaces are not enabled (i.e. OSS) we don't set the // namespace fields because this would cause errors // making API calls (because namespace fields can't be set in OSS). - if consulNamespacesEnabled { + if consulMeta.NamespacesEnabled { // Default to the current namespace (i.e. the namespace of the config entry). - namespace := namespaces.ConsulNamespace(in.Namespace, consulNamespacesEnabled, destinationNamespace, mirroring, prefix) + namespace := namespaces.ConsulNamespace(in.Namespace, consulMeta.NamespacesEnabled, consulMeta.DestinationNamespace, consulMeta.Mirroring, consulMeta.Prefix) for i, listener := range in.Spec.Listeners { for j, service := range listener.Services { if service.Namespace == "" { diff --git a/control-plane/api/v1alpha1/ingressgateway_types_test.go b/control-plane/api/v1alpha1/ingressgateway_types_test.go index a7ec548e89..051aea39fe 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types_test.go +++ b/control-plane/api/v1alpha1/ingressgateway_types_test.go @@ -448,7 +448,7 @@ func TestIngressGateway_Validate(t *testing.T) { for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(testCase.namespacesEnabled) + err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled}) if len(testCase.expectedErrMsgs) != 0 { require.Error(t, err) for _, s := range testCase.expectedErrMsgs { @@ -464,39 +464,44 @@ func TestIngressGateway_Validate(t *testing.T) { // Test defaulting behavior when namespaces are enabled as well as disabled. func TestIngressGateway_DefaultNamespaceFields(t *testing.T) { namespaceConfig := map[string]struct { - enabled bool - destinationNamespace string - mirroring bool - prefix string - expectedDestination string + consulMeta common.ConsulMeta + expectedDestination string }{ "disabled": { - enabled: false, - destinationNamespace: "", - mirroring: false, - prefix: "", - expectedDestination: "", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: false, + DestinationNamespace: "", + Mirroring: false, + Prefix: "", + }, + expectedDestination: "", }, "destinationNS": { - enabled: true, - destinationNamespace: "foo", - mirroring: false, - prefix: "", - expectedDestination: "foo", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "foo", + Mirroring: false, + Prefix: "", + }, + expectedDestination: "foo", }, "mirroringEnabledWithoutPrefix": { - enabled: true, - destinationNamespace: "", - mirroring: true, - prefix: "", - expectedDestination: "bar", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "", + Mirroring: true, + Prefix: "", + }, + expectedDestination: "bar", }, "mirroringWithPrefix": { - enabled: true, - destinationNamespace: "", - mirroring: true, - prefix: "ns-", - expectedDestination: "ns-bar", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "", + Mirroring: true, + Prefix: "ns-", + }, + expectedDestination: "ns-bar", }, } @@ -547,7 +552,7 @@ func TestIngressGateway_DefaultNamespaceFields(t *testing.T) { }, }, } - input.DefaultNamespaceFields(s.enabled, s.destinationNamespace, s.mirroring, s.prefix) + input.DefaultNamespaceFields(s.consulMeta) require.True(t, cmp.Equal(input, output)) }) } diff --git a/control-plane/api/v1alpha1/ingressgateway_webhook.go b/control-plane/api/v1alpha1/ingressgateway_webhook.go index 6a3aee2fd0..8dcc2fa9ee 100644 --- a/control-plane/api/v1alpha1/ingressgateway_webhook.go +++ b/control-plane/api/v1alpha1/ingressgateway_webhook.go @@ -17,26 +17,8 @@ type IngressGatewayWebhook struct { ConsulClient *capi.Client Logger logr.Logger - // EnableConsulNamespaces indicates that a user is running Consul Enterprise - // with version 1.7+ which supports namespaces. - EnableConsulNamespaces bool - - // EnableNSMirroring causes Consul namespaces to be created to match the - // k8s namespace of any config entry custom resource. Config entries will - // be created in the matching Consul namespace. - EnableNSMirroring bool - - // ConsulDestinationNamespace is the namespace in Consul that the config entry created - // in k8s will get mapped into. If the Consul namespace does not already exist, it will - // be created. - ConsulDestinationNamespace string - - // NSMirroringPrefix works in conjunction with Namespace Mirroring. - // It is the prefix added to the Consul namespace to map to a specific. - // k8s namespace. For example, if `mirroringK8SPrefix` is set to "k8s-", a - // service in the k8s `staging` namespace will be registered into the - // `k8s-staging` Consul namespace. - NSMirroringPrefix string + // ConsulMeta contains metadata specific to the Consul installation. + ConsulMeta common.ConsulMeta decoder *admission.Decoder client.Client @@ -57,15 +39,7 @@ func (v *IngressGatewayWebhook) Handle(ctx context.Context, req admission.Reques return admission.Errored(http.StatusBadRequest, err) } - return common.ValidateConfigEntry(ctx, - req, - v.Logger, - v, - &resource, - v.EnableConsulNamespaces, - v.EnableNSMirroring, - v.ConsulDestinationNamespace, - v.NSMirroringPrefix) + return common.ValidateConfigEntry(ctx, req, v.Logger, v, &resource, v.ConsulMeta) } func (v *IngressGatewayWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { diff --git a/control-plane/api/v1alpha1/mesh_types.go b/control-plane/api/v1alpha1/mesh_types.go index 671da5c8e7..c62a684f65 100644 --- a/control-plane/api/v1alpha1/mesh_types.go +++ b/control-plane/api/v1alpha1/mesh_types.go @@ -153,10 +153,10 @@ func (in *Mesh) MatchesConsul(candidate capi.ConfigEntry) bool { return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.MeshConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } -func (in *Mesh) Validate(_ bool) error { +func (in *Mesh) Validate(_ common.ConsulMeta) error { return nil } // DefaultNamespaceFields has no behaviour here as meshes have no namespace specific fields. -func (in *Mesh) DefaultNamespaceFields(_ bool, _ string, _ bool, _ string) { +func (in *Mesh) DefaultNamespaceFields(_ common.ConsulMeta) { } diff --git a/control-plane/api/v1alpha1/mesh_webhook.go b/control-plane/api/v1alpha1/mesh_webhook.go index 54fbe2ff5d..d28cfc193c 100644 --- a/control-plane/api/v1alpha1/mesh_webhook.go +++ b/control-plane/api/v1alpha1/mesh_webhook.go @@ -17,11 +17,9 @@ import ( type MeshWebhook struct { client.Client - ConsulClient *capi.Client - Logger logr.Logger - decoder *admission.Decoder - EnableConsulNamespaces bool - EnableNSMirroring bool + ConsulClient *capi.Client + Logger logr.Logger + decoder *admission.Decoder } // NOTE: The path value in the below line is the path to the webhook. diff --git a/control-plane/api/v1alpha1/partitionexports_types.go b/control-plane/api/v1alpha1/partitionexports_types.go index 9c20377807..9fa01fa333 100644 --- a/control-plane/api/v1alpha1/partitionexports_types.go +++ b/control-plane/api/v1alpha1/partitionexports_types.go @@ -1,13 +1,19 @@ package v1alpha1 import ( + "errors" + "fmt" + "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 PartitionExportsKubeKind = "partitionexports" @@ -178,9 +184,39 @@ func (in *PartitionExports) MatchesConsul(candidate api.ConfigEntry) bool { } -func (in *PartitionExports) Validate(_ bool) error { +func (in *PartitionExports) Validate(consulMeta common.ConsulMeta) error { + var errs field.ErrorList + if !consulMeta.PartitionsEnabled { + return apierrors.NewForbidden( + schema.GroupResource{Group: ConsulHashicorpGroup, Resource: common.PartitionExports}, + in.KubernetesName(), + errors.New("Consul Enterprise Admin Partitions must be enabled to create PartitionExports")) + } + if in.Name != consulMeta.Partition { + errs = append(errs, field.Invalid(field.NewPath("name"), in.Name, fmt.Sprintf(`%s resource name must be the same name as the partition, "%s"`, in.KubeKind(), consulMeta.Partition))) + } + if len(in.Spec.Services) == 0 { + errs = append(errs, field.Invalid(field.NewPath("spec").Child("services"), in.Spec.Services, "at least one service must be exported")) + } + for i, service := range in.Spec.Services { + if err := service.validate(field.NewPath("spec").Child("services").Index(i)); err != nil { + errs = append(errs, err) + } + } + if len(errs) > 0 { + return apierrors.NewInvalid( + schema.GroupKind{Group: ConsulHashicorpGroup, Kind: PartitionExportsKubeKind}, + in.KubernetesName(), errs) + } + return nil +} + +func (in *ExportedService) validate(path *field.Path) *field.Error { + if len(in.Consumers) == 0 { + return field.Invalid(path, in.Consumers, "service must have at least 1 consumer.") + } return nil } -func (in *PartitionExports) DefaultNamespaceFields(_ bool, _ string, _ bool, _ string) { +func (in *PartitionExports) DefaultNamespaceFields(_ common.ConsulMeta) { } diff --git a/control-plane/api/v1alpha1/partitionexports_webhook.go b/control-plane/api/v1alpha1/partitionexports_webhook.go index 6dc2e6c2a6..4311055289 100644 --- a/control-plane/api/v1alpha1/partitionexports_webhook.go +++ b/control-plane/api/v1alpha1/partitionexports_webhook.go @@ -6,6 +6,7 @@ import ( "net/http" "github.com/go-logr/logr" + "github.com/hashicorp/consul-k8s/control-plane/api/common" capi "github.com/hashicorp/consul/api" admissionv1 "k8s.io/api/admission/v1" "sigs.k8s.io/controller-runtime/pkg/client" @@ -16,12 +17,10 @@ import ( type PartitionExportsWebhook struct { client.Client - ConsulClient *capi.Client - Logger logr.Logger - decoder *admission.Decoder - EnableConsulNamespaces bool - EnableNSMirroring bool - PartitionName string + ConsulClient *capi.Client + Logger logr.Logger + decoder *admission.Decoder + ConsulMeta common.ConsulMeta } // NOTE: The path value in the below line is the path to the webhook. @@ -44,12 +43,6 @@ func (v *PartitionExportsWebhook) Handle(ctx context.Context, req admission.Requ if req.Operation == admissionv1.Create { v.Logger.Info("validate create", "name", exports.KubernetesName()) - if exports.KubernetesName() != v.PartitionName { - return admission.Errored(http.StatusBadRequest, - fmt.Errorf(`%s resource name must be the same name as the partition, "%s"`, - exports.KubeKind(), v.PartitionName)) - } - if err := v.Client.List(ctx, &exportsList); err != nil { return admission.Errored(http.StatusInternalServerError, err) } @@ -61,6 +54,10 @@ func (v *PartitionExportsWebhook) Handle(ctx context.Context, req admission.Requ } } + if err := exports.Validate(v.ConsulMeta); err != nil { + return admission.Errored(http.StatusBadRequest, err) + } + return admission.Allowed(fmt.Sprintf("valid %s request", exports.KubeKind())) } diff --git a/control-plane/api/v1alpha1/partitionexports_webhook_test.go b/control-plane/api/v1alpha1/partitionexports_webhook_test.go index 5ee4bc2ce6..caacf3dfbc 100644 --- a/control-plane/api/v1alpha1/partitionexports_webhook_test.go +++ b/control-plane/api/v1alpha1/partitionexports_webhook_test.go @@ -6,6 +6,7 @@ import ( "testing" logrtest "github.com/go-logr/logr/testing" + "github.com/hashicorp/consul-k8s/control-plane/api/common" "github.com/stretchr/testify/require" admissionv1 "k8s.io/api/admission/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -21,6 +22,7 @@ func TestValidatePartitionExports(t *testing.T) { cases := map[string]struct { existingResources []runtime.Object newResource *PartitionExports + consulMeta common.ConsulMeta expAllow bool expErrMessage string }{ @@ -30,7 +32,19 @@ func TestValidatePartitionExports(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: otherPartition, }, - Spec: PartitionExportsSpec{}, + Spec: PartitionExportsSpec{ + Services: []ExportedService{ + { + Name: "service", + Namespace: "service-ns", + Consumers: []ServiceConsumer{{Partition: "other"}}, + }, + }, + }, + }, + consulMeta: common.ConsulMeta{ + PartitionsEnabled: true, + Partition: otherPartition, }, expAllow: true, }, @@ -54,18 +68,98 @@ func TestValidatePartitionExports(t *testing.T) { }, }, }, + consulMeta: common.ConsulMeta{ + PartitionsEnabled: true, + Partition: otherPartition, + }, expAllow: false, expErrMessage: "partitionexports resource already defined - only one partitionexports entry is supported per Kubernetes cluster", }, - "name not exports": { + "name not partition name": { existingResources: []runtime.Object{}, newResource: &PartitionExports{ ObjectMeta: metav1.ObjectMeta{ Name: "local", }, + Spec: PartitionExportsSpec{ + Services: []ExportedService{ + { + Name: "service", + Namespace: "service-ns", + Consumers: []ServiceConsumer{{Partition: "other"}}, + }, + }, + }, + }, + consulMeta: common.ConsulMeta{ + PartitionsEnabled: true, + Partition: otherPartition, + }, + expAllow: false, + expErrMessage: "partitionexports.consul.hashicorp.com \"local\" is invalid: name: Invalid value: \"local\": partitionexports resource name must be the same name as the partition, \"other\"", + }, + "partitions disabled": { + existingResources: []runtime.Object{}, + newResource: &PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: otherPartition, + }, + Spec: PartitionExportsSpec{ + Services: []ExportedService{ + { + Name: "service", + Namespace: "service-ns", + Consumers: []ServiceConsumer{{Partition: "other"}}, + }, + }, + }, + }, + consulMeta: common.ConsulMeta{ + PartitionsEnabled: false, + Partition: "", + }, + expAllow: false, + expErrMessage: "partitionexports.consul.hashicorp.com \"other\" is forbidden: Consul Enterprise Admin Partitions must be enabled to create PartitionExports", + }, + "no services": { + existingResources: []runtime.Object{}, + newResource: &PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: otherPartition, + }, + Spec: PartitionExportsSpec{ + Services: []ExportedService{}, + }, + }, + consulMeta: common.ConsulMeta{ + PartitionsEnabled: true, + Partition: otherPartition, + }, + expAllow: false, + expErrMessage: "partitionexports.consul.hashicorp.com \"other\" is invalid: spec.services: Invalid value: []v1alpha1.ExportedService(nil): at least one service must be exported", + }, + "service with no consumers": { + existingResources: []runtime.Object{}, + newResource: &PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: otherPartition, + }, + Spec: PartitionExportsSpec{ + Services: []ExportedService{ + { + Name: "service", + Namespace: "service-ns", + Consumers: []ServiceConsumer{}, + }, + }, + }, + }, + consulMeta: common.ConsulMeta{ + PartitionsEnabled: true, + Partition: otherPartition, }, expAllow: false, - expErrMessage: "partitionexports resource name must be the same name as the partition, \"other\"", + expErrMessage: "partitionexports.consul.hashicorp.com \"other\" is invalid: spec.services[0]: Invalid value: []v1alpha1.ServiceConsumer(nil): service must have at least 1 consumer.", }, } for name, c := range cases { @@ -80,11 +174,11 @@ func TestValidatePartitionExports(t *testing.T) { require.NoError(t, err) validator := &PartitionExportsWebhook{ - Client: client, - ConsulClient: nil, - Logger: logrtest.TestLogger{T: t}, - PartitionName: otherPartition, - decoder: decoder, + Client: client, + ConsulClient: nil, + Logger: logrtest.TestLogger{T: t}, + decoder: decoder, + ConsulMeta: c.consulMeta, } response := validator.Handle(ctx, admission.Request{ AdmissionRequest: admissionv1.AdmissionRequest{ diff --git a/control-plane/api/v1alpha1/proxydefaults_types.go b/control-plane/api/v1alpha1/proxydefaults_types.go index a296962d11..7d52b32c12 100644 --- a/control-plane/api/v1alpha1/proxydefaults_types.go +++ b/control-plane/api/v1alpha1/proxydefaults_types.go @@ -178,7 +178,7 @@ func (in *ProxyDefaults) MatchesConsul(candidate api.ConfigEntry) bool { cmp.Comparer(transparentProxyConfigComparer)) } -func (in *ProxyDefaults) Validate(namespacesEnabled bool) error { +func (in *ProxyDefaults) Validate(_ common.ConsulMeta) error { var allErrs field.ErrorList path := field.NewPath("spec") @@ -205,7 +205,7 @@ func (in *ProxyDefaults) Validate(namespacesEnabled bool) error { } // DefaultNamespaceFields has no behaviour here as proxy-defaults have no namespace specific fields. -func (in *ProxyDefaults) DefaultNamespaceFields(_ bool, _ string, _ bool, _ string) { +func (in *ProxyDefaults) DefaultNamespaceFields(_ common.ConsulMeta) { } // convertConfig converts the config of type json.RawMessage which is stored diff --git a/control-plane/api/v1alpha1/proxydefaults_types_test.go b/control-plane/api/v1alpha1/proxydefaults_types_test.go index 7b39f4b715..2950a3a36e 100644 --- a/control-plane/api/v1alpha1/proxydefaults_types_test.go +++ b/control-plane/api/v1alpha1/proxydefaults_types_test.go @@ -394,7 +394,7 @@ func TestProxyDefaults_Validate(t *testing.T) { } for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(false) + err := testCase.input.Validate(common.ConsulMeta{}) if testCase.expectedErrMsg != "" { require.EqualError(t, err, testCase.expectedErrMsg) } else { diff --git a/control-plane/api/v1alpha1/proxydefaults_webhook.go b/control-plane/api/v1alpha1/proxydefaults_webhook.go index 85f4a00847..4e221e0130 100644 --- a/control-plane/api/v1alpha1/proxydefaults_webhook.go +++ b/control-plane/api/v1alpha1/proxydefaults_webhook.go @@ -17,11 +17,10 @@ import ( type ProxyDefaultsWebhook struct { client.Client - ConsulClient *capi.Client - Logger logr.Logger - decoder *admission.Decoder - EnableConsulNamespaces bool - EnableNSMirroring bool + ConsulClient *capi.Client + Logger logr.Logger + decoder *admission.Decoder + ConsulMeta common.ConsulMeta } // NOTE: The path value in the below line is the path to the webhook. @@ -61,7 +60,7 @@ func (v *ProxyDefaultsWebhook) Handle(ctx context.Context, req admission.Request } } - if err := proxyDefaults.Validate(v.EnableConsulNamespaces); err != nil { + if err := proxyDefaults.Validate(v.ConsulMeta); err != nil { return admission.Errored(http.StatusBadRequest, err) } return admission.Allowed(fmt.Sprintf("valid %s request", proxyDefaults.KubeKind())) diff --git a/control-plane/api/v1alpha1/servicedefaults_types.go b/control-plane/api/v1alpha1/servicedefaults_types.go index 339f7ff32d..c2aa1ab61e 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types.go +++ b/control-plane/api/v1alpha1/servicedefaults_types.go @@ -3,6 +3,7 @@ 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" capi "github.com/hashicorp/consul/api" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -239,7 +240,7 @@ func (in *ServiceDefaults) ToConsul(datacenter string) capi.ConfigEntry { // Validate validates the fields provided in the spec of the ServiceDefaults and // returns an error which lists all invalid fields in the resource spec. -func (in *ServiceDefaults) Validate(namespacesEnabled bool) error { +func (in *ServiceDefaults) Validate(consulMeta common.ConsulMeta) error { var allErrs field.ErrorList path := field.NewPath("spec") @@ -256,7 +257,7 @@ func (in *ServiceDefaults) Validate(namespacesEnabled bool) error { if err := in.Spec.Mode.validate(path.Child("mode")); err != nil { allErrs = append(allErrs, err) } - allErrs = append(allErrs, in.Spec.UpstreamConfig.validate(path.Child("upstreamConfig"))...) + allErrs = append(allErrs, in.Spec.UpstreamConfig.validate(path.Child("upstreamConfig"), consulMeta.PartitionsEnabled)...) allErrs = append(allErrs, in.Spec.Expose.validate(path.Child("expose"))...) if len(allErrs) > 0 { @@ -268,16 +269,16 @@ func (in *ServiceDefaults) Validate(namespacesEnabled bool) error { return nil } -func (in *Upstreams) validate(path *field.Path) field.ErrorList { +func (in *Upstreams) validate(path *field.Path, partitionsEnabled bool) field.ErrorList { if in == nil { return nil } var errs field.ErrorList - if err := in.Defaults.validate(path.Child("defaults"), defaultUpstream); err != nil { + if err := in.Defaults.validate(path.Child("defaults"), defaultUpstream, partitionsEnabled); err != nil { errs = append(errs, err...) } for i, override := range in.Overrides { - if err := override.validate(path.Child("overrides").Index(i), overrideUpstream); err != nil { + if err := override.validate(path.Child("overrides").Index(i), overrideUpstream, partitionsEnabled); err != nil { errs = append(errs, err...) } } @@ -296,7 +297,7 @@ func (in *Upstreams) toConsul() *capi.UpstreamConfiguration { return upstreams } -func (in *Upstream) validate(path *field.Path, kind string) field.ErrorList { +func (in *Upstream) validate(path *field.Path, kind string, partitionsEnabled bool) field.ErrorList { if in == nil { return nil } @@ -311,6 +312,9 @@ func (in *Upstream) validate(path *field.Path, kind string) field.ErrorList { errs = append(errs, field.Invalid(path.Child("name"), in.Name, "upstream.name for an override upstream cannot be \"\"")) } } + if !partitionsEnabled && in.Partition != "" { + errs = append(errs, field.Invalid(path.Child("partition"), in.Partition, "Consul Enterprise Admin Partitions must be enabled to set upstream.partition")) + } if err := in.MeshGateway.validate(path.Child("meshGateway")); err != nil { errs = append(errs, err) } @@ -357,7 +361,7 @@ func (in *PassiveHealthCheck) toConsul() *capi.PassiveHealthCheck { } // DefaultNamespaceFields has no behaviour here as service-defaults have no namespace specific fields. -func (in *ServiceDefaults) DefaultNamespaceFields(_ bool, _ string, _ bool, _ string) { +func (in *ServiceDefaults) DefaultNamespaceFields(_ common.ConsulMeta) { } // MatchesConsul returns true if entry has the same config as this struct. diff --git a/control-plane/api/v1alpha1/servicedefaults_types_test.go b/control-plane/api/v1alpha1/servicedefaults_types_test.go index 04f86de8eb..8042a5b2b3 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types_test.go +++ b/control-plane/api/v1alpha1/servicedefaults_types_test.go @@ -561,8 +561,9 @@ func TestServiceDefaults_MatchesConsul(t *testing.T) { func TestServiceDefaults_Validate(t *testing.T) { cases := map[string]struct { - input *ServiceDefaults - expectedErrMsg string + input *ServiceDefaults + partitionsEnabled bool + expectedErrMsg string }{ "valid": { input: &ServiceDefaults{ @@ -589,7 +590,7 @@ func TestServiceDefaults_Validate(t *testing.T) { expectedErrMsg: "", }, "protocol": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -597,10 +598,10 @@ func TestServiceDefaults_Validate(t *testing.T) { Protocol: "foo", }, }, - `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.protocol: Invalid value: "foo": must be one of "tcp", "http", "http2", "grpc"`, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.protocol: Invalid value: "foo": must be one of "tcp", "http", "http2", "grpc"`, }, "meshgateway.mode": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -610,10 +611,10 @@ func TestServiceDefaults_Validate(t *testing.T) { }, }, }, - `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.meshGateway.mode: Invalid value: "foobar": must be one of "remote", "local", "none", ""`, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.meshGateway.mode: Invalid value: "foobar": must be one of "remote", "local", "none", ""`, }, "expose.paths[].protocol": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -628,10 +629,10 @@ func TestServiceDefaults_Validate(t *testing.T) { }, }, }, - `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.expose.paths[0].protocol: Invalid value: "invalid-protocol": must be one of "http", "http2"`, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.expose.paths[0].protocol: Invalid value: "invalid-protocol": must be one of "http", "http2"`, }, "expose.paths[].path": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -646,10 +647,10 @@ func TestServiceDefaults_Validate(t *testing.T) { }, }, }, - `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.expose.paths[0].path: Invalid value: "invalid-path": must begin with a '/'`, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.expose.paths[0].path: Invalid value: "invalid-path": must begin with a '/'`, }, "transparentProxy.outboundListenerPort": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -659,10 +660,10 @@ func TestServiceDefaults_Validate(t *testing.T) { }, }, }, - "servicedefaults.consul.hashicorp.com \"my-service\" is invalid: spec.transparentProxy.outboundListenerPort: Invalid value: 1000: use the annotation `consul.hashicorp.com/transparent-proxy-outbound-listener-port` to configure the Outbound Listener Port", + expectedErrMsg: "servicedefaults.consul.hashicorp.com \"my-service\" is invalid: spec.transparentProxy.outboundListenerPort: Invalid value: 1000: use the annotation `consul.hashicorp.com/transparent-proxy-outbound-listener-port` to configure the Outbound Listener Port", }, "mode": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -670,10 +671,10 @@ func TestServiceDefaults_Validate(t *testing.T) { Mode: proxyModeRef("transparent"), }, }, - "servicedefaults.consul.hashicorp.com \"my-service\" is invalid: spec.mode: Invalid value: \"transparent\": use the annotation `consul.hashicorp.com/transparent-proxy` to configure the Transparent Proxy Mode", + expectedErrMsg: "servicedefaults.consul.hashicorp.com \"my-service\" is invalid: spec.mode: Invalid value: \"transparent\": use the annotation `consul.hashicorp.com/transparent-proxy` to configure the Transparent Proxy Mode", }, "upstreamConfig.defaults.meshGateway": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -687,10 +688,10 @@ func TestServiceDefaults_Validate(t *testing.T) { }, }, }, - `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.defaults.meshGateway.mode: Invalid value: "foo": must be one of "remote", "local", "none", ""`, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.defaults.meshGateway.mode: Invalid value: "foo": must be one of "remote", "local", "none", ""`, }, "upstreamConfig.defaults.name": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -702,10 +703,26 @@ func TestServiceDefaults_Validate(t *testing.T) { }, }, }, - `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.defaults.name: Invalid value: "foobar": upstream.name for a default upstream must be ""`, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.defaults.name: Invalid value: "foobar": upstream.name for a default upstream must be ""`, + }, + "upstreamConfig.defaults.partition": { + input: &ServiceDefaults{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-service", + }, + Spec: ServiceDefaultsSpec{ + UpstreamConfig: &Upstreams{ + Defaults: &Upstream{ + Partition: "upstream", + }, + }, + }, + }, + partitionsEnabled: false, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.defaults.partition: Invalid value: "upstream": Consul Enterprise Admin Partitions must be enabled to set upstream.partition`, }, "upstreamConfig.overrides.meshGateway": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -722,10 +739,10 @@ func TestServiceDefaults_Validate(t *testing.T) { }, }, }, - `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.overrides[0].meshGateway.mode: Invalid value: "foo": must be one of "remote", "local", "none", ""`, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.overrides[0].meshGateway.mode: Invalid value: "foo": must be one of "remote", "local", "none", ""`, }, "upstreamConfig.overrides.name": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -739,10 +756,28 @@ func TestServiceDefaults_Validate(t *testing.T) { }, }, }, - `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.overrides[0].name: Invalid value: "": upstream.name for an override upstream cannot be ""`, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.overrides[0].name: Invalid value: "": upstream.name for an override upstream cannot be ""`, + }, + "upstreamConfig.overrides.partition": { + input: &ServiceDefaults{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-service", + }, + Spec: ServiceDefaultsSpec{ + UpstreamConfig: &Upstreams{ + Overrides: []*Upstream{ + { + Name: "service", + Partition: "upstream", + }, + }, + }, + }, + }, + expectedErrMsg: `servicedefaults.consul.hashicorp.com "my-service" is invalid: spec.upstreamConfig.overrides[0].partition: Invalid value: "upstream": Consul Enterprise Admin Partitions must be enabled to set upstream.partition`, }, "multi-error": { - &ServiceDefaults{ + input: &ServiceDefaults{ ObjectMeta: metav1.ObjectMeta{ Name: "my-service", }, @@ -765,13 +800,13 @@ func TestServiceDefaults_Validate(t *testing.T) { Mode: proxyModeRef("transparent"), }, }, - "servicedefaults.consul.hashicorp.com \"my-service\" is invalid: [spec.protocol: Invalid value: \"invalid\": must be one of \"tcp\", \"http\", \"http2\", \"grpc\", spec.meshGateway.mode: Invalid value: \"invalid-mode\": must be one of \"remote\", \"local\", \"none\", \"\", spec.transparentProxy.outboundListenerPort: Invalid value: 1000: use the annotation `consul.hashicorp.com/transparent-proxy-outbound-listener-port` to configure the Outbound Listener Port, spec.mode: Invalid value: \"transparent\": use the annotation `consul.hashicorp.com/transparent-proxy` to configure the Transparent Proxy Mode, spec.expose.paths[0].path: Invalid value: \"invalid-path\": must begin with a '/', spec.expose.paths[0].protocol: Invalid value: \"invalid-protocol\": must be one of \"http\", \"http2\"]", + expectedErrMsg: "servicedefaults.consul.hashicorp.com \"my-service\" is invalid: [spec.protocol: Invalid value: \"invalid\": must be one of \"tcp\", \"http\", \"http2\", \"grpc\", spec.meshGateway.mode: Invalid value: \"invalid-mode\": must be one of \"remote\", \"local\", \"none\", \"\", spec.transparentProxy.outboundListenerPort: Invalid value: 1000: use the annotation `consul.hashicorp.com/transparent-proxy-outbound-listener-port` to configure the Outbound Listener Port, spec.mode: Invalid value: \"transparent\": use the annotation `consul.hashicorp.com/transparent-proxy` to configure the Transparent Proxy Mode, spec.expose.paths[0].path: Invalid value: \"invalid-path\": must begin with a '/', spec.expose.paths[0].protocol: Invalid value: \"invalid-protocol\": must be one of \"http\", \"http2\"]", }, } for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(false) + err := testCase.input.Validate(common.ConsulMeta{}) if testCase.expectedErrMsg != "" { require.EqualError(t, err, testCase.expectedErrMsg) } else { diff --git a/control-plane/api/v1alpha1/servicedefaults_webhook.go b/control-plane/api/v1alpha1/servicedefaults_webhook.go index e218a4f323..a196a6d941 100644 --- a/control-plane/api/v1alpha1/servicedefaults_webhook.go +++ b/control-plane/api/v1alpha1/servicedefaults_webhook.go @@ -17,26 +17,8 @@ type ServiceDefaultsWebhook struct { ConsulClient *capi.Client Logger logr.Logger - // EnableConsulNamespaces indicates that a user is running Consul Enterprise - // with version 1.7+ which supports namespaces. - EnableConsulNamespaces bool - - // EnableNSMirroring causes Consul namespaces to be created to match the - // k8s namespace of any config entry custom resource. Config entries will - // be created in the matching Consul namespace. - EnableNSMirroring bool - - // ConsulDestinationNamespace is the namespace in Consul that the config entry created - // in k8s will get mapped into. If the Consul namespace does not already exist, it will - // be created. - ConsulDestinationNamespace string - - // NSMirroringPrefix works in conjunction with Namespace Mirroring. - // It is the prefix added to the Consul namespace to map to a specific. - // k8s namespace. For example, if `mirroringK8SPrefix` is set to "k8s-", a - // service in the k8s `staging` namespace will be registered into the - // `k8s-staging` Consul namespace. - NSMirroringPrefix string + // ConsulMeta contains metadata specific to the Consul installation. + ConsulMeta common.ConsulMeta decoder *admission.Decoder client.Client @@ -57,15 +39,7 @@ func (v *ServiceDefaultsWebhook) Handle(ctx context.Context, req admission.Reque return admission.Errored(http.StatusBadRequest, err) } - return common.ValidateConfigEntry(ctx, - req, - v.Logger, - v, - &svcDefaults, - v.EnableConsulNamespaces, - v.EnableNSMirroring, - v.ConsulDestinationNamespace, - v.NSMirroringPrefix) + return common.ValidateConfigEntry(ctx, req, v.Logger, v, &svcDefaults, v.ConsulMeta) } func (v *ServiceDefaultsWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { diff --git a/control-plane/api/v1alpha1/serviceintentions_types.go b/control-plane/api/v1alpha1/serviceintentions_types.go index 50dcb98476..80b66054f9 100644 --- a/control-plane/api/v1alpha1/serviceintentions_types.go +++ b/control-plane/api/v1alpha1/serviceintentions_types.go @@ -249,7 +249,7 @@ func (in *ServiceIntentions) MatchesConsul(candidate api.ConfigEntry) bool { ) } -func (in *ServiceIntentions) Validate(namespacesEnabled bool) error { +func (in *ServiceIntentions) Validate(consulMeta common.ConsulMeta) error { var errs field.ErrorList path := field.NewPath("spec") if len(in.Spec.Sources) == 0 { @@ -268,7 +268,8 @@ func (in *ServiceIntentions) Validate(namespacesEnabled bool) error { } } - errs = append(errs, in.validateNamespaces(namespacesEnabled)...) + errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) + errs = append(errs, in.validatePartitions(consulMeta.PartitionsEnabled)...) if len(errs) > 0 { return apierrors.NewInvalid( @@ -279,14 +280,14 @@ func (in *ServiceIntentions) Validate(namespacesEnabled bool) error { } // DefaultNamespaceFields sets the namespace field on spec.destination to their default values if namespaces are enabled. -func (in *ServiceIntentions) DefaultNamespaceFields(consulNamespacesEnabled bool, destinationNamespace string, mirroring bool, prefix string) { +func (in *ServiceIntentions) DefaultNamespaceFields(consulMeta common.ConsulMeta) { // If namespaces are enabled we want to set the destination namespace field to it's // default. If namespaces are not enabled (i.e. OSS) we don't set the // namespace fields because this would cause errors // making API calls (because namespace fields can't be set in OSS). - if consulNamespacesEnabled { + if consulMeta.NamespacesEnabled { // Default to the current namespace (i.e. the namespace of the config entry). - namespace := namespaces.ConsulNamespace(in.Namespace, consulNamespacesEnabled, destinationNamespace, mirroring, prefix) + namespace := namespaces.ConsulNamespace(in.Namespace, consulMeta.NamespacesEnabled, consulMeta.DestinationNamespace, consulMeta.Mirroring, consulMeta.Prefix) if in.Spec.Destination.Namespace == "" { in.Spec.Destination.Namespace = namespace } @@ -453,6 +454,19 @@ func (in *ServiceIntentions) validateNamespaces(namespacesEnabled bool) field.Er return errs } +func (in *ServiceIntentions) validatePartitions(partitionsEnabled bool) field.ErrorList { + var errs field.ErrorList + path := field.NewPath("spec") + if !partitionsEnabled { + for i, source := range in.Spec.Sources { + if source.Partition != "" { + errs = append(errs, field.Invalid(path.Child("sources").Index(i).Child("partition"), source.Partition, `Consul Enterprise Admin Partitions must be enabled to set source.partition`)) + } + } + } + return errs +} + func (in IntentionAction) validate(path *field.Path) *field.Error { actions := []string{"allow", "deny"} if !sliceContains(actions, string(in)) { diff --git a/control-plane/api/v1alpha1/serviceintentions_types_test.go b/control-plane/api/v1alpha1/serviceintentions_types_test.go index 37c6808e4e..e6fbb4109c 100644 --- a/control-plane/api/v1alpha1/serviceintentions_types_test.go +++ b/control-plane/api/v1alpha1/serviceintentions_types_test.go @@ -526,39 +526,44 @@ func TestServiceIntentions_ObjectMeta(t *testing.T) { // Test defaulting behavior when namespaces are enabled as well as disabled. func TestServiceIntentions_DefaultNamespaceFields(t *testing.T) { namespaceConfig := map[string]struct { - enabled bool - destinationNamespace string - mirroring bool - prefix string - expectedDestination string + consulMeta common.ConsulMeta + expectedDestination string }{ "disabled": { - enabled: false, - destinationNamespace: "", - mirroring: false, - prefix: "", - expectedDestination: "", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: false, + DestinationNamespace: "", + Mirroring: false, + Prefix: "", + }, + expectedDestination: "", }, "destinationNS": { - enabled: true, - destinationNamespace: "foo", - mirroring: false, - prefix: "", - expectedDestination: "foo", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "foo", + Mirroring: false, + Prefix: "", + }, + expectedDestination: "foo", }, "mirroringEnabledWithoutPrefix": { - enabled: true, - destinationNamespace: "", - mirroring: true, - prefix: "", - expectedDestination: "bar", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "", + Mirroring: true, + Prefix: "", + }, + expectedDestination: "bar", }, "mirroringWithPrefix": { - enabled: true, - destinationNamespace: "", - mirroring: true, - prefix: "ns-", - expectedDestination: "ns-bar", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "", + Mirroring: true, + Prefix: "ns-", + }, + expectedDestination: "ns-bar", }, } @@ -587,7 +592,7 @@ func TestServiceIntentions_DefaultNamespaceFields(t *testing.T) { }, }, } - input.DefaultNamespaceFields(s.enabled, s.destinationNamespace, s.mirroring, s.prefix) + input.DefaultNamespaceFields(s.consulMeta) require.True(t, cmp.Equal(input, output)) }) } @@ -597,9 +602,10 @@ func TestServiceIntentions_Validate(t *testing.T) { cases := map[string]struct { input *ServiceIntentions namespacesEnabled bool + partitionsEnabled bool expectedErrMsgs []string }{ - "namespaces enabled: valid": { + "partitions enabled: valid": { input: &ServiceIntentions{ ObjectMeta: metav1.ObjectMeta{ Name: "does-not-matter", @@ -651,6 +657,59 @@ func TestServiceIntentions_Validate(t *testing.T) { }, }, namespacesEnabled: true, + partitionsEnabled: true, + expectedErrMsgs: nil, + }, + "namespaces enabled: valid": { + input: &ServiceIntentions{ + ObjectMeta: metav1.ObjectMeta{ + Name: "does-not-matter", + }, + Spec: ServiceIntentionsSpec{ + Destination: Destination{ + Name: "dest-service", + Namespace: "namespace", + }, + Sources: SourceIntentions{ + { + Name: "web", + Namespace: "web", + Action: "allow", + }, + { + Name: "db", + Namespace: "db", + Action: "deny", + }, + { + Name: "bar", + Namespace: "bar", + Permissions: IntentionPermissions{ + { + Action: "allow", + HTTP: &IntentionHTTPPermission{ + PathExact: "/foo", + Header: IntentionHTTPHeaderPermissions{ + { + Name: "header", + Present: true, + Invert: true, + }, + }, + Methods: []string{ + "GET", + "PUT", + }, + }, + }, + }, + Description: "an L7 config", + }, + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: false, expectedErrMsgs: nil, }, "namespaces disabled: valid": { @@ -698,6 +757,7 @@ func TestServiceIntentions_Validate(t *testing.T) { }, }, namespacesEnabled: false, + partitionsEnabled: false, expectedErrMsgs: nil, }, "no sources": { @@ -1177,10 +1237,84 @@ func TestServiceIntentions_Validate(t *testing.T) { `spec.sources[2].namespace: Invalid value: "namespace-d": Consul Enterprise namespaces must be enabled to set source.namespace`, }, }, + "partitions disabled: single source partition specified": { + input: &ServiceIntentions{ + ObjectMeta: metav1.ObjectMeta{ + Name: "does-not-matter", + }, + Spec: ServiceIntentionsSpec{ + Destination: Destination{ + Name: "dest-service", + Namespace: "namespace-a", + }, + Sources: SourceIntentions{ + { + Name: "web", + Action: "allow", + Namespace: "namespace-b", + Partition: "partition-other", + }, + { + Name: "db", + Action: "deny", + Namespace: "namespace-c", + }, + { + Name: "bar", + Namespace: "namespace-d", + }, + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: false, + expectedErrMsgs: []string{ + `spec.sources[0].partition: Invalid value: "partition-other": Consul Enterprise Admin Partitions must be enabled to set source.partition`, + }, + }, + "partitions disabled: multiple source partition specified": { + input: &ServiceIntentions{ + ObjectMeta: metav1.ObjectMeta{ + Name: "does-not-matter", + }, + Spec: ServiceIntentionsSpec{ + Destination: Destination{ + Name: "dest-service", + Namespace: "namespace-a", + }, + Sources: SourceIntentions{ + { + Name: "web", + Action: "allow", + Namespace: "namespace-b", + Partition: "partition-other", + }, + { + Name: "db", + Action: "deny", + Namespace: "namespace-c", + Partition: "partition-first", + }, + { + Name: "bar", + Namespace: "namespace-d", + Partition: "partition-foo", + }, + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: false, + expectedErrMsgs: []string{ + `spec.sources[0].partition: Invalid value: "partition-other": Consul Enterprise Admin Partitions must be enabled to set source.partition`, + `spec.sources[1].partition: Invalid value: "partition-first": Consul Enterprise Admin Partitions must be enabled to set source.partition`, + `spec.sources[2].partition: Invalid value: "partition-foo": Consul Enterprise Admin Partitions must be enabled to set source.partition`, + }, + }, } for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(testCase.namespacesEnabled) + err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled, PartitionsEnabled: testCase.partitionsEnabled}) if len(testCase.expectedErrMsgs) != 0 { require.Error(t, err) for _, s := range testCase.expectedErrMsgs { diff --git a/control-plane/api/v1alpha1/serviceintentions_webhook.go b/control-plane/api/v1alpha1/serviceintentions_webhook.go index 8e5287a457..0287ddfeb8 100644 --- a/control-plane/api/v1alpha1/serviceintentions_webhook.go +++ b/control-plane/api/v1alpha1/serviceintentions_webhook.go @@ -18,13 +18,10 @@ import ( type ServiceIntentionsWebhook struct { client.Client - ConsulClient *capi.Client - Logger logr.Logger - decoder *admission.Decoder - EnableConsulNamespaces bool - EnableNSMirroring bool - ConsulDestinationNamespace string - NSMirroringPrefix string + ConsulClient *capi.Client + Logger logr.Logger + decoder *admission.Decoder + ConsulMeta common.ConsulMeta } // NOTE: The path value in the below line is the path to the webhook. @@ -44,12 +41,12 @@ func (v *ServiceIntentionsWebhook) Handle(ctx context.Context, req admission.Req return admission.Errored(http.StatusBadRequest, err) } - defaultingPatches, err := common.DefaultingPatches(&svcIntentions, v.EnableConsulNamespaces, v.EnableNSMirroring, v.ConsulDestinationNamespace, v.NSMirroringPrefix) + defaultingPatches, err := common.DefaultingPatches(&svcIntentions, v.ConsulMeta) if err != nil { return admission.Errored(http.StatusInternalServerError, err) } - singleConsulDestNS := !(v.EnableConsulNamespaces && v.EnableNSMirroring) + singleConsulDestNS := !(v.ConsulMeta.NamespacesEnabled && v.ConsulMeta.Mirroring) if req.Operation == admissionv1.Create { v.Logger.Info("validate create", "name", svcIntentions.KubernetesName()) @@ -89,7 +86,7 @@ func (v *ServiceIntentionsWebhook) Handle(ctx context.Context, req admission.Req } // ServiceIntentions are invalid if destination namespaces or source namespaces are set when Consul Namespaces are not enabled. - if err := svcIntentions.Validate(v.EnableConsulNamespaces); err != nil { + if err := svcIntentions.Validate(v.ConsulMeta); err != nil { return admission.Errored(http.StatusBadRequest, err) } diff --git a/control-plane/api/v1alpha1/serviceintentions_webhook_test.go b/control-plane/api/v1alpha1/serviceintentions_webhook_test.go index aed9d0b6e2..8c1ba98fd7 100644 --- a/control-plane/api/v1alpha1/serviceintentions_webhook_test.go +++ b/control-plane/api/v1alpha1/serviceintentions_webhook_test.go @@ -7,6 +7,7 @@ import ( "testing" logrtest "github.com/go-logr/logr/testing" + "github.com/hashicorp/consul-k8s/control-plane/api/common" "github.com/stretchr/testify/require" "gomodules.xyz/jsonpatch/v2" admissionv1 "k8s.io/api/admission/v1" @@ -248,12 +249,14 @@ func TestHandle_ServiceIntentions_Create(t *testing.T) { require.NoError(t, err) validator := &ServiceIntentionsWebhook{ - Client: client, - ConsulClient: nil, - Logger: logrtest.TestLogger{T: t}, - decoder: decoder, - EnableConsulNamespaces: true, - EnableNSMirroring: c.mirror, + Client: client, + ConsulClient: nil, + Logger: logrtest.TestLogger{T: t}, + decoder: decoder, + ConsulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + Mirroring: c.mirror, + }, } response := validator.Handle(ctx, admission.Request{ AdmissionRequest: admissionv1.AdmissionRequest{ @@ -436,12 +439,14 @@ func TestHandle_ServiceIntentions_Update(t *testing.T) { require.NoError(t, err) validator := &ServiceIntentionsWebhook{ - Client: client, - ConsulClient: nil, - Logger: logrtest.TestLogger{T: t}, - decoder: decoder, - EnableConsulNamespaces: true, - EnableNSMirroring: c.mirror, + Client: client, + ConsulClient: nil, + Logger: logrtest.TestLogger{T: t}, + decoder: decoder, + ConsulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + Mirroring: c.mirror, + }, } response := validator.Handle(ctx, admission.Request{ AdmissionRequest: admissionv1.AdmissionRequest{ @@ -595,12 +600,14 @@ func TestHandle_ServiceIntentions_Patches(t *testing.T) { require.NoError(t, err) validator := &ServiceIntentionsWebhook{ - Client: client, - ConsulClient: nil, - Logger: logrtest.TestLogger{T: t}, - decoder: decoder, - EnableConsulNamespaces: namespacesEnabled, - EnableNSMirroring: true, + Client: client, + ConsulClient: nil, + Logger: logrtest.TestLogger{T: t}, + decoder: decoder, + ConsulMeta: common.ConsulMeta{ + NamespacesEnabled: namespacesEnabled, + Mirroring: true, + }, } response := validator.Handle(ctx, admission.Request{ AdmissionRequest: admissionv1.AdmissionRequest{ diff --git a/control-plane/api/v1alpha1/serviceresolver_types.go b/control-plane/api/v1alpha1/serviceresolver_types.go index ef8f69db2e..f0ea92d300 100644 --- a/control-plane/api/v1alpha1/serviceresolver_types.go +++ b/control-plane/api/v1alpha1/serviceresolver_types.go @@ -5,6 +5,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "github.com/hashicorp/consul-k8s/control-plane/api/common" capi "github.com/hashicorp/consul/api" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -288,7 +289,7 @@ func (in *ServiceResolver) ConsulGlobalResource() bool { return false } -func (in *ServiceResolver) Validate(namespacesEnabled bool) error { +func (in *ServiceResolver) Validate(consulMeta common.ConsulMeta) error { var errs field.ErrorList path := field.NewPath("spec") @@ -300,7 +301,7 @@ func (in *ServiceResolver) Validate(namespacesEnabled bool) error { errs = append(errs, in.Spec.LoadBalancer.validate(path.Child("loadBalancer"))...) - errs = append(errs, in.validateNamespaces(namespacesEnabled)...) + errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) if len(errs) > 0 { return apierrors.NewInvalid( @@ -312,7 +313,7 @@ func (in *ServiceResolver) Validate(namespacesEnabled bool) error { // DefaultNamespaceFields has no behaviour here as service-resolver have namespace fields // that do not default. -func (in *ServiceResolver) DefaultNamespaceFields(_ bool, _ string, _ bool, _ string) { +func (in *ServiceResolver) DefaultNamespaceFields(_ common.ConsulMeta) { } func (in ServiceResolverSubsetMap) toConsul() map[string]capi.ServiceResolverSubset { diff --git a/control-plane/api/v1alpha1/serviceresolver_types_test.go b/control-plane/api/v1alpha1/serviceresolver_types_test.go index fed0e89d1e..979c1c983c 100644 --- a/control-plane/api/v1alpha1/serviceresolver_types_test.go +++ b/control-plane/api/v1alpha1/serviceresolver_types_test.go @@ -705,7 +705,7 @@ func TestServiceResolver_Validate(t *testing.T) { } for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(testCase.namespacesEnabled) + err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled}) if len(testCase.expectedErrMsgs) != 0 { require.Error(t, err) for _, s := range testCase.expectedErrMsgs { diff --git a/control-plane/api/v1alpha1/serviceresolver_webhook.go b/control-plane/api/v1alpha1/serviceresolver_webhook.go index 602d0a5b6e..1af2fa0383 100644 --- a/control-plane/api/v1alpha1/serviceresolver_webhook.go +++ b/control-plane/api/v1alpha1/serviceresolver_webhook.go @@ -17,26 +17,8 @@ type ServiceResolverWebhook struct { ConsulClient *capi.Client Logger logr.Logger - // EnableConsulNamespaces indicates that a user is running Consul Enterprise - // with version 1.7+ which supports namespaces. - EnableConsulNamespaces bool - - // EnableNSMirroring causes Consul namespaces to be created to match the - // k8s namespace of any config entry custom resource. Config entries will - // be created in the matching Consul namespace. - EnableNSMirroring bool - - // ConsulDestinationNamespace is the namespace in Consul that the config entry created - // in k8s will get mapped into. If the Consul namespace does not already exist, it will - // be created. - ConsulDestinationNamespace string - - // NSMirroringPrefix works in conjunction with Namespace Mirroring. - // It is the prefix added to the Consul namespace to map to a specific. - // k8s namespace. For example, if `mirroringK8SPrefix` is set to "k8s-", a - // service in the k8s `staging` namespace will be registered into the - // `k8s-staging` Consul namespace. - NSMirroringPrefix string + // ConsulMeta contains metadata specific to the Consul installation. + ConsulMeta common.ConsulMeta decoder *admission.Decoder client.Client @@ -57,15 +39,7 @@ func (v *ServiceResolverWebhook) Handle(ctx context.Context, req admission.Reque return admission.Errored(http.StatusBadRequest, err) } - return common.ValidateConfigEntry(ctx, - req, - v.Logger, - v, - &svcResolver, - v.EnableConsulNamespaces, - v.EnableNSMirroring, - v.ConsulDestinationNamespace, - v.NSMirroringPrefix) + return common.ValidateConfigEntry(ctx, req, v.Logger, v, &svcResolver, v.ConsulMeta) } func (v *ServiceResolverWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { diff --git a/control-plane/api/v1alpha1/servicerouter_types.go b/control-plane/api/v1alpha1/servicerouter_types.go index a6077fff7f..a6cdf54f81 100644 --- a/control-plane/api/v1alpha1/servicerouter_types.go +++ b/control-plane/api/v1alpha1/servicerouter_types.go @@ -5,6 +5,7 @@ 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-k8s/control-plane/namespaces" capi "github.com/hashicorp/consul/api" corev1 "k8s.io/api/core/v1" @@ -243,14 +244,14 @@ func (in *ServiceRouter) MatchesConsul(candidate capi.ConfigEntry) bool { return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ServiceRouterConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } -func (in *ServiceRouter) Validate(namespacesEnabled bool) error { +func (in *ServiceRouter) Validate(consulMeta common.ConsulMeta) error { var errs field.ErrorList path := field.NewPath("spec") for i, r := range in.Spec.Routes { errs = append(errs, r.validate(path.Child("routes").Index(i))...) } - errs = append(errs, in.validateNamespaces(namespacesEnabled)...) + errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) if len(errs) > 0 { return apierrors.NewInvalid( @@ -261,14 +262,14 @@ func (in *ServiceRouter) Validate(namespacesEnabled bool) error { } // DefaultNamespaceFields sets the namespace field on spec.routes[].destination to their default values if namespaces are enabled. -func (in *ServiceRouter) DefaultNamespaceFields(consulNamespacesEnabled bool, destinationNamespace string, mirroring bool, prefix string) { +func (in *ServiceRouter) DefaultNamespaceFields(consulMeta common.ConsulMeta) { // If namespaces are enabled we want to set the namespace fields to their // defaults. If namespaces are not enabled (i.e. OSS) we don't set the // namespace fields because this would cause errors // making API calls (because namespace fields can't be set in OSS). - if consulNamespacesEnabled { + if consulMeta.NamespacesEnabled { // Default to the current namespace (i.e. the namespace of the config entry). - namespace := namespaces.ConsulNamespace(in.Namespace, consulNamespacesEnabled, destinationNamespace, mirroring, prefix) + namespace := namespaces.ConsulNamespace(in.Namespace, consulMeta.NamespacesEnabled, consulMeta.DestinationNamespace, consulMeta.Mirroring, consulMeta.Prefix) for i, r := range in.Spec.Routes { if r.Destination != nil { if r.Destination.Namespace == "" { diff --git a/control-plane/api/v1alpha1/servicerouter_types_test.go b/control-plane/api/v1alpha1/servicerouter_types_test.go index 2a7ef7c50c..8795c0713d 100644 --- a/control-plane/api/v1alpha1/servicerouter_types_test.go +++ b/control-plane/api/v1alpha1/servicerouter_types_test.go @@ -595,7 +595,7 @@ func TestServiceRouter_Validate(t *testing.T) { } for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(testCase.namespacesEnabled) + err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled}) if len(testCase.expectedErrMsgs) != 0 { require.Error(t, err) for _, s := range testCase.expectedErrMsgs { @@ -611,39 +611,44 @@ func TestServiceRouter_Validate(t *testing.T) { // Test defaulting behavior when namespaces are enabled as well as disabled. func TestServiceRouter_DefaultNamespaceFields(t *testing.T) { namespaceConfig := map[string]struct { - enabled bool - destinationNamespace string - mirroring bool - prefix string - expectedDestination string + consulMeta common.ConsulMeta + expectedDestination string }{ "disabled": { - enabled: false, - destinationNamespace: "", - mirroring: false, - prefix: "", - expectedDestination: "", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: false, + DestinationNamespace: "", + Mirroring: false, + Prefix: "", + }, + expectedDestination: "", }, "destinationNS": { - enabled: true, - destinationNamespace: "foo", - mirroring: false, - prefix: "", - expectedDestination: "foo", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "foo", + Mirroring: false, + Prefix: "", + }, + expectedDestination: "foo", }, "mirroringEnabledWithoutPrefix": { - enabled: true, - destinationNamespace: "", - mirroring: true, - prefix: "", - expectedDestination: "bar", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "", + Mirroring: true, + Prefix: "", + }, + expectedDestination: "bar", }, "mirroringWithPrefix": { - enabled: true, - destinationNamespace: "", - mirroring: true, - prefix: "ns-", - expectedDestination: "ns-bar", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "", + Mirroring: true, + Prefix: "ns-", + }, + expectedDestination: "ns-bar", }, } @@ -712,7 +717,7 @@ func TestServiceRouter_DefaultNamespaceFields(t *testing.T) { }, }, } - input.DefaultNamespaceFields(s.enabled, s.destinationNamespace, s.mirroring, s.prefix) + input.DefaultNamespaceFields(s.consulMeta) require.True(t, cmp.Equal(input, output)) }) } diff --git a/control-plane/api/v1alpha1/servicerouter_webhook.go b/control-plane/api/v1alpha1/servicerouter_webhook.go index 48af57d7bb..03644432e6 100644 --- a/control-plane/api/v1alpha1/servicerouter_webhook.go +++ b/control-plane/api/v1alpha1/servicerouter_webhook.go @@ -17,26 +17,8 @@ type ServiceRouterWebhook struct { ConsulClient *capi.Client Logger logr.Logger - // EnableConsulNamespaces indicates that a user is running Consul Enterprise - // with version 1.7+ which supports namespaces. - EnableConsulNamespaces bool - - // EnableNSMirroring causes Consul namespaces to be created to match the - // k8s namespace of any config entry custom resource. Config entries will - // be created in the matching Consul namespace. - EnableNSMirroring bool - - // ConsulDestinationNamespace is the namespace in Consul that the config entry created - // in k8s will get mapped into. If the Consul namespace does not already exist, it will - // be created. - ConsulDestinationNamespace string - - // NSMirroringPrefix works in conjunction with Namespace Mirroring. - // It is the prefix added to the Consul namespace to map to a specific. - // k8s namespace. For example, if `mirroringK8SPrefix` is set to "k8s-", a - // service in the k8s `staging` namespace will be registered into the - // `k8s-staging` Consul namespace. - NSMirroringPrefix string + // ConsulMeta contains metadata specific to the Consul installation. + ConsulMeta common.ConsulMeta decoder *admission.Decoder client.Client @@ -57,15 +39,7 @@ func (v *ServiceRouterWebhook) Handle(ctx context.Context, req admission.Request return admission.Errored(http.StatusBadRequest, err) } - return common.ValidateConfigEntry(ctx, - req, - v.Logger, - v, - &svcRouter, - v.EnableConsulNamespaces, - v.EnableNSMirroring, - v.ConsulDestinationNamespace, - v.NSMirroringPrefix) + return common.ValidateConfigEntry(ctx, req, v.Logger, v, &svcRouter, v.ConsulMeta) } func (v *ServiceRouterWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { diff --git a/control-plane/api/v1alpha1/servicesplitter_types.go b/control-plane/api/v1alpha1/servicesplitter_types.go index 97b9e65237..98eaadb8d4 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types.go +++ b/control-plane/api/v1alpha1/servicesplitter_types.go @@ -162,10 +162,10 @@ func (in *ServiceSplitter) MatchesConsul(candidate capi.ConfigEntry) bool { return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ServiceSplitterConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } -func (in *ServiceSplitter) Validate(namespacesEnabled bool) error { +func (in *ServiceSplitter) Validate(consulMeta common.ConsulMeta) error { errs := in.Spec.Splits.validate(field.NewPath("spec").Child("splits")) - errs = append(errs, in.validateNamespaces(namespacesEnabled)...) + errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) if len(errs) > 0 { return apierrors.NewInvalid( @@ -177,7 +177,7 @@ func (in *ServiceSplitter) Validate(namespacesEnabled bool) error { // DefaultNamespaceFields has no behaviour here as service-splitter have namespace fields // that do not default. -func (in *ServiceSplitter) DefaultNamespaceFields(_ bool, _ string, _ bool, _ string) { +func (in *ServiceSplitter) DefaultNamespaceFields(_ common.ConsulMeta) { } func (in ServiceSplits) toConsul() []capi.ServiceSplit { diff --git a/control-plane/api/v1alpha1/servicesplitter_types_test.go b/control-plane/api/v1alpha1/servicesplitter_types_test.go index 2455e6349b..aed14adba7 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types_test.go +++ b/control-plane/api/v1alpha1/servicesplitter_types_test.go @@ -424,7 +424,7 @@ func TestServiceSplitter_Validate(t *testing.T) { } for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(testCase.namespacesEnabled) + err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled}) if len(testCase.expectedErrMsgs) != 0 { require.Error(t, err) for _, s := range testCase.expectedErrMsgs { diff --git a/control-plane/api/v1alpha1/servicesplitter_webhook.go b/control-plane/api/v1alpha1/servicesplitter_webhook.go index 18d2074bdd..f90c49f45a 100644 --- a/control-plane/api/v1alpha1/servicesplitter_webhook.go +++ b/control-plane/api/v1alpha1/servicesplitter_webhook.go @@ -17,26 +17,8 @@ type ServiceSplitterWebhook struct { ConsulClient *capi.Client Logger logr.Logger - // EnableConsulNamespaces indicates that a user is running Consul Enterprise - // with version 1.7+ which supports namespaces. - EnableConsulNamespaces bool - - // EnableNSMirroring causes Consul namespaces to be created to match the - // k8s namespace of any config entry custom resource. Config entries will - // be created in the matching Consul namespace. - EnableNSMirroring bool - - // ConsulDestinationNamespace is the namespace in Consul that the config entry created - // in k8s will get mapped into. If the Consul namespace does not already exist, it will - // be created. - ConsulDestinationNamespace string - - // NSMirroringPrefix works in conjunction with Namespace Mirroring. - // It is the prefix added to the Consul namespace to map to a specific. - // k8s namespace. For example, if `mirroringK8SPrefix` is set to "k8s-", a - // service in the k8s `staging` namespace will be registered into the - // `k8s-staging` Consul namespace. - NSMirroringPrefix string + // ConsulMeta contains metadata specific to the Consul installation. + ConsulMeta common.ConsulMeta decoder *admission.Decoder client.Client @@ -58,15 +40,7 @@ func (v *ServiceSplitterWebhook) Handle(ctx context.Context, req admission.Reque return admission.Errored(http.StatusBadRequest, err) } - return common.ValidateConfigEntry(ctx, - req, - v.Logger, - v, - &serviceSplitter, - v.EnableConsulNamespaces, - v.EnableNSMirroring, - v.ConsulDestinationNamespace, - v.NSMirroringPrefix) + return common.ValidateConfigEntry(ctx, req, v.Logger, v, &serviceSplitter, v.ConsulMeta) } func (v *ServiceSplitterWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { diff --git a/control-plane/api/v1alpha1/terminatinggateway_types.go b/control-plane/api/v1alpha1/terminatinggateway_types.go index 18ede3b47d..2973e58714 100644 --- a/control-plane/api/v1alpha1/terminatinggateway_types.go +++ b/control-plane/api/v1alpha1/terminatinggateway_types.go @@ -5,6 +5,7 @@ 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-k8s/control-plane/namespaces" capi "github.com/hashicorp/consul/api" corev1 "k8s.io/api/core/v1" @@ -176,7 +177,7 @@ func (in *TerminatingGateway) MatchesConsul(candidate capi.ConfigEntry) bool { return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.TerminatingGatewayConfigEntry{}, "Partition", "Namespace", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } -func (in *TerminatingGateway) Validate(namespacesEnabled bool) error { +func (in *TerminatingGateway) Validate(consulMeta common.ConsulMeta) error { var errs field.ErrorList path := field.NewPath("spec") @@ -184,7 +185,7 @@ func (in *TerminatingGateway) Validate(namespacesEnabled bool) error { errs = append(errs, v.validate(path.Child("services").Index(i))...) } - errs = append(errs, in.validateNamespaces(namespacesEnabled)...) + errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) if len(errs) > 0 { return apierrors.NewInvalid( @@ -195,14 +196,14 @@ func (in *TerminatingGateway) Validate(namespacesEnabled bool) error { } // DefaultNamespaceFields sets the namespace field on spec.services to their default values if namespaces are enabled. -func (in *TerminatingGateway) DefaultNamespaceFields(consulNamespacesEnabled bool, destinationNamespace string, mirroring bool, prefix string) { +func (in *TerminatingGateway) DefaultNamespaceFields(consulMeta common.ConsulMeta) { // If namespaces are enabled we want to set the namespace fields to their // defaults. If namespaces are not enabled (i.e. OSS) we don't set the // namespace fields because this would cause errors // making API calls (because namespace fields can't be set in OSS). - if consulNamespacesEnabled { + if consulMeta.NamespacesEnabled { // Default to the current namespace (i.e. the namespace of the config entry). - namespace := namespaces.ConsulNamespace(in.Namespace, consulNamespacesEnabled, destinationNamespace, mirroring, prefix) + namespace := namespaces.ConsulNamespace(in.Namespace, consulMeta.NamespacesEnabled, consulMeta.DestinationNamespace, consulMeta.Mirroring, consulMeta.Prefix) for i, service := range in.Spec.Services { if service.Namespace == "" { in.Spec.Services[i].Namespace = namespace diff --git a/control-plane/api/v1alpha1/terminatinggateway_types_test.go b/control-plane/api/v1alpha1/terminatinggateway_types_test.go index f9da98729c..9d8ba9948d 100644 --- a/control-plane/api/v1alpha1/terminatinggateway_types_test.go +++ b/control-plane/api/v1alpha1/terminatinggateway_types_test.go @@ -268,7 +268,7 @@ func TestTerminatingGateway_Validate(t *testing.T) { for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(testCase.namespacesEnabled) + err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled}) if len(testCase.expectedErrMsgs) != 0 { require.Error(t, err) for _, s := range testCase.expectedErrMsgs { @@ -284,39 +284,44 @@ func TestTerminatingGateway_Validate(t *testing.T) { // Test defaulting behavior when namespaces are enabled as well as disabled. func TestTerminatingGateway_DefaultNamespaceFields(t *testing.T) { namespaceConfig := map[string]struct { - enabled bool - destinationNamespace string - mirroring bool - prefix string - expectedDestination string + consulMeta common.ConsulMeta + expectedDestination string }{ "disabled": { - enabled: false, - destinationNamespace: "", - mirroring: false, - prefix: "", - expectedDestination: "", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: false, + DestinationNamespace: "", + Mirroring: false, + Prefix: "", + }, + expectedDestination: "", }, "destinationNS": { - enabled: true, - destinationNamespace: "foo", - mirroring: false, - prefix: "", - expectedDestination: "foo", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "foo", + Mirroring: false, + Prefix: "", + }, + expectedDestination: "foo", }, "mirroringEnabledWithoutPrefix": { - enabled: true, - destinationNamespace: "", - mirroring: true, - prefix: "", - expectedDestination: "bar", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "", + Mirroring: true, + Prefix: "", + }, + expectedDestination: "bar", }, "mirroringWithPrefix": { - enabled: true, - destinationNamespace: "", - mirroring: true, - prefix: "ns-", - expectedDestination: "ns-bar", + consulMeta: common.ConsulMeta{ + NamespacesEnabled: true, + DestinationNamespace: "", + Mirroring: true, + Prefix: "ns-", + }, + expectedDestination: "ns-bar", }, } @@ -357,7 +362,7 @@ func TestTerminatingGateway_DefaultNamespaceFields(t *testing.T) { }, }, } - input.DefaultNamespaceFields(s.enabled, s.destinationNamespace, s.mirroring, s.prefix) + input.DefaultNamespaceFields(s.consulMeta) require.True(t, cmp.Equal(input, output)) }) } diff --git a/control-plane/api/v1alpha1/terminatinggateway_webhook.go b/control-plane/api/v1alpha1/terminatinggateway_webhook.go index 44d79ecc21..2d3367fcaa 100644 --- a/control-plane/api/v1alpha1/terminatinggateway_webhook.go +++ b/control-plane/api/v1alpha1/terminatinggateway_webhook.go @@ -17,26 +17,8 @@ type TerminatingGatewayWebhook struct { ConsulClient *capi.Client Logger logr.Logger - // EnableConsulNamespaces indicates that a user is running Consul Enterprise - // with version 1.7+ which supports namespaces. - EnableConsulNamespaces bool - - // EnableNSMirroring causes Consul namespaces to be created to match the - // k8s namespace of any config entry custom resource. Config entries will - // be created in the matching Consul namespace. - EnableNSMirroring bool - - // ConsulDestinationNamespace is the namespace in Consul that the config entry created - // in k8s will get mapped into. If the Consul namespace does not already exist, it will - // be created. - ConsulDestinationNamespace string - - // NSMirroringPrefix works in conjunction with Namespace Mirroring. - // It is the prefix added to the Consul namespace to map to a specific. - // k8s namespace. For example, if `mirroringK8SPrefix` is set to "k8s-", a - // service in the k8s `staging` namespace will be registered into the - // `k8s-staging` Consul namespace. - NSMirroringPrefix string + // ConsulMeta contains metadata specific to the Consul installation. + ConsulMeta common.ConsulMeta decoder *admission.Decoder client.Client @@ -57,15 +39,7 @@ func (v *TerminatingGatewayWebhook) Handle(ctx context.Context, req admission.Re return admission.Errored(http.StatusBadRequest, err) } - return common.ValidateConfigEntry(ctx, - req, - v.Logger, - v, - &resource, - v.EnableConsulNamespaces, - v.EnableNSMirroring, - v.ConsulDestinationNamespace, - v.NSMirroringPrefix) + return common.ValidateConfigEntry(ctx, req, v.Logger, v, &resource, v.ConsulMeta) } func (v *TerminatingGatewayWebhook) List(ctx context.Context) ([]common.ConfigEntryResource, error) { diff --git a/control-plane/config/rbac/role.yaml b/control-plane/config/rbac/role.yaml index f1a46e72d3..b544a67a81 100644 --- a/control-plane/config/rbac/role.yaml +++ b/control-plane/config/rbac/role.yaml @@ -106,6 +106,26 @@ rules: - get - patch - update +- apiGroups: + - consul.hashicorp.com + resources: + - serviceexports + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - consul.hashicorp.com + resources: + - serviceexports/status + verbs: + - get + - patch + - update - apiGroups: - consul.hashicorp.com resources: diff --git a/control-plane/config/webhook/manifests.yaml b/control-plane/config/webhook/manifests.yaml index 8264b31887..19b8e7ebda 100644 --- a/control-plane/config/webhook/manifests.yaml +++ b/control-plane/config/webhook/manifests.yaml @@ -111,6 +111,27 @@ webhooks: resources: - servicedefaults sideEffects: None +- admissionReviewVersions: + - v1beta1 + - v1 + clientConfig: + service: + name: webhook-service + namespace: system + path: /mutate-v1alpha1-service-exports + failurePolicy: Fail + name: mutate-mesh.consul.hashicorp.com + rules: + - apiGroups: + - consul.hashicorp.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - mesh + sideEffects: None - admissionReviewVersions: - v1beta1 - v1 diff --git a/control-plane/controller/partitionexports_controller_ent_test.go b/control-plane/controller/partitionexports_controller_ent_test.go new file mode 100644 index 0000000000..7e8ebb2abc --- /dev/null +++ b/control-plane/controller/partitionexports_controller_ent_test.go @@ -0,0 +1,425 @@ +// +build enterprise + +package controller_test + +import ( + "context" + "fmt" + "testing" + "time" + + 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" + capi "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/testutil" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" +) + +// This tests explicitly tests PartitionExportsController instead of using the existing +// pattern of adding tests for the controller to configentry_controller test. That is because +// unlike the other CRDs, PartitionExports are only supported in Consul Enterprise. But the +// test pattern of the enterprise tests already covers a config-entry similar to partition-exports +// ie a "global" configentry. Hence a separate file has been created to test this controller. + +// TODO: remove skips once 1.11-beta2 image is released. + +func TestPartitionExportsController_createsPartitionExports(tt *testing.T) { + tt.Skip() + tt.Parallel() + + cases := map[string]struct { + Mirror bool + MirrorPrefix string + SourceKubeNS string + DestConsulNS string + }{ + "SourceKubeNS=default, DestConsulNS=default": { + SourceKubeNS: "default", + DestConsulNS: "default", + }, + "SourceKubeNS=kube, DestConsulNS=default": { + SourceKubeNS: "kube", + DestConsulNS: "default", + }, + "SourceKubeNS=default, DestConsulNS=other": { + SourceKubeNS: "default", + DestConsulNS: "other", + }, + "SourceKubeNS=kube, DestConsulNS=other": { + SourceKubeNS: "kube", + DestConsulNS: "other", + }, + "SourceKubeNS=default, Mirror=true": { + SourceKubeNS: "default", + Mirror: true, + }, + "SourceKubeNS=kube, Mirror=true": { + SourceKubeNS: "kube", + Mirror: true, + }, + "SourceKubeNS=default, Mirror=true, Prefix=prefix": { + SourceKubeNS: "default", + Mirror: true, + MirrorPrefix: "prefix-", + }, + } + + for name, c := range cases { + tt.Run(name, func(t *testing.T) { + req := require.New(t) + s := runtime.NewScheme() + partitionExport := &v1alpha1.PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + Namespace: c.SourceKubeNS, + }, + Spec: v1alpha1.PartitionExportsSpec{ + Services: []v1alpha1.ExportedService{ + { + Name: "frontend", + Namespace: "front", + Consumers: []v1alpha1.ServiceConsumer{ + {Partition: "foo"}, + {Partition: "bar"}, + }, + }, + }, + }, + } + s.AddKnownTypes(v1alpha1.GroupVersion, partitionExport) + ctx := context.Background() + + consul, err := testutil.NewTestServerConfigT(t, nil) + req.NoError(err) + defer consul.Stop() + consul.WaitForServiceIntentions(t) + consulClient, err := capi.NewClient(&capi.Config{ + Address: consul.HTTPAddr, + }) + req.NoError(err) + + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(partitionExport).Build() + + controller := &controller.PartitionExportsController{ + Client: fakeClient, + Log: logrtest.TestLogger{T: t}, + Scheme: s, + ConfigEntryController: &controller.ConfigEntryController{ + ConsulClient: consulClient, + EnableConsulNamespaces: true, + EnableNSMirroring: c.Mirror, + NSMirroringPrefix: c.MirrorPrefix, + ConsulDestinationNamespace: c.DestConsulNS, + }, + } + + resp, err := controller.Reconcile(ctx, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: c.SourceKubeNS, + Name: partitionExport.KubernetesName(), + }, + }) + req.NoError(err) + req.False(resp.Requeue) + + cfg, _, err := consulClient.ConfigEntries().Get(capi.PartitionExports, partitionExport.ConsulName(), &capi.QueryOptions{ + Namespace: common.DefaultConsulNamespace, + }) + req.NoError(err) + + configEntry, ok := cfg.(*capi.PartitionExportsConfigEntry) + req.True(ok) + req.Equal(configEntry.Services[0].Name, "frontend") + + // Check that the status is "synced". + err = fakeClient.Get(ctx, types.NamespacedName{ + Namespace: c.SourceKubeNS, + Name: partitionExport.KubernetesName(), + }, partitionExport) + req.NoError(err) + conditionSynced := partitionExport.SyncedConditionStatus() + req.Equal(conditionSynced, corev1.ConditionTrue) + }) + } +} + +func TestPartitionExportsController_updatesPartitionExports(tt *testing.T) { + tt.Skip() + tt.Parallel() + + cases := map[string]struct { + Mirror bool + MirrorPrefix string + SourceKubeNS string + DestConsulNS string + }{ + "SourceKubeNS=default, DestConsulNS=default": { + SourceKubeNS: "default", + DestConsulNS: "default", + }, + "SourceKubeNS=kube, DestConsulNS=default": { + SourceKubeNS: "kube", + DestConsulNS: "default", + }, + "SourceKubeNS=default, DestConsulNS=other": { + SourceKubeNS: "default", + DestConsulNS: "other", + }, + "SourceKubeNS=kube, DestConsulNS=other": { + SourceKubeNS: "kube", + DestConsulNS: "other", + }, + "SourceKubeNS=default, Mirror=true": { + SourceKubeNS: "default", + Mirror: true, + }, + "SourceKubeNS=kube, Mirror=true": { + SourceKubeNS: "kube", + Mirror: true, + }, + "SourceKubeNS=default, Mirror=true, Prefix=prefix": { + SourceKubeNS: "default", + Mirror: true, + MirrorPrefix: "prefix-", + }, + } + + for name, c := range cases { + tt.Run(name, func(t *testing.T) { + req := require.New(t) + s := runtime.NewScheme() + partitionExport := &v1alpha1.PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + Namespace: c.SourceKubeNS, + Finalizers: []string{controller.FinalizerName}, + }, + Spec: v1alpha1.PartitionExportsSpec{ + Services: []v1alpha1.ExportedService{ + { + Name: "frontend", + Namespace: "front", + Consumers: []v1alpha1.ServiceConsumer{ + {Partition: "foo"}, + {Partition: "bar"}, + }, + }, + }, + }, + } + s.AddKnownTypes(v1alpha1.GroupVersion, partitionExport) + ctx := context.Background() + + consul, err := testutil.NewTestServerConfigT(t, nil) + req.NoError(err) + defer consul.Stop() + consul.WaitForServiceIntentions(t) + consulClient, err := capi.NewClient(&capi.Config{ + Address: consul.HTTPAddr, + }) + req.NoError(err) + + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(partitionExport).Build() + + controller := &controller.PartitionExportsController{ + Client: fakeClient, + Log: logrtest.TestLogger{T: t}, + Scheme: s, + ConfigEntryController: &controller.ConfigEntryController{ + ConsulClient: consulClient, + EnableConsulNamespaces: true, + EnableNSMirroring: c.Mirror, + NSMirroringPrefix: c.MirrorPrefix, + ConsulDestinationNamespace: c.DestConsulNS, + }, + } + + // We haven't run reconcile yet so ensure it's created in Consul. + { + _, _, err := consulClient.ConfigEntries().Set(&capi.PartitionExportsConfigEntry{ + Name: "default", + Services: []capi.ExportedService{ + { + Name: "frontend", + Namespace: "front", + Consumers: []capi.ServiceConsumer{ + {Partition: "foo"}, + {Partition: "bar"}, + }, + }, + }, + }, &capi.WriteOptions{Namespace: common.DefaultConsulNamespace}) + req.NoError(err) + } + + // Now update it. + { + // First get it so we have the latest revision number. + err = fakeClient.Get(ctx, types.NamespacedName{ + Namespace: c.SourceKubeNS, + Name: partitionExport.KubernetesName(), + }, partitionExport) + req.NoError(err) + + // Update the resource. + partitionExport.Spec.Services[0].Name = "backend" + err := fakeClient.Update(ctx, partitionExport) + req.NoError(err) + + resp, err := controller.Reconcile(ctx, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: c.SourceKubeNS, + Name: partitionExport.KubernetesName(), + }, + }) + req.NoError(err) + req.False(resp.Requeue) + + cfg, _, err := consulClient.ConfigEntries().Get(capi.PartitionExports, partitionExport.ConsulName(), &capi.QueryOptions{ + Namespace: common.DefaultConsulNamespace, + }) + req.NoError(err) + entry := cfg.(*capi.PartitionExportsConfigEntry) + req.Equal("backend", entry.Services[0].Name) + } + }) + } +} + +func TestPartitionExportsController_deletesPartitionExports(tt *testing.T) { + tt.Skip() + tt.Parallel() + + cases := map[string]struct { + Mirror bool + MirrorPrefix string + SourceKubeNS string + DestConsulNS string + }{ + "SourceKubeNS=default, DestConsulNS=default": { + SourceKubeNS: "default", + DestConsulNS: "default", + }, + "SourceKubeNS=kube, DestConsulNS=default": { + SourceKubeNS: "kube", + DestConsulNS: "default", + }, + "SourceKubeNS=default, DestConsulNS=other": { + SourceKubeNS: "default", + DestConsulNS: "other", + }, + "SourceKubeNS=kube, DestConsulNS=other": { + SourceKubeNS: "kube", + DestConsulNS: "other", + }, + "SourceKubeNS=default, Mirror=true": { + SourceKubeNS: "default", + Mirror: true, + }, + "SourceKubeNS=kube, Mirror=true": { + SourceKubeNS: "kube", + Mirror: true, + }, + "SourceKubeNS=default, Mirror=true, Prefix=prefix": { + SourceKubeNS: "default", + Mirror: true, + MirrorPrefix: "prefix-", + }, + } + + for name, c := range cases { + tt.Run(name, func(t *testing.T) { + req := require.New(t) + s := runtime.NewScheme() + partitionExport := &v1alpha1.PartitionExports{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + Namespace: c.SourceKubeNS, + Finalizers: []string{controller.FinalizerName}, + DeletionTimestamp: &metav1.Time{Time: time.Now()}, + }, + Spec: v1alpha1.PartitionExportsSpec{ + Services: []v1alpha1.ExportedService{ + { + Name: "frontend", + Namespace: "front", + Consumers: []v1alpha1.ServiceConsumer{ + {Partition: "foo"}, + {Partition: "bar"}, + }, + }, + }, + }, + } + s.AddKnownTypes(v1alpha1.GroupVersion, partitionExport) + + consul, err := testutil.NewTestServerConfigT(t, nil) + req.NoError(err) + defer consul.Stop() + consul.WaitForServiceIntentions(t) + consulClient, err := capi.NewClient(&capi.Config{ + Address: consul.HTTPAddr, + }) + req.NoError(err) + + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(partitionExport).Build() + + controller := &controller.PartitionExportsController{ + Client: fakeClient, + Log: logrtest.TestLogger{T: t}, + Scheme: s, + ConfigEntryController: &controller.ConfigEntryController{ + ConsulClient: consulClient, + EnableConsulNamespaces: true, + EnableNSMirroring: c.Mirror, + NSMirroringPrefix: c.MirrorPrefix, + ConsulDestinationNamespace: c.DestConsulNS, + }, + } + + // We haven't run reconcile yet so ensure it's created in Consul. + { + _, _, err := consulClient.ConfigEntries().Set(&capi.PartitionExportsConfigEntry{ + Name: "default", + Services: []capi.ExportedService{ + { + Name: "frontend", + Namespace: "front", + Consumers: []capi.ServiceConsumer{ + {Partition: "foo"}, + {Partition: "bar"}, + }, + }, + }, + }, + &capi.WriteOptions{Namespace: common.DefaultConsulNamespace}) + req.NoError(err) + } + + // Now run reconcile. It's marked for deletion so this should delete it. + { + resp, err := controller.Reconcile(context.Background(), ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: c.SourceKubeNS, + Name: partitionExport.KubernetesName(), + }, + }) + req.NoError(err) + req.False(resp.Requeue) + + _, _, err = consulClient.ConfigEntries().Get(capi.PartitionExports, partitionExport.ConsulName(), &capi.QueryOptions{ + Namespace: common.DefaultConsulNamespace, + }) + req.EqualError(err, fmt.Sprintf(`Unexpected response code: 404 (Config entry not found for "%s" / "%s")`, capi.PartitionExports, partitionExport.ConsulName())) + } + }) + } +} diff --git a/control-plane/subcommand/controller/command.go b/control-plane/subcommand/controller/command.go index e1640de4c8..38bc7cc0df 100644 --- a/control-plane/subcommand/controller/command.go +++ b/control-plane/subcommand/controller/command.go @@ -138,6 +138,16 @@ func (c *Command) Run(args []string) int { return 1 } + partitionsEnabled := c.httpFlags.Partition() != "" + consulMeta := common.ConsulMeta{ + PartitionsEnabled: partitionsEnabled, + Partition: c.httpFlags.Partition(), + NamespacesEnabled: c.flagEnableNamespaces, + DestinationNamespace: c.flagConsulDestinationNamespace, + Mirroring: c.flagEnableNSMirroring, + Prefix: c.flagNSMirroringPrefix, + } + configEntryReconciler := &controller.ConfigEntryController{ ConsulClient: consulClient, DatacenterName: c.flagDatacenter, @@ -247,98 +257,72 @@ func (c *Command) Run(args []string) int { // annotation in each webhook file. mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicedefaults", &webhook.Admission{Handler: &v1alpha1.ServiceDefaultsWebhook{ - Client: mgr.GetClient(), - ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceDefaults), - EnableConsulNamespaces: c.flagEnableNamespaces, - EnableNSMirroring: c.flagEnableNSMirroring, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - NSMirroringPrefix: c.flagNSMirroringPrefix, + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceDefaults), + ConsulMeta: consulMeta, }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-serviceresolver", &webhook.Admission{Handler: &v1alpha1.ServiceResolverWebhook{ - Client: mgr.GetClient(), - ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceResolver), - EnableConsulNamespaces: c.flagEnableNamespaces, - EnableNSMirroring: c.flagEnableNSMirroring, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - NSMirroringPrefix: c.flagNSMirroringPrefix, + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceResolver), + ConsulMeta: consulMeta, }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-proxydefaults", &webhook.Admission{Handler: &v1alpha1.ProxyDefaultsWebhook{ - Client: mgr.GetClient(), - ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.ProxyDefaults), - EnableConsulNamespaces: c.flagEnableNamespaces, - EnableNSMirroring: c.flagEnableNSMirroring, + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.ProxyDefaults), + ConsulMeta: consulMeta, }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-mesh", &webhook.Admission{Handler: &v1alpha1.MeshWebhook{ - Client: mgr.GetClient(), - ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.Mesh), - EnableConsulNamespaces: c.flagEnableNamespaces, - EnableNSMirroring: c.flagEnableNSMirroring, + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.Mesh), }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-partitionexports", &webhook.Admission{Handler: &v1alpha1.PartitionExportsWebhook{ - Client: mgr.GetClient(), - ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.PartitionExports), - EnableConsulNamespaces: c.flagEnableNamespaces, - EnableNSMirroring: c.flagEnableNSMirroring, - PartitionName: c.httpFlags.Partition(), + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.PartitionExports), + ConsulMeta: consulMeta, }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicerouter", &webhook.Admission{Handler: &v1alpha1.ServiceRouterWebhook{ - Client: mgr.GetClient(), - ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceRouter), - EnableConsulNamespaces: c.flagEnableNamespaces, - EnableNSMirroring: c.flagEnableNSMirroring, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - NSMirroringPrefix: c.flagNSMirroringPrefix, + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceRouter), + ConsulMeta: consulMeta, }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicesplitter", &webhook.Admission{Handler: &v1alpha1.ServiceSplitterWebhook{ - Client: mgr.GetClient(), - ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceSplitter), - EnableConsulNamespaces: c.flagEnableNamespaces, - EnableNSMirroring: c.flagEnableNSMirroring, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - NSMirroringPrefix: c.flagNSMirroringPrefix, + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceSplitter), + ConsulMeta: consulMeta, }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-serviceintentions", &webhook.Admission{Handler: &v1alpha1.ServiceIntentionsWebhook{ - Client: mgr.GetClient(), - ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceIntentions), - EnableConsulNamespaces: c.flagEnableNamespaces, - EnableNSMirroring: c.flagEnableNSMirroring, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - NSMirroringPrefix: c.flagNSMirroringPrefix, + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.ServiceIntentions), + ConsulMeta: consulMeta, }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-ingressgateway", &webhook.Admission{Handler: &v1alpha1.IngressGatewayWebhook{ - Client: mgr.GetClient(), - ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.IngressGateway), - EnableConsulNamespaces: c.flagEnableNamespaces, - EnableNSMirroring: c.flagEnableNSMirroring, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - NSMirroringPrefix: c.flagNSMirroringPrefix, + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.IngressGateway), + ConsulMeta: consulMeta, }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-terminatinggateway", &webhook.Admission{Handler: &v1alpha1.TerminatingGatewayWebhook{ - Client: mgr.GetClient(), - ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.TerminatingGateway), - EnableConsulNamespaces: c.flagEnableNamespaces, - EnableNSMirroring: c.flagEnableNSMirroring, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - NSMirroringPrefix: c.flagNSMirroringPrefix, + Client: mgr.GetClient(), + ConsulClient: consulClient, + Logger: ctrl.Log.WithName("webhooks").WithName(common.TerminatingGateway), + ConsulMeta: consulMeta, }}) } // +kubebuilder:scaffold:builder From 6e387065c8841f80c501b8c083e5ab3c7cdbfd8d Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 27 Oct 2021 10:58:49 -0400 Subject: [PATCH 094/418] Fix indentation in test file. (#805) --- acceptance/tests/controller/controller_namespaces_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go index 00affb3f19..9649ee7fab 100644 --- a/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -74,7 +74,7 @@ func TestControllerNamespaces(t *testing.T) { ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ - "global.image": "ashwinvenkatesh/consul@sha256:7426f47fa7065e38a2488042be66325aa37cda17a3bc15e58178104ff4619c1b", + "global.image": "ashwinvenkatesh/consul@sha256:7426f47fa7065e38a2488042be66325aa37cda17a3bc15e58178104ff4619c1b", "global.enableConsulNamespaces": "true", "global.adminPartitions.enabled": "true", From d0de8e699826e2044f309b39a54ccb0ace9268ee Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Wed, 27 Oct 2021 11:01:02 -0500 Subject: [PATCH 095/418] Apply suggestions from code review Co-authored-by: Iryna Shustava --- acceptance/framework/vault/vault_cluster.go | 9 ++++----- acceptance/tests/vault/vault_test.go | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index 45dab57dca..b98619c369 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -31,8 +31,8 @@ import ( // then also call bootstrap() to setup the vault cluster for testing. Create(t *testing.T, ctx environment.TestContext) - // bootstrap will execute the Init(), Unseal() process and bootstrap the vault cluster by enabling the KV2 secret - // engine and also enabling the Kube Auth Method. + // bootstrap will init and unseal the Vault cluster and enable the KV2 secret + // engine and the Kube Auth Method. bootstrap(t *testing.T, ctx environment.TestContext) // Destroy will do a helm uninstall of the Vault installation and then delete the data PVC used by Vault and the @@ -148,8 +148,8 @@ func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { return vaultClient } -// bootstrap runs Init, Unseals the Vault installation -// and then does the setup of Auth Methods and Enables Secrets Engines. +// bootstrap initializes and unseals the Vault installation. +// It then sets up Kubernetes auth method and enables secrets engines. func (v *VaultCluster) bootstrap(t *testing.T, ctx environment.TestContext) { v.vaultClient = v.SetupVaultClient(t) @@ -262,7 +262,6 @@ func defaultVaultValues() map[string]string { return map[string]string{ "server.replicas": "1", "server.bootstrapExpect": "1", - //"ui.enabled": "true", "injector.enabled": "true", "global.enabled": "true", } diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 6d58c7365c..7ff23f495e 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -33,7 +33,7 @@ func TestVault_Create(t *testing.T) { _, err := vaultClient.Logical().Write("consul/data/secret/test", params) require.NoError(t, err) - // Validate that the Auth Methods exist. + // Validate that the Auth Method exists. authList, err := vaultClient.Sys().ListAuth() require.NoError(t, err) logger.Log(t, "Auth List: ", authList) From da47c6e2b37a19db0d1f24360b773a6b73934667 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Wed, 27 Oct 2021 14:14:35 -0500 Subject: [PATCH 096/418] review comments --- .circleci/config.yml | 1 - acceptance/framework/consul/consul_cluster.go | 2 +- acceptance/framework/helpers/helpers.go | 10 +- acceptance/framework/vault/vault_cluster.go | 111 +++++------------- acceptance/tests/vault/vault_test.go | 2 + 5 files changed, 34 insertions(+), 92 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cd6a53cda0..a592052168 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -50,7 +50,6 @@ commands: wget https://get.helm.sh/helm-v3.7.0-linux-amd64.tar.gz tar -zxvf helm-v3.7.0-linux-amd64.tar.gz sudo mv linux-amd64/helm /usr/local/bin/helm - /usr/local/bin/helm repo add hashicorp https://helm.releases.hashicorp.com create-kind-clusters: parameters: diff --git a/acceptance/framework/consul/consul_cluster.go b/acceptance/framework/consul/consul_cluster.go index d99551994f..ada9e7b7d9 100644 --- a/acceptance/framework/consul/consul_cluster.go +++ b/acceptance/framework/consul/consul_cluster.go @@ -114,7 +114,7 @@ func (h *HelmCluster) Create(t *testing.T) { }) // Fail if there are any existing installations of the Helm chart. - helpers.CheckForPriorInstallations(t, h.kubernetesClient, h.helmOptions, "consul") + helpers.CheckForPriorInstallations(t, h.kubernetesClient, h.helmOptions, "consul-helm") helm.Install(t, h.helmOptions, config.HelmChartPath, h.releaseName) diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index f1c4494b80..294e395cb2 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -57,18 +57,14 @@ func CheckForPriorInstallations(t *testing.T, client kubernetes.Interface, optio // Wait for all pods in the "default" namespace to exit. A previous // release may not be listed by Helm but its pods may still be terminating. retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { - pods, err := client.CoreV1().Pods(options.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) + pods, err := client.CoreV1().Pods(options.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: fmt.Sprintf("chart=%s", chartName)}) require.NoError(r, err) if len(pods.Items) > 0 { var podNames []string for _, p := range pods.Items { - if strings.Contains(p.Name, chartName) { - podNames = append(podNames, p.Name) - } - } - if len(podNames) > 0 { - r.Errorf("pods from previous installation still running: %s", strings.Join(podNames, ", ")) + podNames = append(podNames, p.Name) } + r.Errorf("pods from previous installation still running: %s", strings.Join(podNames, ", ")) } }) } diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index b98619c369..bad8681b14 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -3,7 +3,10 @@ package vault import ( "context" "fmt" - "strings" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "testing" "time" @@ -12,43 +15,17 @@ import ( terratestLogger "github.com/gruntwork-io/terratest/modules/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/config" "github.com/hashicorp/consul-k8s/acceptance/framework/environment" - "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/sdk/testutil/retry" vapi "github.com/hashicorp/vault/api" "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) -/* - // High level description of the functions implemented for the VaultCluster object: - - // Create will install a vault cluster via helm using the default config defined at the end of this file. It will - // then also call bootstrap() to setup the vault cluster for testing. - Create(t *testing.T, ctx environment.TestContext) - - // bootstrap will init and unseal the Vault cluster and enable the KV2 secret - // engine and the Kube Auth Method. - bootstrap(t *testing.T, ctx environment.TestContext) - - // Destroy will do a helm uninstall of the Vault installation and then delete the data PVC used by Vault and the - // helm secrets. - Destroy(t *testing.T) - - // SetupVaultClient will setup the port-forwarding to the Vault server so that we can create a vault client connection. - // This is run as part of Bootstrap. - SetupVaultClient(t *testing.T) *vapi.Client - - // VaultClient returns the client that was built as part of SetupVaultClient. - VaultClient(t *testing.T) *vapi.Client -*/ - const ( - vaultNS = "default" + vaultNS = "default" + vaultChartVersion = "0.17.0" + vaultRootToken = "abcd1234" ) // VaultCluster @@ -58,8 +35,8 @@ type VaultCluster struct { vaultHelmOptions *helm.Options vaultReleaseName string + vaultChartName string vaultClient *vapi.Client - rootToken string kubectlOptions *terratestk8s.KubectlOptions values map[string]string @@ -91,7 +68,11 @@ func NewVaultCluster( SetValues: defaultVaultValues(), KubectlOptions: kopts, Logger: logger, + Version: vaultChartVersion, } + // Add the vault helm repo in case it is missing, and do an update so we can utilise `vaultChartVersion` to install. + helm.AddRepo(t, &helm.Options{}, "hashicorp/vault", "https://helm.releases.hashicorp.com") + helm.RunHelmCommandAndGetOutputE(t, &helm.Options{}, "repo", "update") return &VaultCluster{ ctx: ctx, @@ -106,6 +87,7 @@ func NewVaultCluster( debugDirectory: cfg.DebugDirectory, logger: logger, vaultReleaseName: releaseName, + vaultChartName: fmt.Sprintf("vault-%s", vaultChartVersion), } } @@ -148,37 +130,14 @@ func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { return vaultClient } -// bootstrap initializes and unseals the Vault installation. -// It then sets up Kubernetes auth method and enables secrets engines. +// bootstrap sets up Kubernetes auth method and enables secrets engines. func (v *VaultCluster) bootstrap(t *testing.T, ctx environment.TestContext) { v.vaultClient = v.SetupVaultClient(t) + v.vaultClient.SetToken(vaultRootToken) - // Init the Vault Cluster and store the rootToken. - initResp, err := v.vaultClient.Sys().Init(&vapi.InitRequest{ - // Init the cluster and only request a single Secret to be used for Unsealing. - SecretShares: 1, - SecretThreshold: 1, - StoredShares: 1, - RecoveryShares: 0, - RecoveryThreshold: 0, - }) - if err != nil { - t.Fatal("unable to init Vault cluster", "err", err) - } - // Store the RootToken and set the client to use it so it can Unseal and finish bootstrapping. - v.rootToken = initResp.RootToken - v.vaultClient.SetToken(v.rootToken) - - // Unseal the Vault Cluster using the Unseal Keys from Init(). - sealResp, err := v.vaultClient.Sys().Unseal(initResp.KeysB64[0]) - if err != nil { - t.Fatal("unable to unseal Vault cluster", "err", err) - } - require.Equal(t, false, sealResp.Sealed) - - // Enable the KV-V2 Secrets engine - err = v.vaultClient.Sys().Mount("consul", &vapi.MountInput{ + // Enable the KV-V2 Secrets engine. + err := v.vaultClient.Sys().Mount("consul", &vapi.MountInput{ Type: "kv-v2", Config: vapi.MountConfigInput{}, }) @@ -197,7 +156,7 @@ func (v *VaultCluster) bootstrap(t *testing.T, ctx environment.TestContext) { } // We need to kubectl exec this one on the vault server: // This is taken from https://learn.hashicorp.com/tutorials/vault/kubernetes-google-cloud-gke?in=vault/kubernetes#configure-kubernetes-authentication - cmdString := fmt.Sprintf("VAULT_TOKEN=%s vault write auth/kubernetes/config token_reviewer_jwt=\"$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\" kubernetes_host=\"https://${KUBERNETES_PORT_443_TCP_ADDR}:443\" kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", v.rootToken) + cmdString := fmt.Sprintf("VAULT_TOKEN=%s vault write auth/kubernetes/config token_reviewer_jwt=\"$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\" kubernetes_host=\"https://${KUBERNETES_PORT_443_TCP_ADDR}:443\" kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", vaultRootToken) v.logger.Logf(t, "updating vault kube auth config") k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "-i", fmt.Sprintf("%s-vault-0", v.vaultReleaseName), "--", "sh", "-c", cmdString) @@ -214,7 +173,7 @@ func (v *VaultCluster) Create(t *testing.T, ctx environment.TestContext) { }) // Fail if there are any existing installations of the Helm chart. - helpers.CheckForPriorInstallations(t, v.kubernetesClient, v.vaultHelmOptions, "vault") + helpers.CheckForPriorInstallations(t, v.kubernetesClient, v.vaultHelmOptions, v.vaultChartName) // Install Vault. helm.Install(t, v.vaultHelmOptions, "hashicorp/vault", v.vaultReleaseName) @@ -231,38 +190,24 @@ func (v *VaultCluster) Create(t *testing.T, ctx environment.TestContext) { v.bootstrap(t, ctx) } -// Destroy issues an helm delete and deletes the PVC + any helm secrets related to the release that are leftover. +// Destroy issues a helm delete and deletes the PVC + any helm secrets related to the release that are leftover. func (v *VaultCluster) Destroy(t *testing.T) { t.Helper() k8s.WritePodsDebugInfoIfFailed(t, v.kubectlOptions, v.debugDirectory, "release="+v.vaultReleaseName) - // Ignore the error returned by the helm delete here so that we can // always idempotently clean up resources in the cluster. - _ = helm.DeleteE(t, v.vaultHelmOptions, v.vaultReleaseName, false) - - // Delete PVCs, these are the only parts that need to be cleaned up in Vault installs. - err := v.kubernetesClient.CoreV1().PersistentVolumeClaims(v.vaultHelmOptions.KubectlOptions.Namespace).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: fmt.Sprintf("app.kubernetes.io/instance=%s", v.vaultReleaseName)}) - require.NoError(t, err) - - // Delete any secrets that have v.releaseName in their name, this is only needed to delete the Helm release secret if it is still around. - secrets, err := v.kubernetesClient.CoreV1().Secrets(v.vaultHelmOptions.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{}) - require.NoError(t, err) - for _, secret := range secrets.Items { - if strings.Contains(secret.Name, v.vaultReleaseName) { - err := v.kubernetesClient.CoreV1().Secrets(v.vaultHelmOptions.KubectlOptions.Namespace).Delete(context.Background(), secret.Name, metav1.DeleteOptions{}) - if !errors.IsNotFound(err) { - require.NoError(t, err) - } - } - } + _ = helm.DeleteE(t, v.vaultHelmOptions, v.vaultReleaseName, true) + // We do not need to do any PVC deletion in vault dev mode. } func defaultVaultValues() map[string]string { return map[string]string{ - "server.replicas": "1", - "server.bootstrapExpect": "1", - "injector.enabled": "true", - "global.enabled": "true", + "server.replicas": "1", + "server.dev.enabled": "true", + "server.dev.devRootToken": vaultRootToken, + "server.bootstrapExpect": "1", + "injector.enabled": "true", + "global.enabled": "true", } } diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 7ff23f495e..fac892bf0e 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -2,6 +2,7 @@ package vault import ( "testing" + "time" "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" @@ -38,4 +39,5 @@ func TestVault_Create(t *testing.T) { require.NoError(t, err) logger.Log(t, "Auth List: ", authList) require.NotNil(t, authList["kubernetes/"]) + time.Sleep(time.Second * 60) } From 400fda62fbd32d0cf8c60f688640a38f48b134ea Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Wed, 27 Oct 2021 14:24:35 -0500 Subject: [PATCH 097/418] fix lint --- acceptance/framework/vault/vault_cluster.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index bad8681b14..36644c1abe 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -72,7 +72,9 @@ func NewVaultCluster( } // Add the vault helm repo in case it is missing, and do an update so we can utilise `vaultChartVersion` to install. helm.AddRepo(t, &helm.Options{}, "hashicorp/vault", "https://helm.releases.hashicorp.com") - helm.RunHelmCommandAndGetOutputE(t, &helm.Options{}, "repo", "update") + // Ignoring the error from `helm repo update` as it could fail due to stale cache or unreachable servers and we're + // asserting a chart version on Install which would fail in an obvious way should this not succeed. + _, _ = helm.RunHelmCommandAndGetOutputE(t, &helm.Options{}, "repo", "update") return &VaultCluster{ ctx: ctx, From 5e25b77d5d526c9d5f439caaeb5ace3438d92695 Mon Sep 17 00:00:00 2001 From: David Yu Date: Thu, 28 Oct 2021 11:30:47 -0700 Subject: [PATCH 098/418] cli: add prometheus deployment and metrics integration to demo preset (#809) * cli: Add prometheus deployment and Consul K8s metrics integration to demo preset is used for `consul-k8s install` --- CHANGELOG.md | 1 + cli/cmd/install/presets.go | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a224794a64..892b099e51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ IMPROVEMENTS: * `kube-system` and `local-path-storage` namespaces are now excluded from connect injection by default on Kubernetes versions >= 1.21. This prevents deadlock issues when `kube-system` components go down and allows Kind to work without changing the failure policy of the mutating webhook. [[GH-726](https://github.com/hashicorp/consul-k8s/pull/726)] * CLI * Add `status` command. [[GH-768](https://github.com/hashicorp/consul-k8s/pull/768)] + * Add Prometheus deployment and Consul K8s metrics integration with demo preset when installing via `-preset=demo`. [[GH-809](https://github.com/hashicorp/consul-k8s/pull/809)] ## 0.35.0 (October 19, 2021) diff --git a/cli/cmd/install/presets.go b/cli/cmd/install/presets.go index 4a3d2523ef..dc0f15c7e6 100644 --- a/cli/cmd/install/presets.go +++ b/cli/cmd/install/presets.go @@ -17,11 +17,24 @@ var presets = map[string]interface{}{ var demo = ` global: name: consul + metrics: + enabled: true + enableAgentMetrics: true connectInject: enabled: true + metrics: + defaultEnabled: true + defaultEnableMerging: true + enableGatewayMetrics: true server: replicas: 1 bootstrapExpect: 1 +ui: + enabled: true + service: + enabled: true +prometheus: + enabled: true ` var secure = ` From 1fc4519fc6358890901268707dcd1796191440bd Mon Sep 17 00:00:00 2001 From: NicoletaPopoviciu <87660255+NicoletaPopoviciu@users.noreply.github.com> Date: Thu, 28 Oct 2021 14:53:56 -0400 Subject: [PATCH 099/418] minor fixes and refactor for uninstall (#804) --- cli/cmd/common/utils.go | 2 +- cli/cmd/install/install.go | 2 +- cli/cmd/uninstall/uninstall.go | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cli/cmd/common/utils.go b/cli/cmd/common/utils.go index f7c0b7eb34..95fafb013e 100644 --- a/cli/cmd/common/utils.go +++ b/cli/cmd/common/utils.go @@ -97,7 +97,7 @@ func InitActionConfig(actionConfig *action.Configuration, namespace string, sett return actionConfig, nil } -// CheckForPreviousInstallations uses the helm Go SDK to find helm releases in all namespaces where the chart name is +// CheckForInstallations uses the helm Go SDK to find helm releases in all namespaces where the chart name is // "consul", and returns the release name and namespace if found, or an error if not found. func CheckForInstallations(settings *helmCLI.EnvSettings, uiLogger action.DebugLog) (string, string, error) { // Need a specific action config to call helm list, where namespace is NOT specified. diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index dbb481c0ea..7b5e68d34a 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -213,7 +213,7 @@ func (c *Command) Run(args []string) int { c.UI.Output("Pre-Install Checks", terminal.WithHeaderStyle()) - // Note the logic here, common's CheckForPreviousInstallations function returns an error if + // Note the logic here, common's CheckForInstallations function returns an error if // the release is not found, which in the install command is what we need for a successful install. if name, ns, err := common.CheckForInstallations(settings, uiLogger); err == nil { c.UI.Output(fmt.Sprintf("existing Consul installation found (name=%s, namespace=%s) - run "+ diff --git a/cli/cmd/uninstall/uninstall.go b/cli/cmd/uninstall/uninstall.go index 5bb6c69e61..0e218c5d0f 100644 --- a/cli/cmd/uninstall/uninstall.go +++ b/cli/cmd/uninstall/uninstall.go @@ -316,8 +316,7 @@ func (c *Command) findExistingInstallation(settings *helmCLI.EnvSettings, uiLogg releaseName, namespace, err := common.CheckForInstallations(settings, uiLogger) if err != nil { return false, "", "", err - } else if (c.flagNamespace != defaultAllNamespaces && c.flagNamespace == namespace) || - (c.flagNamespace == defaultAllNamespaces) { + } else if c.flagNamespace == defaultAllNamespaces || c.flagNamespace == namespace { return true, releaseName, namespace, nil } else { return false, "", "", fmt.Errorf("could not find consul installation in namespace %s", c.flagNamespace) From 5eaf12a874792ee623605558e35a3844dc822c01 Mon Sep 17 00:00:00 2001 From: David Yu Date: Thu, 28 Oct 2021 13:14:21 -0700 Subject: [PATCH 100/418] cli: install - move not ready library log messages behind -verbose flag (#810) * cli: remove not ready library log messages * adding verbose flag and selectively output logs when verbose is not set * Update cli/cmd/install/install.go adding -v alias Co-authored-by: Nitya Dhanushkodi * small comment change * adding changelog * Update cli/cmd/install/install.go Co-authored-by: Thomas Eckert Co-authored-by: Nitya Dhanushkodi Co-authored-by: Thomas Eckert --- CHANGELOG.md | 1 + cli/cmd/install/install.go | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 892b099e51..3e35d539ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ IMPROVEMENTS: * `kube-system` and `local-path-storage` namespaces are now excluded from connect injection by default on Kubernetes versions >= 1.21. This prevents deadlock issues when `kube-system` components go down and allows Kind to work without changing the failure policy of the mutating webhook. [[GH-726](https://github.com/hashicorp/consul-k8s/pull/726)] * CLI * Add `status` command. [[GH-768](https://github.com/hashicorp/consul-k8s/pull/768)] + * Add `-verbose`, `-v` flag to the `consul-k8s install` command, which outputs all logs emitted from the installation. By default, verbose is set to `false` to hide logs that show resources are not ready. [[GH-810](https://github.com/hashicorp/consul-k8s/pull/810)] * Add Prometheus deployment and Consul K8s metrics integration with demo preset when installing via `-preset=demo`. [[GH-809](https://github.com/hashicorp/consul-k8s/pull/809)] ## 0.35.0 (October 19, 2021) diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index 7b5e68d34a..689fbbcc3e 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -44,6 +44,9 @@ const ( flagNameTimeout = "timeout" defaultTimeout = "10m" + flagNameVerbose = "verbose" + defaultVerbose = false + flagNameWait = "wait" defaultWait = true ) @@ -65,6 +68,7 @@ type Command struct { flagFileValues []string flagTimeout string timeoutDuration time.Duration + flagVerbose bool flagWait bool flagKubeConfig string @@ -135,6 +139,13 @@ func (c *Command) init() { Default: defaultTimeout, Usage: "Timeout to wait for installation to be ready.", }) + f.BoolVar(&flag.BoolVar{ + Name: flagNameVerbose, + Aliases: []string{"v"}, + Target: &c.flagVerbose, + Default: defaultVerbose, + Usage: "Output verbose logs from the install command with the status of resources being installed.", + }) f.BoolVar(&flag.BoolVar{ Name: flagNameWait, Target: &c.flagWait, @@ -192,7 +203,16 @@ func (c *Command) Run(args []string) int { // Setup logger to stream Helm library logs var uiLogger = func(s string, args ...interface{}) { logMsg := fmt.Sprintf(s, args...) - c.UI.Output(logMsg, terminal.WithLibraryStyle()) + + if c.flagVerbose { + // Only output all logs when verbose is enabled + c.UI.Output(logMsg, terminal.WithLibraryStyle()) + } else { + // When verbose is not enabled, output all logs except not ready messages for resources + if !strings.Contains(logMsg, "not ready") { + c.UI.Output(logMsg, terminal.WithLibraryStyle()) + } + } } // Set up the kubernetes client to use for non Helm SDK calls to the Kubernetes API From 1a902353cba826d257493d70278e5f4d8f1f0be7 Mon Sep 17 00:00:00 2001 From: David Yu Date: Thu, 28 Oct 2021 13:15:04 -0700 Subject: [PATCH 101/418] README.md: change install command and bump to helm CLI 3.2+ (#812) --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0a83bc50ab..8a377ed3ba 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ use Consul with Kubernetes, please see the [Consul and Kubernetes documentation](https://www.consul.io/docs/platform/k8s/index.html). ### Prerequisites - * **Helm 3.0+** (Helm 2 is not supported) + * **Helm 3.2+** (Helm 2 is not supported) * **Kubernetes 1.18+** - This is the earliest version of Kubernetes tested. It is possible that this chart works with earlier versions but it is untested. @@ -75,11 +75,12 @@ Detailed installation instructions for Consul on Kubernetes are found [here](htt $ helm search repo hashicorp/consul NAME CHART VERSION APP VERSION DESCRIPTION - hashicorp/consul 0.33.0 1.10.0 Official HashiCorp Consul Chart + hashicorp/consul 0.35.0 1.10.3 Official HashiCorp Consul Chart -3. Now you're ready to install Consul! To install Consul with the default configuration using Helm 3 run: +3. Now you're ready to install Consul! To install Consul with the default configuration using Helm 3.2 run the following command below. + This will create a `consul` Kubernetes namespace if not already present, and install Consul on the dedicated namespace. - $ helm install consul hashicorp/consul --set global.name=consul + $ helm install consul hashicorp/consul --set global.name=consul --create-namespace -n consul NAME: consul Please see the many options supported in the `values.yaml` From 5b243b6c0c4fd8dbd71811012f2f89043bcbb11d Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Thu, 28 Oct 2021 15:26:57 -0600 Subject: [PATCH 102/418] Reenable TestConnectInject_RestartConsulClients (#813) --- acceptance/tests/connect/connect_inject_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/acceptance/tests/connect/connect_inject_test.go b/acceptance/tests/connect/connect_inject_test.go index 283f5eb0b7..464c134702 100644 --- a/acceptance/tests/connect/connect_inject_test.go +++ b/acceptance/tests/connect/connect_inject_test.go @@ -116,9 +116,6 @@ func TestConnectInject_CleanupKilledPods(t *testing.T) { // the services get re-registered and can continue to talk to each other. func TestConnectInject_RestartConsulClients(t *testing.T) { cfg := suite.Config() - if cfg.EnableTransparentProxy { - t.Skip("skipping this test because it's currently flakey when transparent proxy is enabled") - } ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ From 35cc9527d7dac36bcce65f00df07f14bf61e1cfe Mon Sep 17 00:00:00 2001 From: David Yu Date: Thu, 28 Oct 2021 14:43:05 -0700 Subject: [PATCH 103/418] README.md: reformat CLI instructions for install (#814) * README.md: reformat CLI instructions for install * Update README.md Co-authored-by: Thomas Eckert * Update README.md Co-authored-by: Thomas Eckert * Update README.md Co-authored-by: Thomas Eckert * remove responses from CLI examples Co-authored-by: Thomas Eckert --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8a377ed3ba..719c5d51dc 100644 --- a/README.md +++ b/README.md @@ -66,22 +66,24 @@ use Consul with Kubernetes, please see the Detailed installation instructions for Consul on Kubernetes are found [here](https://www.consul.io/docs/k8s/installation/overview). -1. Add the HashiCorp Helm Repository: +1. Add the HashiCorp Helm repository: + + ``` bash + helm repo add hashicorp https://helm.releases.hashicorp.com + ``` - $ helm repo add hashicorp https://helm.releases.hashicorp.com - "hashicorp" has been added to your repositories - -2. Ensure you have access to the consul chart: +2. Ensure you have access to the Consul Helm chart and you see the latest chart version listed. Otherwise run `helm repo update` if you have + previously added the HashiCorp Helm repository. - $ helm search repo hashicorp/consul - NAME CHART VERSION APP VERSION DESCRIPTION - hashicorp/consul 0.35.0 1.10.3 Official HashiCorp Consul Chart + ``` bash + helm search repo hashicorp/consul + ``` 3. Now you're ready to install Consul! To install Consul with the default configuration using Helm 3.2 run the following command below. This will create a `consul` Kubernetes namespace if not already present, and install Consul on the dedicated namespace. - - $ helm install consul hashicorp/consul --set global.name=consul --create-namespace -n consul - NAME: consul + + ``` bash + helm install consul hashicorp/consul --set global.name=consul --create-namespace -n consul Please see the many options supported in the `values.yaml` file. These are also fully documented directly on the From 52f10e4441a7281873133f18632689c147ee2a2e Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Fri, 29 Oct 2021 09:36:33 -0600 Subject: [PATCH 104/418] Separate CRD fixtures into OSS and enterprise (#815) Previously, all config entries were OSS, but now the new PartitionsExports exists only in consul enterprise. To make tests work, we now need to create different sets of CRs depending if we're running OSS or enterprise --- .../tests/controller/controller_namespaces_test.go | 2 +- acceptance/tests/controller/controller_test.go | 4 ++-- .../{crds => bases/crds-oss}/ingressgateway.yaml | 0 .../tests/fixtures/bases/crds-oss/kustomization.yaml | 10 ++++++++++ .../tests/fixtures/{crds => bases/crds-oss}/mesh.yaml | 0 .../{crds => bases/crds-oss}/proxydefaults.yaml | 0 .../{crds => bases/crds-oss}/servicedefaults.yaml | 0 .../{crds => bases/crds-oss}/serviceintentions.yaml | 0 .../{crds => bases/crds-oss}/serviceresolver.yaml | 0 .../{crds => bases/crds-oss}/servicerouter.yaml | 0 .../{crds => bases/crds-oss}/servicesplitter.yaml | 0 .../{crds => bases/crds-oss}/terminatinggateway.yaml | 0 .../tests/fixtures/cases/crds-ent/kustomization.yaml | 3 +++ .../{crds => cases/crds-ent}/partitionexports.yaml | 0 .../cases/static-client-inject/kustomization.yaml | 2 +- .../cases/static-client-multi-dc/kustomization.yaml | 2 +- .../cases/static-client-namespaces/kustomization.yaml | 2 +- .../cases/static-client-partition/kustomization.yaml | 2 +- .../cases/static-client-tproxy/kustomization.yaml | 2 +- .../cases/static-server-inject/kustomization.yaml | 2 +- 20 files changed, 22 insertions(+), 9 deletions(-) rename acceptance/tests/fixtures/{crds => bases/crds-oss}/ingressgateway.yaml (100%) create mode 100644 acceptance/tests/fixtures/bases/crds-oss/kustomization.yaml rename acceptance/tests/fixtures/{crds => bases/crds-oss}/mesh.yaml (100%) rename acceptance/tests/fixtures/{crds => bases/crds-oss}/proxydefaults.yaml (100%) rename acceptance/tests/fixtures/{crds => bases/crds-oss}/servicedefaults.yaml (100%) rename acceptance/tests/fixtures/{crds => bases/crds-oss}/serviceintentions.yaml (100%) rename acceptance/tests/fixtures/{crds => bases/crds-oss}/serviceresolver.yaml (100%) rename acceptance/tests/fixtures/{crds => bases/crds-oss}/servicerouter.yaml (100%) rename acceptance/tests/fixtures/{crds => bases/crds-oss}/servicesplitter.yaml (100%) rename acceptance/tests/fixtures/{crds => bases/crds-oss}/terminatinggateway.yaml (100%) create mode 100644 acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml rename acceptance/tests/fixtures/{crds => cases/crds-ent}/partitionexports.yaml (100%) diff --git a/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go index 9649ee7fab..fe07dbbbf4 100644 --- a/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -125,7 +125,7 @@ func TestControllerNamespaces(t *testing.T) { // Retry the kubectl apply because we've seen sporadic // "connection refused" errors where the mutating webhook // endpoint fails initially. - out, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-n", KubeNS, "-f", "../fixtures/crds") + out, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-n", KubeNS, "-k", "../fixtures/cases/crds-ent") require.NoError(r, err, out) // NOTE: No need to clean up because the namespace will be deleted. }) diff --git a/acceptance/tests/controller/controller_test.go b/acceptance/tests/controller/controller_test.go index ffc0b2e68b..e6405f3ccf 100644 --- a/acceptance/tests/controller/controller_test.go +++ b/acceptance/tests/controller/controller_test.go @@ -58,12 +58,12 @@ func TestController(t *testing.T) { // Retry the kubectl apply because we've seen sporadic // "connection refused" errors where the mutating webhook // endpoint fails initially. - out, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-f", "../fixtures/crds") + out, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "apply", "-k", "../fixtures/bases/crds-oss") require.NoError(r, err, out) helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { // Ignore errors here because if the test ran as expected // the custom resources will have been deleted. - k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-f", "../fixtures/crds") + k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "delete", "-k", "../fixtures/bases/crds-oss") }) }) diff --git a/acceptance/tests/fixtures/crds/ingressgateway.yaml b/acceptance/tests/fixtures/bases/crds-oss/ingressgateway.yaml similarity index 100% rename from acceptance/tests/fixtures/crds/ingressgateway.yaml rename to acceptance/tests/fixtures/bases/crds-oss/ingressgateway.yaml diff --git a/acceptance/tests/fixtures/bases/crds-oss/kustomization.yaml b/acceptance/tests/fixtures/bases/crds-oss/kustomization.yaml new file mode 100644 index 0000000000..040b64f155 --- /dev/null +++ b/acceptance/tests/fixtures/bases/crds-oss/kustomization.yaml @@ -0,0 +1,10 @@ +resources: + - ingressgateway.yaml + - mesh.yaml + - proxydefaults.yaml + - servicedefaults.yaml + - serviceintentions.yaml + - serviceresolver.yaml + - servicerouter.yaml + - servicesplitter.yaml + - terminatinggateway.yaml diff --git a/acceptance/tests/fixtures/crds/mesh.yaml b/acceptance/tests/fixtures/bases/crds-oss/mesh.yaml similarity index 100% rename from acceptance/tests/fixtures/crds/mesh.yaml rename to acceptance/tests/fixtures/bases/crds-oss/mesh.yaml diff --git a/acceptance/tests/fixtures/crds/proxydefaults.yaml b/acceptance/tests/fixtures/bases/crds-oss/proxydefaults.yaml similarity index 100% rename from acceptance/tests/fixtures/crds/proxydefaults.yaml rename to acceptance/tests/fixtures/bases/crds-oss/proxydefaults.yaml diff --git a/acceptance/tests/fixtures/crds/servicedefaults.yaml b/acceptance/tests/fixtures/bases/crds-oss/servicedefaults.yaml similarity index 100% rename from acceptance/tests/fixtures/crds/servicedefaults.yaml rename to acceptance/tests/fixtures/bases/crds-oss/servicedefaults.yaml diff --git a/acceptance/tests/fixtures/crds/serviceintentions.yaml b/acceptance/tests/fixtures/bases/crds-oss/serviceintentions.yaml similarity index 100% rename from acceptance/tests/fixtures/crds/serviceintentions.yaml rename to acceptance/tests/fixtures/bases/crds-oss/serviceintentions.yaml diff --git a/acceptance/tests/fixtures/crds/serviceresolver.yaml b/acceptance/tests/fixtures/bases/crds-oss/serviceresolver.yaml similarity index 100% rename from acceptance/tests/fixtures/crds/serviceresolver.yaml rename to acceptance/tests/fixtures/bases/crds-oss/serviceresolver.yaml diff --git a/acceptance/tests/fixtures/crds/servicerouter.yaml b/acceptance/tests/fixtures/bases/crds-oss/servicerouter.yaml similarity index 100% rename from acceptance/tests/fixtures/crds/servicerouter.yaml rename to acceptance/tests/fixtures/bases/crds-oss/servicerouter.yaml diff --git a/acceptance/tests/fixtures/crds/servicesplitter.yaml b/acceptance/tests/fixtures/bases/crds-oss/servicesplitter.yaml similarity index 100% rename from acceptance/tests/fixtures/crds/servicesplitter.yaml rename to acceptance/tests/fixtures/bases/crds-oss/servicesplitter.yaml diff --git a/acceptance/tests/fixtures/crds/terminatinggateway.yaml b/acceptance/tests/fixtures/bases/crds-oss/terminatinggateway.yaml similarity index 100% rename from acceptance/tests/fixtures/crds/terminatinggateway.yaml rename to acceptance/tests/fixtures/bases/crds-oss/terminatinggateway.yaml diff --git a/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml b/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml new file mode 100644 index 0000000000..75ca5cd845 --- /dev/null +++ b/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml @@ -0,0 +1,3 @@ +resources: + - ../../bases/crds-oss + - partitionexports.yaml diff --git a/acceptance/tests/fixtures/crds/partitionexports.yaml b/acceptance/tests/fixtures/cases/crds-ent/partitionexports.yaml similarity index 100% rename from acceptance/tests/fixtures/crds/partitionexports.yaml rename to acceptance/tests/fixtures/cases/crds-ent/partitionexports.yaml diff --git a/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml index 974fbd4fe1..9834f91903 100644 --- a/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-inject/kustomization.yaml @@ -1,4 +1,4 @@ -bases: +resources: - ../../bases/static-client patchesStrategicMerge: diff --git a/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml index 974fbd4fe1..9834f91903 100644 --- a/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-multi-dc/kustomization.yaml @@ -1,4 +1,4 @@ -bases: +resources: - ../../bases/static-client patchesStrategicMerge: diff --git a/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml index 4ddbaa9915..4c5d895a98 100644 --- a/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-namespaces/kustomization.yaml @@ -1,4 +1,4 @@ -bases: +resources: - ../../bases/static-client patchesStrategicMerge: diff --git a/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml index 974fbd4fe1..9834f91903 100644 --- a/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml @@ -1,4 +1,4 @@ -bases: +resources: - ../../bases/static-client patchesStrategicMerge: diff --git a/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml index 974fbd4fe1..9834f91903 100644 --- a/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-tproxy/kustomization.yaml @@ -1,4 +1,4 @@ -bases: +resources: - ../../bases/static-client patchesStrategicMerge: diff --git a/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml b/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml index a8978db882..bac892baa0 100644 --- a/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-server-inject/kustomization.yaml @@ -1,4 +1,4 @@ -bases: +resources: - ../../bases/static-server patchesStrategicMerge: From 0a6e091ebbe787a64478018c3aefe53bf4c4fb7f Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 29 Oct 2021 12:07:32 -0400 Subject: [PATCH 105/418] Support Cross Partition Networking (#807) * Add support for cross partition networking. --- .../bases/crds-oss/serviceexports.yaml | 10 + .../kustomization.yaml | 2 +- .../default-ns-default-partition/patch.yaml | 10 + .../default-ns-partition/kustomization.yaml | 5 + .../default-ns-partition}/patch.yaml | 0 .../ns-default-partition/kustomization.yaml | 5 + .../ns-default-partition/patch.yaml | 10 + .../ns-partition/kustomization.yaml | 5 + .../ns-partition/patch.yaml | 10 + .../tests/partitions/partitions_test.go | 566 +++++++++++++++++- .../templates/mesh-gateway-deployment.yaml | 7 + .../test/unit/mesh-gateway-deployment.bats | 56 ++ 12 files changed, 658 insertions(+), 28 deletions(-) create mode 100644 acceptance/tests/fixtures/bases/crds-oss/serviceexports.yaml rename acceptance/tests/fixtures/cases/{static-client-partition => static-client-partitions/default-ns-default-partition}/kustomization.yaml (59%) create mode 100644 acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/patch.yaml create mode 100644 acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/kustomization.yaml rename acceptance/tests/fixtures/cases/{static-client-partition => static-client-partitions/default-ns-partition}/patch.yaml (100%) create mode 100644 acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/kustomization.yaml create mode 100644 acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/patch.yaml create mode 100644 acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/kustomization.yaml create mode 100644 acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/patch.yaml diff --git a/acceptance/tests/fixtures/bases/crds-oss/serviceexports.yaml b/acceptance/tests/fixtures/bases/crds-oss/serviceexports.yaml new file mode 100644 index 0000000000..8ae095cd8e --- /dev/null +++ b/acceptance/tests/fixtures/bases/crds-oss/serviceexports.yaml @@ -0,0 +1,10 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceExports +metadata: + name: exports +spec: + services: + - name: frontend + namespace: frontend + consumers: + - partition: other \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/kustomization.yaml similarity index 59% rename from acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml rename to acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/kustomization.yaml index 9834f91903..7191edfb80 100644 --- a/acceptance/tests/fixtures/cases/static-client-partition/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/kustomization.yaml @@ -1,5 +1,5 @@ resources: - - ../../bases/static-client + - ../../../bases/static-client patchesStrategicMerge: - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/patch.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/patch.yaml new file mode 100644 index 0000000000..43507364f8 --- /dev/null +++ b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-default-partition/patch.yaml @@ -0,0 +1,10 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: static-client +spec: + template: + metadata: + annotations: + "consul.hashicorp.com/connect-inject": "true" + "consul.hashicorp.com/connect-service-upstreams": "static-server.default.default:1234" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/kustomization.yaml new file mode 100644 index 0000000000..7191edfb80 --- /dev/null +++ b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - ../../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partition/patch.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/patch.yaml similarity index 100% rename from acceptance/tests/fixtures/cases/static-client-partition/patch.yaml rename to acceptance/tests/fixtures/cases/static-client-partitions/default-ns-partition/patch.yaml diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/kustomization.yaml new file mode 100644 index 0000000000..7191edfb80 --- /dev/null +++ b/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - ../../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/patch.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/patch.yaml new file mode 100644 index 0000000000..2fa8ec7e27 --- /dev/null +++ b/acceptance/tests/fixtures/cases/static-client-partitions/ns-default-partition/patch.yaml @@ -0,0 +1,10 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: static-client +spec: + template: + metadata: + annotations: + "consul.hashicorp.com/connect-inject": "true" + "consul.hashicorp.com/connect-service-upstreams": "static-server.ns1.default:1234" \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/kustomization.yaml new file mode 100644 index 0000000000..7191edfb80 --- /dev/null +++ b/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - ../../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/patch.yaml b/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/patch.yaml new file mode 100644 index 0000000000..f0ceb634bd --- /dev/null +++ b/acceptance/tests/fixtures/cases/static-client-partitions/ns-partition/patch.yaml @@ -0,0 +1,10 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: static-client +spec: + template: + metadata: + annotations: + "consul.hashicorp.com/connect-inject": "true" + "consul.hashicorp.com/connect-service-upstreams": "static-server.ns1.secondary:1234" \ No newline at end of file diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 0e48ddaa4d..96dc80d96e 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -25,7 +25,7 @@ const staticClientNamespace = "ns2" // Test that Connect works in a default installation. // i.e. without ACLs because TLS is required for setting up Admin Partitions. -func TestPartitions(t *testing.T) { +func TestPartitionsWithoutMesh(t *testing.T) { env := suite.Environment() cfg := suite.Config() @@ -41,6 +41,9 @@ func TestPartitions(t *testing.T) { t.Skipf("skipping this test because -enable-transparent-proxy is true") } + const defaultPartition = "default" + const secondaryPartition = "secondary" + const defaultNamespace = "default" cases := []struct { name string destinationNamespace string @@ -49,13 +52,13 @@ func TestPartitions(t *testing.T) { }{ { "default namespace", - "default", + defaultNamespace, false, false, }, { "default namespace; secure", - "default", + defaultNamespace, false, true, }, @@ -159,9 +162,9 @@ func TestPartitions(t *testing.T) { var partitionSvcIP string if !cfg.UseKind { // Get the IP of the partition service to configure the external server address in the values file for the workload cluster. - partitionServiceName := fmt.Sprintf("%s-partition-secret", releaseName) + partitionSecretName := fmt.Sprintf("%s-partition-secret", releaseName) logger.Logf(t, "retrieving partition service to determine external IP for servers") - partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionServiceName, metav1.GetOptions{}) + partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionSecretName, metav1.GetOptions{}) require.NoError(t, err) partitionSvcIP = partitionsSvc.Status.LoadBalancer.Ingress[0].IP } else { @@ -171,11 +174,14 @@ func TestPartitions(t *testing.T) { partitionSvcIP = nodeList.Items[0].Status.Addresses[0].Address } - // The Kubernetes AuthMethod IP for Kind is read from the endpoint for the Kubernetes service. On other clouds, - // this can be identified by reading the cluster config. - kubernetesEndpoint, err := clientClusterContext.KubernetesClient(t).CoreV1().Endpoints("default").Get(ctx, "kubernetes", metav1.GetOptions{}) - require.NoError(t, err) - k8sAuthMethodHost := fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) + var k8sAuthMethodHost string + if cfg.UseKind { + // The Kubernetes AuthMethod IP for Kind is read from the endpoint for the Kubernetes service. On other clouds, + // this can be identified by reading the cluster config. + kubernetesEndpoint, err := clientClusterContext.KubernetesClient(t).CoreV1().Endpoints(defaultNamespace).Get(ctx, "kubernetes", metav1.GetOptions{}) + require.NoError(t, err) + k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) + } // Create client cluster. clientHelmValues := map[string]string{ @@ -198,16 +204,15 @@ func TestPartitions(t *testing.T) { "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), "global.adminPartitions.enabled": "true", - "global.adminPartitions.name": "secondary", + "global.adminPartitions.name": secondaryPartition, "global.enableConsulNamespaces": "true", "global.tls.caCert.secretName": tlsCert, "global.tls.caCert.secretKey": "tls.crt", - "externalServers.enabled": "true", - "externalServers.hosts[0]": partitionSvcIP, - "externalServers.tlsServerName": "server.dc1.consul", - "externalServers.k8sAuthMethodHost": k8sAuthMethodHost, + "externalServers.enabled": "true", + "externalServers.hosts[0]": partitionSvcIP, + "externalServers.tlsServerName": "server.dc1.consul", "client.enabled": "true", "client.exposeGossipPorts": "true", @@ -218,6 +223,7 @@ func TestPartitions(t *testing.T) { // setup partition token if ACLs enabled. clientHelmValues["global.acls.bootstrapToken.secretName"] = partitionToken clientHelmValues["global.acls.bootstrapToken.secretKey"] = "token" + clientHelmValues["externalServers.k8sAuthMethodHost"] = k8sAuthMethodHost } else { // provide CA key when auto-encrypt is disabled. clientHelmValues["global.tls.caKey.secretName"] = tlsKey @@ -289,17 +295,17 @@ func TestPartitions(t *testing.T) { consulClient := serverConsulCluster.SetupConsulClient(t, c.secure) - serverQueryServerOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: "default"} - clientQueryServerOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: "default"} + serverQueryServerOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: defaultPartition} + clientQueryServerOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: defaultPartition} - serverQueryClientOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: "secondary"} - clientQueryClientOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: "secondary"} + serverQueryClientOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: secondaryPartition} + clientQueryClientOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: secondaryPartition} if !c.mirrorK8S { - serverQueryServerOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: "default"} - clientQueryServerOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: "default"} - serverQueryClientOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: "secondary"} - clientQueryClientOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: "secondary"} + serverQueryServerOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: defaultPartition} + clientQueryServerOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: defaultPartition} + serverQueryClientOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: secondaryPartition} + clientQueryClientOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: secondaryPartition} } // Check that the ACL token is deleted. @@ -339,14 +345,14 @@ func TestPartitions(t *testing.T) { logger.Log(t, "creating static-server and static-client deployments in server cluster") k8s.DeployKustomize(t, serverClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if c.destinationNamespace == "default" { + if c.destinationNamespace == defaultNamespace { k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") } else { k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") } logger.Log(t, "creating static-server and static-client deployments in client cluster") k8s.DeployKustomize(t, clientClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if c.destinationNamespace == "default" { + if c.destinationNamespace == defaultNamespace { k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") } else { k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") @@ -416,9 +422,515 @@ func TestPartitions(t *testing.T) { } logger.Log(t, "creating intention") - _, err := consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: "default"}) + _, err := consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: defaultPartition}) + require.NoError(t, err) + _, err = consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: secondaryPartition}) + require.NoError(t, err) + } + + logger.Log(t, "checking that connection is successful") + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") + + // Test that kubernetes readiness status is synced to Consul. + // Create the file so that the readiness probe of the static-server pod fails. + logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") + k8s.RunKubectl(t, serverClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, clientClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + + // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry + // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. + // We are expecting a "connection reset by peer" error because in a case of health checks, + // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply + // from server, which is the case when a connection is unsuccessful due to intentions in other tests. + logger.Log(t, "checking that connection is unsuccessful") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + }) + } +} + +// Test that Connect works in a default installation using mesh gateways for X-Partition networking. +func TestPartitionsWithMesh(t *testing.T) { + env := suite.Environment() + cfg := suite.Config() + + if !cfg.EnableEnterprise { + t.Skipf("skipping this test because -enable-enterprise is not set") + } + + if !cfg.UseKind { + t.Skipf("skipping this test because Admin Partition tests are only supported in Kind for now") + } + + if cfg.EnableTransparentProxy { + t.Skipf("skipping this test because -enable-transparent-proxy is true") + } + + const defaultPartition = "default" + const secondaryPartition = "secondary" + const defaultNamespace = "default" + cases := []struct { + name string + destinationNamespace string + mirrorK8S bool + secure bool + }{ + { + "default namespace", + defaultNamespace, + false, + false, + }, + { + "default namespace; secure", + defaultNamespace, + false, + true, + }, + { + "single destination namespace", + staticServerNamespace, + false, + false, + }, + { + "single destination namespace; secure", + staticServerNamespace, + false, + true, + }, + { + "mirror k8s namespaces", + staticServerNamespace, + true, + false, + }, + { + "mirror k8s namespaces; secure", + staticServerNamespace, + true, + true, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + serverClusterContext := env.DefaultContext(t) + clientClusterContext := env.Context(t, environment.SecondaryContextName) + + ctx := context.Background() + + serverHelmValues := map[string]string{ + "global.datacenter": "dc1", + "global.image": "ashwinvenkatesh/consul@sha256:e321bd719da2c2284c358846163d2b48e8fc27822ae5caba4b22c397c6e09356", + "global.imageK8S": "ashwinvenkatesh/consul-k8s@sha256:e777b8f2dab5ffc10e08febc16ccf4403c4feb62465c5bdc1ac6855a6b995acb", + + "global.adminPartitions.enabled": "true", + "global.enableConsulNamespaces": "true", + "global.tls.enabled": "true", + "global.tls.httpsOnly": strconv.FormatBool(c.secure), + "global.tls.enableAutoEncrypt": strconv.FormatBool(c.secure), + + "server.exposeGossipAndRPCPorts": "true", + + "connectInject.enabled": "true", + // When mirroringK8S is set, this setting is ignored. + "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, + "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.mirrorK8S), + "connectInject.transparentProxy.defaultEnabled": "false", + + "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), + + "meshGateway.enabled": "true", + "meshGateway.replicas": "1", + + "controller.enabled": "true", + } + + if cfg.UseKind { + serverHelmValues["global.adminPartitions.service.type"] = "NodePort" + serverHelmValues["global.adminPartitions.service.nodePort.https"] = "30000" + serverHelmValues["meshGateway.service.type"] = "NodePort" + serverHelmValues["meshGateway.service.nodePort"] = "30100" + } + + releaseName := helpers.RandomName() + + // Install the consul cluster with servers in the default kubernetes context. + serverConsulCluster := consul.NewHelmCluster(t, serverHelmValues, serverClusterContext, cfg, releaseName) + serverConsulCluster.Create(t) + + // Get the TLS CA certificate and key secret from the server cluster and apply it to client cluster. + tlsCert := fmt.Sprintf("%s-consul-ca-cert", releaseName) + tlsKey := fmt.Sprintf("%s-consul-ca-key", releaseName) + + logger.Logf(t, "retrieving ca cert secret %s from the server cluster and applying to the client cluster", tlsCert) + caCertSecret, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, tlsCert, metav1.GetOptions{}) + caCertSecret.ResourceVersion = "" + require.NoError(t, err) + _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, caCertSecret, metav1.CreateOptions{}) + require.NoError(t, err) + + if !c.secure { + // When running in the insecure mode, auto-encrypt is disabled which requires both + // the CA cert and CA key to be available in the clients cluster. + logger.Logf(t, "retrieving ca key secret %s from the server cluster and applying to the client cluster", tlsKey) + caKeySecret, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, tlsKey, metav1.GetOptions{}) + caKeySecret.ResourceVersion = "" + require.NoError(t, err) + _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, caKeySecret, metav1.CreateOptions{}) + require.NoError(t, err) + } + + partitionToken := fmt.Sprintf("%s-consul-partitions-acl-token", releaseName) + if c.secure { + logger.Logf(t, "retrieving partition token secret %s from the server cluster and applying to the client cluster", tlsKey) + token, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionToken, metav1.GetOptions{}) + token.ResourceVersion = "" + require.NoError(t, err) + _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, token, metav1.CreateOptions{}) + require.NoError(t, err) + } + + var partitionSvcIP string + if !cfg.UseKind { + // Get the IP of the partition service to configure the external server address in the values file for the workload cluster. + partitionSecretName := fmt.Sprintf("%s-partition-secret", releaseName) + logger.Logf(t, "retrieving partition service to determine external IP for servers") + partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionSecretName, metav1.GetOptions{}) + require.NoError(t, err) + partitionSvcIP = partitionsSvc.Status.LoadBalancer.Ingress[0].IP + } else { + nodeList, err := serverClusterContext.KubernetesClient(t).CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + // Get the address of the (only) node from the Kind cluster. + partitionSvcIP = nodeList.Items[0].Status.Addresses[0].Address + } + + var k8sAuthMethodHost string + if cfg.UseKind { + // The Kubernetes AuthMethod IP for Kind is read from the endpoint for the Kubernetes service. On other clouds, + // this can be identified by reading the cluster config. + kubernetesEndpoint, err := clientClusterContext.KubernetesClient(t).CoreV1().Endpoints(defaultNamespace).Get(ctx, "kubernetes", metav1.GetOptions{}) + require.NoError(t, err) + k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) + } + + // Create client cluster. + clientHelmValues := map[string]string{ + "global.datacenter": "dc1", + "global.image": "ashwinvenkatesh/consul@sha256:e321bd719da2c2284c358846163d2b48e8fc27822ae5caba4b22c397c6e09356", + "global.imageK8S": "ashwinvenkatesh/consul-k8s@sha256:e777b8f2dab5ffc10e08febc16ccf4403c4feb62465c5bdc1ac6855a6b995acb", + "global.enabled": "false", + + "global.tls.enabled": "true", + "global.tls.httpsOnly": strconv.FormatBool(c.secure), + "global.tls.enableAutoEncrypt": strconv.FormatBool(c.secure), + + "server.exposeGossipAndRPCPorts": "true", + + "connectInject.enabled": "true", + // When mirroringK8S is set, this setting is ignored. + "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, + "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.mirrorK8S), + "connectInject.transparentProxy.defaultEnabled": "false", + + "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), + + "global.adminPartitions.enabled": "true", + "global.adminPartitions.name": secondaryPartition, + "global.enableConsulNamespaces": "true", + + "meshGateway.enabled": "true", + "meshGateway.replicas": "1", + + "controller.enabled": "true", + + "global.tls.caCert.secretName": tlsCert, + "global.tls.caCert.secretKey": "tls.crt", + + "externalServers.enabled": "true", + "externalServers.hosts[0]": partitionSvcIP, + "externalServers.tlsServerName": "server.dc1.consul", + + "client.enabled": "true", + "client.exposeGossipPorts": "true", + "client.join[0]": partitionSvcIP, + } + + if c.secure { + // setup partition token if ACLs enabled. + clientHelmValues["global.acls.bootstrapToken.secretName"] = partitionToken + clientHelmValues["global.acls.bootstrapToken.secretKey"] = "token" + clientHelmValues["externalServers.k8sAuthMethodHost"] = k8sAuthMethodHost + } else { + // provide CA key when auto-encrypt is disabled. + clientHelmValues["global.tls.caKey.secretName"] = tlsKey + clientHelmValues["global.tls.caKey.secretKey"] = "tls.key" + } + + if cfg.UseKind { + clientHelmValues["externalServers.httpsPort"] = "30000" + clientHelmValues["meshGateway.service.type"] = "NodePort" + clientHelmValues["meshGateway.service.nodePort"] = "30100" + } + + // Install the consul cluster without servers in the client cluster kubernetes context. + clientConsulCluster := consul.NewHelmCluster(t, clientHelmValues, clientClusterContext, cfg, releaseName) + clientConsulCluster.Create(t) + + // Ensure consul client are created. + agentPodList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(clientClusterContext.KubectlOptions(t).Namespace).List(ctx, metav1.ListOptions{LabelSelector: "app=consul,component=client"}) + require.NoError(t, err) + require.Len(t, agentPodList.Items, 1) + + output, err := k8s.RunKubectlAndGetOutputE(t, clientClusterContext.KubectlOptions(t), "logs", agentPodList.Items[0].Name, "-n", clientClusterContext.KubectlOptions(t).Namespace) + require.NoError(t, err) + require.Contains(t, output, "Partition: 'secondary'") + + serverClusterStaticServerOpts := &terratestk8s.KubectlOptions{ + ContextName: serverClusterContext.KubectlOptions(t).ContextName, + ConfigPath: serverClusterContext.KubectlOptions(t).ConfigPath, + Namespace: staticServerNamespace, + } + serverClusterStaticClientOpts := &terratestk8s.KubectlOptions{ + ContextName: serverClusterContext.KubectlOptions(t).ContextName, + ConfigPath: serverClusterContext.KubectlOptions(t).ConfigPath, + Namespace: staticClientNamespace, + } + clientClusterStaticServerOpts := &terratestk8s.KubectlOptions{ + ContextName: clientClusterContext.KubectlOptions(t).ContextName, + ConfigPath: clientClusterContext.KubectlOptions(t).ConfigPath, + Namespace: staticServerNamespace, + } + clientClusterStaticClientOpts := &terratestk8s.KubectlOptions{ + ContextName: clientClusterContext.KubectlOptions(t).ContextName, + ConfigPath: clientClusterContext.KubectlOptions(t).ConfigPath, + Namespace: staticClientNamespace, + } + + logger.Logf(t, "creating namespaces %s and %s in servers cluster", staticServerNamespace, staticClientNamespace) + k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) + k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "create", "ns", staticClientNamespace) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace, staticClientNamespace) + }) + + logger.Logf(t, "creating namespaces %s and %s in clients cluster", staticServerNamespace, staticClientNamespace) + k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) + k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "create", "ns", staticClientNamespace) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace, staticClientNamespace) + }) + + consulClient := serverConsulCluster.SetupConsulClient(t, c.secure) + + serverQueryServerOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: defaultPartition} + clientQueryServerOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: defaultPartition} + + serverQueryClientOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: secondaryPartition} + clientQueryClientOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: secondaryPartition} + + if !c.mirrorK8S { + serverQueryServerOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: defaultPartition} + clientQueryServerOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: defaultPartition} + serverQueryClientOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: secondaryPartition} + clientQueryClientOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: secondaryPartition} + } + + // Check that the ACL token is deleted. + if c.secure { + // We need to register the cleanup function before we create the deployments + // because golang will execute them in reverse order i.e. the last registered + // cleanup function will be executed first. + t.Cleanup(func() { + if c.secure { + retry.Run(t, func(r *retry.R) { + tokens, _, err := consulClient.ACL().TokenList(serverQueryServerOpts) + require.NoError(r, err) + for _, token := range tokens { + require.NotContains(r, token.Description, staticServerName) + } + + tokens, _, err = consulClient.ACL().TokenList(clientQueryServerOpts) + require.NoError(r, err) + for _, token := range tokens { + require.NotContains(r, token.Description, staticClientName) + } + tokens, _, err = consulClient.ACL().TokenList(serverQueryClientOpts) + require.NoError(r, err) + for _, token := range tokens { + require.NotContains(r, token.Description, staticServerName) + } + + tokens, _, err = consulClient.ACL().TokenList(clientQueryClientOpts) + require.NoError(r, err) + for _, token := range tokens { + require.NotContains(r, token.Description, staticClientName) + } + }) + } + }) + } + + // Create a ProxyDefaults resource to configure services to use the mesh + // gateways. + logger.Log(t, "creating proxy-defaults config") + kustomizeDir := "../fixtures/bases/mesh-gateway" + + k8s.KubectlApplyK(t, serverClusterContext.KubectlOptions(t), kustomizeDir) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.KubectlDeleteK(t, serverClusterContext.KubectlOptions(t), kustomizeDir) + }) + + k8s.KubectlApplyK(t, clientClusterContext.KubectlOptions(t), kustomizeDir) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.KubectlDeleteK(t, clientClusterContext.KubectlOptions(t), kustomizeDir) + }) + + logger.Log(t, "creating static-server and static-client deployments in server cluster") + k8s.DeployKustomize(t, serverClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if c.destinationNamespace == defaultNamespace { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-partition") + } else { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-partition") + } + logger.Log(t, "creating static-server and static-client deployments in client cluster") + k8s.DeployKustomize(t, clientClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if c.destinationNamespace == defaultNamespace { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-default-partition") + } else { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-default-partition") + } + // Check that both static-server and static-client have been injected and now have 2 containers in server cluster. + for _, labelSelector := range []string{"app=static-server", "app=static-client"} { + podList, err := serverClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 2) + } + + // Check that both static-server and static-client have been injected and now have 2 containers in client cluster. + for _, labelSelector := range []string{"app=static-server", "app=static-client"} { + podList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 2) + } + + // Make sure that services are registered in the correct namespace. + // If mirroring is enabled, we expect services to be registered in the + // Consul namespace with the same name as their source + // Kubernetes namespace. + // If a single destination namespace is set, we expect all services + // to be registered in that destination Consul namespace. + // Server cluster. + // We are going to test that static-clients deployed in each partition can + // access the static-servers running in another partition. + // ie default -> secondary and secondary -> default. + services, _, err := consulClient.Catalog().Service(staticServerName, "", serverQueryServerOpts) + require.NoError(t, err) + require.Len(t, services, 1) + + services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryServerOpts) + require.NoError(t, err) + require.Len(t, services, 1) + + // Client cluster. + services, _, err = consulClient.Catalog().Service(staticServerName, "", serverQueryClientOpts) + require.NoError(t, err) + require.Len(t, services, 1) + + services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryClientOpts) + require.NoError(t, err) + require.Len(t, services, 1) + + defaultPartitionExports := &api.PartitionExportsConfigEntry{ + Name: defaultPartition, + Services: []api.ExportedService{ + { + Name: "mesh-gateway", + Namespace: defaultNamespace, + Consumers: []api.ServiceConsumer{ + {Partition: secondaryPartition}, + }, + }, + { + Name: staticServerName, + Namespace: staticServerNamespace, + Consumers: []api.ServiceConsumer{ + {Partition: secondaryPartition}, + }, + }, + }, + } + secondaryPartitionExports := &api.PartitionExportsConfigEntry{ + Name: secondaryPartition, + Services: []api.ExportedService{ + { + Name: "mesh-gateway", + Namespace: defaultNamespace, + Consumers: []api.ServiceConsumer{ + {Partition: defaultPartition}, + }, + }, + { + Name: staticServerName, + Namespace: staticServerNamespace, + Consumers: []api.ServiceConsumer{ + {Partition: defaultPartition}, + }, + }, + }, + } + + if !c.mirrorK8S { + defaultPartitionExports.Services[1].Namespace = c.destinationNamespace + secondaryPartitionExports.Services[1].Namespace = c.destinationNamespace + } + + logger.Log(t, "creating partition exports") + _, _, err = consulClient.ConfigEntries().Set(defaultPartitionExports, &api.WriteOptions{Partition: defaultPartition}) + require.NoError(t, err) + _, _, err = consulClient.ConfigEntries().Set(secondaryPartitionExports, &api.WriteOptions{Partition: secondaryPartition}) + require.NoError(t, err) + + if c.secure { + logger.Log(t, "checking that the connection is not successful because there's no intention") + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") + + intention := &api.ServiceIntentionsConfigEntry{ + Name: staticServerName, + Kind: api.ServiceIntentions, + Namespace: staticServerNamespace, + Sources: []*api.SourceIntention{ + { + Name: staticClientName, + Namespace: staticClientNamespace, + Action: api.IntentionActionAllow, + }, + }, + } + + // Set the destination namespace to be the same + // unless mirrorK8S is true. + if !c.mirrorK8S { + intention.Namespace = c.destinationNamespace + intention.Sources[0].Namespace = c.destinationNamespace + } + + logger.Log(t, "creating intention") + intention.Sources[0].Partition = secondaryPartition + _, _, err := consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: defaultPartition}) require.NoError(t, err) - _, err = consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: "secondary"}) + intention.Sources[0].Partition = defaultPartition + _, _, err = consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: secondaryPartition}) require.NoError(t, err) } diff --git a/charts/consul/templates/mesh-gateway-deployment.yaml b/charts/consul/templates/mesh-gateway-deployment.yaml index 4d87baf678..a66242e2c8 100644 --- a/charts/consul/templates/mesh-gateway-deployment.yaml +++ b/charts/consul/templates/mesh-gateway-deployment.yaml @@ -7,6 +7,7 @@ {{- if .Values.global.lifecycleSidecarContainer }}{{ fail "global.lifecycleSidecarContainer has been renamed to global.consulSidecarContainer. Please set values using global.consulSidecarContainer." }}{{ end }} {{- /* The below test checks if clients are disabled (and if so, fails). We use the conditional from other client files and prepend 'not' */ -}} {{- if not (or (and (ne (.Values.client.enabled | toString) "-") .Values.client.enabled) (and (eq (.Values.client.enabled | toString) "-") .Values.global.enabled)) }}{{ fail "clients must be enabled" }}{{ end -}} +{{- if and .Values.global.adminPartitions.enabled (not .Values.global.enableConsulNamespaces) }}{{ fail "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" }}{{ end }} apiVersion: apps/v1 kind: Deployment metadata: @@ -185,6 +186,9 @@ spec: {{- end }} port = {{ .Values.meshGateway.containerPort }} address = "${POD_IP}" + {{- if .Values.global.adminPartitions.enabled }} + partition = "{{ .Values.global.adminPartitions.name }}" + {{- end }} tagged_addresses { lan { address = "${POD_IP}" @@ -291,6 +295,9 @@ spec: - connect - envoy - -mesh-gateway + {{- if .Values.global.adminPartitions.enabled }} + - -partition={{ .Values.global.adminPartitions.name }} + {{- end }} livenessProbe: tcpSocket: port: {{ .Values.meshGateway.containerPort }} diff --git a/charts/consul/test/unit/mesh-gateway-deployment.bats b/charts/consul/test/unit/mesh-gateway-deployment.bats index aab58a8413..f1af2fc2b2 100755 --- a/charts/consul/test/unit/mesh-gateway-deployment.bats +++ b/charts/consul/test/unit/mesh-gateway-deployment.bats @@ -1475,3 +1475,59 @@ EOF [ "$status" -eq 1 ] [[ "$output" =~ "meshGateway.globalMode is no longer supported; instead, you must migrate to CRDs (see www.consul.io/docs/k8s/crds/upgrade-to-crds)" ]] } + +#-------------------------------------------------------------------- +# partitions + +@test "meshGateway/Deployment: partitions options disabled by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | any(contains("partition"))' | tee /dev/stderr) + + [ "${actual}" = "false" ] +} + +@test "meshGateway/Deployment: partition name set on initContainer with .global.adminPartitions.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[1].command | any(contains("partition = \"default\""))' | tee /dev/stderr) + + [ "${actual}" = "true" ] +} + +@test "meshGateway/Deployment: partition name set on container with .global.adminPartitions.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enableConsulNamespaces=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | any(contains("partition=default"))' | tee /dev/stderr) + + [ "${actual}" = "true" ] +} + +@test "meshGateway/Deployment: fails if namespaces are disabled and .global.adminPartitions.enabled=true" { + cd `chart_dir` + run helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.enableConsulNamespaces=false' \ + --set 'meshGateway.enabled=true' . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" ]] +} \ No newline at end of file From 0a364e0f6b5c80c72becfe097c7ab89d0e7fa0f5 Mon Sep 17 00:00:00 2001 From: David Yu Date: Fri, 29 Oct 2021 10:05:00 -0700 Subject: [PATCH 106/418] README: artifacthub readme update (#817) * README: artifactory readme update * README: update with consul-k8s-control-plane reference * Update README.md Co-authored-by: Iryna Shustava * Update README.md Co-authored-by: Iryna Shustava --- README.md | 8 +++++--- charts/consul/README.md | 14 ++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 719c5d51dc..f8ef63ea9f 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,9 @@ by contacting us at [security@hashicorp.com](mailto:security@hashicorp.com). automatically configure the Consul and Kubernetes integration to run within an existing Kubernetes cluster. - * A [Docker image `hashicorp/consul-k8s`](https://hub.docker.com/r/hashicorp/consul-k8s) is available. This can be used to manually run `consul-k8s` within a scheduled environment. + * A [Docker image `hashicorp/consul-k8s-control-plane`](https://hub.docker.com/r/hashicorp/consul-k8s-control-plane) is available. This can be used to manually run `consul-k8s-control-plane` within a scheduled environment. + + * Consul K8s CLI, distributed as `consul-k8s`, can be used to install and uninstall Consul Kubernetes. See the [Consul K8s CLI Reference](https://www.consul.io/docs/k8s/k8s-cli) for more details on usage. * Raw binaries are available in the [HashiCorp releases directory](https://releases.hashicorp.com/consul-k8s/). These can be used to run `consul-k8s` directly or build custom packages. @@ -72,8 +74,8 @@ Detailed installation instructions for Consul on Kubernetes are found [here](htt helm repo add hashicorp https://helm.releases.hashicorp.com ``` -2. Ensure you have access to the Consul Helm chart and you see the latest chart version listed. Otherwise run `helm repo update` if you have - previously added the HashiCorp Helm repository. +2. Ensure you have access to the Consul Helm chart and you see the latest chart version listed. If you have previously added the + HashiCorp Helm repository, run `helm repo update`. ``` bash helm search repo hashicorp/consul diff --git a/charts/consul/README.md b/charts/consul/README.md index 12e8aff1fb..d5e0eef355 100644 --- a/charts/consul/README.md +++ b/charts/consul/README.md @@ -26,8 +26,8 @@ by contacting us at [security@hashicorp.com](mailto:security@hashicorp.com). non-Kubernetes nodes to easily discover and access Kubernetes services. ### Prerequisites - * **Helm 3.0+** (Helm 2 is not supported) - * **Kubernetes 1.17+** - This is the earliest version of Kubernetes tested. + * **Helm 3.2+** (Helm 2 is not supported) + * **Kubernetes 1.18+** - This is the earliest version of Kubernetes tested. It is possible that this chart works with earlier versions but it is untested. @@ -40,15 +40,17 @@ Detailed installation instructions for Consul on Kubernetes are found [here](htt $ helm repo add hashicorp https://helm.releases.hashicorp.com "hashicorp" has been added to your repositories -2. Ensure you have access to the consul chart: +2. Ensure you have access to the Consul Helm chart and you see the latest chart version listed. + If you have previously added the HashiCorp Helm repository, run `helm repo update`. $ helm search repo hashicorp/consul NAME CHART VERSION APP VERSION DESCRIPTION - hashicorp/consul x.xx.x x.xx.x Official HashiCorp Consul Chart + hashicorp/consul 0.35.0 1.10.3 Official HashiCorp Consul Chart -3. Now you're ready to install Consul! To install Consul with the default configuration using Helm 3 run: +3. Now you're ready to install Consul! To install Consul with the default configuration using Helm 3.2 run the following command below. + This will create a `consul` Kubernetes namespace if not already present, and install Consul on the dedicated namespace. - $ helm install consul hashicorp/consul --set global.name=consul + $ helm install consul hashicorp/consul --set global.name=consul --create-namespace -n consul NAME: consul Please see the many options supported in the `values.yaml` From 28a637d2f129c9c1fdbe636bb3080852cd41eab6 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Fri, 29 Oct 2021 15:07:25 -0400 Subject: [PATCH 107/418] Remove acl: "write" from controller policy (#822) --- control-plane/subcommand/server-acl-init/rules.go | 1 - control-plane/subcommand/server-acl-init/rules_test.go | 3 --- 2 files changed, 4 deletions(-) diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index c6f5cdf29c..4598281306 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -335,7 +335,6 @@ func (c *Command) controllerRules() (string, error) { {{- if .EnablePartitions }} partition "{{ .PartitionName }}" { mesh = "write" - acl = "write" {{- else }} operator = "write" {{- end }} diff --git a/control-plane/subcommand/server-acl-init/rules_test.go b/control-plane/subcommand/server-acl-init/rules_test.go index 9914f23585..e7c996545d 100644 --- a/control-plane/subcommand/server-acl-init/rules_test.go +++ b/control-plane/subcommand/server-acl-init/rules_test.go @@ -827,7 +827,6 @@ func TestControllerRules(t *testing.T) { Expected: ` partition "part-1" { mesh = "write" - acl = "write" namespace "consul" { policy = "write" service_prefix "" { @@ -846,7 +845,6 @@ partition "part-1" { Expected: ` partition "part-1" { mesh = "write" - acl = "write" namespace_prefix "" { policy = "write" service_prefix "" { @@ -866,7 +864,6 @@ partition "part-1" { Expected: ` partition "part-1" { mesh = "write" - acl = "write" namespace_prefix "prefix-" { policy = "write" service_prefix "" { From 23f366927f2c4544f3e4ebfb0be4c747495c7767 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Fri, 29 Oct 2021 18:38:05 -0400 Subject: [PATCH 108/418] When set_dev_mode is called, also set for CLI (#823) * When set_dev_mode is called, also set for CLI * Commit the CLI version.go as well --- control-plane/build-support/functions/10-util.sh | 9 +++++++-- control-plane/build-support/scripts/dev.sh | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/control-plane/build-support/functions/10-util.sh b/control-plane/build-support/functions/10-util.sh index 1fb2f45b3a..a39b2307e7 100644 --- a/control-plane/build-support/functions/10-util.sh +++ b/control-plane/build-support/functions/10-util.sh @@ -795,9 +795,14 @@ function set_dev_mode { local sdir="$1" local vers="$(parse_version "${sdir}" false false)" - status_stage "==> Setting VersionPreRelease back to 'dev'" + status_stage "==> Setting VersionPreRelease back to 'dev' for Control Plane" update_version "${sdir}/version/version.go" "${vers}" dev || return 1 + # This function has been modified for Consul-K8s monorepo. It now sets dev mode + # for the CLI module as well. + status_stage "==> Setting VersionPreRelease back to 'dev' for CLI" + update_version "${sdir}/../cli/version/version.go" "${vers}" dev || return 1 + status_stage "==> Adding new UNRELEASED label in CHANGELOG.md" add_unreleased_to_changelog "${sdir}/.." || return 1 @@ -857,7 +862,7 @@ function commit_dev_mode { pushd "$1" > /dev/null status "Staging CHANGELOG.md and version_*.go files" - git add CHANGELOG.md && git add control-plane/version/version*.go + git add CHANGELOG.md && git add */version/version*.go ret=$? if test ${ret} -eq 0 diff --git a/control-plane/build-support/scripts/dev.sh b/control-plane/build-support/scripts/dev.sh index a128698193..7cb79d01e1 100755 --- a/control-plane/build-support/scripts/dev.sh +++ b/control-plane/build-support/scripts/dev.sh @@ -84,6 +84,7 @@ function main { esac done + # Set dev mode for both CLI and Control Plane modules set_dev_mode "${sdir}" || return 1 @@ -91,6 +92,7 @@ function main { then status_stage "==> Commiting Dev Mode Changes" # Currently ${sdir} is consul-k8s/control-plane, but for git functions we should be in top-level, so we pass in "${sdir}/..". + # This will commit `version.go` for both CLI and Control Plane modules as well as the CHANGELOG.md. commit_dev_mode "${sdir}/.." || return 1 if is_set "${do_push}" From 438b14dccd477eab27a6b49e2965eff9f7de7110 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Mon, 1 Nov 2021 16:33:21 -0400 Subject: [PATCH 109/418] Controller acls reenabled (#824) * Revert "Remove acl: "write" from controller policy (#822)" This reverts commit 28a637d2f129c9c1fdbe636bb3080852cd41eab6. * Update accetance test with consul-k8s image * Update ACL policies for sync and controller --- .../tests/controller/controller_namespaces_test.go | 2 +- acceptance/tests/partitions/partitions_test.go | 8 ++++---- control-plane/subcommand/server-acl-init/rules.go | 9 +++++++++ .../subcommand/server-acl-init/rules_test.go | 13 +++++++++++++ 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go index fe07dbbbf4..1b6bde2e26 100644 --- a/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -74,7 +74,7 @@ func TestControllerNamespaces(t *testing.T) { ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ - "global.image": "ashwinvenkatesh/consul@sha256:7426f47fa7065e38a2488042be66325aa37cda17a3bc15e58178104ff4619c1b", + "global.image": "ashwinvenkatesh/consul@sha256:70c8ba1c8c7c092e34473f4d45f08f148bf52f372bce830babfdd7dbfc1ce5d4", "global.enableConsulNamespaces": "true", "global.adminPartitions.enabled": "true", diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 96dc80d96e..b60ed8c4db 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -97,7 +97,7 @@ func TestPartitionsWithoutMesh(t *testing.T) { serverHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta1", + "global.image": "ashwinvenkatesh/consul@sha256:70c8ba1c8c7c092e34473f4d45f08f148bf52f372bce830babfdd7dbfc1ce5d4", "global.adminPartitions.enabled": "true", "global.enableConsulNamespaces": "true", @@ -186,7 +186,7 @@ func TestPartitionsWithoutMesh(t *testing.T) { // Create client cluster. clientHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta1", + "global.image": "ashwinvenkatesh/consul@sha256:70c8ba1c8c7c092e34473f4d45f08f148bf52f372bce830babfdd7dbfc1ce5d4", "global.enabled": "false", "global.tls.enabled": "true", @@ -523,7 +523,7 @@ func TestPartitionsWithMesh(t *testing.T) { serverHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "ashwinvenkatesh/consul@sha256:e321bd719da2c2284c358846163d2b48e8fc27822ae5caba4b22c397c6e09356", + "global.image": "ashwinvenkatesh/consul@sha256:70c8ba1c8c7c092e34473f4d45f08f148bf52f372bce830babfdd7dbfc1ce5d4", "global.imageK8S": "ashwinvenkatesh/consul-k8s@sha256:e777b8f2dab5ffc10e08febc16ccf4403c4feb62465c5bdc1ac6855a6b995acb", "global.adminPartitions.enabled": "true", @@ -620,7 +620,7 @@ func TestPartitionsWithMesh(t *testing.T) { // Create client cluster. clientHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "ashwinvenkatesh/consul@sha256:e321bd719da2c2284c358846163d2b48e8fc27822ae5caba4b22c397c6e09356", + "global.image": "ashwinvenkatesh/consul@sha256:70c8ba1c8c7c092e34473f4d45f08f148bf52f372bce830babfdd7dbfc1ce5d4", "global.imageK8S": "ashwinvenkatesh/consul-k8s@sha256:e777b8f2dab5ffc10e08febc16ccf4403c4feb62465c5bdc1ac6855a6b995acb", "global.enabled": "false", diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index 4598281306..1ab5076db3 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -229,6 +229,9 @@ partition "{{ .PartitionName }}" { return c.renderGatewayRules(terminatingGatewayRulesTpl, name, namespace) } +// acl = "write" is required when creating namespace with a default policy. +// Attaching a default ACL policy to a namespace requires acl = "write" in the +// namespace that the policy is defined in, which in our case is "default". func (c *Command) syncRules() (string, error) { syncRulesTpl := ` node "{{ .SyncConsulNodeName }}" { @@ -236,6 +239,7 @@ func (c *Command) syncRules() (string, error) { } {{- if .EnableNamespaces }} operator = "write" +acl = "write" {{- if .SyncEnableNSMirroring }} namespace_prefix "{{ .SyncNSMirroringPrefix }}" { {{- else }} @@ -330,13 +334,18 @@ partition "default" { } // policy = "write" is required when creating namespaces within a partition. +// acl = "write" is required when creating namespace with a default policy. +// Attaching a default ACL policy to a namespace requires acl = "write" in the +// namespace that the policy is defined in, which in our case is "default". func (c *Command) controllerRules() (string, error) { controllerRules := ` {{- if .EnablePartitions }} partition "{{ .PartitionName }}" { mesh = "write" + acl = "write" {{- else }} operator = "write" + acl = "write" {{- end }} {{- if .EnableNamespaces }} {{- if .InjectEnableNSMirroring }} diff --git a/control-plane/subcommand/server-acl-init/rules_test.go b/control-plane/subcommand/server-acl-init/rules_test.go index e7c996545d..ad3d385121 100644 --- a/control-plane/subcommand/server-acl-init/rules_test.go +++ b/control-plane/subcommand/server-acl-init/rules_test.go @@ -477,6 +477,7 @@ func TestSyncRules(t *testing.T) { policy = "write" } operator = "write" +acl = "write" namespace "sync-namespace" { node_prefix "" { policy = "read" @@ -496,6 +497,7 @@ namespace "sync-namespace" { policy = "write" } operator = "write" +acl = "write" namespace "sync-namespace" { node_prefix "" { policy = "read" @@ -515,6 +517,7 @@ namespace "sync-namespace" { policy = "write" } operator = "write" +acl = "write" namespace_prefix "" { node_prefix "" { policy = "read" @@ -534,6 +537,7 @@ namespace_prefix "" { policy = "write" } operator = "write" +acl = "write" namespace_prefix "" { node_prefix "" { policy = "read" @@ -554,6 +558,7 @@ namespace_prefix "" { policy = "write" } operator = "write" +acl = "write" namespace_prefix "prefix-" { node_prefix "" { policy = "read" @@ -574,6 +579,7 @@ namespace_prefix "prefix-" { policy = "write" } operator = "write" +acl = "write" namespace_prefix "prefix-" { node_prefix "" { policy = "read" @@ -773,6 +779,7 @@ func TestControllerRules(t *testing.T) { Name: "namespaces=disabled, partitions=disabled", Expected: ` operator = "write" + acl = "write" service_prefix "" { policy = "write" intentions = "write" @@ -784,6 +791,7 @@ func TestControllerRules(t *testing.T) { DestConsulNS: "consul", Expected: ` operator = "write" + acl = "write" namespace "consul" { service_prefix "" { policy = "write" @@ -797,6 +805,7 @@ func TestControllerRules(t *testing.T) { Mirroring: true, Expected: ` operator = "write" + acl = "write" namespace_prefix "" { service_prefix "" { policy = "write" @@ -811,6 +820,7 @@ func TestControllerRules(t *testing.T) { MirroringPrefix: "prefix-", Expected: ` operator = "write" + acl = "write" namespace_prefix "prefix-" { service_prefix "" { policy = "write" @@ -827,6 +837,7 @@ func TestControllerRules(t *testing.T) { Expected: ` partition "part-1" { mesh = "write" + acl = "write" namespace "consul" { policy = "write" service_prefix "" { @@ -845,6 +856,7 @@ partition "part-1" { Expected: ` partition "part-1" { mesh = "write" + acl = "write" namespace_prefix "" { policy = "write" service_prefix "" { @@ -864,6 +876,7 @@ partition "part-1" { Expected: ` partition "part-1" { mesh = "write" + acl = "write" namespace_prefix "prefix-" { policy = "write" service_prefix "" { From cef2c731cdf119470648d41d61c4bf0abe525683 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Mon, 1 Nov 2021 23:04:06 -0400 Subject: [PATCH 110/418] use image 1.11.0-beta2 --- .circleci/config.yml | 4 ++-- .../tests/controller/controller_namespaces_test.go | 2 +- acceptance/tests/partitions/partitions_test.go | 10 ++++------ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a592052168..cb74cea58c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,8 +9,8 @@ executors: - image: docker.mirror.hashicorp.services/circleci/golang:1.16 environment: TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.11.0-beta1 # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.11.0+ent-beta1 # Consul's enterprise version to use in tests + CONSUL_VERSION: 1.11.0-beta2 # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.0+ent-beta2 # Consul's enterprise version to use in tests control-plane-path : &control-plane-path control-plane cli-path : &cli-path cli diff --git a/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go index 1b6bde2e26..356c21d2a5 100644 --- a/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -74,7 +74,7 @@ func TestControllerNamespaces(t *testing.T) { ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ - "global.image": "ashwinvenkatesh/consul@sha256:70c8ba1c8c7c092e34473f4d45f08f148bf52f372bce830babfdd7dbfc1ce5d4", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta2", "global.enableConsulNamespaces": "true", "global.adminPartitions.enabled": "true", diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index b60ed8c4db..79968c7856 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -97,7 +97,7 @@ func TestPartitionsWithoutMesh(t *testing.T) { serverHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "ashwinvenkatesh/consul@sha256:70c8ba1c8c7c092e34473f4d45f08f148bf52f372bce830babfdd7dbfc1ce5d4", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta2", "global.adminPartitions.enabled": "true", "global.enableConsulNamespaces": "true", @@ -186,7 +186,7 @@ func TestPartitionsWithoutMesh(t *testing.T) { // Create client cluster. clientHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "ashwinvenkatesh/consul@sha256:70c8ba1c8c7c092e34473f4d45f08f148bf52f372bce830babfdd7dbfc1ce5d4", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta2", "global.enabled": "false", "global.tls.enabled": "true", @@ -523,8 +523,7 @@ func TestPartitionsWithMesh(t *testing.T) { serverHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "ashwinvenkatesh/consul@sha256:70c8ba1c8c7c092e34473f4d45f08f148bf52f372bce830babfdd7dbfc1ce5d4", - "global.imageK8S": "ashwinvenkatesh/consul-k8s@sha256:e777b8f2dab5ffc10e08febc16ccf4403c4feb62465c5bdc1ac6855a6b995acb", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta2", "global.adminPartitions.enabled": "true", "global.enableConsulNamespaces": "true", @@ -620,8 +619,7 @@ func TestPartitionsWithMesh(t *testing.T) { // Create client cluster. clientHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "ashwinvenkatesh/consul@sha256:70c8ba1c8c7c092e34473f4d45f08f148bf52f372bce830babfdd7dbfc1ce5d4", - "global.imageK8S": "ashwinvenkatesh/consul-k8s@sha256:e777b8f2dab5ffc10e08febc16ccf4403c4feb62465c5bdc1ac6855a6b995acb", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta2", "global.enabled": "false", "global.tls.enabled": "true", From 08396a5d4124438adb17d4facf35aecfd62a64bb Mon Sep 17 00:00:00 2001 From: David Yu Date: Tue, 2 Nov 2021 00:16:24 -0700 Subject: [PATCH 111/418] cli: improve secure preset (#818) * cli: improve secure preset * remove bootstrapExpect since it defaults to replicas * Update cli/cmd/install/presets.go Co-authored-by: Iryna Shustava * Update cli/cmd/install/presets.go Co-authored-by: Iryna Shustava * Update cli/cmd/install/presets.go Co-authored-by: Iryna Shustava * adding controller to demo preset * Changelog Co-authored-by: Iryna Shustava --- CHANGELOG.md | 5 ++++- cli/cmd/install/presets.go | 18 +++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e35d539ea..3e9bab3a40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ BREAKING CHANGES: * Helm Chart * The `kube-system` and `local-path-storage` namespaces are now _excluded_ from connect injection by default on Kubernetes versions >= 1.21. If you wish to enable injection on those namespaces, set `connectInject.namespaceSelector` to `null`. [[GH-726](https://github.com/hashicorp/consul-k8s/pull/726)] + IMPROVEMENTS: * Helm Chart * Automatic retry for `gossip-encryption-autogenerate-job` on failure [[GH-789](https://github.com/hashicorp/consul-k8s/pull/789)] @@ -10,7 +11,9 @@ IMPROVEMENTS: * CLI * Add `status` command. [[GH-768](https://github.com/hashicorp/consul-k8s/pull/768)] * Add `-verbose`, `-v` flag to the `consul-k8s install` command, which outputs all logs emitted from the installation. By default, verbose is set to `false` to hide logs that show resources are not ready. [[GH-810](https://github.com/hashicorp/consul-k8s/pull/810)] - * Add Prometheus deployment and Consul K8s metrics integration with demo preset when installing via `-preset=demo`. [[GH-809](https://github.com/hashicorp/consul-k8s/pull/809)] + * Set `prometheus.enabled` to true and enable all metrics for Consul K8s when installing via the `demo` preset. [[GH-809](https://github.com/hashicorp/consul-k8s/pull/809)] + * Set `controller.enabled` to `true` when installing via the `demo` preset. [[GH818](https://github.com/hashicorp/consul-k8s/pull/818)] + * Set `global.gossipEncryption.autoGenerate` to `true` and `global.tls.enableAutoEncrypt` to `true` when installing via the `secure` preset. [[GH818](https://github.com/hashicorp/consul-k8s/pull/818)] ## 0.35.0 (October 19, 2021) diff --git a/cli/cmd/install/presets.go b/cli/cmd/install/presets.go index dc0f15c7e6..f901d1e930 100644 --- a/cli/cmd/install/presets.go +++ b/cli/cmd/install/presets.go @@ -13,7 +13,6 @@ var presets = map[string]interface{}{ PresetSecure: convert(secure), } -// TODO: enable prometheus in demo installation var demo = ` global: name: consul @@ -28,7 +27,8 @@ connectInject: enableGatewayMetrics: true server: replicas: 1 - bootstrapExpect: 1 +controller: + enabled: true ui: enabled: true service: @@ -40,15 +40,19 @@ prometheus: var secure = ` global: name: consul - acls: - manageSystemACLs: true + gossipEncryption: + autoGenerate: true tls: enabled: true -connectInject: - enabled: true + enableAutoEncrypt: true + acls: + manageSystemACLs: true server: replicas: 1 - bootstrapExpect: 1 +connectInject: + enabled: true +controller: + enabled: true ` var globalNameConsul = ` From 0325eaf89449054ce02bce2b73794fae05766843 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 2 Nov 2021 10:26:55 -0400 Subject: [PATCH 112/418] update-changelog (#827) --- CHANGELOG.md | 6 ++++++ docs/admin-partitions-with-acls.md | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e9bab3a40..cb96dc1cda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,18 @@ IMPROVEMENTS: * Helm Chart * Automatic retry for `gossip-encryption-autogenerate-job` on failure [[GH-789](https://github.com/hashicorp/consul-k8s/pull/789)] * `kube-system` and `local-path-storage` namespaces are now excluded from connect injection by default on Kubernetes versions >= 1.21. This prevents deadlock issues when `kube-system` components go down and allows Kind to work without changing the failure policy of the mutating webhook. [[GH-726](https://github.com/hashicorp/consul-k8s/pull/726)] + * Add support for services across Admin Partitions to communicate using mesh gateways. [[GH-807](https://github.com/hashicorp/consul-k8s/pull/807)] + * Documentation for the installation can be found [here](https://github.com/hashicorp/consul-k8s/blob/main/docs/admin-partitions-with-acls.md). + * Add support for PartitionExports CRD to enable cross-partition networking. [[GH-802](https://github.com/hashicorp/consul-k8s/pull/802)] * CLI * Add `status` command. [[GH-768](https://github.com/hashicorp/consul-k8s/pull/768)] * Add `-verbose`, `-v` flag to the `consul-k8s install` command, which outputs all logs emitted from the installation. By default, verbose is set to `false` to hide logs that show resources are not ready. [[GH-810](https://github.com/hashicorp/consul-k8s/pull/810)] * Set `prometheus.enabled` to true and enable all metrics for Consul K8s when installing via the `demo` preset. [[GH-809](https://github.com/hashicorp/consul-k8s/pull/809)] * Set `controller.enabled` to `true` when installing via the `demo` preset. [[GH818](https://github.com/hashicorp/consul-k8s/pull/818)] * Set `global.gossipEncryption.autoGenerate` to `true` and `global.tls.enableAutoEncrypt` to `true` when installing via the `secure` preset. [[GH818](https://github.com/hashicorp/consul-k8s/pull/818)] + * Add Prometheus deployment and Consul K8s metrics integration with demo preset when installing via `-preset=demo`. [[GH-809](https://github.com/hashicorp/consul-k8s/pull/809)] +* Control Plane + * Add support for partition-exports config entry as a Custom Resource Definition to help manage cross-partition networking. [[GH-802](https://github.com/hashicorp/consul-k8s/pull/802)] ## 0.35.0 (October 19, 2021) diff --git a/docs/admin-partitions-with-acls.md b/docs/admin-partitions-with-acls.md index 6ff5be54f1..8c9cf06c38 100644 --- a/docs/admin-partitions-with-acls.md +++ b/docs/admin-partitions-with-acls.md @@ -25,6 +25,8 @@ connectInject: mirroringK8S: true controller: enabled: true +meshGateway: + enabled: true ``` Identify the LoadBalancer External IP of the `partition-service` @@ -90,5 +92,7 @@ connectInject: mirroringK8S: true controller: enabled: true +meshGateway: + enabled: true ``` This should create clusters that have Admin Partitions deployed on them with ACLs enabled. From 2d09c46578ad265fe06093831245337d963956cf Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 2 Nov 2021 11:49:35 -0400 Subject: [PATCH 113/418] Update go.mod to the latest from consul-api (#828) --- acceptance/go.mod | 2 +- acceptance/go.sum | 4 ++-- control-plane/go.mod | 2 +- control-plane/go.sum | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/acceptance/go.mod b/acceptance/go.mod index 0113dd8adb..8f073c8764 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/gruntwork-io/terratest v0.31.2 - github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c + github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb github.com/hashicorp/consul/sdk v0.8.0 github.com/stretchr/testify v1.5.1 gopkg.in/yaml.v2 v2.2.8 diff --git a/acceptance/go.sum b/acceptance/go.sum index 67d784e957..8bb9b7620f 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -225,8 +225,8 @@ github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arn github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= -github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c h1:7hQzN7YHI2XscCNqPVW5pORQSwJWdFgObnwXNFdEJI8= -github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb h1:RNuoY5+OLW+hC9FTPEf8/gXPgPo80lMjyFmS3+BUpkA= +github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= diff --git a/control-plane/go.mod b/control-plane/go.mod index 044d9f347c..f37ac394a6 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/go-cmp v0.5.6 github.com/google/go-querystring v1.0.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c + github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f diff --git a/control-plane/go.sum b/control-plane/go.sum index e80510e6c9..523a395f69 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -297,8 +297,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c h1:7hQzN7YHI2XscCNqPVW5pORQSwJWdFgObnwXNFdEJI8= -github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb h1:RNuoY5+OLW+hC9FTPEf8/gXPgPo80lMjyFmS3+BUpkA= +github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= From f7ea0f610b8c975acffc89b90cafdeb2a3f66128 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 2 Nov 2021 13:27:27 -0400 Subject: [PATCH 114/418] =?UTF-8?q?=F0=9F=9A=80=F0=9F=9A=80=F0=9F=9A=80=20?= =?UTF-8?q?Release/0.36.0=20(#830)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update `imageK8S` in values.yaml to 0.35.1 * Update `image` in `values.yaml` to `1.11.0` * Update `imageK8S` to `0.36.0` * Set `image` to `1.10.3` * Set version in Chart.yaml * Update artifact control plane to 0.36.0 * Set CLI version to 0.36.0 * Rev version for CLI back to 0.35.0 (pipeline will take care of it) --- charts/consul/Chart.yaml | 4 ++-- charts/consul/values.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index 78502183ff..35f1b226b7 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: consul -version: 0.35.0 +version: 0.36.0 appVersion: 1.10.3 kubeVersion: ">=1.17.0-0" description: Official HashiCorp Consul Chart @@ -15,7 +15,7 @@ annotations: - name: consul image: hashicorp/consul:1.10.3 - name: consul-k8s-control-plane - image: hashicorp/consul-k8s-control-plane:0.35.0 + image: hashicorp/consul-k8s-control-plane:0.36.0 - name: envoy image: envoyproxy/envoy-alpine:v1.18.4 artifacthub.io/license: MPL-2.0 diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 44b81cc327..68ffbb6630 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -105,7 +105,7 @@ global: # image that is used for functionality such as catalog sync. # This can be overridden per component. # @default: hashicorp/consul-k8s-control-plane: - imageK8S: "hashicorp/consul-k8s-control-plane:0.35.0" + imageK8S: "hashicorp/consul-k8s-control-plane:0.36.0" # The name of the datacenter that the agents should # register as. This can't be changed once the Consul cluster is up and running From 22110a56b4885ba3e93064f003f2a24837e515fc Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Tue, 2 Nov 2021 18:49:23 +0000 Subject: [PATCH 115/418] Release v0.36.0 --- CHANGELOG.md | 2 +- cli/version/version.go | 2 +- control-plane/version/version.go | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb96dc1cda..643191de22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.36.0 (November 02, 2021) BREAKING CHANGES: * Helm Chart diff --git a/cli/version/version.go b/cli/version/version.go index fc82a0063a..aa315f3b57 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -14,7 +14,7 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.35.0" + Version = "0.36.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 9ccf557a41..aa315f3b57 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.35.0" + Version = "0.36.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 344379937b70855233d07b79841f7ee14cc79855 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Tue, 2 Nov 2021 19:58:13 +0000 Subject: [PATCH 116/418] Putting source back into Dev Mode --- CHANGELOG.md | 2 ++ cli/version/version.go | 2 +- control-plane/version/version.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 643191de22..46848b5848 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## UNRELEASED + ## 0.36.0 (November 02, 2021) BREAKING CHANGES: diff --git a/cli/version/version.go b/cli/version/version.go index aa315f3b57..8740d28984 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index aa315f3b57..8740d28984 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable From bfb52ac89d83c36609a1fcd0e01bc85fb0b31f39 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 2 Nov 2021 13:28:11 -0700 Subject: [PATCH 117/418] Always set server acl tokens If server-acl-init is re-run, ensure that server ACL tokens have been created for each server and call the update token API for each server again. This ensures that if server-acl-init fails to pass out tokens to every server that when it is re-run it won't assume that every server has a token. --- CHANGELOG.md | 7 + .../subcommand/server-acl-init/command.go | 40 ++---- .../server-acl-init/command_test.go | 122 +++++++++++++++-- .../subcommand/server-acl-init/servers.go | 126 +++++++++++------- 4 files changed, 211 insertions(+), 84 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46848b5848..dd5be5c5cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ ## UNRELEASED +BUG FIXES: +* Control Plane + * ACLs: Fix issue where if one or more servers fail to have their ACL tokens set on the initial run of server-acl-init + then on subsequent re-runs of server-acl-init the tokens are never set. [[GH-825](https://github.com/hashicorp/consul-k8s/issues/825)] + * ACLs: Fix issue where if the number of Consul servers is increased, the new servers are never provisioned + an ACL token. [[GH-677](https://github.com/hashicorp/consul-k8s/issues/677)] + ## 0.36.0 (November 02, 2021) BREAKING CHANGES: diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index 9e7bd3d355..5c12dd1523 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -11,11 +11,6 @@ import ( "sync" "time" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/subcommand" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" - k8sflags "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" "github.com/hashicorp/consul/api" "github.com/hashicorp/go-discover" "github.com/hashicorp/go-hclog" @@ -24,6 +19,12 @@ import ( k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" + + "github.com/hashicorp/consul-k8s/control-plane/consul" + "github.com/hashicorp/consul-k8s/control-plane/subcommand" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" + k8sflags "github.com/hashicorp/consul-k8s/control-plane/subcommand/flags" ) type Command struct { @@ -313,7 +314,6 @@ func (c *Command) Run(args []string) int { scheme = "https" } - var updateServerPolicy bool var bootstrapToken string if c.flagBootstrapTokenFile != "" { @@ -340,19 +340,13 @@ func (c *Command) Run(args []string) int { if bootstrapToken != "" { c.log.Info(fmt.Sprintf("ACLs already bootstrapped - retrieved bootstrap token from Secret %q", bootTokenSecretName)) - - // Mark that we should update the server ACL policy in case - // there are namespace related config changes. Because of the - // organization of the server token creation code, the policy - // otherwise won't be updated. - updateServerPolicy = true } else { c.log.Info("No bootstrap token from previous installation found, continuing on to bootstrapping") - bootstrapToken, err = c.bootstrapServers(serverAddresses, bootTokenSecretName, scheme) - if err != nil { - c.log.Error(err.Error()) - return 1 - } + } + bootstrapToken, err = c.bootstrapServers(serverAddresses, bootstrapToken, bootTokenSecretName, scheme) + if err != nil { + c.log.Error(err.Error()) + return 1 } } @@ -384,18 +378,6 @@ func (c *Command) Run(args []string) int { c.log.Info("Current datacenter", "datacenter", consulDC, "primaryDC", primaryDC) isPrimary := consulDC == primaryDC - // With the addition of namespaces, the ACL policies associated - // with the server tokens may need to be updated if Enterprise Consul - // users upgrade to 1.7+. This updates the policy if the bootstrap - // token had previously existed, which signals a potential config change. - if updateServerPolicy { - _, err = c.setServerPolicy(consulClient) - if err != nil { - c.log.Error("Error updating the server ACL policy", "err", err) - return 1 - } - } - if c.flagEnablePartitions && c.flagPartitionName == consulDefaultPartition && isPrimary { // Partition token is local because only the Primary datacenter can have Admin Partitions. err := c.createLocalACL("partitions", partitionRules, consulDC, isPrimary, consulClient) diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index a70a2383c6..e15e8db3cf 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -15,10 +15,6 @@ import ( "testing" "time" - "github.com/hashicorp/consul-k8s/control-plane/helper/cert" - "github.com/hashicorp/consul-k8s/control-plane/helper/go-discover/mocks" - "github.com/hashicorp/consul-k8s/control-plane/helper/test" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/freeport" "github.com/hashicorp/consul/sdk/testutil" @@ -31,6 +27,11 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" + + "github.com/hashicorp/consul-k8s/control-plane/helper/cert" + "github.com/hashicorp/consul-k8s/control-plane/helper/go-discover/mocks" + "github.com/hashicorp/consul-k8s/control-plane/helper/test" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" ) var ns = "default" @@ -1284,6 +1285,8 @@ func TestRun_NoLeader(t *testing.T) { numACLBootCalls++ case "/v1/agent/self": fmt.Fprintln(w, `{"Config": {"Datacenter": "dc1", "PrimaryDatacenter": "dc1"}}`) + case "/v1/acl/tokens": + fmt.Fprintln(w, `[]`) default: fmt.Fprintln(w, "{}") } @@ -1342,6 +1345,10 @@ func TestRun_NoLeader(t *testing.T) { "PUT", "/v1/acl/policy", }, + { + "GET", + "/v1/acl/tokens", + }, { "PUT", "/v1/acl/token", @@ -1496,6 +1503,8 @@ func TestRun_ClientTokensRetry(t *testing.T) { numPolicyCalls++ case "/v1/agent/self": fmt.Fprintln(w, `{"Config": {"Datacenter": "dc1", "PrimaryDatacenter": "dc1"}}`) + case "/v1/acl/tokens": + fmt.Fprintln(w, `[]`) default: fmt.Fprintln(w, "{}") } @@ -1530,6 +1539,10 @@ func TestRun_ClientTokensRetry(t *testing.T) { "PUT", "/v1/acl/policy", }, + { + "GET", + "/v1/acl/tokens", + }, { "PUT", "/v1/acl/token", @@ -1558,8 +1571,8 @@ func TestRun_ClientTokensRetry(t *testing.T) { }, consulAPICalls) } -// Test if there is an old bootstrap Secret we assume the servers were -// bootstrapped already and continue on to the next step. +// Test if there is an old bootstrap Secret we still try to create and set +// server tokens. func TestRun_AlreadyBootstrapped(t *testing.T) { t.Parallel() require := require.New(t) @@ -1581,6 +1594,8 @@ func TestRun_AlreadyBootstrapped(t *testing.T) { switch r.URL.Path { case "/v1/agent/self": fmt.Fprintln(w, `{"Config": {"Datacenter": "dc1", "PrimaryDatacenter": "dc1"}}`) + case "/v1/acl/tokens": + fmt.Fprintln(w, `[]`) default: // Send an empty JSON response with code 200 to all calls. fmt.Fprintln(w, "{}") @@ -1629,15 +1644,27 @@ func TestRun_AlreadyBootstrapped(t *testing.T) { // Test that the expected API calls were made. require.Equal([]APICall{ - // We only expect the calls for creating client tokens - // and updating the server policy. + // We expect calls for updating the server policy, setting server tokens, + // and updating client policy. + { + "PUT", + "/v1/acl/policy", + }, { "GET", - "/v1/agent/self", + "/v1/acl/tokens", }, { "PUT", - "/v1/acl/policy", + "/v1/acl/token", + }, + { + "PUT", + "/v1/agent/token/agent", + }, + { + "GET", + "/v1/agent/self", }, { "PUT", @@ -1650,6 +1677,81 @@ func TestRun_AlreadyBootstrapped(t *testing.T) { }, consulAPICalls) } +// Test if there is an old bootstrap Secret and the server token exists +// that we don't try and recreate the token. +func TestRun_AlreadyBootstrapped_ServerTokenExists(t *testing.T) { + t.Parallel() + require := require.New(t) + + // First set everything up with ACLs bootstrapped. + bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + k8s, testAgent := completeBootstrappedSetup(t, bootToken) + setUpK8sServiceAccount(t, k8s, ns) + defer testAgent.Stop() + k8s.CoreV1().Secrets(ns).Create(context.Background(), &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourcePrefix + "-bootstrap-acl-token", + }, + Data: map[string][]byte{ + "token": []byte(bootToken), + }, + }, metav1.CreateOptions{}) + + consulClient, err := api.NewClient(&api.Config{ + Address: testAgent.HTTPAddr, + Token: bootToken, + }) + require.NoError(err) + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + clientset: k8s, + } + + // Create the server policy and token _before_ we run the command. + agentPolicyRules, err := cmd.agentRules() + require.NoError(err) + policy, _, err := consulClient.ACL().PolicyCreate(&api.ACLPolicy{ + Name: "agent-token", + Description: "Agent Token Policy", + Rules: agentPolicyRules, + }, nil) + require.NoError(err) + _, _, err = consulClient.ACL().TokenCreate(&api.ACLToken{ + Description: fmt.Sprintf("Server Token for %s", strings.Split(testAgent.HTTPAddr, ":")[0]), + Policies: []*api.ACLTokenPolicyLink{ + { + Name: policy.Name, + }, + }, + }, nil) + require.NoError(err) + + // Run the command. + cmdArgs := []string{ + "-timeout=1m", + "-k8s-namespace", ns, + "-server-address", strings.Split(testAgent.HTTPAddr, ":")[0], + "-server-port", strings.Split(testAgent.HTTPAddr, ":")[1], + "-resource-prefix", resourcePrefix, + } + + responseCode := cmd.Run(cmdArgs) + require.Equal(0, responseCode, ui.ErrorWriter.String()) + + // Check that only one server token exists, i.e. it didn't create an + // extra token. + tokens, _, err := consulClient.ACL().TokenList(nil) + require.NoError(err) + count := 0 + for _, token := range tokens { + if len(token.Policies) == 1 && token.Policies[0].Name == policy.Name { + count++ + } + } + require.Equal(1, count) +} + // Test if there is a provided bootstrap we skip bootstrapping of the servers // and continue on to the next step. func TestRun_SkipBootstrapping_WhenBootstrapTokenIsProvided(t *testing.T) { diff --git a/control-plane/subcommand/server-acl-init/servers.go b/control-plane/subcommand/server-acl-init/servers.go index 09f1c6e789..844fc5c03d 100644 --- a/control-plane/subcommand/server-acl-init/servers.go +++ b/control-plane/subcommand/server-acl-init/servers.go @@ -5,17 +5,53 @@ import ( "fmt" "strings" - "github.com/hashicorp/consul-k8s/control-plane/consul" - "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" "github.com/hashicorp/consul/api" apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/hashicorp/consul-k8s/control-plane/consul" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" ) // bootstrapServers bootstraps ACLs and ensures each server has an ACL token. -func (c *Command) bootstrapServers(serverAddresses []string, bootTokenSecretName, scheme string) (string, error) { +// If bootstrapToken is not empty then ACLs are already bootstrapped. +func (c *Command) bootstrapServers(serverAddresses []string, bootstrapToken, bootTokenSecretName, scheme string) (string, error) { // Pick the first server address to connect to for bootstrapping and set up connection. firstServerAddr := fmt.Sprintf("%s:%d", serverAddresses[0], c.flagServerPort) + + if bootstrapToken == "" { + var err error + bootstrapToken, err = c.bootstrapACLs(firstServerAddr, scheme, bootTokenSecretName) + if err != nil { + return "", err + } + } + + // Override our original client with a new one that has the bootstrap token + // set. + consulClient, err := consul.NewClient(&api.Config{ + Address: firstServerAddr, + Scheme: scheme, + Token: bootstrapToken, + TLSConfig: api.TLSConfig{ + Address: c.flagConsulTLSServerName, + CAFile: c.flagConsulCACert, + }, + }) + if err != nil { + return "", fmt.Errorf("creating Consul client for address %s: %s", firstServerAddr, err) + } + + // Create new tokens for each server and apply them. + if err := c.setServerTokens(consulClient, serverAddresses, bootstrapToken, scheme); err != nil { + return "", err + } + return bootstrapToken, nil +} + +// bootstrapACLs makes the ACL bootstrap API call and writes the bootstrap token +// to a kube secret. +func (c *Command) bootstrapACLs(firstServerAddr string, scheme string, bootTokenSecretName string) (string, error) { consulClient, err := consul.NewClient(&api.Config{ Address: firstServerAddr, Scheme: scheme, @@ -29,13 +65,13 @@ func (c *Command) bootstrapServers(serverAddresses []string, bootTokenSecretName } // Call bootstrap ACLs API. - var bootstrapToken []byte + var bootstrapToken string var unrecoverableErr error err = c.untilSucceeds("bootstrapping ACLs - PUT /v1/acl/bootstrap", func() error { bootstrapResp, _, err := consulClient.ACL().Bootstrap() if err == nil { - bootstrapToken = []byte(bootstrapResp.SecretID) + bootstrapToken = bootstrapResp.SecretID return nil } @@ -69,36 +105,13 @@ func (c *Command) bootstrapServers(serverAddresses []string, bootTokenSecretName Name: bootTokenSecretName, }, Data: map[string][]byte{ - common.ACLTokenSecretKey: bootstrapToken, + common.ACLTokenSecretKey: []byte(bootstrapToken), }, } _, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Create(c.ctx, secret, metav1.CreateOptions{}) return err }) - if err != nil { - return "", err - } - - // Override our original client with a new one that has the bootstrap token - // set. - consulClient, err = consul.NewClient(&api.Config{ - Address: firstServerAddr, - Scheme: scheme, - Token: string(bootstrapToken), - TLSConfig: api.TLSConfig{ - Address: c.flagConsulTLSServerName, - CAFile: c.flagConsulCACert, - }, - }) - if err != nil { - return "", fmt.Errorf("creating Consul client for address %s: %s", firstServerAddr, err) - } - - // Create new tokens for each server and apply them. - if err := c.setServerTokens(consulClient, serverAddresses, string(bootstrapToken), scheme); err != nil { - return "", err - } - return string(bootstrapToken), nil + return bootstrapToken, err } // setServerTokens creates policies and associated ACL token for each server @@ -109,9 +122,14 @@ func (c *Command) setServerTokens(consulClient *api.Client, serverAddresses []st return err } + existingTokens, _, err := consulClient.ACL().TokenList(nil) + if err != nil { + return err + } + // Create agent token for each server agent. for _, host := range serverAddresses { - var token *api.ACLToken + var tokenSecretID string // We create a new client for each server because we need to call each // server specifically. @@ -128,26 +146,44 @@ func (c *Command) setServerTokens(consulClient *api.Client, serverAddresses []st return err } - // Create token for the server - err = c.untilSucceeds(fmt.Sprintf("creating server token for %s - PUT /v1/acl/token", host), - func() error { - tokenReq := api.ACLToken{ - Description: fmt.Sprintf("Server Token for %s", host), - Policies: []*api.ACLTokenPolicyLink{{Name: agentPolicy.Name}}, + tokenDescription := fmt.Sprintf("Server Token for %s", host) + + // Check if the token was already created. We're matching on the description + // since that's the only part that's unique. + for _, t := range existingTokens { + if len(t.Policies) == 1 && t.Policies[0].Name == agentPolicy.Name { + if t.Description == tokenDescription { + tokenSecretID = t.SecretID + break } - var err error - token, _, err = serverClient.ACL().TokenCreate(&tokenReq, nil) + } + } + + // Create token for the server if it doesn't already exist. + if tokenSecretID == "" { + err = c.untilSucceeds(fmt.Sprintf("creating server token for %s - PUT /v1/acl/token", host), + func() error { + tokenReq := api.ACLToken{ + Description: tokenDescription, + Policies: []*api.ACLTokenPolicyLink{{Name: agentPolicy.Name}}, + } + token, _, err := serverClient.ACL().TokenCreate(&tokenReq, nil) + if err != nil { + return err + } + tokenSecretID = token.SecretID + return nil + }) + if err != nil { return err - }) - if err != nil { - return err + } } - // Pass out agent tokens to servers. - // Update token. + // Pass out agent tokens to servers. It's okay to make this API call + // even if the server already has a token since the call is idempotent. err = c.untilSucceeds(fmt.Sprintf("updating server token for %s - PUT /v1/agent/token/agent", host), func() error { - _, err := serverClient.Agent().UpdateAgentACLToken(token.SecretID, nil) + _, err := serverClient.Agent().UpdateAgentACLToken(tokenSecretID, nil) return err }) if err != nil { From 9ac3af5b1aa575a8e394295c2ab7e687c81bfd92 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 4 Nov 2021 09:48:54 -0400 Subject: [PATCH 118/418] Update CONTRIBUTING to reflect monorepo change (#836) * Update CONTRIBUTING to reflect monorepo change * Change numbering back to all 1s --- CONTRIBUTING.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 31a46a4712..e6d2fcec16 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -794,30 +794,30 @@ Here are some things to consider before adding a test: ## Helm Reference Docs -The helm reference docs (https://www.consul.io/docs/k8s/helm) are automatically +The Helm reference docs (https://www.consul.io/docs/k8s/helm) are automatically generated from our `values.yaml` file. ### Generating Helm Reference Docs To generate the docs and update the `helm.mdx` file: -1. Fork `hashicorp/consul` (https://github.com/hashicorp/consul) on GitHub +1. Fork `hashicorp/consul` (https://github.com/hashicorp/consul) on GitHub. 1. Clone your fork: ```shell-session - git clone https://github.com/your-username/consul.git + git clone https://github.com//consul.git ``` -1. Change directory into your `consul-helm` repo: +1. Change directory into your `consul-k8s` repo: ```shell-session - cd /path/to/consul-helm + cd /path/to/consul-k8s ``` -1. Run `make gen-docs` using the path to your consul (not consul-helm) repo: +1. Run `make gen-docs` using the path to your consul (not consul-k8s) repo: ```shell-session make gen-docs consul= # Examples: # make gen-docs consul=/Users/my-name/code/hashicorp/consul # make gen-docs consul=../consul ``` -1. Open up a pull request to `hashicorp/consul` (in addition to your `hashicorp/consul-helm` pull request) +1. Open up a pull request to `hashicorp/consul` (in addition to your `hashicorp/consul-k8s` pull request) ### values.yaml Annotations From 9c344e186a45ad0a3b252af30ce46b29fb565e76 Mon Sep 17 00:00:00 2001 From: David Yu Date: Thu, 4 Nov 2021 08:45:10 -0700 Subject: [PATCH 119/418] CHANGELOG: remove duplicate entry for CLI on 0.36.0 (#838) * CHANGELOG: remove duplicate entry * Direct link to Consul K8s learn guides at bottom of readme --- CHANGELOG.md | 1 - README.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46848b5848..1847cd6671 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,6 @@ IMPROVEMENTS: * Set `prometheus.enabled` to true and enable all metrics for Consul K8s when installing via the `demo` preset. [[GH-809](https://github.com/hashicorp/consul-k8s/pull/809)] * Set `controller.enabled` to `true` when installing via the `demo` preset. [[GH818](https://github.com/hashicorp/consul-k8s/pull/818)] * Set `global.gossipEncryption.autoGenerate` to `true` and `global.tls.enableAutoEncrypt` to `true` when installing via the `secure` preset. [[GH818](https://github.com/hashicorp/consul-k8s/pull/818)] - * Add Prometheus deployment and Consul K8s metrics integration with demo preset when installing via `-preset=demo`. [[GH-809](https://github.com/hashicorp/consul-k8s/pull/809)] * Control Plane * Add support for partition-exports config entry as a Custom Resource Definition to help manage cross-partition networking. [[GH-802](https://github.com/hashicorp/consul-k8s/pull/802)] diff --git a/README.md b/README.md index f8ef63ea9f..f1be598922 100644 --- a/README.md +++ b/README.md @@ -94,4 +94,4 @@ file. These are also fully documented directly on the # Tutorials You can find examples and complete tutorials on how to deploy Consul on -Kubernetes using Helm on the [HashiCorp Learn website](https://learn.hashicorp.com/consul). +Kubernetes using Helm on the [HashiCorp Learn website](https://learn.hashicorp.com/collections/consul/kubernetes). From 1de9bca6e04d788f1e07449e717f881bbeff30b1 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Wed, 3 Nov 2021 16:09:29 -0700 Subject: [PATCH 120/418] Fix bug where webhookconfig would not be updated Fixes an issue where if the webhookconfiguration is updated after the webhook cert manager starts, then it is never reset to the correct configuration until the manager is restarted or the certificate expires. The issue was occurring because in the loop where we check the webhookconfiguration we are only checking the webhookconfiguration of the last updated certificate bundle. If there are multiple webhook configurations then we are only watching a single one at a time since the loop always operates on one bundle. The fix is for each webhook to run its own loop. In addition, the reason this was causing issues is because during a helm upgrade we were resetting the webhookconfiguration's caBundle fields. I've removed the caBundle setting (which already didn't exist in the connect injector's webhook config) so that during a helm upgrade it doesn't overwrite that field. --- CHANGELOG.md | 2 + ...ntroller-mutatingwebhookconfiguration.yaml | 9 -- .../webhook-cert-manager/command.go | 7 +- .../webhook-cert-manager/command_test.go | 100 ++++++++++++++++++ 4 files changed, 105 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 661dd5d7e8..405961f42e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ BUG FIXES: then on subsequent re-runs of server-acl-init the tokens are never set. [[GH-825](https://github.com/hashicorp/consul-k8s/issues/825)] * ACLs: Fix issue where if the number of Consul servers is increased, the new servers are never provisioned an ACL token. [[GH-677](https://github.com/hashicorp/consul-k8s/issues/677)] + * Fix issue where after a `helm upgrade`, users would see `x509: certificate signed by unknown authority.` + errors when modifying config entry resources. [[GH-837](https://github.com/hashicorp/consul-k8s/pull/837)] ## 0.36.0 (November 02, 2021) diff --git a/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml b/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml index e2f33f79e2..7bef2e6c27 100644 --- a/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml +++ b/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml @@ -12,7 +12,6 @@ metadata: component: controller webhooks: - clientConfig: - caBundle: Cg== service: name: {{ template "consul.fullname" . }}-controller-webhook namespace: {{ .Release.Namespace }} @@ -34,7 +33,6 @@ webhooks: - proxydefaults sideEffects: None - clientConfig: - caBundle: Cg== service: name: {{ template "consul.fullname" . }}-controller-webhook namespace: {{ .Release.Namespace }} @@ -56,7 +54,6 @@ webhooks: - meshes sideEffects: None - clientConfig: - caBundle: Cg== service: name: {{ template "consul.fullname" . }}-controller-webhook namespace: {{ .Release.Namespace }} @@ -78,7 +75,6 @@ webhooks: - servicedefaults sideEffects: None - clientConfig: - caBundle: Cg== service: name: {{ template "consul.fullname" . }}-controller-webhook namespace: {{ .Release.Namespace }} @@ -100,7 +96,6 @@ webhooks: - serviceresolvers sideEffects: None - clientConfig: - caBundle: Cg== service: name: {{ template "consul.fullname" . }}-controller-webhook namespace: {{ .Release.Namespace }} @@ -122,7 +117,6 @@ webhooks: - servicerouters sideEffects: None - clientConfig: - caBundle: Cg== service: name: {{ template "consul.fullname" . }}-controller-webhook namespace: {{ .Release.Namespace }} @@ -144,7 +138,6 @@ webhooks: - servicesplitters sideEffects: None - clientConfig: - caBundle: Cg== service: name: {{ template "consul.fullname" . }}-controller-webhook namespace: {{ .Release.Namespace }} @@ -166,7 +159,6 @@ webhooks: - serviceintentions sideEffects: None - clientConfig: - caBundle: Cg== service: name: {{ template "consul.fullname" . }}-controller-webhook namespace: {{ .Release.Namespace }} @@ -188,7 +180,6 @@ webhooks: - ingressgateways sideEffects: None - clientConfig: - caBundle: Cg== service: name: {{ template "consul.fullname" . }}-controller-webhook namespace: {{ .Release.Namespace }} diff --git a/control-plane/subcommand/webhook-cert-manager/command.go b/control-plane/subcommand/webhook-cert-manager/command.go index 4db313a323..6c044f06c6 100644 --- a/control-plane/subcommand/webhook-cert-manager/command.go +++ b/control-plane/subcommand/webhook-cert-manager/command.go @@ -157,8 +157,6 @@ func (c *Command) Run(args []string) int { } } - certCh := make(chan cert.MetaBundle) - // Create the certificate notifier so we can update certificates, // then start all the background routines for updating certificates. var notifiers []*cert.Notify @@ -179,13 +177,14 @@ func (c *Command) Run(args []string) int { Expiry: expiry, } } + + certCh := make(chan cert.MetaBundle) certNotify := &cert.Notify{Source: certSource, Ch: certCh, WebhookConfigName: config.Name, SecretName: config.SecretName, SecretNamespace: config.SecretNamespace} notifiers = append(notifiers, certNotify) go certNotify.Start(ctx) + go c.certWatcher(ctx, certCh, c.clientset, c.logger) } - go c.certWatcher(ctx, certCh, c.clientset, c.logger) - // We define a signal handler for OS interrupts, and when an SIGINT or SIGTERM is received, // we gracefully shut down, by first stopping our cert notifiers and then cancelling // all the contexts that have been created by the process. diff --git a/control-plane/subcommand/webhook-cert-manager/command_test.go b/control-plane/subcommand/webhook-cert-manager/command_test.go index 3fde5ffa8f..7df7029241 100644 --- a/control-plane/subcommand/webhook-cert-manager/command_test.go +++ b/control-plane/subcommand/webhook-cert-manager/command_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" "github.com/hashicorp/consul-k8s/control-plane/subcommand/webhook-cert-manager/mocks" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/mitchellh/cli" @@ -485,6 +486,105 @@ func TestRun_SecretUpdates(t *testing.T) { }) } +// Test that when the MutatingWebhookConfiguration is modified, that we correctly +// reset it to the expected CA bundle. +func TestRun_WebhookConfigModified(t *testing.T) { + t.Parallel() + + deploymentName := "deployment" + deploymentNamespace := "deploy-ns" + webhook1ConfigName := "webhookOne" + webhook2ConfigName := "webhookTwo" + caBundle1 := []byte("bootstrapped-CA1") + caBundle2 := []byte("bootstrapped-CA2") + + deployment := &appsv1.Deployment{ + ObjectMeta: metav1.ObjectMeta{ + Name: deploymentName, + Namespace: deploymentNamespace, + UID: types.UID("this-is-a-uid"), + }, + } + + initialWebhook1Config := &admissionv1.MutatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: webhook1ConfigName, + }, + Webhooks: []admissionv1.MutatingWebhook{ + { + Name: "webhook1-under-test", + ClientConfig: admissionv1.WebhookClientConfig{ + CABundle: caBundle1, + }, + }, + }, + } + initialWebhook2Config := &admissionv1.MutatingWebhookConfiguration{ + ObjectMeta: metav1.ObjectMeta{ + Name: webhook2ConfigName, + }, + Webhooks: []admissionv1.MutatingWebhook{ + { + Name: "webhook2-under-test", + ClientConfig: admissionv1.WebhookClientConfig{ + CABundle: caBundle2, + }, + }, + }, + } + + // The k8s cluster will start with the two webhook configs and the deployment. + k8s := fake.NewSimpleClientset(initialWebhook1Config, initialWebhook2Config, deployment) + ctx := context.Background() + + // We don't want the certs to expire. This test is only checking if + // the MutatingWebhookConfiguration is modified that it gets reset. + certExpiry := 1 * time.Hour + + // Start the command. + cmd := Command{ + UI: cli.NewMockUi(), + clientset: k8s, + certExpiry: &certExpiry, + } + + configFile := common.WriteTempFile(t, configFile) + exitCh := runCommandAsynchronously(&cmd, []string{ + "-config-file", configFile, + "-deployment-name", deploymentName, + "-deployment-namespace", deploymentNamespace, + }) + defer stopCommand(t, &cmd, exitCh) + + // First, check that the mutatingwebhookconfiguration contents are updated when the cert-manager starts. + timer := &retry.Timer{Timeout: 10 * time.Second, Wait: 500 * time.Millisecond} + retry.RunWith(timer, t, func(r *retry.R) { + webhookConfig1, err := k8s.AdmissionregistrationV1().MutatingWebhookConfigurations().Get(ctx, webhook1ConfigName, metav1.GetOptions{}) + require.NoError(r, err) + require.NotEqual(r, webhookConfig1.Webhooks[0].ClientConfig.CABundle, caBundle1) + + webhookConfig2, err := k8s.AdmissionregistrationV1().MutatingWebhookConfigurations().Get(ctx, webhook2ConfigName, metav1.GetOptions{}) + require.NoError(r, err) + require.NotEqual(r, webhookConfig2.Webhooks[0].ClientConfig.CABundle, caBundle2) + }) + + // Now, edit the mutatingwebhookconfigurations and reset the caBundle fields. + k8s.AdmissionregistrationV1().MutatingWebhookConfigurations().Update(ctx, initialWebhook1Config, metav1.UpdateOptions{}) + k8s.AdmissionregistrationV1().MutatingWebhookConfigurations().Update(ctx, initialWebhook2Config, metav1.UpdateOptions{}) + + // Check that both mutatingwebhookconfigurations have their caBundle fields reset. + timer = &retry.Timer{Timeout: 10 * time.Second, Wait: 500 * time.Millisecond} + retry.RunWith(timer, t, func(r *retry.R) { + webhookConfig1, err := k8s.AdmissionregistrationV1().MutatingWebhookConfigurations().Get(ctx, webhook1ConfigName, metav1.GetOptions{}) + require.NoError(r, err) + require.NotEqual(r, webhookConfig1.Webhooks[0].ClientConfig.CABundle, caBundle1) + + webhookConfig2, err := k8s.AdmissionregistrationV1().MutatingWebhookConfigurations().Get(ctx, webhook2ConfigName, metav1.GetOptions{}) + require.NoError(r, err) + require.NotEqual(r, webhookConfig2.Webhooks[0].ClientConfig.CABundle, caBundle2) + }) +} + // This test verifies that when there is an error while attempting to update // the certs or the webhook config, it retries the update every second until // it succeeds. From 0de1b1f1b52d0505b1cd26d48209712da45adb05 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 4 Nov 2021 10:56:47 -0700 Subject: [PATCH 121/418] Increase wait time to 10m The wait time for pods to be ready was accidentally reduced to 3m. --- acceptance/framework/helpers/helpers.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index e4a2c02c91..5869176bbb 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -34,10 +34,10 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac logger.Log(t, "Waiting for pods to be ready.") - // Wait up to 15m. + // Wait up to 10m. // On Azure, volume provisioning can sometimes take close to 5 min, // so we need to give a bit more time for pods to become healthy. - counter := &retry.Counter{Count: 180, Wait: 1 * time.Second} + counter := &retry.Counter{Count: 600, Wait: 1 * time.Second} retry.RunWith(counter, t, func(r *retry.R) { pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) require.NoError(r, err) From a3d023d3e95b47e01b49986433a7b39ef9633a32 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Fri, 5 Nov 2021 12:12:30 -0700 Subject: [PATCH 122/418] Support PKCS1 and PKCS8 private keys (#843) * Support PKCS1 and PKCS8 private keys for server ca cert --- CHANGELOG.md | 4 + control-plane/helper/cert/tls_util.go | 19 ++ .../subcommand/tls-init/command_test.go | 215 +++++++++++++----- 3 files changed, 184 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 405961f42e..23b0621ec1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## UNRELEASED +IMPROVEMENTS: +* Control Plane + * TLS: Support PKCS1 and PKCS8 private keys for Consul certificate authority. [[GH-843](https://github.com/hashicorp/consul-k8s/pull/843)] + BUG FIXES: * Control Plane * ACLs: Fix issue where if one or more servers fail to have their ACL tokens set on the initial run of server-acl-init diff --git a/control-plane/helper/cert/tls_util.go b/control-plane/helper/cert/tls_util.go index d56bcc9989..37e2f4ea97 100644 --- a/control-plane/helper/cert/tls_util.go +++ b/control-plane/helper/cert/tls_util.go @@ -17,6 +17,9 @@ import ( "time" ) +// NOTE: A lot of this code is taken from +// https://github.com/hashicorp/consul/blob/44c023a3020fdd139c5be330f318a3c12339f08e/agent/connect/parsing.go. + // GenerateCA generates a CA with the provided // common name valid for 10 years. It returns the private key as // a crypto.Signer and a PEM string and certificate @@ -162,6 +165,22 @@ func ParseSigner(pemValue string) (crypto.Signer, error) { switch block.Type { case "EC PRIVATE KEY": return x509.ParseECPrivateKey(block.Bytes) + + case "RSA PRIVATE KEY": + return x509.ParsePKCS1PrivateKey(block.Bytes) + + case "PRIVATE KEY": + signer, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, err + } + pk, ok := signer.(crypto.Signer) + if !ok { + return nil, fmt.Errorf("private key is not a valid format") + } + + return pk, nil + default: return nil, fmt.Errorf("unknown PEM block type for signing key: %s", block.Type) } diff --git a/control-plane/subcommand/tls-init/command_test.go b/control-plane/subcommand/tls-init/command_test.go index 7405754e18..e22254008a 100644 --- a/control-plane/subcommand/tls-init/command_test.go +++ b/control-plane/subcommand/tls-init/command_test.go @@ -58,50 +58,79 @@ func TestRun_FlagValidation(t *testing.T) { } func TestRun_CreatesServerCertificatesWithExistingCAAsFiles(t *testing.T) { - ui := cli.NewMockUi() - cmd := Command{UI: ui} - k8s := fake.NewSimpleClientset() - cmd.clientset = k8s - ca, err := ioutil.TempFile("", "") - require.NoError(t, err) - defer os.RemoveAll(ca.Name()) - err = ioutil.WriteFile(ca.Name(), []byte(caCert), 0644) - require.NoError(t, err) + cases := []struct { + caCert string + caKey string + algorithm string + }{ + { + caCert: caCertEC, + caKey: caKeyEC, + algorithm: "ec", + }, + { + caCert: caCertRSA, + caKey: caKeyRSA, + algorithm: "rsa", + }, + { + // caCertRSA is used because the key is just caKeyRSA encrypted. + caCert: caCertRSA, + caKey: caKeyPKCS8, + algorithm: "pkcs8", + }, + } - key, err := ioutil.TempFile("", "") - require.NoError(t, err) - defer os.RemoveAll(key.Name()) - err = ioutil.WriteFile(key.Name(), []byte(caKey), 0644) - require.NoError(t, err) + for _, c := range cases { + t.Run(c.algorithm, func(t *testing.T) { + ui := cli.NewMockUi() + cmd := Command{UI: ui} + k8s := fake.NewSimpleClientset() + cmd.clientset = k8s - flags := []string{"-name-prefix", "consul", "-ca", ca.Name(), "-key", key.Name()} + ca, err := ioutil.TempFile("", "") + require.NoError(t, err) + defer os.RemoveAll(ca.Name()) + err = ioutil.WriteFile(ca.Name(), []byte(c.caCert), 0644) + require.NoError(t, err) - exitCode := cmd.Run(flags) - require.Equal(t, 0, exitCode) + key, err := ioutil.TempFile("", "") + require.NoError(t, err) + defer os.RemoveAll(key.Name()) + err = ioutil.WriteFile(key.Name(), []byte(c.caKey), 0644) + require.NoError(t, err) - caCertBlock, _ := pem.Decode([]byte(caCert)) - caCertificate, err := x509.ParseCertificate(caCertBlock.Bytes) - require.NoError(t, err) + flags := []string{"-name-prefix", "consul", "-ca", ca.Name(), "-key", key.Name()} - serverCertSecret, err := k8s.CoreV1().Secrets("default").Get(context.Background(), "consul-server-cert", metav1.GetOptions{}) - require.NoError(t, err) - serverCert := serverCertSecret.Data[corev1.TLSCertKey] - serverKey := serverCertSecret.Data[corev1.TLSPrivateKeyKey] + exitCode := cmd.Run(flags) + require.Equal(t, 0, exitCode) - certBlock, _ := pem.Decode(serverCert) - certificate, err := x509.ParseCertificate(certBlock.Bytes) - require.NoError(t, err) - require.False(t, certificate.IsCA) - require.Equal(t, []string{"server.dc1.consul", "localhost"}, certificate.DNSNames) - require.Equal(t, []net.IP{net.ParseIP("127.0.0.1").To4()}, certificate.IPAddresses) + caCertBlock, _ := pem.Decode([]byte(c.caCert)) + caCertificate, err := x509.ParseCertificate(caCertBlock.Bytes) + require.NoError(t, err) - keyBlock, _ := pem.Decode(serverKey) - privateKey, err := x509.ParseECPrivateKey(keyBlock.Bytes) - require.NoError(t, err) - require.Equal(t, &privateKey.PublicKey, certificate.PublicKey) + serverCertSecret, err := k8s.CoreV1().Secrets("default").Get(context.Background(), "consul-server-cert", metav1.GetOptions{}) + require.NoError(t, err) + serverCert := serverCertSecret.Data[corev1.TLSCertKey] + serverKey := serverCertSecret.Data[corev1.TLSPrivateKeyKey] - require.NoError(t, certificate.CheckSignatureFrom(caCertificate)) + certBlock, _ := pem.Decode(serverCert) + certificate, err := x509.ParseCertificate(certBlock.Bytes) + require.NoError(t, err) + require.False(t, certificate.IsCA) + require.Equal(t, []string{"server.dc1.consul", "localhost"}, certificate.DNSNames) + require.Equal(t, []net.IP{net.ParseIP("127.0.0.1").To4()}, certificate.IPAddresses) + + keyBlock, _ := pem.Decode(serverKey) + privateKey, err := x509.ParseECPrivateKey(keyBlock.Bytes) + require.NoError(t, err) + require.Equal(t, &privateKey.PublicKey, certificate.PublicKey) + + require.NoError(t, certificate.CheckSignatureFrom(caCertificate)) + + }) + } } func TestRun_UpdatesServerCertificatesWithExistingCertsAsFiles(t *testing.T) { @@ -126,13 +155,13 @@ func TestRun_UpdatesServerCertificatesWithExistingCertsAsFiles(t *testing.T) { ca, err := ioutil.TempFile("", "") require.NoError(t, err) defer os.RemoveAll(ca.Name()) - err = ioutil.WriteFile(ca.Name(), []byte(caCert), 0644) + err = ioutil.WriteFile(ca.Name(), []byte(caCertEC), 0644) require.NoError(t, err) key, err := ioutil.TempFile("", "") require.NoError(t, err) defer os.RemoveAll(key.Name()) - err = ioutil.WriteFile(key.Name(), []byte(caKey), 0644) + err = ioutil.WriteFile(key.Name(), []byte(caKeyEC), 0644) require.NoError(t, err) flags := []string{"-name-prefix", "consul", "-ca", ca.Name(), "-key", key.Name(), "-additional-dnsname", "test.dns.name"} @@ -140,7 +169,7 @@ func TestRun_UpdatesServerCertificatesWithExistingCertsAsFiles(t *testing.T) { exitCode := cmd.Run(flags) require.Equal(t, 0, exitCode) - caCertBlock, _ := pem.Decode([]byte(caCert)) + caCertBlock, _ := pem.Decode([]byte(caCertEC)) caCertificate, err := x509.ParseCertificate(caCertBlock.Bytes) require.NoError(t, err) @@ -176,7 +205,7 @@ func TestRun_CreatesServerCertificatesWithExistingCertsAsSecrets(t *testing.T) { Namespace: "default", }, Data: map[string][]byte{ - corev1.TLSCertKey: []byte(caCert), + corev1.TLSCertKey: []byte(caCertEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -188,7 +217,7 @@ func TestRun_CreatesServerCertificatesWithExistingCertsAsSecrets(t *testing.T) { Namespace: "default", }, Data: map[string][]byte{ - corev1.TLSPrivateKeyKey: []byte(caKey), + corev1.TLSPrivateKeyKey: []byte(caKeyEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -201,7 +230,7 @@ func TestRun_CreatesServerCertificatesWithExistingCertsAsSecrets(t *testing.T) { exitCode := cmd.Run(flags) require.Equal(t, 0, exitCode) - caCertBlock, _ := pem.Decode([]byte(caCert)) + caCertBlock, _ := pem.Decode([]byte(caCertEC)) caCertificate, err := x509.ParseCertificate(caCertBlock.Bytes) require.NoError(t, err) @@ -265,7 +294,7 @@ func TestRun_UpdatesServerCertificatesWithExistingCertsAsSecrets(t *testing.T) { Namespace: "default", }, Data: map[string][]byte{ - corev1.TLSCertKey: []byte(caCert), + corev1.TLSCertKey: []byte(caCertEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -277,7 +306,7 @@ func TestRun_UpdatesServerCertificatesWithExistingCertsAsSecrets(t *testing.T) { Namespace: "default", }, Data: map[string][]byte{ - corev1.TLSPrivateKeyKey: []byte(caKey), + corev1.TLSPrivateKeyKey: []byte(caKeyEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -300,7 +329,7 @@ func TestRun_UpdatesServerCertificatesWithExistingCertsAsSecrets(t *testing.T) { exitCode := cmd.Run(flags) require.Equal(t, 0, exitCode) - caCertBlock, _ := pem.Decode([]byte(caCert)) + caCertBlock, _ := pem.Decode([]byte(caCertEC)) caCertificate, err := x509.ParseCertificate(caCertBlock.Bytes) require.NoError(t, err) @@ -337,7 +366,7 @@ func TestRun_CreatesServerCertificatesWithExpiryWithinSpecifiedDays(t *testing.T Namespace: "default", }, Data: map[string][]byte{ - corev1.TLSCertKey: []byte(caCert), + corev1.TLSCertKey: []byte(caCertEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -349,7 +378,7 @@ func TestRun_CreatesServerCertificatesWithExpiryWithinSpecifiedDays(t *testing.T Namespace: "default", }, Data: map[string][]byte{ - corev1.TLSPrivateKeyKey: []byte(caKey), + corev1.TLSPrivateKeyKey: []byte(caKeyEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -382,7 +411,7 @@ func TestRun_CreatesServerCertificatesWithProvidedHosts(t *testing.T) { Namespace: "default", }, Data: map[string][]byte{ - corev1.TLSCertKey: []byte(caCert), + corev1.TLSCertKey: []byte(caCertEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -394,7 +423,7 @@ func TestRun_CreatesServerCertificatesWithProvidedHosts(t *testing.T) { Namespace: "default", }, Data: map[string][]byte{ - corev1.TLSPrivateKeyKey: []byte(caKey), + corev1.TLSPrivateKeyKey: []byte(caKeyEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -428,7 +457,7 @@ func TestRun_CreatesServerCertificatesWithSpecifiedDomainAndDC(t *testing.T) { Namespace: "default", }, Data: map[string][]byte{ - corev1.TLSCertKey: []byte(caCert), + corev1.TLSCertKey: []byte(caCertEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -440,7 +469,7 @@ func TestRun_CreatesServerCertificatesWithSpecifiedDomainAndDC(t *testing.T) { Namespace: "default", }, Data: map[string][]byte{ - corev1.TLSPrivateKeyKey: []byte(caKey), + corev1.TLSPrivateKeyKey: []byte(caKeyEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -481,7 +510,7 @@ func TestRun_CreatesServerCertificatesInSpecifiedNamespace(t *testing.T) { Namespace: namespace, }, Data: map[string][]byte{ - corev1.TLSCertKey: []byte(caCert), + corev1.TLSCertKey: []byte(caCertEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -493,7 +522,7 @@ func TestRun_CreatesServerCertificatesInSpecifiedNamespace(t *testing.T) { Namespace: namespace, }, Data: map[string][]byte{ - corev1.TLSPrivateKeyKey: []byte(caKey), + corev1.TLSPrivateKeyKey: []byte(caKeyEC), }, Type: corev1.SecretTypeOpaque, }, metav1.CreateOptions{}) @@ -508,7 +537,7 @@ func TestRun_CreatesServerCertificatesInSpecifiedNamespace(t *testing.T) { } const ( - caCert string = `-----BEGIN CERTIFICATE----- + caCertEC string = `-----BEGIN CERTIFICATE----- MIIDPjCCAuWgAwIBAgIRAOjdIMIYBXgeoXBDydhFImcwCgYIKoZIzj0EAwIwgZEx CzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj bzEaMBgGA1UECRMRMTAxIFNlY29uZCBTdHJlZXQxDjAMBgNVBBETBTk0MTA1MRcw @@ -529,7 +558,7 @@ WBJ2jlEV/kttcHlcHpvyO3GHCp3AE+G4f27NWqYdYeACIDJkx6OjZBU7i4K3HSrO qlxZIl+NFZSHr8XS6BFNB8vc -----END CERTIFICATE-----` - caKey string = `-----BEGIN EC PRIVATE KEY----- + caKeyEC string = `-----BEGIN EC PRIVATE KEY----- MHcCAQEEIO+ASjxFB5gYZju94Ujx81ykp54K53b1TvQNQW/zgbFqoAoGCCqGSM49 AwEHoUQDQgAEvETlXGiuMdIH3nOTf/1RGYmBoZA9RaaDp1T9kcABGuzoxEA+P7VO rd4cnIiTnYqkslAdqcXWmoFEubPFTuKghw== @@ -560,4 +589,82 @@ MHcCAQEEINVuQ1fmOWH5HDG7wEqB1KObSs7q26czY7P+WLhtLDZPoAoGCCqGSM49 AwEHoUQDQgAEu6FUB4WbJpJmXe9cXC2vf9xlvLB5aj9lfAzg4uPL+yXHUpHMYyZy tdsZa0jHMVkDIrNoL8nmxu6X578xNY304w== -----END EC PRIVATE KEY-----` + + caCertRSA string = `-----BEGIN CERTIFICATE----- +MIIDGjCCAgICCQC9IJfDAbKSIjANBgkqhkiG9w0BAQsFADBPMQswCQYDVQQGEwJD +QTEZMBcGA1UECAwQQnJpdGlzaCBDb2x1bWJpYTERMA8GA1UEBwwIVmFuY292ZXIx +EjAQBgNVBAoMCUhhc2hpQ29ycDAeFw0yMTExMDQyMjQ0MjJaFw0yMTEyMDQyMjQ0 +MjJaME8xCzAJBgNVBAYTAkNBMRkwFwYDVQQIDBBCcml0aXNoIENvbHVtYmlhMREw +DwYDVQQHDAhWYW5jb3ZlcjESMBAGA1UECgwJSGFzaGlDb3JwMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxTVd5sFGuVOZxkPv3tE69khUToVcRb85NRWW +eWBSyrTE4UWr06kG4reSTVrGgR2hojrP4nzVynu7EslCJITb6Df5sn34bKVDpqWJ +gDFJoEYoTzajRxEDjSkwau+iPhuaJ6pB97+JimOg0Jnqe0QVZ2NtjwgpXYSGkevn +iVxZHaurLxnhDry5KyDJ79p48c7aKNxAxU2syrhKkrWNJaCg4WVTOc/eQU4elUZb +TwYIZ/Zi4gOkS+vz0ceggRmXg5MzYT6cBlccHRrA7BaSRkoD7bNbDh+mRTz67UgO +KUjIi+o1TsUhmvO2Know+zIGd1mfAf9qFT+4KXPFh3yN5DeMkQIDAQABMA0GCSqG +SIb3DQEBCwUAA4IBAQC6LAK0NnmnxuWvKZano3hI9DPRlktB4LVfYSBNFnQllxUC +ZYBIouJXFKK4dTccMkgLlQU7hFXj/YWdSRmf78w/w0GbWYAnUDnGfYro7+ZRUtFV +v7FT+xV2hFe+2cp4+btux5kfqD6OC58Gp9FWXMzRhJCWSDAk2rIYJ2MM7og+ad+Q +mJAYoOBLuY1rXc080v0Vdcl3tQ24UvvvLhuyOyL795OaZZl3uVvbaNHpM8lfJNEg +XfsbHpePEKd9ORLV6jUirl0YheqY8Mdx5hfwFHi1FL4eH6vzRm6GF2hUkkfjOUGO +x8JijLHx5rnkFyNOynhoH8QlwYeMPZbc4js7DWuG +-----END CERTIFICATE-----` + + caKeyRSA string = `-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAxTVd5sFGuVOZxkPv3tE69khUToVcRb85NRWWeWBSyrTE4UWr +06kG4reSTVrGgR2hojrP4nzVynu7EslCJITb6Df5sn34bKVDpqWJgDFJoEYoTzaj +RxEDjSkwau+iPhuaJ6pB97+JimOg0Jnqe0QVZ2NtjwgpXYSGkevniVxZHaurLxnh +Dry5KyDJ79p48c7aKNxAxU2syrhKkrWNJaCg4WVTOc/eQU4elUZbTwYIZ/Zi4gOk +S+vz0ceggRmXg5MzYT6cBlccHRrA7BaSRkoD7bNbDh+mRTz67UgOKUjIi+o1TsUh +mvO2Know+zIGd1mfAf9qFT+4KXPFh3yN5DeMkQIDAQABAoH/E0Ii6WX2giKn4bTA +uAG2wFZP5Vsgp68E5yo0h6Xgb+s3Tsh+/yyCf6FtqCA1QmaiYjVcF8IZHqz2l98P +loFi+Ep/F+81U2bQNHX1947Yoc44IYQ0bbw7nI1pLQg5z9biNv1pc8hApkMUcUqW +m3MKpA4RpOYnI/rNKXLgKYnbKgptyniJSyFm+pOLgpSnwZIiSIBqHnppHS1b8Bjq +H2ZYqEYNB7dHLu0HpHB1zGVC4CAzmBqtLw4fNDp1lsHTis0SJpRuBiD5IZU6+1TS +QvgkmfJKStRFIT+0YRap0J+rSYtqwPalPPbV4ePfZTpj4d9Ll0Xx97Pn3oinUQgl +auhBAoGBAOIeH5tEaj3U8DTNGGMWmMBVediJEhqDITyjPVGoKZAt+29tqwlDg+aw +hEEGgaIOPE+mQ3CEbvJnRC4Z/ntYRJpv1arBziRQKfznyb3yyFvy/JBSkNEkyFhz +KHYv/uQyg8XHIAIE41IpKdUk9MZ6BVvHjFdBbU01KerPl8Dfm7aJAoGBAN9FNFyv +A61q44oCwGRTxpYzRshHkk7GsO4Jg/vMKpU8bOCvz8GLD7cx38Xt1bV+uUlNGZc6 +4EZxKrv0P9Fsj//WREc+0K11U3aN6HIYNdVV9Vel2v6Bis8+zTzNY6fSF4sx1Dw9 +5q1BkE6sP3IPHz58Tt0pWNW8lmucZS7Q3KPJAoGBAJuy0GKytlFDOe+xtfQtEBuH +//GpWMzmtFEzujprB8uezf6JTnd/hOipbTf1SfgTw1W5D8D/gAHsN5djEMdQHVUW +YtNExjRc+ryJwnHIJkyiQWUDZXKN2GKHUToojGQHoJLkLVcWlIzziTmaS+4LAXuU +KT+/7op2bBmivkTx9B+5AoGBALyJxhPWPra8onSyqiCOlg3UMxuBRM18/3+jTW7e +E79+DTsXe8smURkT5rFPi739yx1ZHBkWwLj7a2jYcuO4V0lleLbpFnLDtr1QTE+8 +ngkO02U2S13LqpojoFCN6G+Y/ASxCVXtt9Pqn5+v2MvKdUng0v/zoG6tGCC7Kr6D +5S3xAoGAZTYnX/rV1n2YuVvd12T9Xs2EBD9Q3FfL/oDfchU2nWiXyQA8HXhb8aBw +5Mw4BOuo0JgkSTqIxqda10tAViNeqlNiQKvOMt9y8Ugl4eEd4SdutmdTZuVPwK4/ +yLi0ot+KP/8sbKAZjcAiJJIZFsqVY4wRdhSo3jzI72Zsx9CqJvE= +-----END RSA PRIVATE KEY-----` + + // caKeyPKCS8 is caKeyRSA converted to PKCS8 form. + caKeyPKCS8 string = `-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDFNV3mwUa5U5nG +Q+/e0Tr2SFROhVxFvzk1FZZ5YFLKtMThRavTqQbit5JNWsaBHaGiOs/ifNXKe7sS +yUIkhNvoN/myffhspUOmpYmAMUmgRihPNqNHEQONKTBq76I+G5onqkH3v4mKY6DQ +mep7RBVnY22PCCldhIaR6+eJXFkdq6svGeEOvLkrIMnv2njxztoo3EDFTazKuEqS +tY0loKDhZVM5z95BTh6VRltPBghn9mLiA6RL6/PRx6CBGZeDkzNhPpwGVxwdGsDs +FpJGSgPts1sOH6ZFPPrtSA4pSMiL6jVOxSGa87YqejD7MgZ3WZ8B/2oVP7gpc8WH +fI3kN4yRAgMBAAECgf8TQiLpZfaCIqfhtMC4AbbAVk/lWyCnrwTnKjSHpeBv6zdO +yH7/LIJ/oW2oIDVCZqJiNVwXwhkerPaX3w+WgWL4Sn8X7zVTZtA0dfX3jtihzjgh +hDRtvDucjWktCDnP1uI2/WlzyECmQxRxSpabcwqkDhGk5icj+s0pcuApidsqCm3K +eIlLIWb6k4uClKfBkiJIgGoeemkdLVvwGOofZlioRg0Ht0cu7QekcHXMZULgIDOY +Gq0vDh80OnWWwdOKzRImlG4GIPkhlTr7VNJC+CSZ8kpK1EUhP7RhFqnQn6tJi2rA +9qU89tXh499lOmPh30uXRfH3s+feiKdRCCVq6EECgYEA4h4fm0RqPdTwNM0YYxaY +wFV52IkSGoMhPKM9UagpkC37b22rCUOD5rCEQQaBog48T6ZDcIRu8mdELhn+e1hE +mm/VqsHOJFAp/OfJvfLIW/L8kFKQ0STIWHModi/+5DKDxccgAgTjUikp1ST0xnoF +W8eMV0FtTTUp6s+XwN+btokCgYEA30U0XK8DrWrjigLAZFPGljNGyEeSTsaw7gmD ++8wqlTxs4K/PwYsPtzHfxe3VtX65SU0ZlzrgRnEqu/Q/0WyP/9ZERz7QrXVTdo3o +chg11VX1V6Xa/oGKzz7NPM1jp9IXizHUPD3mrUGQTqw/cg8fPnxO3SlY1byWa5xl +LtDco8kCgYEAm7LQYrK2UUM577G19C0QG4f/8alYzOa0UTO6OmsHy57N/olOd3+E +6KltN/VJ+BPDVbkPwP+AAew3l2MQx1AdVRZi00TGNFz6vInCccgmTKJBZQNlco3Y +YodROiiMZAegkuQtVxaUjPOJOZpL7gsBe5QpP7/uinZsGaK+RPH0H7kCgYEAvInG +E9Y+tryidLKqII6WDdQzG4FEzXz/f6NNbt4Tv34NOxd7yyZRGRPmsU+Lvf3LHVkc +GRbAuPtraNhy47hXSWV4tukWcsO2vVBMT7yeCQ7TZTZLXcuqmiOgUI3ob5j8BLEJ +Ve230+qfn6/Yy8p1SeDS//Ogbq0YILsqvoPlLfECgYBlNidf+tXWfZi5W93XZP1e +zYQEP1DcV8v+gN9yFTadaJfJADwdeFvxoHDkzDgE66jQmCRJOojGp1rXS0BWI16q +U2JAq84y33LxSCXh4R3hJ262Z1Nm5U/Arj/IuLSi34o//yxsoBmNwCIkkhkWypVj +jBF2FKjePMjvZmzH0Kom8Q== +-----END PRIVATE KEY-----` ) From 26b49ed7c3e0061d6abae924e0c20645411e8155 Mon Sep 17 00:00:00 2001 From: NicoletaPopoviciu <87660255+NicoletaPopoviciu@users.noreply.github.com> Date: Fri, 5 Nov 2021 18:25:56 -0400 Subject: [PATCH 123/418] Cleanup additional resources during uninstall (#820) * delete any jobs, cluster roles, cluster roles bindings during uninstall * augment the uninstall tests w negative test Co-authored-by: Kyle Schochenmaier Co-authored-by: David Yu --- CHANGELOG.md | 2 + cli/cmd/uninstall/uninstall.go | 104 +++++++++++++++- cli/cmd/uninstall/uninstall_test.go | 177 +++++++++++++++++++++++++++- 3 files changed, 277 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23b0621ec1..5f86399f0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ IMPROVEMENTS: * Control Plane * TLS: Support PKCS1 and PKCS8 private keys for Consul certificate authority. [[GH-843](https://github.com/hashicorp/consul-k8s/pull/843)] +* CLI + * Delete jobs, cluster roles, and cluster role bindings on `uninstall`. [[GH-820](https://github.com/hashicorp/consul-k8s/pull/820)] BUG FIXES: * Control Plane diff --git a/cli/cmd/uninstall/uninstall.go b/cli/cmd/uninstall/uninstall.go index 0e218c5d0f..0e85ea4eef 100644 --- a/cli/cmd/uninstall/uninstall.go +++ b/cli/cmd/uninstall/uninstall.go @@ -257,10 +257,11 @@ func (c *Command) Run(args []string) int { c.UI.Output("Name: %s", foundReleaseName, terminal.WithInfoStyle()) c.UI.Output("Namespace %s", foundReleaseNamespace, terminal.WithInfoStyle()) } - // Prompt with a warning for approval before deleting PVCs, Secrets, Service Accounts, Roles, and Role Bindings. + // Prompt with a warning for approval before deleting PVCs, Secrets, Service Accounts, Roles, Role Bindings, + // Jobs, Cluster Roles, and Cluster Role Bindings. if !c.flagAutoApprove { confirmation, err := c.UI.Input(&terminal.Input{ - Prompt: fmt.Sprintf("WARNING: Proceed with deleting PVCs, Secrets, Service Accounts, Roles, and Role Bindings for the following installation? \n\n Name: %s \n Namespace: %s \n\n Only approve if all data from this installation can be deleted. (y/N)", foundReleaseName, foundReleaseNamespace), + Prompt: fmt.Sprintf("WARNING: Proceed with deleting PVCs, Secrets, Service Accounts, Roles, Role Bindings, Jobs, Cluster Roles, and Cluster Role Bindings for the following installation? \n\n Name: %s \n Namespace: %s \n\n Only approve if all data from this installation can be deleted. (y/N)", foundReleaseName, foundReleaseNamespace), Style: terminal.WarningStyle, Secret: false, }) @@ -299,6 +300,21 @@ func (c *Command) Run(args []string) int { return 1 } + if err := c.deleteJobs(foundReleaseName, foundReleaseNamespace); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if err := c.deleteClusterRoles(foundReleaseName); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if err := c.deleteClusterRoleBindings(foundReleaseName); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + return 0 } @@ -476,3 +492,87 @@ func (c *Command) deleteRoleBindings(foundReleaseName, foundReleaseNamespace str } return nil } + +// deleteJobs deletes jobs that have the label release={{foundReleaseName}}. +func (c *Command) deleteJobs(foundReleaseName, foundReleaseNamespace string) error { + var jobNames []string + jobSelector := metav1.ListOptions{LabelSelector: fmt.Sprintf("release=%s", foundReleaseName)} + jobs, err := c.kubernetes.BatchV1().Jobs(foundReleaseNamespace).List(c.Ctx, jobSelector) + if err != nil { + return fmt.Errorf("deleteJobs: %s", err) + } + if len(jobs.Items) == 0 { + c.UI.Output("No Consul jobs found.", terminal.WithSuccessStyle()) + return nil + } + for _, job := range jobs.Items { + err := c.kubernetes.BatchV1().Jobs(foundReleaseNamespace).Delete(c.Ctx, job.Name, metav1.DeleteOptions{}) + if err != nil { + return fmt.Errorf("deleteJobs: error deleting Job %q: %s", job.Name, err) + } + jobNames = append(jobNames, job.Name) + } + if len(jobNames) > 0 { + for _, job := range jobNames { + c.UI.Output("Deleted Jobs => %s", job, terminal.WithSuccessStyle()) + } + c.UI.Output("Consul jobs deleted.", terminal.WithSuccessStyle()) + } + return nil +} + +// deleteClusterRoles deletes clusterRoles that have the label release={{foundReleaseName}}. +func (c *Command) deleteClusterRoles(foundReleaseName string) error { + var clusterRolesNames []string + clusterRolesSelector := metav1.ListOptions{LabelSelector: fmt.Sprintf("release=%s", foundReleaseName)} + clusterRoles, err := c.kubernetes.RbacV1().ClusterRoles().List(c.Ctx, clusterRolesSelector) + if err != nil { + return fmt.Errorf("deleteClusterRoles: %s", err) + } + if len(clusterRoles.Items) == 0 { + c.UI.Output("No Consul cluster roles found.", terminal.WithSuccessStyle()) + return nil + } + for _, clusterRole := range clusterRoles.Items { + err := c.kubernetes.RbacV1().ClusterRoles().Delete(c.Ctx, clusterRole.Name, metav1.DeleteOptions{}) + if err != nil { + return fmt.Errorf("deleteClusterRoles: error deleting cluster role %q: %s", clusterRole.Name, err) + } + clusterRolesNames = append(clusterRolesNames, clusterRole.Name) + } + if len(clusterRolesNames) > 0 { + for _, clusterRole := range clusterRolesNames { + c.UI.Output("Deleted cluster role => %s", clusterRole, terminal.WithSuccessStyle()) + } + c.UI.Output("Consul cluster roles deleted.", terminal.WithSuccessStyle()) + } + return nil +} + +// deleteClusterRoleBindings deletes clusterrolebindings that have the label release={{foundReleaseName}}. +func (c *Command) deleteClusterRoleBindings(foundReleaseName string) error { + var clusterRoleBindingsNames []string + clusterRoleBindingsSelector := metav1.ListOptions{LabelSelector: fmt.Sprintf("release=%s", foundReleaseName)} + clusterRoleBindings, err := c.kubernetes.RbacV1().ClusterRoleBindings().List(c.Ctx, clusterRoleBindingsSelector) + if err != nil { + return fmt.Errorf("deleteClusterRoleBindings: %s", err) + } + if len(clusterRoleBindings.Items) == 0 { + c.UI.Output("No Consul cluster role bindings found.", terminal.WithSuccessStyle()) + return nil + } + for _, clusterRoleBinding := range clusterRoleBindings.Items { + err := c.kubernetes.RbacV1().ClusterRoleBindings().Delete(c.Ctx, clusterRoleBinding.Name, metav1.DeleteOptions{}) + if err != nil { + return fmt.Errorf("deleteClusterRoleBindings: error deleting cluster role binding %q: %s", clusterRoleBinding.Name, err) + } + clusterRoleBindingsNames = append(clusterRoleBindingsNames, clusterRoleBinding.Name) + } + if len(clusterRoleBindingsNames) > 0 { + for _, clusterRoleBinding := range clusterRoleBindingsNames { + c.UI.Output("Deleted cluster role binding => %s", clusterRoleBinding, terminal.WithSuccessStyle()) + } + c.UI.Output("Consul cluster role bindings deleted.", terminal.WithSuccessStyle()) + } + return nil +} diff --git a/cli/cmd/uninstall/uninstall_test.go b/cli/cmd/uninstall/uninstall_test.go index 95696b481c..6e46f51506 100644 --- a/cli/cmd/uninstall/uninstall_test.go +++ b/cli/cmd/uninstall/uninstall_test.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/require" + batchv1 "k8s.io/api/batch/v1" v1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -52,6 +53,7 @@ func TestDeletePVCs(t *testing.T) { pvcs, err := c.kubernetes.CoreV1().PersistentVolumeClaims("default").List(context.Background(), metav1.ListOptions{}) require.NoError(t, err) require.Len(t, pvcs.Items, 1) + require.Equal(t, pvcs.Items[0].Name, pvc3.Name) } func TestDeleteSecrets(t *testing.T) { @@ -73,15 +75,26 @@ func TestDeleteSecrets(t *testing.T) { }, }, } + secret3 := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "unrelated-test-secret3", + Labels: map[string]string{ + "release": "unrelated", + }, + }, + } _, err := c.kubernetes.CoreV1().Secrets("default").Create(context.Background(), secret, metav1.CreateOptions{}) require.NoError(t, err) _, err = c.kubernetes.CoreV1().Secrets("default").Create(context.Background(), secret2, metav1.CreateOptions{}) require.NoError(t, err) + _, err = c.kubernetes.CoreV1().Secrets("default").Create(context.Background(), secret3, metav1.CreateOptions{}) + require.NoError(t, err) err = c.deleteSecrets("consul", "default") require.NoError(t, err) secrets, err := c.kubernetes.CoreV1().Secrets("default").List(context.Background(), metav1.ListOptions{}) require.NoError(t, err) - require.Len(t, secrets.Items, 0) + require.Len(t, secrets.Items, 1) + require.Equal(t, secrets.Items[0].Name, secret3.Name) } func TestDeleteServiceAccounts(t *testing.T) { @@ -103,15 +116,26 @@ func TestDeleteServiceAccounts(t *testing.T) { }, }, } + sa3 := &v1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-sa3", + Labels: map[string]string{ + "release": "unrelated", + }, + }, + } _, err := c.kubernetes.CoreV1().ServiceAccounts("default").Create(context.Background(), sa, metav1.CreateOptions{}) require.NoError(t, err) _, err = c.kubernetes.CoreV1().ServiceAccounts("default").Create(context.Background(), sa2, metav1.CreateOptions{}) require.NoError(t, err) + _, err = c.kubernetes.CoreV1().ServiceAccounts("default").Create(context.Background(), sa3, metav1.CreateOptions{}) + require.NoError(t, err) err = c.deleteServiceAccounts("consul", "default") require.NoError(t, err) sas, err := c.kubernetes.CoreV1().ServiceAccounts("default").List(context.Background(), metav1.ListOptions{}) require.NoError(t, err) - require.Len(t, sas.Items, 0) + require.Len(t, sas.Items, 1) + require.Equal(t, sas.Items[0].Name, sa3.Name) } func TestDeleteRoles(t *testing.T) { @@ -133,15 +157,26 @@ func TestDeleteRoles(t *testing.T) { }, }, } + role3 := &rbacv1.Role{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-role3", + Labels: map[string]string{ + "release": "unrelated", + }, + }, + } _, err := c.kubernetes.RbacV1().Roles("default").Create(context.Background(), role, metav1.CreateOptions{}) require.NoError(t, err) _, err = c.kubernetes.RbacV1().Roles("default").Create(context.Background(), role2, metav1.CreateOptions{}) require.NoError(t, err) + _, err = c.kubernetes.RbacV1().Roles("default").Create(context.Background(), role3, metav1.CreateOptions{}) + require.NoError(t, err) err = c.deleteRoles("consul", "default") require.NoError(t, err) roles, err := c.kubernetes.RbacV1().Roles("default").List(context.Background(), metav1.ListOptions{}) require.NoError(t, err) - require.Len(t, roles.Items, 0) + require.Len(t, roles.Items, 1) + require.Equal(t, roles.Items[0].Name, role3.Name) } func TestDeleteRoleBindings(t *testing.T) { @@ -163,15 +198,149 @@ func TestDeleteRoleBindings(t *testing.T) { }, }, } + rolebinding3 := &rbacv1.RoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-role3", + Labels: map[string]string{ + "release": "unrelated", + }, + }, + } _, err := c.kubernetes.RbacV1().RoleBindings("default").Create(context.Background(), rolebinding, metav1.CreateOptions{}) require.NoError(t, err) _, err = c.kubernetes.RbacV1().RoleBindings("default").Create(context.Background(), rolebinding2, metav1.CreateOptions{}) require.NoError(t, err) + _, err = c.kubernetes.RbacV1().RoleBindings("default").Create(context.Background(), rolebinding3, metav1.CreateOptions{}) + require.NoError(t, err) err = c.deleteRoleBindings("consul", "default") require.NoError(t, err) rolebindings, err := c.kubernetes.RbacV1().RoleBindings("default").List(context.Background(), metav1.ListOptions{}) require.NoError(t, err) - require.Len(t, rolebindings.Items, 0) + require.Len(t, rolebindings.Items, 1) + require.Equal(t, rolebindings.Items[0].Name, rolebinding3.Name) +} + +func TestDeleteJobs(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + job := &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-job1", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + job2 := &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-job2", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + job3 := &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-job3", + Labels: map[string]string{ + "release": "unrelated", + }, + }, + } + _, err := c.kubernetes.BatchV1().Jobs("default").Create(context.Background(), job, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.BatchV1().Jobs("default").Create(context.Background(), job2, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.BatchV1().Jobs("default").Create(context.Background(), job3, metav1.CreateOptions{}) + require.NoError(t, err) + err = c.deleteJobs("consul", "default") + require.NoError(t, err) + jobs, err := c.kubernetes.BatchV1().Jobs("default").List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + require.Len(t, jobs.Items, 1) + require.Equal(t, jobs.Items[0].Name, job3.Name) +} + +func TestDeleteClusterRoles(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + clusterrole := &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-clusterrole1", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + clusterrole2 := &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-clusterrole2", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + clusterrole3 := &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-clusterrole3", + Labels: map[string]string{ + "release": "unrelated", + }, + }, + } + _, err := c.kubernetes.RbacV1().ClusterRoles().Create(context.Background(), clusterrole, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.RbacV1().ClusterRoles().Create(context.Background(), clusterrole2, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.RbacV1().ClusterRoles().Create(context.Background(), clusterrole3, metav1.CreateOptions{}) + require.NoError(t, err) + err = c.deleteClusterRoles("consul") + require.NoError(t, err) + clusterroles, err := c.kubernetes.RbacV1().ClusterRoles().List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + require.Len(t, clusterroles.Items, 1) + require.Equal(t, clusterroles.Items[0].Name, clusterrole3.Name) +} + +func TestDeleteClusterRoleBindings(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + clusterrolebinding := &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-clusterrolebinding1", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + clusterrolebinding2 := &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-clusterrolebinding2", + Labels: map[string]string{ + "release": "consul", + }, + }, + } + clusterrolebinding3 := &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-test-clusterrolebinding3", + Labels: map[string]string{ + "release": "unrelated", + }, + }, + } + _, err := c.kubernetes.RbacV1().ClusterRoleBindings().Create(context.Background(), clusterrolebinding, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.RbacV1().ClusterRoleBindings().Create(context.Background(), clusterrolebinding2, metav1.CreateOptions{}) + require.NoError(t, err) + _, err = c.kubernetes.RbacV1().ClusterRoleBindings().Create(context.Background(), clusterrolebinding3, metav1.CreateOptions{}) + require.NoError(t, err) + err = c.deleteClusterRoleBindings("consul") + require.NoError(t, err) + clusterrolebindings, err := c.kubernetes.RbacV1().ClusterRoleBindings().List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + require.Len(t, clusterrolebindings.Items, 1) + require.Equal(t, clusterrolebindings.Items[0].Name, clusterrolebinding3.Name) } // getInitializedCommand sets up a command struct for tests. From 9e20ed1770e1145b13a95d012fd09ff2d964980d Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Mon, 8 Nov 2021 10:10:49 -0800 Subject: [PATCH 124/418] Prevent using reserved names for ns's/partitions (#846) * Prevent using reserved names for ns's/partitions Some names are reserved by Consul and can't be used for namespaces or partitions. Catching this early before the helm install is a better UX than having the install fail (in the case of partitions) or succeed (in the case of namespaces) and then fail during syncing or injection. --- CHANGELOG.md | 3 ++ charts/consul/templates/_helpers.tpl | 18 +++++++++ .../templates/connect-inject-deployment.yaml | 1 + .../consul/templates/partition-init-job.yaml | 1 + .../templates/sync-catalog-deployment.yaml | 1 + .../test/unit/connect-inject-deployment.bats | 39 ++++++++++++++++++- .../consul/test/unit/partition-init-job.bats | 38 ++++++++++++++++++ .../test/unit/sync-catalog-deployment.bats | 36 +++++++++++++++++ 8 files changed, 136 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f86399f0b..97e3994119 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,9 @@ BUG FIXES: an ACL token. [[GH-677](https://github.com/hashicorp/consul-k8s/issues/677)] * Fix issue where after a `helm upgrade`, users would see `x509: certificate signed by unknown authority.` errors when modifying config entry resources. [[GH-837](https://github.com/hashicorp/consul-k8s/pull/837)] +* Helm Chart + * **(Consul Enterprise only)** Error on Helm install if a reserved name is used for the admin partition name or a + Consul destination namespace for connect or catalog sync. [[GH-846](https://github.com/hashicorp/consul-k8s/pull/846)] ## 0.36.0 (November 02, 2021) diff --git a/charts/consul/templates/_helpers.tpl b/charts/consul/templates/_helpers.tpl index 173eb68cc9..49676dc329 100644 --- a/charts/consul/templates/_helpers.tpl +++ b/charts/consul/templates/_helpers.tpl @@ -119,3 +119,21 @@ This template is for an init container. memory: "50Mi" cpu: "50m" {{- end -}} + +{{/* +Fails when a reserved name is passed in. This should be used to test against +Consul namespaces and partition names. +This template accepts an array that contains two elements. The first element +is the name that's being checked and the second is the name of the values.yaml +key that's setting the name. + +Usage: {{ template "consul.reservedNamesFailer" (list .Values.key "key") }} + +*/}} +{{- define "consul.reservedNamesFailer" -}} +{{- $name := index . 0 -}} +{{- $key := index . 1 -}} +{{- if or (eq "system" $name) (eq "universal" $name) (eq "consul" $name) (eq "operator" $name) (eq "root" $name) }} +{{- fail (cat "The name" $name "set for key" $key "is reserved by Consul for future use." ) }} +{{- end }} +{{- end -}} diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index f3f9f9a754..c12727aaf6 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -8,6 +8,7 @@ {{- if .Values.connectInject.centralConfig }}{{ if .Values.connectInject.centralConfig.proxyDefaults }}{{- if ne (trim .Values.connectInject.centralConfig.proxyDefaults) `{}` }}{{ fail "connectInject.centralConfig.proxyDefaults is no longer supported; instead you must migrate to CRDs (see www.consul.io/docs/k8s/crds/upgrade-to-crds)" }}{{ end }}{{ end }}{{ end -}} {{- if .Values.connectInject.imageEnvoy }}{{ fail "connectInject.imageEnvoy must be specified in global.imageEnvoy" }}{{ end }} {{- if .Values.global.lifecycleSidecarContainer }}{{ fail "global.lifecycleSidecarContainer has been renamed to global.consulSidecarContainer. Please set values using global.consulSidecarContainer." }}{{ end }} +{{- template "consul.reservedNamesFailer" (list .Values.connectInject.consulNamespaces.consulDestinationNamespace "connectInject.consulNamespaces.consulDestinationNamespace") }} # The deployment for running the Connect sidecar injector apiVersion: apps/v1 kind: Deployment diff --git a/charts/consul/templates/partition-init-job.yaml b/charts/consul/templates/partition-init-job.yaml index 10772cd75d..f3e2006a95 100644 --- a/charts/consul/templates/partition-init-job.yaml +++ b/charts/consul/templates/partition-init-job.yaml @@ -1,5 +1,6 @@ {{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} {{- if (and .Values.global.adminPartitions.enabled (not $serverEnabled)) }} +{{- template "consul.reservedNamesFailer" (list .Values.global.adminPartitions.name "global.adminPartitions.name") }} apiVersion: batch/v1 kind: Job metadata: diff --git a/charts/consul/templates/sync-catalog-deployment.yaml b/charts/consul/templates/sync-catalog-deployment.yaml index 50a847b354..6c158204c3 100644 --- a/charts/consul/templates/sync-catalog-deployment.yaml +++ b/charts/consul/templates/sync-catalog-deployment.yaml @@ -1,5 +1,6 @@ {{- $clientEnabled := (or (and (ne (.Values.client.enabled | toString) "-") .Values.client.enabled) (and (eq (.Values.client.enabled | toString) "-") .Values.global.enabled)) }} {{- if (or (and (ne (.Values.syncCatalog.enabled | toString) "-") .Values.syncCatalog.enabled) (and (eq (.Values.syncCatalog.enabled | toString) "-") .Values.global.enabled)) }} +{{- template "consul.reservedNamesFailer" (list .Values.syncCatalog.consulNamespaces.consulDestinationNamespace "syncCatalog.consulNamespaces.consulDestinationNamespace") }} # The deployment for running the sync-catalog pod apiVersion: apps/v1 kind: Deployment diff --git a/charts/consul/test/unit/connect-inject-deployment.bats b/charts/consul/test/unit/connect-inject-deployment.bats index 75df185d3f..a8e23d0c53 100755 --- a/charts/consul/test/unit/connect-inject-deployment.bats +++ b/charts/consul/test/unit/connect-inject-deployment.bats @@ -1512,4 +1512,41 @@ EOF yq '.spec.replicas' | tee /dev/stderr) [ "${actual}" = "3" ] -} \ No newline at end of file +} + +#-------------------------------------------------------------------- +# consulDestinationNamespace reserved name + +@test "connectInject/Deployment: fails when consulDestinationNamespace=system" { + reservedNameTest "system" +} + +@test "connectInject/Deployment: fails when consulDestinationNamespace=universal" { + reservedNameTest "universal" +} + +@test "connectInject/Deployment: fails when consulDestinationNamespace=consul" { + reservedNameTest "consul" +} + +@test "connectInject/Deployment: fails when consulDestinationNamespace=operator" { + reservedNameTest "operator" +} + +@test "connectInject/Deployment: fails when consulDestinationNamespace=root" { + reservedNameTest "root" +} + +# reservedNameTest is a helper function that tests if certain Consul destination +# namespace names fail because the name is reserved. +reservedNameTest() { + cd `chart_dir` + local -r name="$1" + run helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set "connectInject.consulNamespaces.consulDestinationNamespace=$name" . + + [ "$status" -eq 1 ] + [[ "$output" =~ "The name $name set for key connectInject.consulNamespaces.consulDestinationNamespace is reserved by Consul for future use" ]] +} diff --git a/charts/consul/test/unit/partition-init-job.bats b/charts/consul/test/unit/partition-init-job.bats index addf34266e..5dc60e9888 100644 --- a/charts/consul/test/unit/partition-init-job.bats +++ b/charts/consul/test/unit/partition-init-job.bats @@ -110,3 +110,41 @@ load _helpers yq '[.spec.template.spec.containers[0].env[].name] | any(contains("CONSUL_HTTP_TOKEN"))' | tee /dev/stderr) [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# partition reserved name + +@test "partitionInit/Job: fails when adminPartitions.name=system" { + reservedNameTest "system" +} + +@test "partitionInit/Job: fails when adminPartitions.name=universal" { + reservedNameTest "universal" +} + +@test "partitionInit/Job: fails when adminPartitions.name=consul" { + reservedNameTest "consul" +} + +@test "partitionInit/Job: fails when adminPartitions.name=operator" { + reservedNameTest "operator" +} + +@test "partitionInit/Job: fails when adminPartitions.name=root" { + reservedNameTest "root" +} + +# reservedNameTest is a helper function that tests if certain partition names +# fail because the name is reserved. +reservedNameTest() { + cd `chart_dir` + local -r name="$1" + run helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.enabled=false' \ + --set 'global.adminPartitions.enabled=true' \ + --set "global.adminPartitions.name=$name" . + + [ "$status" -eq 1 ] + [[ "$output" =~ "The name $name set for key global.adminPartitions.name is reserved by Consul for future use" ]] +} diff --git a/charts/consul/test/unit/sync-catalog-deployment.bats b/charts/consul/test/unit/sync-catalog-deployment.bats index 904ac699ce..2b297d3cd7 100755 --- a/charts/consul/test/unit/sync-catalog-deployment.bats +++ b/charts/consul/test/unit/sync-catalog-deployment.bats @@ -978,3 +978,39 @@ load _helpers [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# consulDestinationNamespace reserved name + +@test "syncCatalog/Deployment: fails when consulDestinationNamespace=system" { + reservedNameTest "system" +} + +@test "syncCatalog/Deployment: fails when consulDestinationNamespace=universal" { + reservedNameTest "universal" +} + +@test "syncCatalog/Deployment: fails when consulDestinationNamespace=consul" { + reservedNameTest "consul" +} + +@test "syncCatalog/Deployment: fails when consulDestinationNamespace=operator" { + reservedNameTest "operator" +} + +@test "syncCatalog/Deployment: fails when consulDestinationNamespace=root" { + reservedNameTest "root" +} + +# reservedNameTest is a helper function that tests if certain Consul destination +# namespace names fail because the name is reserved. +reservedNameTest() { + cd `chart_dir` + local -r name="$1" + run helm template \ + -s templates/sync-catalog-deployment.yaml \ + --set 'syncCatalog.enabled=true' \ + --set "syncCatalog.consulNamespaces.consulDestinationNamespace=$name" . + + [ "$status" -eq 1 ] + [[ "$output" =~ "The name $name set for key syncCatalog.consulNamespaces.consulDestinationNamespace is reserved by Consul for future use" ]] +} From 5778495b811e4e4eb10ab4d565c8212c227ce047 Mon Sep 17 00:00:00 2001 From: tjhiggins Date: Mon, 8 Nov 2021 13:22:30 -0500 Subject: [PATCH 125/418] Truncate the statefulset pvc name to be max 63 chars (#799) * Truncate the statefulset pvc name to be max 63 chars --- .../consul/templates/server-statefulset.yaml | 4 ++-- .../consul/test/unit/server-statefulset.bats | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index fe2dcff468..2e332cb7ae 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -257,7 +257,7 @@ spec: -config-file=/consul/extra-config/extra-from-values.json \ -server volumeMounts: - - name: data-{{ .Release.Namespace }} + - name: data-{{ .Release.Namespace | trunc 58 | trimSuffix "-" }} mountPath: /consul/data - name: config mountPath: /consul/config @@ -365,7 +365,7 @@ spec: {{- end }} volumeClaimTemplates: - metadata: - name: data-{{ .Release.Namespace }} + name: data-{{ .Release.Namespace | trunc 58 | trimSuffix "-" }} spec: accessModes: - ReadWriteOnce diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 6418cef313..ea10cc163d 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -138,6 +138,28 @@ load _helpers [ "${actual}" = "2" ] } +#-------------------------------------------------------------------- +# volumeClaim name + +@test "server/StatefulSet: no truncation for namespace <= 58 chars" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + . | tee /dev/stderr | + yq -r '.spec.volumeClaimTemplates[0].metadata.name' | tee /dev/stderr) + [ "${actual}" = "data-default" ] +} + +@test "server/StatefulSet: truncation for namespace > 58 chars" { + cd `chart_dir` + local actual=$(helm template \ + -n really-really-really-really-really-really-really-long-namespace \ + -s templates/server-statefulset.yaml \ + . | tee /dev/stderr | + yq -r '.spec.volumeClaimTemplates[0].metadata.name' | tee /dev/stderr) + [ "${actual}" = "data-really-really-really-really-really-really-really-long-name" ] +} + #-------------------------------------------------------------------- # storageClass From 03d4b932256b68ba9fdccba4c00951bb3de275be Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Mon, 8 Nov 2021 11:49:59 -0800 Subject: [PATCH 126/418] Update CHANGELOG.md (#850) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97e3994119..a0637ab958 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ BUG FIXES: * Helm Chart * **(Consul Enterprise only)** Error on Helm install if a reserved name is used for the admin partition name or a Consul destination namespace for connect or catalog sync. [[GH-846](https://github.com/hashicorp/consul-k8s/pull/846)] + * Truncate Persistent Volume Claim names when namespace names are too long. [[GH-799](https://github.com/hashicorp/consul-k8s/pull/799)] ## 0.36.0 (November 02, 2021) From 4f783fecf268d5c45da1cefd24f471557a3b144f Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 9 Nov 2021 16:02:49 -0800 Subject: [PATCH 127/418] Use component label everywhere (#840) * Use component label everywhere Also add a test to ensure every file has it. * Rename component autogeneration => autogenerate --- CHANGELOG.md | 4 ++++ .../consul/templates/client-config-configmap.yaml | 1 + charts/consul/templates/client-daemonset.yaml | 1 + .../consul/templates/client-podsecuritypolicy.yaml | 1 + charts/consul/templates/client-role.yaml | 1 + charts/consul/templates/client-rolebinding.yaml | 1 + .../client-securitycontextconstraints.yaml | 3 ++- charts/consul/templates/client-serviceaccount.yaml | 1 + .../client-snapshot-agent-deployment.yaml | 1 + .../client-snapshot-agent-podsecuritypolicy.yaml | 1 + .../templates/client-snapshot-agent-role.yaml | 1 + .../client-snapshot-agent-rolebinding.yaml | 1 + .../client-snapshot-agent-serviceaccount.yaml | 1 + .../connect-inject-authmethod-clusterrole.yaml | 1 + ...nnect-inject-authmethod-clusterrolebinding.yaml | 1 + .../connect-inject-authmethod-serviceaccount.yaml | 1 + .../templates/connect-inject-clusterrole.yaml | 1 + .../connect-inject-clusterrolebinding.yaml | 1 + .../templates/connect-inject-deployment.yaml | 1 + .../connect-inject-leader-election-role.yaml | 2 +- ...connect-inject-leader-election-rolebinding.yaml | 2 +- .../templates/connect-inject-mutatingwebhook.yaml | 1 + .../connect-inject-podsecuritypolicy.yaml | 1 + .../consul/templates/connect-inject-service.yaml | 1 + .../templates/connect-inject-serviceaccount.yaml | 1 + ...create-federation-secret-podsecuritypolicy.yaml | 1 + .../consul/templates/enterprise-license-job.yaml | 1 + .../enterprise-license-podsecuritypolicy.yaml | 1 + .../consul/templates/enterprise-license-role.yaml | 1 + .../templates/enterprise-license-rolebinding.yaml | 1 + .../enterprise-license-serviceaccount.yaml | 1 + .../gossip-encryption-autogenerate-job.yaml | 3 ++- ...-encryption-autogenerate-podsecuritypolicy.yaml | 1 + .../gossip-encryption-autogenerate-role.yaml | 1 + ...gossip-encryption-autogenerate-rolebinding.yaml | 1 + ...sip-encryption-autogenerate-serviceaccount.yaml | 1 + charts/consul/templates/partition-init-job.yaml | 1 + .../partition-init-podsecuritypolicy.yaml | 1 + charts/consul/templates/partition-init-role.yaml | 1 + .../templates/partition-init-rolebinding.yaml | 1 + .../templates/partition-init-serviceaccount.yaml | 1 + .../consul/templates/partition-name-configmap.yaml | 1 + .../templates/server-acl-init-cleanup-job.yaml | 1 + .../server-acl-init-cleanup-podsecuritypolicy.yaml | 1 + .../templates/server-acl-init-cleanup-role.yaml | 1 + .../server-acl-init-cleanup-rolebinding.yaml | 1 + .../server-acl-init-cleanup-serviceaccount.yaml | 1 + charts/consul/templates/server-acl-init-job.yaml | 1 + .../server-acl-init-podsecuritypolicy.yaml | 1 + charts/consul/templates/server-acl-init-role.yaml | 1 + .../templates/server-acl-init-rolebinding.yaml | 1 + .../templates/server-acl-init-serviceaccount.yaml | 1 + .../consul/templates/server-config-configmap.yaml | 1 + .../consul/templates/server-disruptionbudget.yaml | 1 + .../consul/templates/server-podsecuritypolicy.yaml | 1 + charts/consul/templates/server-role.yaml | 1 + charts/consul/templates/server-rolebinding.yaml | 1 + .../server-securitycontextconstraints.yaml | 1 + charts/consul/templates/server-serviceaccount.yaml | 1 + .../consul/templates/sync-catalog-clusterrole.yaml | 1 + .../templates/sync-catalog-clusterrolebinding.yaml | 1 + .../consul/templates/sync-catalog-deployment.yaml | 1 + .../templates/sync-catalog-podsecuritypolicy.yaml | 1 + .../templates/sync-catalog-serviceaccount.yaml | 1 + charts/consul/templates/tls-init-cleanup-job.yaml | 1 + .../tls-init-cleanup-podsecuritypolicy.yaml | 1 + charts/consul/templates/tls-init-cleanup-role.yaml | 1 + .../templates/tls-init-cleanup-rolebinding.yaml | 1 + .../templates/tls-init-cleanup-serviceaccount.yaml | 1 + charts/consul/templates/tls-init-job.yaml | 1 + .../templates/tls-init-podsecuritypolicy.yaml | 1 + charts/consul/templates/tls-init-role.yaml | 1 + charts/consul/templates/tls-init-rolebinding.yaml | 1 + .../consul/templates/tls-init-serviceaccount.yaml | 1 + charts/consul/test/unit/client-daemonset.bats | 6 +++--- charts/consul/test/unit/helpers.bats | 14 ++++++++++++++ charts/consul/test/unit/server-statefulset.bats | 6 +++--- 77 files changed, 99 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0637ab958..15df277aa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ BUG FIXES: Consul destination namespace for connect or catalog sync. [[GH-846](https://github.com/hashicorp/consul-k8s/pull/846)] * Truncate Persistent Volume Claim names when namespace names are too long. [[GH-799](https://github.com/hashicorp/consul-k8s/pull/799)] +IMPROVEMENTS: +* Helm Chart + * Add `component` labels to all resources. [[GH-840](https://github.com/hashicorp/consul-k8s/pull/840)] + ## 0.36.0 (November 02, 2021) BREAKING CHANGES: diff --git a/charts/consul/templates/client-config-configmap.yaml b/charts/consul/templates/client-config-configmap.yaml index f4e5ade095..4ba0785576 100644 --- a/charts/consul/templates/client-config-configmap.yaml +++ b/charts/consul/templates/client-config-configmap.yaml @@ -11,6 +11,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client data: extra-from-values.json: |- {{ tpl .Values.client.extraConfig . | trimAll "\"" | indent 4 }} diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index d4e1c05107..7689b3ff8a 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -13,6 +13,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client spec: {{- if .Values.client.updateStrategy }} updateStrategy: diff --git a/charts/consul/templates/client-podsecuritypolicy.yaml b/charts/consul/templates/client-podsecuritypolicy.yaml index 81ecd8d640..15950f75fd 100644 --- a/charts/consul/templates/client-podsecuritypolicy.yaml +++ b/charts/consul/templates/client-podsecuritypolicy.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client spec: privileged: false # Required to prevent escalations to root. diff --git a/charts/consul/templates/client-role.yaml b/charts/consul/templates/client-role.yaml index 8295a5d1f8..7f05b82e6b 100644 --- a/charts/consul/templates/client-role.yaml +++ b/charts/consul/templates/client-role.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client {{- if (or .Values.global.acls.manageSystemACLs .Values.global.enablePodSecurityPolicies .Values.global.openshift.enabled) }} rules: {{- if .Values.global.enablePodSecurityPolicies }} diff --git a/charts/consul/templates/client-rolebinding.yaml b/charts/consul/templates/client-rolebinding.yaml index 25681c6e14..b034c70e55 100644 --- a/charts/consul/templates/client-rolebinding.yaml +++ b/charts/consul/templates/client-rolebinding.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client roleRef: apiGroup: rbac.authorization.k8s.io kind: Role diff --git a/charts/consul/templates/client-securitycontextconstraints.yaml b/charts/consul/templates/client-securitycontextconstraints.yaml index 0328abbd9c..07e7711384 100644 --- a/charts/consul/templates/client-securitycontextconstraints.yaml +++ b/charts/consul/templates/client-securitycontextconstraints.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client annotations: kubernetes.io/description: {{ template "consul.fullname" . }}-client are the security context constraints required to run the consul client. @@ -52,4 +53,4 @@ volumes: {{- if .Values.client.dataDirectoryHostPath }} - hostPath {{- end }} -{{- end}} \ No newline at end of file +{{- end}} diff --git a/charts/consul/templates/client-serviceaccount.yaml b/charts/consul/templates/client-serviceaccount.yaml index 650f1e1333..addd757b84 100644 --- a/charts/consul/templates/client-serviceaccount.yaml +++ b/charts/consul/templates/client-serviceaccount.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client {{- if .Values.client.serviceAccount.annotations }} annotations: {{ tpl .Values.client.serviceAccount.annotations . | nindent 4 | trim }} diff --git a/charts/consul/templates/client-snapshot-agent-deployment.yaml b/charts/consul/templates/client-snapshot-agent-deployment.yaml index 864c2125d1..42b6c67b01 100644 --- a/charts/consul/templates/client-snapshot-agent-deployment.yaml +++ b/charts/consul/templates/client-snapshot-agent-deployment.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client-snapshot-agent spec: replicas: {{ .Values.client.snapshotAgent.replicas }} selector: diff --git a/charts/consul/templates/client-snapshot-agent-podsecuritypolicy.yaml b/charts/consul/templates/client-snapshot-agent-podsecuritypolicy.yaml index 7c80b5054b..dd324a3971 100644 --- a/charts/consul/templates/client-snapshot-agent-podsecuritypolicy.yaml +++ b/charts/consul/templates/client-snapshot-agent-podsecuritypolicy.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client-snapshot-agent spec: privileged: false # Required to prevent escalations to root. diff --git a/charts/consul/templates/client-snapshot-agent-role.yaml b/charts/consul/templates/client-snapshot-agent-role.yaml index 07781430c7..6691750487 100644 --- a/charts/consul/templates/client-snapshot-agent-role.yaml +++ b/charts/consul/templates/client-snapshot-agent-role.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client-snapshot-agent {{- if (or .Values.global.acls.manageSystemACLs .Values.global.enablePodSecurityPolicies) }} rules: {{- if .Values.global.enablePodSecurityPolicies }} diff --git a/charts/consul/templates/client-snapshot-agent-rolebinding.yaml b/charts/consul/templates/client-snapshot-agent-rolebinding.yaml index bc5d9e72b2..e966c4e2a8 100644 --- a/charts/consul/templates/client-snapshot-agent-rolebinding.yaml +++ b/charts/consul/templates/client-snapshot-agent-rolebinding.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client-snapshot-agent roleRef: apiGroup: rbac.authorization.k8s.io kind: Role diff --git a/charts/consul/templates/client-snapshot-agent-serviceaccount.yaml b/charts/consul/templates/client-snapshot-agent-serviceaccount.yaml index 2a0ad36217..a485ff0a5c 100644 --- a/charts/consul/templates/client-snapshot-agent-serviceaccount.yaml +++ b/charts/consul/templates/client-snapshot-agent-serviceaccount.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: client-snapshot-agent {{- if .Values.client.snapshotAgent.serviceAccount.annotations }} annotations: {{ tpl .Values.client.snapshotAgent.serviceAccount.annotations . | nindent 4 | trim }} diff --git a/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml b/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml index c70f51d7e7..6655de5e84 100644 --- a/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml +++ b/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: connect-injector rules: - apiGroups: [""] resources: diff --git a/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml b/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml index bb9e1a0d7e..ff2b5548c6 100644 --- a/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml +++ b/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: connect-injector roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml b/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml index 7ba0424be0..98c7b209be 100644 --- a/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml +++ b/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: connect-injector {{- with .Values.global.imagePullSecrets }} imagePullSecrets: {{- range . }} diff --git a/charts/consul/templates/connect-inject-clusterrole.yaml b/charts/consul/templates/connect-inject-clusterrole.yaml index 7ba2942aa8..873623cd84 100644 --- a/charts/consul/templates/connect-inject-clusterrole.yaml +++ b/charts/consul/templates/connect-inject-clusterrole.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: connect-injector rules: - apiGroups: [""] resources: ["pods", "endpoints", "services", "namespaces"] diff --git a/charts/consul/templates/connect-inject-clusterrolebinding.yaml b/charts/consul/templates/connect-inject-clusterrolebinding.yaml index 87ab8bc9df..fd8e320a65 100644 --- a/charts/consul/templates/connect-inject-clusterrolebinding.yaml +++ b/charts/consul/templates/connect-inject-clusterrolebinding.yaml @@ -8,6 +8,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: connect-injector roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index c12727aaf6..d89635d059 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -20,6 +20,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: connect-injector spec: replicas: {{ .Values.connectInject.replicas }} selector: diff --git a/charts/consul/templates/connect-inject-leader-election-role.yaml b/charts/consul/templates/connect-inject-leader-election-role.yaml index 334dc6bfd9..703aaffaac 100644 --- a/charts/consul/templates/connect-inject-leader-election-role.yaml +++ b/charts/consul/templates/connect-inject-leader-election-role.yaml @@ -9,7 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} - component: controller + component: connect-injector rules: - apiGroups: - "" diff --git a/charts/consul/templates/connect-inject-leader-election-rolebinding.yaml b/charts/consul/templates/connect-inject-leader-election-rolebinding.yaml index be3c351876..bb903c719b 100644 --- a/charts/consul/templates/connect-inject-leader-election-rolebinding.yaml +++ b/charts/consul/templates/connect-inject-leader-election-rolebinding.yaml @@ -9,7 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} - component: controller + component: connect-injector roleRef: apiGroup: rbac.authorization.k8s.io kind: Role diff --git a/charts/consul/templates/connect-inject-mutatingwebhook.yaml b/charts/consul/templates/connect-inject-mutatingwebhook.yaml index 0ce6f80dd9..ad8ea41b10 100644 --- a/charts/consul/templates/connect-inject-mutatingwebhook.yaml +++ b/charts/consul/templates/connect-inject-mutatingwebhook.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: connect-injector webhooks: - name: {{ template "consul.fullname" . }}-connect-injector.consul.hashicorp.com # The webhook will fail scheduling all pods that are not part of consul if all replicas of the webhook are unhealthy. diff --git a/charts/consul/templates/connect-inject-podsecuritypolicy.yaml b/charts/consul/templates/connect-inject-podsecuritypolicy.yaml index b4c10361a6..45fd6afc27 100644 --- a/charts/consul/templates/connect-inject-podsecuritypolicy.yaml +++ b/charts/consul/templates/connect-inject-podsecuritypolicy.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: connect-injector spec: privileged: false # Required to prevent escalations to root. diff --git a/charts/consul/templates/connect-inject-service.yaml b/charts/consul/templates/connect-inject-service.yaml index 8004d8277d..497ea14547 100644 --- a/charts/consul/templates/connect-inject-service.yaml +++ b/charts/consul/templates/connect-inject-service.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: connect-injector spec: ports: - port: 443 diff --git a/charts/consul/templates/connect-inject-serviceaccount.yaml b/charts/consul/templates/connect-inject-serviceaccount.yaml index ad14895527..f615c42bc1 100644 --- a/charts/consul/templates/connect-inject-serviceaccount.yaml +++ b/charts/consul/templates/connect-inject-serviceaccount.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: connect-injector {{- if .Values.connectInject.serviceAccount.annotations }} annotations: {{ tpl .Values.connectInject.serviceAccount.annotations . | nindent 4 | trim }} diff --git a/charts/consul/templates/create-federation-secret-podsecuritypolicy.yaml b/charts/consul/templates/create-federation-secret-podsecuritypolicy.yaml index ced8e42f00..8217311992 100644 --- a/charts/consul/templates/create-federation-secret-podsecuritypolicy.yaml +++ b/charts/consul/templates/create-federation-secret-podsecuritypolicy.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: create-federation-secret annotations: "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation diff --git a/charts/consul/templates/enterprise-license-job.yaml b/charts/consul/templates/enterprise-license-job.yaml index 2e0dbdfab0..0999277c7e 100644 --- a/charts/consul/templates/enterprise-license-job.yaml +++ b/charts/consul/templates/enterprise-license-job.yaml @@ -13,6 +13,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: license annotations: "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-weight": "100" diff --git a/charts/consul/templates/enterprise-license-podsecuritypolicy.yaml b/charts/consul/templates/enterprise-license-podsecuritypolicy.yaml index 2972a184f3..2db9ce5530 100644 --- a/charts/consul/templates/enterprise-license-podsecuritypolicy.yaml +++ b/charts/consul/templates/enterprise-license-podsecuritypolicy.yaml @@ -11,6 +11,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: license spec: privileged: false # Allow core volume types. diff --git a/charts/consul/templates/enterprise-license-role.yaml b/charts/consul/templates/enterprise-license-role.yaml index 9824834246..f3e5554508 100644 --- a/charts/consul/templates/enterprise-license-role.yaml +++ b/charts/consul/templates/enterprise-license-role.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: license {{- if or .Values.global.acls.manageSystemACLs .Values.global.enablePodSecurityPolicies }} rules: {{- if .Values.global.acls.manageSystemACLs }} diff --git a/charts/consul/templates/enterprise-license-rolebinding.yaml b/charts/consul/templates/enterprise-license-rolebinding.yaml index 8070aecde2..7df1c4fa2c 100644 --- a/charts/consul/templates/enterprise-license-rolebinding.yaml +++ b/charts/consul/templates/enterprise-license-rolebinding.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: license roleRef: apiGroup: rbac.authorization.k8s.io kind: Role diff --git a/charts/consul/templates/enterprise-license-serviceaccount.yaml b/charts/consul/templates/enterprise-license-serviceaccount.yaml index 70b1c179bb..54d4523ff9 100644 --- a/charts/consul/templates/enterprise-license-serviceaccount.yaml +++ b/charts/consul/templates/enterprise-license-serviceaccount.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: license {{- with .Values.global.imagePullSecrets }} imagePullSecrets: {{- range . }} diff --git a/charts/consul/templates/gossip-encryption-autogenerate-job.yaml b/charts/consul/templates/gossip-encryption-autogenerate-job.yaml index 3811f36703..e7c2b52209 100644 --- a/charts/consul/templates/gossip-encryption-autogenerate-job.yaml +++ b/charts/consul/templates/gossip-encryption-autogenerate-job.yaml @@ -13,6 +13,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: gossip-encryption-autogenerate annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-weight": "1" @@ -25,7 +26,7 @@ spec: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} release: {{ .Release.Name }} - component: gossip-encryption-autogeneneration + component: gossip-encryption-autogenerate annotations: "consul.hashicorp.com/connect-inject": "false" spec: diff --git a/charts/consul/templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml b/charts/consul/templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml index 6121fbbe30..707ebe57c9 100644 --- a/charts/consul/templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml +++ b/charts/consul/templates/gossip-encryption-autogenerate-podsecuritypolicy.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: gossip-encryption-autogenerate annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/gossip-encryption-autogenerate-role.yaml b/charts/consul/templates/gossip-encryption-autogenerate-role.yaml index ee5afac0ba..8c51c96ffe 100644 --- a/charts/consul/templates/gossip-encryption-autogenerate-role.yaml +++ b/charts/consul/templates/gossip-encryption-autogenerate-role.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: gossip-encryption-autogenerate annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/gossip-encryption-autogenerate-rolebinding.yaml b/charts/consul/templates/gossip-encryption-autogenerate-rolebinding.yaml index caef0d221e..7118475f64 100644 --- a/charts/consul/templates/gossip-encryption-autogenerate-rolebinding.yaml +++ b/charts/consul/templates/gossip-encryption-autogenerate-rolebinding.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: gossip-encryption-autogenerate annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/gossip-encryption-autogenerate-serviceaccount.yaml b/charts/consul/templates/gossip-encryption-autogenerate-serviceaccount.yaml index a711f9a4c1..1fd620237f 100644 --- a/charts/consul/templates/gossip-encryption-autogenerate-serviceaccount.yaml +++ b/charts/consul/templates/gossip-encryption-autogenerate-serviceaccount.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: gossip-encryption-autogenerate annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/partition-init-job.yaml b/charts/consul/templates/partition-init-job.yaml index f3e2006a95..3bdfa58a23 100644 --- a/charts/consul/templates/partition-init-job.yaml +++ b/charts/consul/templates/partition-init-job.yaml @@ -11,6 +11,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: partition-init annotations: "helm.sh/hook": pre-install "helm.sh/hook-weight": "2" diff --git a/charts/consul/templates/partition-init-podsecuritypolicy.yaml b/charts/consul/templates/partition-init-podsecuritypolicy.yaml index 9e2ec994cb..f335e59084 100644 --- a/charts/consul/templates/partition-init-podsecuritypolicy.yaml +++ b/charts/consul/templates/partition-init-podsecuritypolicy.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: partition-init annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/partition-init-role.yaml b/charts/consul/templates/partition-init-role.yaml index 68f60f58f7..1223e18e5d 100644 --- a/charts/consul/templates/partition-init-role.yaml +++ b/charts/consul/templates/partition-init-role.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: partition-init annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/partition-init-rolebinding.yaml b/charts/consul/templates/partition-init-rolebinding.yaml index 61038ecfa6..432d6df6ec 100644 --- a/charts/consul/templates/partition-init-rolebinding.yaml +++ b/charts/consul/templates/partition-init-rolebinding.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: partition-init annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/partition-init-serviceaccount.yaml b/charts/consul/templates/partition-init-serviceaccount.yaml index f39e08a30f..65fcf43b08 100644 --- a/charts/consul/templates/partition-init-serviceaccount.yaml +++ b/charts/consul/templates/partition-init-serviceaccount.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: partition-init annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/partition-name-configmap.yaml b/charts/consul/templates/partition-name-configmap.yaml index 4d568f0889..ee330b0f46 100644 --- a/charts/consul/templates/partition-name-configmap.yaml +++ b/charts/consul/templates/partition-name-configmap.yaml @@ -12,6 +12,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: partition-init immutable: true data: partitionName: {{ .Values.global.adminPartitions.name }} diff --git a/charts/consul/templates/server-acl-init-cleanup-job.yaml b/charts/consul/templates/server-acl-init-cleanup-job.yaml index 9ef60cf395..4db5e356e3 100644 --- a/charts/consul/templates/server-acl-init-cleanup-job.yaml +++ b/charts/consul/templates/server-acl-init-cleanup-job.yaml @@ -22,6 +22,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server-acl-init-cleanup annotations: "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-weight": "0" diff --git a/charts/consul/templates/server-acl-init-cleanup-podsecuritypolicy.yaml b/charts/consul/templates/server-acl-init-cleanup-podsecuritypolicy.yaml index 3d44c7fc18..dd5dad24df 100644 --- a/charts/consul/templates/server-acl-init-cleanup-podsecuritypolicy.yaml +++ b/charts/consul/templates/server-acl-init-cleanup-podsecuritypolicy.yaml @@ -12,6 +12,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server-acl-init-cleanup spec: privileged: false # Allow core volume types. diff --git a/charts/consul/templates/server-acl-init-cleanup-role.yaml b/charts/consul/templates/server-acl-init-cleanup-role.yaml index 8d2e3d03b3..0a2f296a60 100644 --- a/charts/consul/templates/server-acl-init-cleanup-role.yaml +++ b/charts/consul/templates/server-acl-init-cleanup-role.yaml @@ -11,6 +11,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server-acl-init-cleanup rules: - apiGroups: ["batch"] resources: ["jobs"] diff --git a/charts/consul/templates/server-acl-init-cleanup-rolebinding.yaml b/charts/consul/templates/server-acl-init-cleanup-rolebinding.yaml index d2e61807d2..268eaa5677 100644 --- a/charts/consul/templates/server-acl-init-cleanup-rolebinding.yaml +++ b/charts/consul/templates/server-acl-init-cleanup-rolebinding.yaml @@ -11,6 +11,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server-acl-init-cleanup roleRef: apiGroup: rbac.authorization.k8s.io kind: Role diff --git a/charts/consul/templates/server-acl-init-cleanup-serviceaccount.yaml b/charts/consul/templates/server-acl-init-cleanup-serviceaccount.yaml index a5c39a4e5e..604e6d784c 100644 --- a/charts/consul/templates/server-acl-init-cleanup-serviceaccount.yaml +++ b/charts/consul/templates/server-acl-init-cleanup-serviceaccount.yaml @@ -11,6 +11,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server-acl-init-cleanup {{- with .Values.global.imagePullSecrets }} imagePullSecrets: {{- range . }} diff --git a/charts/consul/templates/server-acl-init-job.yaml b/charts/consul/templates/server-acl-init-job.yaml index 07b9ab8e6b..a3b3e76e8c 100644 --- a/charts/consul/templates/server-acl-init-job.yaml +++ b/charts/consul/templates/server-acl-init-job.yaml @@ -22,6 +22,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server-acl-init spec: template: metadata: diff --git a/charts/consul/templates/server-acl-init-podsecuritypolicy.yaml b/charts/consul/templates/server-acl-init-podsecuritypolicy.yaml index a6881ffa68..abe46e300a 100644 --- a/charts/consul/templates/server-acl-init-podsecuritypolicy.yaml +++ b/charts/consul/templates/server-acl-init-podsecuritypolicy.yaml @@ -12,6 +12,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server-acl-init spec: privileged: false # Allow core volume types. diff --git a/charts/consul/templates/server-acl-init-role.yaml b/charts/consul/templates/server-acl-init-role.yaml index 4f22d47b7f..d1fae46cff 100644 --- a/charts/consul/templates/server-acl-init-role.yaml +++ b/charts/consul/templates/server-acl-init-role.yaml @@ -11,6 +11,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server-acl-init rules: - apiGroups: [""] resources: diff --git a/charts/consul/templates/server-acl-init-rolebinding.yaml b/charts/consul/templates/server-acl-init-rolebinding.yaml index 2c54452603..fda4726d9f 100644 --- a/charts/consul/templates/server-acl-init-rolebinding.yaml +++ b/charts/consul/templates/server-acl-init-rolebinding.yaml @@ -11,6 +11,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server-acl-init roleRef: apiGroup: rbac.authorization.k8s.io kind: Role diff --git a/charts/consul/templates/server-acl-init-serviceaccount.yaml b/charts/consul/templates/server-acl-init-serviceaccount.yaml index 0f8e5e817c..c0e257de96 100644 --- a/charts/consul/templates/server-acl-init-serviceaccount.yaml +++ b/charts/consul/templates/server-acl-init-serviceaccount.yaml @@ -11,6 +11,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server-acl-init {{- with .Values.global.imagePullSecrets }} imagePullSecrets: {{- range . }} diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index 6faf60b4b9..4cadf0c303 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server data: extra-from-values.json: |- {{ tpl .Values.server.extraConfig . | trimAll "\"" | indent 4 }} diff --git a/charts/consul/templates/server-disruptionbudget.yaml b/charts/consul/templates/server-disruptionbudget.yaml index 34b1118f5c..866698aac8 100644 --- a/charts/consul/templates/server-disruptionbudget.yaml +++ b/charts/consul/templates/server-disruptionbudget.yaml @@ -15,6 +15,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server spec: maxUnavailable: {{ template "consul.pdb.maxUnavailable" . }} selector: diff --git a/charts/consul/templates/server-podsecuritypolicy.yaml b/charts/consul/templates/server-podsecuritypolicy.yaml index afd1c3e839..b45f9521f5 100644 --- a/charts/consul/templates/server-podsecuritypolicy.yaml +++ b/charts/consul/templates/server-podsecuritypolicy.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server spec: privileged: false # Required to prevent escalations to root. diff --git a/charts/consul/templates/server-role.yaml b/charts/consul/templates/server-role.yaml index c01f3dabb4..202518bf67 100644 --- a/charts/consul/templates/server-role.yaml +++ b/charts/consul/templates/server-role.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server {{- if (or (and .Values.global.openshift.enabled .Values.server.exposeGossipAndRPCPorts) .Values.global.enablePodSecurityPolicies) }} rules: {{- if .Values.global.enablePodSecurityPolicies }} diff --git a/charts/consul/templates/server-rolebinding.yaml b/charts/consul/templates/server-rolebinding.yaml index 788fc978f7..8ab705ddbc 100644 --- a/charts/consul/templates/server-rolebinding.yaml +++ b/charts/consul/templates/server-rolebinding.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server roleRef: apiGroup: rbac.authorization.k8s.io kind: Role diff --git a/charts/consul/templates/server-securitycontextconstraints.yaml b/charts/consul/templates/server-securitycontextconstraints.yaml index e9acadceae..8edd784ea7 100644 --- a/charts/consul/templates/server-securitycontextconstraints.yaml +++ b/charts/consul/templates/server-securitycontextconstraints.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server annotations: kubernetes.io/description: {{ template "consul.fullname" . }}-server are the security context constraints required to run the consul server. diff --git a/charts/consul/templates/server-serviceaccount.yaml b/charts/consul/templates/server-serviceaccount.yaml index 815e1e71f9..a1617975ae 100644 --- a/charts/consul/templates/server-serviceaccount.yaml +++ b/charts/consul/templates/server-serviceaccount.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: server {{- if .Values.server.serviceAccount.annotations }} annotations: {{ tpl .Values.server.serviceAccount.annotations . | nindent 4 | trim }} diff --git a/charts/consul/templates/sync-catalog-clusterrole.yaml b/charts/consul/templates/sync-catalog-clusterrole.yaml index 41609f7747..5ceeb03d47 100644 --- a/charts/consul/templates/sync-catalog-clusterrole.yaml +++ b/charts/consul/templates/sync-catalog-clusterrole.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: sync-catalog rules: - apiGroups: [""] resources: diff --git a/charts/consul/templates/sync-catalog-clusterrolebinding.yaml b/charts/consul/templates/sync-catalog-clusterrolebinding.yaml index 648bd30727..818823cca3 100644 --- a/charts/consul/templates/sync-catalog-clusterrolebinding.yaml +++ b/charts/consul/templates/sync-catalog-clusterrolebinding.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: sync-catalog roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole diff --git a/charts/consul/templates/sync-catalog-deployment.yaml b/charts/consul/templates/sync-catalog-deployment.yaml index 6c158204c3..e1c0519e86 100644 --- a/charts/consul/templates/sync-catalog-deployment.yaml +++ b/charts/consul/templates/sync-catalog-deployment.yaml @@ -12,6 +12,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: sync-catalog spec: replicas: 1 selector: diff --git a/charts/consul/templates/sync-catalog-podsecuritypolicy.yaml b/charts/consul/templates/sync-catalog-podsecuritypolicy.yaml index 22f3e23eaa..cc70feaab1 100644 --- a/charts/consul/templates/sync-catalog-podsecuritypolicy.yaml +++ b/charts/consul/templates/sync-catalog-podsecuritypolicy.yaml @@ -9,6 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: sync-catalog spec: privileged: false # Required to prevent escalations to root. diff --git a/charts/consul/templates/sync-catalog-serviceaccount.yaml b/charts/consul/templates/sync-catalog-serviceaccount.yaml index d029088a1b..deab1ad075 100644 --- a/charts/consul/templates/sync-catalog-serviceaccount.yaml +++ b/charts/consul/templates/sync-catalog-serviceaccount.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: sync-catalog {{- if .Values.syncCatalog.serviceAccount.annotations }} annotations: {{ tpl .Values.syncCatalog.serviceAccount.annotations . | nindent 4 | trim }} diff --git a/charts/consul/templates/tls-init-cleanup-job.yaml b/charts/consul/templates/tls-init-cleanup-job.yaml index dc658d733d..d3b1096921 100644 --- a/charts/consul/templates/tls-init-cleanup-job.yaml +++ b/charts/consul/templates/tls-init-cleanup-job.yaml @@ -11,6 +11,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: tls-init-cleanup annotations: "helm.sh/hook": pre-delete "helm.sh/hook-delete-policy": hook-succeeded diff --git a/charts/consul/templates/tls-init-cleanup-podsecuritypolicy.yaml b/charts/consul/templates/tls-init-cleanup-podsecuritypolicy.yaml index c8dc00f62d..4e2b24678b 100644 --- a/charts/consul/templates/tls-init-cleanup-podsecuritypolicy.yaml +++ b/charts/consul/templates/tls-init-cleanup-podsecuritypolicy.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: tls-init-cleanup annotations: "helm.sh/hook": pre-delete "helm.sh/hook-delete-policy": hook-succeeded diff --git a/charts/consul/templates/tls-init-cleanup-role.yaml b/charts/consul/templates/tls-init-cleanup-role.yaml index 3922144997..77bd4bff61 100644 --- a/charts/consul/templates/tls-init-cleanup-role.yaml +++ b/charts/consul/templates/tls-init-cleanup-role.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: tls-init-cleanup annotations: "helm.sh/hook": pre-delete "helm.sh/hook-delete-policy": hook-succeeded diff --git a/charts/consul/templates/tls-init-cleanup-rolebinding.yaml b/charts/consul/templates/tls-init-cleanup-rolebinding.yaml index c02f4d2e40..12cd08c74b 100644 --- a/charts/consul/templates/tls-init-cleanup-rolebinding.yaml +++ b/charts/consul/templates/tls-init-cleanup-rolebinding.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: tls-init-cleanup annotations: "helm.sh/hook": pre-delete "helm.sh/hook-delete-policy": hook-succeeded diff --git a/charts/consul/templates/tls-init-cleanup-serviceaccount.yaml b/charts/consul/templates/tls-init-cleanup-serviceaccount.yaml index f26d14122f..198dab86f8 100644 --- a/charts/consul/templates/tls-init-cleanup-serviceaccount.yaml +++ b/charts/consul/templates/tls-init-cleanup-serviceaccount.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: tls-init-cleanup annotations: "helm.sh/hook": pre-delete "helm.sh/hook-delete-policy": hook-succeeded diff --git a/charts/consul/templates/tls-init-job.yaml b/charts/consul/templates/tls-init-job.yaml index 019513c897..5cfefe1294 100644 --- a/charts/consul/templates/tls-init-job.yaml +++ b/charts/consul/templates/tls-init-job.yaml @@ -12,6 +12,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: tls-init annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-weight": "1" diff --git a/charts/consul/templates/tls-init-podsecuritypolicy.yaml b/charts/consul/templates/tls-init-podsecuritypolicy.yaml index 4f188bd819..93aeb9f193 100644 --- a/charts/consul/templates/tls-init-podsecuritypolicy.yaml +++ b/charts/consul/templates/tls-init-podsecuritypolicy.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: tls-init annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/tls-init-role.yaml b/charts/consul/templates/tls-init-role.yaml index 5a27d8b44b..a862925901 100644 --- a/charts/consul/templates/tls-init-role.yaml +++ b/charts/consul/templates/tls-init-role.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: tls-init annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/tls-init-rolebinding.yaml b/charts/consul/templates/tls-init-rolebinding.yaml index 3ac92e7316..1867826236 100644 --- a/charts/consul/templates/tls-init-rolebinding.yaml +++ b/charts/consul/templates/tls-init-rolebinding.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: tls-init annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/templates/tls-init-serviceaccount.yaml b/charts/consul/templates/tls-init-serviceaccount.yaml index e8b2d94ab1..7d21ee811c 100644 --- a/charts/consul/templates/tls-init-serviceaccount.yaml +++ b/charts/consul/templates/tls-init-serviceaccount.yaml @@ -10,6 +10,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} + component: tls-init annotations: "helm.sh/hook": pre-install,pre-upgrade "helm.sh/hook-delete-policy": before-hook-creation diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index 64a9d0e4c0..e986c2984a 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -549,7 +549,7 @@ load _helpers -s templates/client-daemonset.yaml \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 779a0e24c2ed561c727730698a75b1c552f562c100f0c3315ff2cb925f5e296b ] + [ "${actual}" = 004aa147bf69db24da4d7f61ee4e3fc725dcb04effcec707a66dab1ae91543cc ] } @test "client/DaemonSet: config-checksum annotation changes when extraConfig is provided" { @@ -559,7 +559,7 @@ load _helpers --set 'client.extraConfig="{\"hello\": \"world\"}"' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = ba1ceb79d2d18e136d3cc40a9dfddcf2a252aa19ca1703bee3219ca28f1ee187 ] + [ "${actual}" = 6ab8217573bf5486889ff6d3fe8d2f70a0a1d0bfbb48c20f568a4fc566cb3909 ] } @test "client/DaemonSet: config-checksum annotation changes when connectInject.enabled=true" { @@ -569,7 +569,7 @@ load _helpers --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = b45de202f61d7d3b6118c1f47c351d357c2a83af09675f269d3617ae4a65a01c ] + [ "${actual}" = 1b0252854bdef3197902ee928716ebd691ef39b173a19ad0d4e883ddb0443b88 ] } #-------------------------------------------------------------------- diff --git a/charts/consul/test/unit/helpers.bats b/charts/consul/test/unit/helpers.bats index 235338adc6..8e02152ff2 100644 --- a/charts/consul/test/unit/helpers.bats +++ b/charts/consul/test/unit/helpers.bats @@ -119,6 +119,20 @@ load _helpers [ "${actual}" = '' ] } +#-------------------------------------------------------------------- +# component label +# +# This test ensures that we set a "component: " in every file. +# +# If this test fails, you're likely missing setting that label somewhere. + +@test "helper/component-label: used everywhere" { + cd `chart_dir` + # Grep for files that don't have 'component: ' in them + local actual=$(grep -L 'component: ' templates/*.yaml | tee /dev/stderr ) + [ "${actual}" = '' ] +} + #-------------------------------------------------------------------- # consul.getAutoEncryptClientCA # Similarly to consul.fullname tests, these tests use test-runner.yaml to test the diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index ea10cc163d..6936bce1e0 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -686,7 +686,7 @@ load _helpers -s templates/server-statefulset.yaml \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = df8f3705556144cfb39ae46653965f84faf85001af69306f74d01793503908f4 ] + [ "${actual}" = b56ac97f873dd8c41c779964e24a458c58fc41404fa2642d3b12b24cd2091e43 ] } @test "server/StatefulSet: adds config-checksum annotation when extraConfig is provided" { @@ -696,7 +696,7 @@ load _helpers --set 'server.extraConfig="{\"hello\": \"world\"}"' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = a97d7f332bb6585541f1eab2d1782f8b00bd16b883c34b2db3dd3ce7d67ba39e ] + [ "${actual}" = d637bd5c2a3738c2885d483fd003d59badc164883897e6032ac2dbe543bb6539 ] } @test "server/StatefulSet: adds config-checksum annotation when config is updated" { @@ -706,7 +706,7 @@ load _helpers --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 023154f44972402c58062dbb8ab09095563dd99c23b9dab9d51d705486e767b7 ] + [ "${actual}" = daf925cbf6af12cc87f5d7791370e28dddbe9ca78d8ad9fc963e558c60a333e7 ] } #-------------------------------------------------------------------- From 0ad49a9880b1c2aef3d6bbd7cc1926e1f4b1d752 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 9 Nov 2021 16:06:47 -0800 Subject: [PATCH 128/418] Fix logic for enabling ui metrics (#841) * Fix logic for enabling ui metrics Previously ui metrics would be enabled when `global.metrics.enabled=false` and `ui.metrics.enabled=-`. Now that would cause UI metrics to be disabled which makes sense since "-" means inherit from `global.metrics.enabled`. The logic is now to enable ui metrics when: ``` ui.enabled && ( (global.metrics.enabled == true && ui.metrics.enabled == "-") || (ui.metrics.enabled == true) ) ``` --- CHANGELOG.md | 12 ++++++---- .../templates/server-config-configmap.yaml | 2 +- .../test/unit/server-config-configmap.bats | 22 +++++++++++++++++++ .../consul/test/unit/server-statefulset.bats | 6 ++--- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15df277aa1..6f26d88bef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,17 @@ ## UNRELEASED +BREAKING CHANGES: +* Previously [UI metrics](https://www.consul.io/docs/connect/observability/ui-visualization) would be enabled when + `global.metrics=false` and `ui.metrics.enabled=-`. If you are no longer seeing UI metrics, + set `global.metrics=true` or `ui.metrics.enabled=true`. [[GH-841](https://github.com/hashicorp/consul-k8s/pull/841)] + IMPROVEMENTS: * Control Plane * TLS: Support PKCS1 and PKCS8 private keys for Consul certificate authority. [[GH-843](https://github.com/hashicorp/consul-k8s/pull/843)] * CLI * Delete jobs, cluster roles, and cluster role bindings on `uninstall`. [[GH-820](https://github.com/hashicorp/consul-k8s/pull/820)] +* Helm Chart + * Add `component` labels to all resources. [[GH-840](https://github.com/hashicorp/consul-k8s/pull/840)] BUG FIXES: * Control Plane @@ -18,10 +25,7 @@ BUG FIXES: * **(Consul Enterprise only)** Error on Helm install if a reserved name is used for the admin partition name or a Consul destination namespace for connect or catalog sync. [[GH-846](https://github.com/hashicorp/consul-k8s/pull/846)] * Truncate Persistent Volume Claim names when namespace names are too long. [[GH-799](https://github.com/hashicorp/consul-k8s/pull/799)] - -IMPROVEMENTS: -* Helm Chart - * Add `component` labels to all resources. [[GH-840](https://github.com/hashicorp/consul-k8s/pull/840)] + * Fix issue where UI metrics would be enabled when `global.metrics=false` and `ui.metrics.enabled=-`. [[GH-841](https://github.com/hashicorp/consul-k8s/pull/841)] ## 0.36.0 (November 02, 2021) diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index 4cadf0c303..83b31755fc 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -28,7 +28,7 @@ data: } } {{- end }} - {{- if (and .Values.ui.enabled (or .Values.ui.metrics.enabled (and .Values.global.metrics.enabled (eq (.Values.ui.metrics.enabled | toString) "-")))) }} + {{- if (and .Values.ui.enabled (or (eq "true" (.Values.ui.metrics.enabled | toString) ) (and .Values.global.metrics.enabled (eq "-" (.Values.ui.metrics.enabled | toString))))) }} ui-config.json: |- { "ui_config": { diff --git a/charts/consul/test/unit/server-config-configmap.bats b/charts/consul/test/unit/server-config-configmap.bats index 25a08da37c..f7fd6ce033 100755 --- a/charts/consul/test/unit/server-config-configmap.bats +++ b/charts/consul/test/unit/server-config-configmap.bats @@ -86,6 +86,28 @@ load _helpers [ "${actual}" = "true" ] } +@test "server/ConfigMap: does not create ui config when .ui.enabled=false and .ui.metrics.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'ui.enabled=false' \ + --set 'ui.metrics.enabled=false' \ + . | tee /dev/stderr | + yq -r '.data["ui-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: does not create ui config when .ui.enabled=true and .global.metrics.enabled=false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'ui.enabled=true' \ + --set 'global.metrics.enabled=false' \ + . | tee /dev/stderr | + yq -r '.data["ui-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + @test "server/ConfigMap: does not create ui config when .ui.enabled=true and .ui.metrics.enabled=false" { cd `chart_dir` local actual=$(helm template \ diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 6936bce1e0..647ad2994d 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -686,7 +686,7 @@ load _helpers -s templates/server-statefulset.yaml \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = b56ac97f873dd8c41c779964e24a458c58fc41404fa2642d3b12b24cd2091e43 ] + [ "${actual}" = 2c5397272acdc6fe5b079bf25c846c5a17f474603c794c64e7226ce0690625f7 ] } @test "server/StatefulSet: adds config-checksum annotation when extraConfig is provided" { @@ -696,7 +696,7 @@ load _helpers --set 'server.extraConfig="{\"hello\": \"world\"}"' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = d637bd5c2a3738c2885d483fd003d59badc164883897e6032ac2dbe543bb6539 ] + [ "${actual}" = b0d22cb051216505edc0e61b57f9eacc0d7e15b24719d815842df88f06f1abe0 ] } @test "server/StatefulSet: adds config-checksum annotation when config is updated" { @@ -706,7 +706,7 @@ load _helpers --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = daf925cbf6af12cc87f5d7791370e28dddbe9ca78d8ad9fc963e558c60a333e7 ] + [ "${actual}" = 7772975be982e25cc8df101375374e2ba672a55737f8f1580011e0d88d8752a8 ] } #-------------------------------------------------------------------- From 8a63540547ababee7d0ff245a9b18308fa5e1dcd Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 9 Nov 2021 16:07:11 -0800 Subject: [PATCH 129/418] Give better error when using default service acct (#842) * Give better error when using default service acct If consul login fails when the service account name is `default` then give an explicit warning that the reason it failed is because in default installations that is not a support service account name. We can't fail during injection because we support modifying the binding rule such that `default` _is_ a valid svc account name. --- CHANGELOG.md | 1 + control-plane/subcommand/connect-init/command.go | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f26d88bef..4f4d60e80a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ BREAKING CHANGES: IMPROVEMENTS: * Control Plane * TLS: Support PKCS1 and PKCS8 private keys for Consul certificate authority. [[GH-843](https://github.com/hashicorp/consul-k8s/pull/843)] + * Connect: Log a warning when ACLs are enabled and the default service account is used. [[GH-842](https://github.com/hashicorp/consul-k8s/pull/842)] * CLI * Delete jobs, cluster roles, and cluster role bindings on `uninstall`. [[GH-820](https://github.com/hashicorp/consul-k8s/pull/820)] * Helm Chart diff --git a/control-plane/subcommand/connect-init/command.go b/control-plane/subcommand/connect-init/command.go index d8158b5f20..e7487fb9e1 100644 --- a/control-plane/subcommand/connect-init/command.go +++ b/control-plane/subcommand/connect-init/command.go @@ -138,6 +138,12 @@ func (c *Command) Run(args []string) int { return err }, backoff.WithMaxRetries(backoff.NewConstantBackOff(1*time.Second), numLoginRetries)) if err != nil { + if c.flagServiceAccountName == "default" { + c.logger.Warn("The service account name for this Pod is \"default\"." + + " In default installations this is not a supported service account name." + + " The service account name must match the name of the Kubernetes Service" + + " or the consul.hashicorp.com/connect-service annotation.") + } c.logger.Error("Hit maximum retries for consul login", "error", err) return 1 } From 4afb4182faf0ef23fd45783eac3cecb4b449ee65 Mon Sep 17 00:00:00 2001 From: David Yu Date: Tue, 9 Nov 2021 16:09:58 -0800 Subject: [PATCH 130/418] CONTRIBUTING: change to consul-k8s-control-plane in Contributing 101 and formatting (#852) * CHANGELOG: change to consul-k8s-control-plane in Contributing 101 and formatting * Update CONTRIBUTING.md * adding command to install off of dev charts * Update CONTRIBUTING.md * Update CONTRIBUTING.md * Update CONTRIBUTING.md * Update CONTRIBUTING.md * Adding CLI section * Update CONTRIBUTING.md Co-authored-by: Luke Kysow <1034429+lkysow@users.noreply.github.com> Co-authored-by: Luke Kysow <1034429+lkysow@users.noreply.github.com> --- CONTRIBUTING.md | 107 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 25 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e6d2fcec16..13183ad2ff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,28 +1,32 @@ # Contributing to Consul on Kubernetes 1. [Contributing 101](#contributing-101) - 1. [Running Linters Locally](#running-linters-locally) - 2. [Rebasing Contributions against main](#rebasing-contributions-against-main) -3. [Creating a new CRD](#creating-a-new-crd) + 1. [Building and running `consul-k8s-control-plane`](#building-and-running-consul-k8s-control-plane) + 1. [Building and running the `consul-k8s` CLI](#building-and-running-the-consul-k8s-cli) + 3. [Running Linters Locally](#running-linters-locally) + 4. [Rebasing Contributions against main](#rebasing-contributions-against-main) +1. [Creating a new CRD](#creating-a-new-crd) 1. [The Structs](#the-structs) - 2. [Spec Methods](#spec-methods) - 3. [Spec Tests](#spec-tests) - 4. [Controller](#controller) - 5. [Webhook](#webhook) - 6. [Update command.go](#update-commandgo) - 7. [Generating YAML](#generating-yaml) - 8. [Updating consul-helm](#updating-consul-helm) - 9. [Testing a new CRD](#testing-a-new-crd) - 10. [Update Consul K8s accpetance tests](#update-consul-k8s-acceptance-tests) + 1. [Spec Methods](#spec-methods) + 1. [Spec Tests](#spec-tests) + 1. [Controller](#controller) + 1. [Webhook](#webhook) + 1. [Update command.go](#update-commandgo) + 1. [Generating YAML](#generating-yaml) + 1. [Updating consul-helm](#updating-consul-helm) + 1. [Testing a new CRD](#testing-a-new-crd) + 1. [Update Consul K8s accpetance tests](#update-consul-k8s-acceptance-tests) 5. [Testing the Helm chart](#testing-the-helm-chart) -6. [Running the tests](#running-the-tests) - 1. [Writing Unit tests](#writing-unit-tests) - 2. [Writing Acceptance tests](#writing-acceptance-tests) -8. [Helm Reference Docs](#helm-reference-docs) + 1. [Running the tests](#running-the-tests) + 1. [Writing Unit tests](#writing-unit-tests) + 1. [Writing Acceptance tests](#writing-acceptance-tests) +1. [Helm Reference Docs](#helm-reference-docs) ## Contributing 101 +### Building and running `consul-k8s-control-plane` + To build and install the control plane binary `consul-k8s` locally, Go version 1.11.4+ is required because this repository uses go modules and go 1.11.4 introduced changes to checksumming of modules to correct a symlink problem. You will also need to install the Docker engine: @@ -48,15 +52,9 @@ To compile the `consul-k8s` binary for your local machine: $ make dev ``` -This will compile the `consul-k8s` binary into `bin/consul-k8s` as +This will compile the `consul-k8s-control-plane` binary into `bin/consul-k8s-control-plane` as well as your `$GOPATH` and run the test suite. -Or run the following to generate all binaries: - -```shell -$ make dist -``` - If you just want to run the tests: ```shell @@ -75,6 +73,67 @@ To create a docker image with your local changes: $ make dev-docker ``` +If you'd like to use your docker images in a dev deployment of Consul K8s, you would need to push those images to Docker Hub since +deploying off of local images is not supported unless you host your own local Docker registry: + +``` +$ docker tag consul-k8s-control-plane-dev /consul-k8s-control-plane-dev +$ docker push /consul-k8s-control-plane-dev +Using default tag: latest +The push refers to repository [docker.io//consul-k8s-control-plane-dev] +4c5225fbac5e: Pushed +737cd00c4260: Pushed +7a9c7d9855c2: Pushed +e2eb06d8af82: Pushed +latest: digest: sha256:0b3e90e0b32da8aba1b11cda6a6a768a5eb4d83664a408d53f1502db8703ef8a size: 1160 +``` + +Create a `values.dev.yaml` file that includes the `global.imageK8S` flag to point to dev images you just pushed: + +```yaml +global: + tls: + enabled: true + imageK8S: /consul-k8s-control-plane-dev +server: + replicas: 1 +connectInject: + enabled: true +ui: + enabled: true + service: + enabled: true +controller: + enabled: true +``` + +Run a `helm install` from the project root directory to target your dev version of the Helm chart. + +```shell +helm install consul --create-namespace -n consul -f ./values.dev.yaml ./charts/consul +``` + +### Building and running the `consul-k8s` CLI + +Change directory into the `cli` folder where the golang code resides. + +```shell +cd cli +``` + +Build the CLI binary using the following command + +```shell +go build -o bin/consul-k8s +``` + +Run the CLI as follows + +```shell +./bin/consul-k8s version +consul-k8s 0.36.0-dev +``` + ### Running linters locally [`golangci-lint`](https://golangci-lint.run/) is used in CI to enforce coding and style standards and help catch bugs ahead of time. The configuration that CI runs is stored in `.golangci.yml` at the top level of the repository. @@ -445,8 +504,6 @@ The acceptance tests require a Kubernetes cluster with a configured `kubectl`. ```bash brew install golang ``` - ---- ### Running The Tests From 44f81dbab00b94b3f28ccea4a23b579955cc40ee Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Wed, 10 Nov 2021 11:31:13 -0800 Subject: [PATCH 131/418] Automate DNS redirection to Consul DNS (#833) * template kube dns service IP using api request * when dns is enabled, dns queries are directed to consul. * Update control-plane/connect-inject/container_init.go * Add CHANGELOG Co-authored-by: Ashwin Venkatesh Co-authored-by: Luke Kysow <1034429+lkysow@users.noreply.github.com> --- CHANGELOG.md | 7 ++ charts/consul/templates/_helpers.tpl | 12 ++ charts/consul/templates/client-daemonset.yaml | 7 ++ .../templates/connect-inject-deployment.yaml | 6 +- .../consul/templates/server-statefulset.yaml | 7 ++ charts/consul/test/unit/client-daemonset.bats | 22 ++++ .../test/unit/connect-inject-deployment.bats | 34 ++++++ .../consul/test/unit/server-statefulset.bats | 22 ++++ charts/consul/values.yaml | 6 + control-plane/connect-inject/annotations.go | 6 + .../connect-inject/container_init.go | 51 ++++++++ .../connect-inject/container_init_test.go | 110 ++++++++++++++++++ control-plane/connect-inject/handler.go | 8 ++ .../subcommand/inject-connect/command.go | 10 ++ 14 files changed, 306 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f4d60e80a..cec3581f34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ ## UNRELEASED +FEATURES: +* Helm Chart + * Add support for Consul services to utilize Consul DNS for service discovery. Set `dns.enableRedirection` to allow services to + use Consul DNS via the Consul DNS Service. [[GH-833](https://github.com/hashicorp/consul-k8s/pull/833)] +* Control Plane + * Connect: Allow services using Connect to utilize Consul DNS to perform service discovery. [[GH-833](https://github.com/hashicorp/consul-k8s/pull/833)] + BREAKING CHANGES: * Previously [UI metrics](https://www.consul.io/docs/connect/observability/ui-visualization) would be enabled when `global.metrics=false` and `ui.metrics.enabled=-`. If you are no longer seeing UI metrics, diff --git a/charts/consul/templates/_helpers.tpl b/charts/consul/templates/_helpers.tpl index 49676dc329..480c4b8895 100644 --- a/charts/consul/templates/_helpers.tpl +++ b/charts/consul/templates/_helpers.tpl @@ -28,6 +28,18 @@ is passed to consul as a -config-file param on command line. [ -n "${HOSTNAME}" ] && sed -Ei "s|HOSTNAME|${HOSTNAME?}|g" /consul/extra-config/extra-from-values.json {{- end -}} +{{/* +Sets up a list of recusor flags for Consul agents by iterating over the IPs of every nameserver +in /etc/resolv.conf and concatenating them into a string of arguments that can be passed directly +to the consul agent command. +*/}} +{{- define "consul.recursors" -}} + recursor_flags="" + for ip in $(cat /etc/resolv.conf | grep nameserver | cut -d' ' -f2) + do + recursor_flags="$recursor_flags -recursor=$ip" + done +{{- end -}} {{/* Create chart name and version as used by the chart label. diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index 7689b3ff8a..28c9512ce6 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -203,6 +203,10 @@ spec: - | CONSUL_FULLNAME="{{template "consul.fullname" . }}" + {{- if (and .Values.dns.enabled .Values.dns.enableRedirection) }} + {{ template "consul.recursors" }} + {{- end }} + {{ template "consul.extraconfig" }} exec /usr/local/bin/docker-entrypoint.sh consul agent \ @@ -276,6 +280,9 @@ spec: {{- range $value := .Values.global.recursors }} -recursor={{ quote $value }} \ {{- end }} + {{- if (and .Values.dns.enabled .Values.dns.enableRedirection) }} + $recursor_flags \ + {{- end }} -config-file=/consul/extra-config/extra-from-values.json \ -domain={{ .Values.global.domain }} volumeMounts: diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index d89635d059..11946b6235 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -83,8 +83,6 @@ spec: - "/bin/sh" - "-ec" - | - CONSUL_FULLNAME="{{template "consul.fullname" . }}" - consul-k8s-control-plane inject-connect \ -log-level={{ default .Values.global.logLevel .Values.connectInject.logLevel }} \ -log-json={{ .Values.global.logJSON }} \ @@ -108,6 +106,10 @@ spec: {{- else }} -transparent-proxy-default-overwrite-probes=false \ {{- end }} + -resource-prefix={{ template "consul.fullname" . }} \ + {{- if (and .Values.dns.enabled .Values.dns.enableRedirection) }} + -enable-consul-dns=true \ + {{- end }} {{- if .Values.global.openshift.enabled }} -enable-openshift \ {{- end }} diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 2e332cb7ae..5e8cc89e76 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -192,6 +192,10 @@ spec: - | CONSUL_FULLNAME="{{template "consul.fullname" . }}" + {{- if (and .Values.dns.enabled .Values.dns.enableRedirection) }} + {{ template "consul.recursors" }} + {{- end }} + {{ template "consul.extraconfig" }} exec /usr/local/bin/docker-entrypoint.sh consul agent \ @@ -254,6 +258,9 @@ spec: {{- range $value := .Values.global.recursors }} -recursor={{ quote $value }} \ {{- end }} + {{- if (and .Values.dns.enabled .Values.dns.enableRedirection) }} + $recursor_flags \ + {{- end }} -config-file=/consul/extra-config/extra-from-values.json \ -server volumeMounts: diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index e986c2984a..a6f8a63b1a 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1170,6 +1170,28 @@ load _helpers [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# DNS + +@test "client/DaemonSet: recursor flags is not set by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-daemonset.yaml \ + . | tee /dev/stderr | + yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("$recursor_flags")' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "client/DaemonSet: add recursor flags if dns.enableRedirection is true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'dns.enableRedirection=true' \ + . | tee /dev/stderr | + yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("$recursor_flags")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + #-------------------------------------------------------------------- # hostNetwork diff --git a/charts/consul/test/unit/connect-inject-deployment.bats b/charts/consul/test/unit/connect-inject-deployment.bats index a8e23d0c53..1fb0dad743 100755 --- a/charts/consul/test/unit/connect-inject-deployment.bats +++ b/charts/consul/test/unit/connect-inject-deployment.bats @@ -519,6 +519,40 @@ EOF [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# DNS + +@test "connectInject/Deployment: -enable-consul-dns unset by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("-enable-consul-dns=true")' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "connectInject/Deployment: -enable-consul-dns is true if dns.enabled=true and dns.enableRedirection=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'dns.enableRedirection=true' \ + . | tee /dev/stderr | + yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("-enable-consul-dns=true")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "connectInject/Deployment: -resource-prefix always set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("-resource-prefix=RELEASE-NAME-consul")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + #-------------------------------------------------------------------- # global.tls.enabled diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 647ad2994d..a7a31bb84d 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -580,6 +580,28 @@ load _helpers [ "${actualBaz}" = "qux" ] } +#-------------------------------------------------------------------- +# DNS + +@test "server/StatefulSet: recursor flags unset by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + . | tee /dev/stderr | + yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("$recursor_flags")' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/StatefulSet: add recursor flags if dns.enableRedirection is true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'dns.enableRedirection=true' \ + . | tee /dev/stderr | + yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("$recursor_flags")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + #-------------------------------------------------------------------- # annotations diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 68ffbb6630..9d5af13ac8 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -1122,6 +1122,12 @@ dns: # @type: boolean enabled: "-" + # If true, services using Consul Connect will use Consul DNS + # for default DNS resolution. The DNS lookups fall back to the nameserver IPs + # listed in /etc/resolv.conf if not found in Consul. + # @type: boolean + enableRedirection: false + # Used to control the type of service created. For # example, setting this to "LoadBalancer" will create an external load # balancer (for supported K8S installations) diff --git a/control-plane/connect-inject/annotations.go b/control-plane/connect-inject/annotations.go index 929c9e4c69..ccc9ab6341 100644 --- a/control-plane/connect-inject/annotations.go +++ b/control-plane/connect-inject/annotations.go @@ -90,6 +90,12 @@ const ( // annotationConsulNamespace is the Consul namespace the service is registered into. annotationConsulNamespace = "consul.hashicorp.com/consul-namespace" + // keyConsulDNS enables or disables Consul DNS for a given pod. It can also be set as a label + // on a namespace to define the default behaviour for connect-injected pods which do not otherwise override this setting + // with their own annotation. + // This annotation/label takes a boolean value (true/false). + keyConsulDNS = "consul.hashicorp.com/consul-dns" + // keyTransparentProxy enables or disables transparent proxy for a given pod. It can also be set as a label // on a namespace to define the default behaviour for connect-injected pods which do not otherwise override this setting // with their own annotation. diff --git a/control-plane/connect-inject/container_init.go b/control-plane/connect-inject/container_init.go index e69a91fbb1..18831fa57b 100644 --- a/control-plane/connect-inject/container_init.go +++ b/control-plane/connect-inject/container_init.go @@ -2,6 +2,8 @@ package connectinject import ( "bytes" + "fmt" + "os" "strconv" "strings" "text/template" @@ -16,6 +18,7 @@ const ( envoyUserAndGroupID = 5995 copyContainerUserAndGroupID = 5996 netAdminCapability = "NET_ADMIN" + dnsServiceHostEnvSuffix = "DNS_SERVICE_HOST" ) type initContainerCommandData struct { @@ -66,6 +69,9 @@ type initContainerCommandData struct { // TProxyExcludeUIDs is a list of additional user IDs to exclude from traffic redirection via // the consul connect redirect-traffic command. TProxyExcludeUIDs []string + + // ConsulDNSClusterIP is the IP of the Consul DNS Service. + ConsulDNSClusterIP string } // initCopyContainer returns the init container spec for the copy container which places @@ -107,6 +113,22 @@ func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod) (cor return corev1.Container{}, err } + dnsEnabled, err := consulDNSEnabled(namespace, pod, h.EnableConsulDNS) + if err != nil { + return corev1.Container{}, err + } + + var consulDNSClusterIP string + if dnsEnabled { + // If Consul DNS is enabled, we find the environment variable that has the value + // of the ClusterIP of the Consul DNS Service. constructDNSServiceHostName returns + // the name of the env variable whose value is the ClusterIP of the Consul DNS Service. + consulDNSClusterIP = os.Getenv(h.constructDNSServiceHostName()) + if consulDNSClusterIP == "" { + return corev1.Container{}, fmt.Errorf("environment variable %s is not found", h.constructDNSServiceHostName()) + } + } + data := initContainerCommandData{ AuthMethod: h.AuthMethod, ConsulPartition: h.ConsulPartition, @@ -118,6 +140,7 @@ func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod) (cor TProxyExcludeOutboundPorts: splitCommaSeparatedItemsFromAnnotation(annotationTProxyExcludeOutboundPorts, pod), TProxyExcludeOutboundCIDRs: splitCommaSeparatedItemsFromAnnotation(annotationTProxyExcludeOutboundCIDRs, pod), TProxyExcludeUIDs: splitCommaSeparatedItemsFromAnnotation(annotationTProxyExcludeUIDs, pod), + ConsulDNSClusterIP: consulDNSClusterIP, EnvoyUID: envoyUserAndGroupID, } @@ -223,6 +246,15 @@ func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod) (cor return container, nil } +// constructDNSServiceHostName use the resource prefix and the DNS Service hostname suffix to construct the +// key of the env variable whose value is the cluster IP of the Consul DNS Service. +// It translates "resource-prefix" into "RESOURCE_PREFIX_DNS_SERVICE_HOST". +func (h *Handler) constructDNSServiceHostName() string { + upcaseResourcePrefix := strings.ToUpper(h.ResourcePrefix) + upcaseResourcePrefixWithUnderscores := strings.ReplaceAll(upcaseResourcePrefix, "-", "_") + return strings.Join([]string{upcaseResourcePrefixWithUnderscores, dnsServiceHostEnvSuffix}, "_") +} + // transparentProxyEnabled returns true if transparent proxy should be enabled for this pod. // It returns an error when the annotation value cannot be parsed by strconv.ParseBool or if we are unable // to read the pod's namespace label when it exists. @@ -239,6 +271,22 @@ func transparentProxyEnabled(namespace corev1.Namespace, pod corev1.Pod, globalE return globalEnabled, nil } +// consulDNSEnabled returns true if Consul DNS should be enabled for this pod. +// It returns an error when the annotation value cannot be parsed by strconv.ParseBool or if we are unable +// to read the pod's namespace label when it exists. +func consulDNSEnabled(namespace corev1.Namespace, pod corev1.Pod, globalEnabled bool) (bool, error) { + // First check to see if the pod annotation exists to override the namespace or global settings. + if raw, ok := pod.Annotations[keyConsulDNS]; ok { + return strconv.ParseBool(raw) + } + // Next see if the namespace has been defaulted. + if raw, ok := namespace.Labels[keyConsulDNS]; ok { + return strconv.ParseBool(raw) + } + // Else fall back to the global default. + return globalEnabled, nil +} + // pointerToInt64 takes an int64 and returns a pointer to it. func pointerToInt64(i int64) *int64 { return &i @@ -331,6 +379,9 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD {{- if .ConsulNamespace }} -namespace="{{ .ConsulNamespace }}" \ {{- end }} + {{- if .ConsulDNSClusterIP }} + -consul-dns-ip="{{ .ConsulDNSClusterIP }}" \ + {{- end }} {{- range .TProxyExcludeInboundPorts }} -exclude-inbound-port="{{ . }}" \ {{- end }} diff --git a/control-plane/connect-inject/container_init_test.go b/control-plane/connect-inject/container_init_test.go index e131ba20f7..58cfe95d73 100644 --- a/control-plane/connect-inject/container_init_test.go +++ b/control-plane/connect-inject/container_init_test.go @@ -2,6 +2,7 @@ package connectinject import ( "fmt" + "os" "strings" "testing" @@ -310,6 +311,115 @@ func TestHandlerContainerInit_transparentProxy(t *testing.T) { } } +func TestHandlerContainerInit_consulDNS(t *testing.T) { + cases := map[string]struct { + globalEnabled bool + annotations map[string]string + expectedContainsCmd string + namespaceLabel map[string]string + }{ + "enabled globally, ns not set, annotation not provided": { + globalEnabled: true, + expectedContainsCmd: `/consul/connect-inject/consul connect redirect-traffic \ + -consul-dns-ip="10.0.34.16" \ + -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -proxy-uid=5995`, + }, + "enabled globally, ns not set, annotation is false": { + globalEnabled: true, + annotations: map[string]string{keyConsulDNS: "false"}, + expectedContainsCmd: `/consul/connect-inject/consul connect redirect-traffic \ + -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -proxy-uid=5995`, + }, + "enabled globally, ns not set, annotation is true": { + globalEnabled: true, + annotations: map[string]string{keyConsulDNS: "true"}, + expectedContainsCmd: `/consul/connect-inject/consul connect redirect-traffic \ + -consul-dns-ip="10.0.34.16" \ + -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -proxy-uid=5995`, + }, + "disabled globally, ns not set, annotation not provided": { + expectedContainsCmd: `/consul/connect-inject/consul connect redirect-traffic \ + -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -proxy-uid=5995`, + }, + "disabled globally, ns not set, annotation is false": { + annotations: map[string]string{keyConsulDNS: "false"}, + expectedContainsCmd: `/consul/connect-inject/consul connect redirect-traffic \ + -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -proxy-uid=5995`, + }, + "disabled globally, ns not set, annotation is true": { + annotations: map[string]string{keyConsulDNS: "true"}, + expectedContainsCmd: `/consul/connect-inject/consul connect redirect-traffic \ + -consul-dns-ip="10.0.34.16" \ + -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -proxy-uid=5995`, + }, + "disabled globally, ns enabled, annotation not set": { + expectedContainsCmd: `/consul/connect-inject/consul connect redirect-traffic \ + -consul-dns-ip="10.0.34.16" \ + -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -proxy-uid=5995`, + namespaceLabel: map[string]string{keyConsulDNS: "true"}, + }, + "enabled globally, ns disabled, annotation not set": { + globalEnabled: true, + expectedContainsCmd: `/consul/connect-inject/consul connect redirect-traffic \ + -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + -proxy-uid=5995`, + namespaceLabel: map[string]string{keyConsulDNS: "false"}, + }, + } + for name, c := range cases { + t.Run(name, func(t *testing.T) { + h := Handler{EnableConsulDNS: c.globalEnabled, EnableTransparentProxy: true, ResourcePrefix: "consul-consul"} + os.Setenv("CONSUL_CONSUL_DNS_SERVICE_HOST", "10.0.34.16") + defer os.Unsetenv("CONSUL_CONSUL_DNS_SERVICE_HOST") + + pod := minimal() + pod.Annotations = c.annotations + + ns := testNS + ns.Labels = c.namespaceLabel + container, err := h.containerInit(ns, *pod) + require.NoError(t, err) + actualCmd := strings.Join(container.Command, " ") + + require.Contains(t, actualCmd, c.expectedContainsCmd) + }) + } +} + +func TestHandler_constructDNSServiceHostName(t *testing.T) { + cases := []struct { + prefix string + result string + }{ + { + prefix: "consul-consul", + result: "CONSUL_CONSUL_DNS_SERVICE_HOST", + }, + { + prefix: "release", + result: "RELEASE_DNS_SERVICE_HOST", + }, + { + prefix: "consul-dc1", + result: "CONSUL_DC1_DNS_SERVICE_HOST", + }, + } + + for _, c := range cases { + t.Run(c.prefix, func(t *testing.T) { + h := Handler{ResourcePrefix: c.prefix} + require.Equal(t, c.result, h.constructDNSServiceHostName()) + }) + } +} + func TestHandlerContainerInit_namespacesAndPartitionsEnabled(t *testing.T) { minimal := func() *corev1.Pod { return &corev1.Pod{ diff --git a/control-plane/connect-inject/handler.go b/control-plane/connect-inject/handler.go index aad0c4c53f..da2b4f681d 100644 --- a/control-plane/connect-inject/handler.go +++ b/control-plane/connect-inject/handler.go @@ -134,6 +134,14 @@ type Handler struct { // to point them to the Envoy proxy. TProxyOverwriteProbes bool + // EnableConsulDNS enables traffic redirection so that DNS requests are directed to Consul + // from mesh services. + EnableConsulDNS bool + + // ResourcePrefix is the prefix used for the installation which is used to determine the Service + // name of the Consul DNS service. + ResourcePrefix string + // EnableOpenShift indicates that when tproxy is enabled, the security context for the Envoy and init // containers should not be added because OpenShift sets a random user for those and will not allow // those containers to be created otherwise. diff --git a/control-plane/subcommand/inject-connect/command.go b/control-plane/subcommand/inject-connect/command.go index e93e07a48e..abebf69b81 100644 --- a/control-plane/subcommand/inject-connect/command.go +++ b/control-plane/subcommand/inject-connect/command.go @@ -92,6 +92,10 @@ type Command struct { flagDefaultEnableTransparentProxy bool flagTransparentProxyDefaultOverwriteProbes bool + // Consul DNS flags. + flagEnableConsulDNS bool + flagResourcePrefix string + flagEnableOpenShift bool flagSet *flag.FlagSet @@ -161,6 +165,10 @@ func (c *Command) init() { "Enable transparent proxy mode for all Consul service mesh applications by default.") c.flagSet.BoolVar(&c.flagTransparentProxyDefaultOverwriteProbes, "transparent-proxy-default-overwrite-probes", true, "Overwrite Kubernetes probes to point to Envoy by default when in Transparent Proxy mode.") + c.flagSet.BoolVar(&c.flagEnableConsulDNS, "enable-consul-dns", false, + "Enables Consul DNS lookup for services in the mesh.") + c.flagSet.StringVar(&c.flagResourcePrefix, "resource-prefix", "", + "Release prefix of the Consul installation used to determine Consul DNS Service name.") c.flagSet.BoolVar(&c.flagEnableOpenShift, "enable-openshift", false, "Indicates that the command runs in an OpenShift cluster.") c.flagSet.StringVar(&c.flagLogLevel, "log-level", zapcore.InfoLevel.String(), @@ -471,6 +479,8 @@ func (c *Command) Run(args []string) int { CrossNamespaceACLPolicy: c.flagCrossNamespaceACLPolicy, EnableTransparentProxy: c.flagDefaultEnableTransparentProxy, TProxyOverwriteProbes: c.flagTransparentProxyDefaultOverwriteProbes, + EnableConsulDNS: c.flagEnableConsulDNS, + ResourcePrefix: c.flagResourcePrefix, EnableOpenShift: c.flagEnableOpenShift, Log: ctrl.Log.WithName("handler").WithName("connect"), LogLevel: c.flagLogLevel, From ae3b7927d43c889ee1343ed21eb1e01f2502d15b Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 10 Nov 2021 15:57:31 -0500 Subject: [PATCH 132/418] Migrate server.enterpriseLicense to global.enterpriseLicense (#856) --- CHANGELOG.md | 3 + acceptance/framework/config/config.go | 4 +- acceptance/framework/config/config_test.go | 4 +- charts/consul/templates/client-daemonset.yaml | 10 +- .../client-snapshot-agent-deployment.yaml | 14 +- .../templates/enterprise-license-job.yaml | 7 +- .../enterprise-license-podsecuritypolicy.yaml | 2 +- .../templates/enterprise-license-role.yaml | 2 +- .../enterprise-license-rolebinding.yaml | 2 +- .../enterprise-license-serviceaccount.yaml | 2 +- .../consul/templates/server-acl-init-job.yaml | 2 +- .../consul/templates/server-statefulset.yaml | 10 +- charts/consul/test/unit/client-daemonset.bats | 24 ++-- .../client-snapshot-agent-deployment.bats | 24 ++-- .../test/unit/enterprise-license-job.bats | 129 ++++++++++-------- .../enterprise-license-podsecuritypolicy.bats | 32 ++--- .../test/unit/enterprise-license-role.bats | 43 +++--- .../unit/enterprise-license-rolebinding.bats | 24 ++-- .../enterprise-license-serviceaccount.bats | 30 ++-- .../consul/test/unit/server-acl-init-job.bats | 14 +- .../consul/test/unit/server-statefulset.bats | 12 +- charts/consul/values.yaml | 30 ++-- 22 files changed, 220 insertions(+), 204 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cec3581f34..cb848c3487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ BREAKING CHANGES: * Previously [UI metrics](https://www.consul.io/docs/connect/observability/ui-visualization) would be enabled when `global.metrics=false` and `ui.metrics.enabled=-`. If you are no longer seeing UI metrics, set `global.metrics=true` or `ui.metrics.enabled=true`. [[GH-841](https://github.com/hashicorp/consul-k8s/pull/841)] +* The `enterpriseLicense` section of the values file has been migrated from being under the `server` stanza to being + under the `global` stanza. Migrating the contents of `server.enterpriseLicense` to `global.enterpriseLicense` will + ensure the license job works. [[GH-856](https://github.com/hashicorp/consul-k8s/pull/856)] IMPROVEMENTS: * Control Plane diff --git a/acceptance/framework/config/config.go b/acceptance/framework/config/config.go index 28803faa20..7834b1adb7 100644 --- a/acceptance/framework/config/config.go +++ b/acceptance/framework/config/config.go @@ -66,8 +66,8 @@ func (t *TestConfig) HelmValuesFromConfig() (map[string]string, error) { } if t.EnterpriseLicense != "" { - setIfNotEmpty(helmValues, "server.enterpriseLicense.secretName", LicenseSecretName) - setIfNotEmpty(helmValues, "server.enterpriseLicense.secretKey", LicenseSecretKey) + setIfNotEmpty(helmValues, "global.enterpriseLicense.secretName", LicenseSecretName) + setIfNotEmpty(helmValues, "global.enterpriseLicense.secretKey", LicenseSecretKey) } if t.EnableOpenshift { diff --git a/acceptance/framework/config/config_test.go b/acceptance/framework/config/config_test.go index df320687b8..f628c8afc9 100644 --- a/acceptance/framework/config/config_test.go +++ b/acceptance/framework/config/config_test.go @@ -61,8 +61,8 @@ func TestConfig_HelmValuesFromConfig(t *testing.T) { EnterpriseLicense: "ent-license", }, map[string]string{ - "server.enterpriseLicense.secretName": "license", - "server.enterpriseLicense.secretKey": "key", + "global.enterpriseLicense.secretName": "license", + "global.enterpriseLicense.secretKey": "key", "connectInject.transparentProxy.defaultEnabled": "false", }, }, diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index 28c9512ce6..c98265480d 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -131,10 +131,10 @@ spec: - name: aclconfig emptyDir: {} {{- else }} - {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: consul-license secret: - secretName: {{ .Values.server.enterpriseLicense.secretName }} + secretName: {{ .Values.global.enterpriseLicense.secretName }} {{- end }} {{- end }} containers: @@ -181,9 +181,9 @@ spec: key: {{ .Values.global.gossipEncryption.secretKey }} {{- end }} {{- end }} - {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload (not .Values.global.acls.manageSystemACLs)) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload (not .Values.global.acls.manageSystemACLs)) }} - name: CONSUL_LICENSE_PATH - value: /consul/license/{{ .Values.server.enterpriseLicense.secretKey }} + value: /consul/license/{{ .Values.global.enterpriseLicense.secretKey }} {{- end }} {{- if .Values.global.tls.enabled }} - name: CONSUL_HTTP_ADDR @@ -309,7 +309,7 @@ spec: - name: aclconfig mountPath: /consul/aclconfig {{- else }} - {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: consul-license mountPath: /consul/license readOnly: true diff --git a/charts/consul/templates/client-snapshot-agent-deployment.yaml b/charts/consul/templates/client-snapshot-agent-deployment.yaml index 42b6c67b01..80fa46dfc9 100644 --- a/charts/consul/templates/client-snapshot-agent-deployment.yaml +++ b/charts/consul/templates/client-snapshot-agent-deployment.yaml @@ -38,7 +38,7 @@ spec: {{- if .Values.client.priorityClassName }} priorityClassName: {{ .Values.client.priorityClassName | quote }} {{- end }} - {{- if (or .Values.global.acls.manageSystemACLs .Values.global.tls.enabled (and .Values.client.snapshotAgent.configSecret.secretName .Values.client.snapshotAgent.configSecret.secretKey) (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload)) }} + {{- if (or .Values.global.acls.manageSystemACLs .Values.global.tls.enabled (and .Values.client.snapshotAgent.configSecret.secretName .Values.client.snapshotAgent.configSecret.secretKey) (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload)) }} volumes: {{- if (and .Values.client.snapshotAgent.configSecret.secretName .Values.client.snapshotAgent.configSecret.secretKey) }} - name: snapshot-config @@ -52,10 +52,10 @@ spec: - name: aclconfig emptyDir: {} {{- else }} - {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: consul-license secret: - secretName: {{ .Values.server.enterpriseLicense.secretName }} + secretName: {{ .Values.global.enterpriseLicense.secretName }} {{- end }} {{- end }} {{- if .Values.global.tls.enabled }} @@ -102,9 +102,9 @@ spec: name: "{{ template "consul.fullname" . }}-client-snapshot-agent-acl-token" key: "token" {{- else }} - {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: CONSUL_LICENSE_PATH - value: /consul/license/{{ .Values.server.enterpriseLicense.secretKey }} + value: /consul/license/{{ .Values.global.enterpriseLicense.secretKey }} {{- end }} {{- end}} command: @@ -123,7 +123,7 @@ spec: {{- if .Values.global.acls.manageSystemACLs }} -config-dir=/consul/aclconfig \ {{- end }} - {{- if (or .Values.global.acls.manageSystemACLs .Values.global.tls.enabled (and .Values.client.snapshotAgent.configSecret.secretName .Values.client.snapshotAgent.configSecret.secretKey) (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload)) }} + {{- if (or .Values.global.acls.manageSystemACLs .Values.global.tls.enabled (and .Values.client.snapshotAgent.configSecret.secretName .Values.client.snapshotAgent.configSecret.secretKey) (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload)) }} volumeMounts: {{- if (and .Values.client.snapshotAgent.configSecret.secretName .Values.client.snapshotAgent.configSecret.secretKey) }} - name: snapshot-config @@ -134,7 +134,7 @@ spec: - name: aclconfig mountPath: /consul/aclconfig {{- else }} - {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: consul-license mountPath: /consul/license readOnly: true diff --git a/charts/consul/templates/enterprise-license-job.yaml b/charts/consul/templates/enterprise-license-job.yaml index 0999277c7e..1509d9479e 100644 --- a/charts/consul/templates/enterprise-license-job.yaml +++ b/charts/consul/templates/enterprise-license-job.yaml @@ -1,5 +1,6 @@ +{{- if .Values.server.enterpriseLicense }}{{ fail "server.enterpriseLicense has been moved to global.enterpriseLicense" }}{{ end -}} {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey (not .Values.server.enterpriseLicense.enableLicenseAutoload)) }} +{{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey (not .Values.global.enterpriseLicense.enableLicenseAutoload)) }} apiVersion: batch/v1 kind: Job metadata: @@ -55,8 +56,8 @@ spec: - name: ENTERPRISE_LICENSE valueFrom: secretKeyRef: - name: {{ .Values.server.enterpriseLicense.secretName }} - key: {{ .Values.server.enterpriseLicense.secretKey }} + name: {{ .Values.global.enterpriseLicense.secretName }} + key: {{ .Values.global.enterpriseLicense.secretKey }} - name: CONSUL_HTTP_ADDR {{- if .Values.global.tls.enabled }} value: https://{{ template "consul.fullname" . }}-server:8501 diff --git a/charts/consul/templates/enterprise-license-podsecuritypolicy.yaml b/charts/consul/templates/enterprise-license-podsecuritypolicy.yaml index 2db9ce5530..cf96367473 100644 --- a/charts/consul/templates/enterprise-license-podsecuritypolicy.yaml +++ b/charts/consul/templates/enterprise-license-podsecuritypolicy.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey (not .Values.server.enterpriseLicense.enableLicenseAutoload)) }} +{{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey (not .Values.global.enterpriseLicense.enableLicenseAutoload)) }} {{- if .Values.global.enablePodSecurityPolicies }} apiVersion: policy/v1beta1 kind: PodSecurityPolicy diff --git a/charts/consul/templates/enterprise-license-role.yaml b/charts/consul/templates/enterprise-license-role.yaml index f3e5554508..6a1b7fdffa 100644 --- a/charts/consul/templates/enterprise-license-role.yaml +++ b/charts/consul/templates/enterprise-license-role.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey (not .Values.server.enterpriseLicense.enableLicenseAutoload)) }} +{{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey (not .Values.global.enterpriseLicense.enableLicenseAutoload)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: diff --git a/charts/consul/templates/enterprise-license-rolebinding.yaml b/charts/consul/templates/enterprise-license-rolebinding.yaml index 7df1c4fa2c..a21118b431 100644 --- a/charts/consul/templates/enterprise-license-rolebinding.yaml +++ b/charts/consul/templates/enterprise-license-rolebinding.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey (not .Values.server.enterpriseLicense.enableLicenseAutoload)) }} +{{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey (not .Values.global.enterpriseLicense.enableLicenseAutoload)) }} apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: diff --git a/charts/consul/templates/enterprise-license-serviceaccount.yaml b/charts/consul/templates/enterprise-license-serviceaccount.yaml index 54d4523ff9..31c9da841e 100644 --- a/charts/consul/templates/enterprise-license-serviceaccount.yaml +++ b/charts/consul/templates/enterprise-license-serviceaccount.yaml @@ -1,5 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} -{{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey (not .Values.server.enterpriseLicense.enableLicenseAutoload)) }} +{{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey (not .Values.global.enterpriseLicense.enableLicenseAutoload)) }} apiVersion: v1 kind: ServiceAccount metadata: diff --git a/charts/consul/templates/server-acl-init-job.yaml b/charts/consul/templates/server-acl-init-job.yaml index a3b3e76e8c..1fb43cbd02 100644 --- a/charts/consul/templates/server-acl-init-job.yaml +++ b/charts/consul/templates/server-acl-init-job.yaml @@ -192,7 +192,7 @@ spec: -acl-binding-rule-selector={{ .Values.connectInject.aclBindingRuleSelector }} \ {{- end }} - {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey) }} -create-enterprise-license-token=true \ {{- end }} diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 5e8cc89e76..2380486793 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -102,10 +102,10 @@ spec: secretName: {{ template "consul.fullname" . }}-server-cert {{- end }} {{- end }} - {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: consul-license secret: - secretName: {{ .Values.server.enterpriseLicense.secretName }} + secretName: {{ .Values.global.enterpriseLicense.secretName }} {{- end }} {{- range .Values.server.extraVolumes }} - name: userconfig-{{ .name }} @@ -174,9 +174,9 @@ spec: - name: CONSUL_CACERT value: /consul/tls/ca/tls.crt {{- end }} - {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: CONSUL_LICENSE_PATH - value: /consul/license/{{ .Values.server.enterpriseLicense.secretKey }} + value: /consul/license/{{ .Values.global.enterpriseLicense.secretKey }} {{- end }} {{- if (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) }} - name: ACL_REPLICATION_TOKEN @@ -276,7 +276,7 @@ spec: mountPath: /consul/tls/server readOnly: true {{- end }} - {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: consul-license mountPath: /consul/license readOnly: true diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index a6f8a63b1a..2d03f2f3aa 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1349,8 +1349,8 @@ rollingUpdate: cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.volumes[] | select(.name == "consul-license")' | tee /dev/stderr) [ "${actual}" = '{"name":"consul-license","secret":{"secretName":"foo"}}' ] @@ -1360,8 +1360,8 @@ rollingUpdate: cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-license")' | tee /dev/stderr) [ "${actual}" = '{"name":"consul-license","mountPath":"/consul/license","readOnly":true}' ] @@ -1371,8 +1371,8 @@ rollingUpdate: cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.containers[0].env[] | select(.name == "CONSUL_LICENSE_PATH")' | tee /dev/stderr) [ "${actual}" = '{"name":"CONSUL_LICENSE_PATH","value":"/consul/license/bar"}' ] @@ -1382,8 +1382,8 @@ rollingUpdate: cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.volumes[] | select(.name == "consul-license")' | tee /dev/stderr) @@ -1394,8 +1394,8 @@ rollingUpdate: cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-license")' | tee /dev/stderr) @@ -1406,8 +1406,8 @@ rollingUpdate: cd `chart_dir` local actual=$(helm template \ -s templates/client-daemonset.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.containers[0].env[] | select(.name == "CONSUL_LICENSE_PATH")' | tee /dev/stderr) diff --git a/charts/consul/test/unit/client-snapshot-agent-deployment.bats b/charts/consul/test/unit/client-snapshot-agent-deployment.bats index 07d96a68bf..48023c2bf7 100644 --- a/charts/consul/test/unit/client-snapshot-agent-deployment.bats +++ b/charts/consul/test/unit/client-snapshot-agent-deployment.bats @@ -389,8 +389,8 @@ exec /bin/consul snapshot agent \' local actual=$(helm template \ -s templates/client-snapshot-agent-deployment.yaml \ --set 'client.snapshotAgent.enabled=true' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.volumes[] | select(.name == "consul-license")' | tee /dev/stderr) [ "${actual}" = '{"name":"consul-license","secret":{"secretName":"foo"}}' ] @@ -401,8 +401,8 @@ exec /bin/consul snapshot agent \' local actual=$(helm template \ -s templates/client-snapshot-agent-deployment.yaml \ --set 'client.snapshotAgent.enabled=true' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-license")' | tee /dev/stderr) [ "${actual}" = '{"name":"consul-license","mountPath":"/consul/license","readOnly":true}' ] @@ -413,8 +413,8 @@ exec /bin/consul snapshot agent \' local actual=$(helm template \ -s templates/client-snapshot-agent-deployment.yaml \ --set 'client.snapshotAgent.enabled=true' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.containers[0].env[] | select(.name == "CONSUL_LICENSE_PATH")' | tee /dev/stderr) [ "${actual}" = '{"name":"CONSUL_LICENSE_PATH","value":"/consul/license/bar"}' ] @@ -425,8 +425,8 @@ exec /bin/consul snapshot agent \' local actual=$(helm template \ -s templates/client-snapshot-agent-deployment.yaml \ --set 'client.snapshotAgent.enabled=true' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.volumes[] | select(.name == "consul-license")' | tee /dev/stderr) @@ -438,8 +438,8 @@ exec /bin/consul snapshot agent \' local actual=$(helm template \ -s templates/client-snapshot-agent-deployment.yaml \ --set 'client.snapshotAgent.enabled=true' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-license")' | tee /dev/stderr) @@ -451,8 +451,8 @@ exec /bin/consul snapshot agent \' local actual=$(helm template \ -s templates/client-snapshot-agent-deployment.yaml \ --set 'client.snapshotAgent.enabled=true' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.containers[0].env[] | select(.name == "CONSUL_LICENSE_PATH")' | tee /dev/stderr) diff --git a/charts/consul/test/unit/enterprise-license-job.bats b/charts/consul/test/unit/enterprise-license-job.bats index dfaad6bf03..02bf995a20 100644 --- a/charts/consul/test/unit/enterprise-license-job.bats +++ b/charts/consul/test/unit/enterprise-license-job.bats @@ -2,86 +2,99 @@ load _helpers -@test "server/EnterpriseLicense: disabled by default" { +@test "enterpriseLicense/Job: disabled by default" { cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-job.yaml \ . } -@test "server/EnterpriseLicense: disabled if autoload is true (default) { +@test "enterpriseLicense/Job: disabled if autoload is true (default) { cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . } -@test "server/EnterpriseLicense: disabled when servers are disabled" { +@test "enterpriseLicense/Job: disabled when servers are disabled" { cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-job.yaml \ --set 'server.enabled=false' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } -@test "server/EnterpriseLicense: disabled when secretName is missing" { +@test "enterpriseLicense/Job: disabled when secretName is missing" { cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } -@test "server/EnterpriseLicense: disabled when secretKey is missing" { +@test "enterpriseLicense/Job: disabled when secretKey is missing" { cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } -@test "server/EnterpriseLicense: enabled when secretName, secretKey is provided and autoload is disabled" { +@test "enterpriseLicense/Job: enabled when secretName, secretKey is provided and autoload is disabled" { cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . | tee /dev/stderr | yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] } +@test "enterpriseLicense/Job: fail is server.enterpriseLicense is set" { + cd `chart_dir` + run helm template \ + -s templates/enterprise-license-job.yaml \ + --set 'server.enterpriseLicense.secretName=foo' \ + --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + . + + [ "$status" -eq 1 ] + [[ "$output" =~ "server.enterpriseLicense has been moved to global.enterpriseLicense" ]] +} + #-------------------------------------------------------------------- # global.acls.manageSystemACLs -@test "server/EnterpriseLicense: CONSUL_HTTP_TOKEN env variable created when global.acls.manageSystemACLs=true" { +@test "enterpriseLicense/Job: CONSUL_HTTP_TOKEN env variable created when global.acls.manageSystemACLs=true" { cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq '[.spec.template.spec.containers[0].env[].name] | any(contains("CONSUL_HTTP_TOKEN"))' | tee /dev/stderr) [ "${actual}" = "true" ] } -@test "server/EnterpriseLicense: init container is created when global.acls.manageSystemACLs=true" { +@test "enterpriseLicense/Job: init container is created when global.acls.manageSystemACLs=true" { cd `chart_dir` local object=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq '.spec.template.spec.initContainers[0]' | tee /dev/stderr) @@ -98,104 +111,104 @@ load _helpers #-------------------------------------------------------------------- # global.tls.enabled -@test "server/EnterpriseLicense: no volumes when TLS is disabled" { +@test "enterpriseLicense/Job: no volumes when TLS is disabled" { cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.tls.enabled=false' \ . | tee /dev/stderr | yq '.spec.template.spec.volumes | length' | tee /dev/stderr) [ "${actual}" = "0" ] } -@test "server/EnterpriseLicense: volumes present when TLS is enabled" { +@test "enterpriseLicense/Job: volumes present when TLS is enabled" { cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.tls.enabled=true' \ . | tee /dev/stderr | yq '.spec.template.spec.volumes | length' | tee /dev/stderr) [ "${actual}" = "1" ] } -@test "server/EnterpriseLicense: no volumes mounted when TLS is disabled" { +@test "enterpriseLicense/Job: no volumes mounted when TLS is disabled" { cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.tls.enabled=false' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].volumeMounts | length' | tee /dev/stderr) [ "${actual}" = "0" ] } -@test "server/EnterpriseLicense: volumes mounted when TLS is enabled" { +@test "enterpriseLicense/Job: volumes mounted when TLS is enabled" { cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.tls.enabled=true' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].volumeMounts | length' | tee /dev/stderr) [ "${actual}" = "1" ] } -@test "server/EnterpriseLicense: URL is http when TLS is disabled" { +@test "enterpriseLicense/Job: URL is http when TLS is disabled" { cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.tls.enabled=false' \ . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env[] | select(.name == "CONSUL_HTTP_ADDR") | .value' | tee /dev/stderr) [ "${actual}" = "http://RELEASE-NAME-consul-server:8500" ] } -@test "server/EnterpriseLicense: URL is https when TLS is enabled" { +@test "enterpriseLicense/Job: URL is https when TLS is enabled" { cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.tls.enabled=true' \ . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env[] | select(.name == "CONSUL_HTTP_ADDR") | .value' | tee /dev/stderr) [ "${actual}" = "https://RELEASE-NAME-consul-server:8501" ] } -@test "server/EnterpriseLicense: CA certificate is specified when TLS is enabled" { +@test "enterpriseLicense/Job: CA certificate is specified when TLS is enabled" { cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.tls.enabled=true' \ . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].env[] | select(.name == "CONSUL_CACERT") | .value' | tee /dev/stderr) [ "${actual}" = "/consul/tls/ca/tls.crt" ] } -@test "server/EnterpriseLicense: can overwrite CA secret with the provided one" { +@test "enterpriseLicense/Job: can overwrite CA secret with the provided one" { cd `chart_dir` local ca_cert_volume=$(helm template \ -s templates/enterprise-license-job.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.tls.enabled=true' \ --set 'global.tls.caCert.secretName=foo-ca-cert' \ --set 'global.tls.caCert.secretKey=key' \ diff --git a/charts/consul/test/unit/enterprise-license-podsecuritypolicy.bats b/charts/consul/test/unit/enterprise-license-podsecuritypolicy.bats index f22fc9010e..a23134303d 100644 --- a/charts/consul/test/unit/enterprise-license-podsecuritypolicy.bats +++ b/charts/consul/test/unit/enterprise-license-podsecuritypolicy.bats @@ -13,9 +13,9 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-podsecuritypolicy.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -24,9 +24,9 @@ load _helpers assert_empty helm template \ -s templates/enterprise-license-podsecuritypolicy.yaml \ --set 'server.enabled=false' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -34,8 +34,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-podsecuritypolicy.yaml \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -43,8 +43,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-podsecuritypolicy.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -52,9 +52,9 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-podsecuritypolicy.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.enablePodSecurityPolicies=false' \ . } @@ -63,9 +63,9 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-podsecuritypolicy.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.enablePodSecurityPolicies=true' \ . | tee /dev/stderr | yq 'length > 0' | tee /dev/stderr) diff --git a/charts/consul/test/unit/enterprise-license-role.bats b/charts/consul/test/unit/enterprise-license-role.bats index f3eca4abdb..3ffd0ed5e8 100644 --- a/charts/consul/test/unit/enterprise-license-role.bats +++ b/charts/consul/test/unit/enterprise-license-role.bats @@ -13,8 +13,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-role.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . } @@ -23,9 +23,9 @@ load _helpers assert_empty helm template \ -s templates/enterprise-license-role.yaml \ --set 'server.enabled=false' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -33,8 +33,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-role.yaml \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -42,8 +42,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-role.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -51,9 +51,9 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-role.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . | tee /dev/stderr | yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] @@ -63,9 +63,9 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-role.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . | tee /dev/stderr | yq '.rules | length' | tee /dev/stderr) [ "${actual}" = "0" ] @@ -78,16 +78,15 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-role.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq -r '.rules | map(select(.resourceNames[0] == "RELEASE-NAME-consul-enterprise-license-acl-token")) | length' | tee /dev/stderr) [ "${actual}" = "1" ] } - #-------------------------------------------------------------------- # global.enablePodSecurityPolicies @@ -95,9 +94,9 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-role.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.enablePodSecurityPolicies=true' \ . | tee /dev/stderr | yq -r '.rules | map(select(.resources[0] == "podsecuritypolicies")) | length' | tee /dev/stderr) diff --git a/charts/consul/test/unit/enterprise-license-rolebinding.bats b/charts/consul/test/unit/enterprise-license-rolebinding.bats index edb8970fcb..0d03ee5b4e 100644 --- a/charts/consul/test/unit/enterprise-license-rolebinding.bats +++ b/charts/consul/test/unit/enterprise-license-rolebinding.bats @@ -13,8 +13,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-rolebinding.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . } @@ -23,9 +23,9 @@ load _helpers assert_empty helm template \ -s templates/enterprise-license-rolebinding.yaml \ --set 'server.enabled=false' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -33,8 +33,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-rolebinding.yaml \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -42,8 +42,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-rolebinding.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -51,9 +51,9 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-rolebinding.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . | tee /dev/stderr | yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] diff --git a/charts/consul/test/unit/enterprise-license-serviceaccount.bats b/charts/consul/test/unit/enterprise-license-serviceaccount.bats index a863e0091c..5f83421657 100644 --- a/charts/consul/test/unit/enterprise-license-serviceaccount.bats +++ b/charts/consul/test/unit/enterprise-license-serviceaccount.bats @@ -13,8 +13,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-serviceaccount.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . } @@ -23,9 +23,9 @@ load _helpers assert_empty helm template \ -s templates/enterprise-license-serviceaccount.yaml \ --set 'server.enabled=false' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -33,8 +33,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-serviceaccount.yaml \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -42,8 +42,8 @@ load _helpers cd `chart_dir` assert_empty helm template \ -s templates/enterprise-license-serviceaccount.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . } @@ -51,9 +51,9 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/enterprise-license-serviceaccount.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ . | tee /dev/stderr | yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] @@ -66,9 +66,9 @@ load _helpers cd `chart_dir` local object=$(helm template \ -s templates/enterprise-license-serviceaccount.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ - --set 'server.enterpriseLicense.enableLicenseAutoload=false' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ --set 'global.imagePullSecrets[0].name=my-secret' \ --set 'global.imagePullSecrets[1].name=my-secret2' \ . | tee /dev/stderr) diff --git a/charts/consul/test/unit/server-acl-init-job.bats b/charts/consul/test/unit/server-acl-init-job.bats index a0ae9a34c5..fe5b09e615 100644 --- a/charts/consul/test/unit/server-acl-init-job.bats +++ b/charts/consul/test/unit/server-acl-init-job.bats @@ -204,35 +204,35 @@ load _helpers #-------------------------------------------------------------------- # enterpriseLicense -@test "serverACLInit/Job: ent license acl option enabled with server.enterpriseLicense.secretName and server.enterpriseLicense.secretKey set" { +@test "serverACLInit/Job: ent license acl option enabled with global.enterpriseLicense.secretName and global.enterpriseLicense.secretKey set" { cd `chart_dir` local actual=$(helm template \ -s templates/server-acl-init-job.yaml \ --set 'global.acls.manageSystemACLs=true' \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].command | any(contains("-create-enterprise-license-token"))' | tee /dev/stderr) [ "${actual}" = "true" ] } -@test "serverACLInit/Job: ent license acl option disabled missing server.enterpriseLicense.secretName" { +@test "serverACLInit/Job: ent license acl option disabled missing global.enterpriseLicense.secretName" { cd `chart_dir` local actual=$(helm template \ -s templates/server-acl-init-job.yaml \ --set 'global.acls.manageSystemACLs=true' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].command | any(contains("-create-enterprise-license-token"))' | tee /dev/stderr) [ "${actual}" = "false" ] } -@test "serverACLInit/Job: ent license acl option disabled missing server.enterpriseLicense.secretKey" { +@test "serverACLInit/Job: ent license acl option disabled missing global.enterpriseLicense.secretKey" { cd `chart_dir` local actual=$(helm template \ -s templates/server-acl-init-job.yaml \ --set 'global.acls.manageSystemACLs=true' \ - --set 'server.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretName=foo' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].command | any(contains("-create-enterprise-license-token"))' | tee /dev/stderr) [ "${actual}" = "false" ] diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index a7a31bb84d..e11018f279 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -1345,8 +1345,8 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/server-statefulset.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.volumes[] | select(.name == "consul-license")' | tee /dev/stderr) [ "${actual}" = '{"name":"consul-license","secret":{"secretName":"foo"}}' ] @@ -1356,8 +1356,8 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/server-statefulset.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-license")' | tee /dev/stderr) [ "${actual}" = '{"name":"consul-license","mountPath":"/consul/license","readOnly":true}' ] @@ -1367,8 +1367,8 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/server-statefulset.yaml \ - --set 'server.enterpriseLicense.secretName=foo' \ - --set 'server.enterpriseLicense.secretKey=bar' \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=bar' \ . | tee /dev/stderr | yq -r -c '.spec.template.spec.containers[0].env[] | select(.name == "CONSUL_LICENSE_PATH")' | tee /dev/stderr) [ "${actual}" = '{"name":"CONSUL_LICENSE_PATH","value":"/consul/license/bar"}' ] diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 9d5af13ac8..099b5d8c43 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -262,6 +262,21 @@ global: # The key of the Kubernetes secret. secretKey: null + # [Enterprise Only] This value refers to a Kubernetes secret that you have created + # that contains your enterprise license. It is required if you are using an + # enterprise binary. Defining it here applies it to your cluster once a leader + # has been elected. If you are not using an enterprise image or if you plan to + # introduce the license key via another route, then set these fields to null. + # Note: the job to apply license runs on both Helm installs and upgrades. + enterpriseLicense: + # The name of the Kubernetes secret that holds the enterprise license. + # The secret must be in the same namespace that Consul is installed into. + secretName: null + # The key within the Kubernetes secret that holds the enterprise license. + secretKey: null + # Manages license autoload. Required in Consul 1.10.0+, 1.9.7+ and 1.8.12+. + enableLicenseAutoload: true + # Configure federation. federation: # If enabled, this datacenter will be federation-capable. Only federation @@ -364,21 +379,6 @@ server: # @type: int bootstrapExpect: null - # [Enterprise Only] This value refers to a Kubernetes secret that you have created - # that contains your enterprise license. It is required if you are using an - # enterprise binary. Defining it here applies it to your cluster once a leader - # has been elected. If you are not using an enterprise image or if you plan to - # introduce the license key via another route, then set these fields to null. - # Note: the job to apply license runs on both Helm installs and upgrades. - enterpriseLicense: - # The name of the Kubernetes secret that holds the enterprise license. - # The secret must be in the same namespace that Consul is installed into. - secretName: null - # The key within the Kubernetes secret that holds the enterprise license. - secretKey: null - # Manages license autoload. Required in Consul 1.10.0+, 1.9.7+ and 1.8.12+. - enableLicenseAutoload: true - # A Kubernetes secret containing a certificate & key for the server agents to use # for TLS communication within the Consul cluster. Cert needs to be provided with # additional DNS name SANs so that it will work within the Kubernetes cluster: From 1eb20757a573ea896974eaec9f410a7259003bcc Mon Sep 17 00:00:00 2001 From: David Yu Date: Wed, 10 Nov 2021 13:41:02 -0800 Subject: [PATCH 133/418] CONTRIBUTING: Making changes (#855) * CONTRIBUTING: Making changes add section on making changes --- CONTRIBUTING.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 13183ad2ff..ec4aaf9192 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,8 +3,9 @@ 1. [Contributing 101](#contributing-101) 1. [Building and running `consul-k8s-control-plane`](#building-and-running-consul-k8s-control-plane) 1. [Building and running the `consul-k8s` CLI](#building-and-running-the-consul-k8s-cli) - 3. [Running Linters Locally](#running-linters-locally) - 4. [Rebasing Contributions against main](#rebasing-contributions-against-main) + 1. [Making changes to consul-k8s](#making-changes-to-consul-k8s) + 1. [Running linters locally](#running-linters-locally) + 1. [Rebasing contributions against main](#rebasing-contributions-against-main) 1. [Creating a new CRD](#creating-a-new-crd) 1. [The Structs](#the-structs) 1. [Spec Methods](#spec-methods) @@ -134,6 +135,22 @@ Run the CLI as follows consul-k8s 0.36.0-dev ``` +### Making changes to consul-k8s + +The first step to making changes is to fork Consul K8s. Afterwards, the easiest way +to work on the fork is to set it as a remote of the Consul K8s project: + +1. Rename the existing remote's name: `git remote rename origin upstream`. +1. Add your fork as a remote by running + `git remote add origin `. For example: + `git remote add origin https://github.com/myusername/consul-k8s`. +1. Checkout a feature branch: `git checkout -t -b new-feature` +1. Make changes (i.e. `git commit -am 'message'`) +1. Push changes to the fork when ready to submit PR: + `git push -u origin new-feature` + +>Note: If you make any changes to the code, run `gofmt -s -w` to automatically format the code according to Go standards. + ### Running linters locally [`golangci-lint`](https://golangci-lint.run/) is used in CI to enforce coding and style standards and help catch bugs ahead of time. The configuration that CI runs is stored in `.golangci.yml` at the top level of the repository. From 80102a5edb7d07f4fd4e165d98a498439cc298bf Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Fri, 12 Nov 2021 13:12:25 -0600 Subject: [PATCH 134/418] Bootstrap gossip encryption with Vault (#811) * Add base bootstrapping logic and acceptance tests for gossip encryption in Vault Co-authored-by: Iryna Shustava --- acceptance/framework/consul/consul_cluster.go | 2 +- acceptance/framework/helpers/helpers.go | 4 +- acceptance/framework/vault/vault_cluster.go | 41 +++---- acceptance/tests/vault/vault_test.go | 109 ++++++++++++++--- charts/consul/templates/_helpers.tpl | 6 + charts/consul/templates/client-daemonset.yaml | 17 +++ .../consul/templates/server-statefulset.yaml | 19 +++ charts/consul/test/unit/client-daemonset.bats | 93 +++++++++++++- .../gossip-encryption-autogenerate-job.bats | 16 +-- .../consul/test/unit/server-statefulset.bats | 115 +++++++++++++++--- charts/consul/values.yaml | 55 ++++++++- 11 files changed, 398 insertions(+), 79 deletions(-) diff --git a/acceptance/framework/consul/consul_cluster.go b/acceptance/framework/consul/consul_cluster.go index 15cd39a28c..90b5dc392b 100644 --- a/acceptance/framework/consul/consul_cluster.go +++ b/acceptance/framework/consul/consul_cluster.go @@ -114,7 +114,7 @@ func (h *HelmCluster) Create(t *testing.T) { }) // Fail if there are any existing installations of the Helm chart. - helpers.CheckForPriorInstallations(t, h.kubernetesClient, h.helmOptions, "consul-helm") + helpers.CheckForPriorInstallations(t, h.kubernetesClient, h.helmOptions, "consul-helm", "chart=consul-helm") helm.Install(t, h.helmOptions, config.HelmChartPath, h.releaseName) diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index 294e395cb2..f173aeea6f 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -29,7 +29,7 @@ func RandomName() string { // CheckForPriorInstallations checks if there is an existing Helm release // for this Helm chart already installed. If there is, it fails the tests. -func CheckForPriorInstallations(t *testing.T, client kubernetes.Interface, options *helm.Options, chartName string) { +func CheckForPriorInstallations(t *testing.T, client kubernetes.Interface, options *helm.Options, chartName, labelSelector string) { t.Helper() var helmListOutput string @@ -57,7 +57,7 @@ func CheckForPriorInstallations(t *testing.T, client kubernetes.Interface, optio // Wait for all pods in the "default" namespace to exit. A previous // release may not be listed by Helm but its pods may still be terminating. retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { - pods, err := client.CoreV1().Pods(options.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: fmt.Sprintf("chart=%s", chartName)}) + pods, err := client.CoreV1().Pods(options.KubectlOptions.Namespace).List(context.Background(), metav1.ListOptions{LabelSelector: labelSelector}) require.NoError(r, err) if len(pods.Items) > 0 { var podNames []string diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index 36644c1abe..01e3141e1f 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -1,12 +1,7 @@ package vault import ( - "context" "fmt" - "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" - "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "testing" "time" @@ -15,6 +10,8 @@ import ( terratestLogger "github.com/gruntwork-io/terratest/modules/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/config" "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/sdk/testutil/retry" vapi "github.com/hashicorp/vault/api" @@ -23,9 +20,9 @@ import ( ) const ( - vaultNS = "default" - vaultChartVersion = "0.17.0" - vaultRootToken = "abcd1234" + vaultNS = "default" + vaultPodLabel = "app.kubernetes.io/instance=" + vaultRootToken = "abcd1234" ) // VaultCluster @@ -35,7 +32,6 @@ type VaultCluster struct { vaultHelmOptions *helm.Options vaultReleaseName string - vaultChartName string vaultClient *vapi.Client kubectlOptions *terratestk8s.KubectlOptions @@ -68,13 +64,14 @@ func NewVaultCluster( SetValues: defaultVaultValues(), KubectlOptions: kopts, Logger: logger, - Version: vaultChartVersion, } - // Add the vault helm repo in case it is missing, and do an update so we can utilise `vaultChartVersion` to install. - helm.AddRepo(t, &helm.Options{}, "hashicorp/vault", "https://helm.releases.hashicorp.com") + helm.AddRepo(t, vaultHelmOpts, "hashicorp", "https://helm.releases.hashicorp.com") // Ignoring the error from `helm repo update` as it could fail due to stale cache or unreachable servers and we're // asserting a chart version on Install which would fail in an obvious way should this not succeed. - _, _ = helm.RunHelmCommandAndGetOutputE(t, &helm.Options{}, "repo", "update") + _, err := helm.RunHelmCommandAndGetOutputE(t, &helm.Options{}, "repo", "update") + if err != nil { + logger.Logf(t, "Unable to update helm repository, proceeding anyway: %s.", err) + } return &VaultCluster{ ctx: ctx, @@ -89,7 +86,6 @@ func NewVaultCluster( debugDirectory: cfg.DebugDirectory, logger: logger, vaultReleaseName: releaseName, - vaultChartName: fmt.Sprintf("vault-%s", vaultChartVersion), } } @@ -115,7 +111,7 @@ func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { v.logger) // Retry creating the port forward since it can fail occasionally. - retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 3}, t, func(r *retry.R) { + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { // NOTE: It's okay to pass in `t` to ForwardPortE despite being in a retry // because we're using ForwardPortE (not ForwardPort) so the `t` won't // get used to fail the test, just for logging. @@ -158,7 +154,7 @@ func (v *VaultCluster) bootstrap(t *testing.T, ctx environment.TestContext) { } // We need to kubectl exec this one on the vault server: // This is taken from https://learn.hashicorp.com/tutorials/vault/kubernetes-google-cloud-gke?in=vault/kubernetes#configure-kubernetes-authentication - cmdString := fmt.Sprintf("VAULT_TOKEN=%s vault write auth/kubernetes/config token_reviewer_jwt=\"$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\" kubernetes_host=\"https://${KUBERNETES_PORT_443_TCP_ADDR}:443\" kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", vaultRootToken) + cmdString := fmt.Sprintf("VAULT_TOKEN=%s vault write auth/kubernetes/config disable_iss_validation=\"true\" token_reviewer_jwt=\"$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\" kubernetes_host=\"https://${KUBERNETES_PORT_443_TCP_ADDR}:443\" kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", vaultRootToken) v.logger.Logf(t, "updating vault kube auth config") k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "-i", fmt.Sprintf("%s-vault-0", v.vaultReleaseName), "--", "sh", "-c", cmdString) @@ -175,19 +171,12 @@ func (v *VaultCluster) Create(t *testing.T, ctx environment.TestContext) { }) // Fail if there are any existing installations of the Helm chart. - helpers.CheckForPriorInstallations(t, v.kubernetesClient, v.vaultHelmOptions, v.vaultChartName) + helpers.CheckForPriorInstallations(t, v.kubernetesClient, v.vaultHelmOptions, "", fmt.Sprintf("%s=%s", vaultPodLabel, v.vaultReleaseName)) // Install Vault. helm.Install(t, v.vaultHelmOptions, "hashicorp/vault", v.vaultReleaseName) - // Wait for the injector pod to become Ready, but not the server. - helpers.WaitForAllPodsToBeReady(t, v.kubernetesClient, v.vaultHelmOptions.KubectlOptions.Namespace, "app.kubernetes.io/name=vault-agent-injector") - // Wait for the server pod to be PodRunning, it will not be Ready because it has not been Init+Unseal'd yet. - // The vault server has health checks bound to unseal status, and Unseal is done as part of bootstrap (below). - retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 30}, t, func(r *retry.R) { - pod, err := v.kubernetesClient.CoreV1().Pods(v.vaultHelmOptions.KubectlOptions.Namespace).Get(context.Background(), fmt.Sprintf("%s-vault-0", v.vaultReleaseName), metav1.GetOptions{}) - require.NoError(r, err) - require.Equal(r, pod.Status.Phase, corev1.PodRunning) - }) + // Wait for the injector and vault server pods to become Ready. + helpers.WaitForAllPodsToBeReady(t, v.kubernetesClient, v.vaultHelmOptions.KubectlOptions.Namespace, fmt.Sprintf("%s=%s", vaultPodLabel, v.vaultReleaseName)) // Now call bootstrap() v.bootstrap(t, ctx) } diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index fac892bf0e..67b81f1884 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -1,43 +1,118 @@ package vault import ( - "testing" - "time" - + "crypto/rand" + "encoding/base64" + "fmt" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/vault" "github.com/stretchr/testify/require" + "testing" ) -// Installs Vault, bootstraps it with the kube auth method -// and then validates that the KV2 secrets engine is online -// and the Kube Auth Method is enabled. -func TestVault_Create(t *testing.T) { +// generateGossipSecret generates a random 32 byte secret returned as a base64 encoded string. +func generateGossipSecret() (string, error) { + // This code was copied from Consul's Keygen command: + // https://github.com/hashicorp/consul/blob/d652cc86e3d0322102c2b5e9026c6a60f36c17a5/command/keygen/keygen.go + + key := make([]byte, 32) + n, err := rand.Reader.Read(key) + if err != nil { + return "", fmt.Errorf("error reading random data: %s", err) + } + if n != 32 { + return "", fmt.Errorf("couldn't read enough entropy") + } + + return base64.StdEncoding.EncodeToString(key), nil +} + +// Installs Vault, bootstraps it with secrets, policies, and Kube Auth Method +// then creates a gossip encryption secret and uses this to bootstrap Consul. +func TestVault_BootstrapConsulGossipEncryptionKey(t *testing.T) { cfg := suite.Config() ctx := suite.Environment().DefaultContext(t) + consulReleaseName := helpers.RandomName() vaultReleaseName := helpers.RandomName() + consulClientServiceAccountName := fmt.Sprintf("%s-consul-client", consulReleaseName) + consulServerServiceAccountName := fmt.Sprintf("%s-consul-server", consulReleaseName) + vaultCluster := vault.NewVaultCluster(t, nil, ctx, cfg, vaultReleaseName) vaultCluster.Create(t, ctx) - logger.Log(t, "Finished Installing and Bootstrapping") + // Vault is now installed in the cluster. + // Now fetch the Vault client so we can create the policies and secrets. vaultClient := vaultCluster.VaultClient(t) - // Write to the KV2 engine succeeds. - logger.Log(t, "Creating a KV2 Secret") + // Create the Vault Policy for the gossip key. + logger.Log(t, "Creating the gossip policy") + rules := ` +path "consul/data/secret/gossip" { + capabilities = ["read"] +}` + err := vaultClient.Sys().PutPolicy("consul-gossip", rules) + require.NoError(t, err) + + // Create the Auth Roles for consul-server + consul-client. + logger.Log(t, "Creating the consul-server and consul-client-roles") params := map[string]interface{}{ + "bound_service_account_names": consulClientServiceAccountName, + "bound_service_account_namespaces": "default", + "policies": "consul-gossip", + "ttl": "24h", + } + _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-client", params) + require.NoError(t, err) + + params = map[string]interface{}{ + "bound_service_account_names": consulServerServiceAccountName, + "bound_service_account_namespaces": "default", + "policies": "consul-gossip", + "ttl": "24h", + } + _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-server", params) + require.NoError(t, err) + + gossipKey, err := generateGossipSecret() + require.NoError(t, err) + + // Create the gossip secret. + logger.Log(t, "Creating the gossip secret") + params = map[string]interface{}{ "data": map[string]interface{}{ - "foo": "bar", + "gossip": gossipKey, }, } - _, err := vaultClient.Logical().Write("consul/data/secret/test", params) + _, err = vaultClient.Logical().Write("consul/data/secret/gossip", params) require.NoError(t, err) - // Validate that the Auth Method exists. - authList, err := vaultClient.Sys().ListAuth() + consulHelmValues := map[string]string{ + "server.enabled": "true", + "server.replicas": "1", + + "connectInject.enabled": "true", + + "global.secretsBackend.vault.enabled": "true", + "global.secretsBackend.vault.consulServerRole": "consul-server", + "global.secretsBackend.vault.consulClientRole": "consul-client", + + "global.acls.manageSystemACLs": "true", + "global.tls.enabled": "true", + "global.gossipEncryption.secretName": "consul/data/secret/gossip", + "global.gossipEncryption.secretKey": "gossip", + } + logger.Log(t, "Installing Consul") + consulCluster := consul.NewHelmCluster(t, consulHelmValues, ctx, cfg, consulReleaseName) + consulCluster.Create(t) + + // Validate that the gossip encryption key is set correctly. + logger.Log(t, "Validating the gossip key has been set correctly.") + consulClient := consulCluster.SetupConsulClient(t, true) + keys, err := consulClient.Operator().KeyringList(nil) require.NoError(t, err) - logger.Log(t, "Auth List: ", authList) - require.NotNil(t, authList["kubernetes/"]) - time.Sleep(time.Second * 60) + // We use keys[0] because KeyringList returns a list of keyrings for each dc, in this case there is only 1 dc. + require.Equal(t, 1, keys[0].PrimaryKeys[gossipKey]) } diff --git a/charts/consul/templates/_helpers.tpl b/charts/consul/templates/_helpers.tpl index 173eb68cc9..07ced2d778 100644 --- a/charts/consul/templates/_helpers.tpl +++ b/charts/consul/templates/_helpers.tpl @@ -15,6 +15,12 @@ as well as the global.name setting. {{- end -}} {{- end -}} +{{- define "consul.vaultGossipTemplate" -}} + | + {{ "{{" }}- with secret "{{ .secretName }}" -{{ "}}" }} + {{ "{{" }}- {{ printf ".Data.data.%s" .secretKey }} -{{ "}}" }} + {{ "{{" }}- end -{{ "}}" }} +{{- end -}} {{/* Sets up the extra-from-values config file passed to consul and then uses sed to do any necessary substitution for HOST_IP/POD_IP/HOSTNAME. Useful for dogstats telemetry. The output file diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index d4e1c05107..af213f9e4e 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -2,6 +2,7 @@ {{- if (and (and .Values.global.tls.enabled .Values.global.tls.httpsOnly) (and .Values.global.metrics.enabled .Values.global.metrics.enableAgentMetrics))}}{{ fail "global.metrics.enableAgentMetrics cannot be enabled if TLS (HTTPS only) is enabled" }}{{ end -}} {{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} {{- if (and .Values.global.adminPartitions.enabled $serverEnabled (ne .Values.global.adminPartitions.name "default"))}}{{ fail "global.adminPartitions.name has to be \"default\" in the server cluster" }}{{ end -}} +{{- if (and (not .Values.global.secretsBackend.vault.consulClientRole) .Values.global.secretsBackend.vault.enabled) }}{{ fail "global.secretsBackend.vault.consulClientRole must be provided if global.secretsBackend.vault.enabled=true." }}{{ end -}} # DaemonSet to run the Consul clients on every node. apiVersion: apps/v1 kind: DaemonSet @@ -37,6 +38,16 @@ spec: {{- toYaml .Values.client.extraLabels | nindent 8 }} {{- end }} annotations: + {{- if .Values.global.secretsBackend.vault.enabled }} + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": "{{ .Values.global.secretsBackend.vault.consulClientRole }}" + {{- if .Values.global.gossipEncryption.secretName }} + {{- with .Values.global.gossipEncryption }} + "vault.hashicorp.com/agent-inject-secret-gossip.txt": "{{ .secretName }}" + "vault.hashicorp.com/agent-inject-template-gossip.txt": {{ template "consul.vaultGossipTemplate" . }} + {{- end }} + {{- end }} + {{- end }} "consul.hashicorp.com/connect-inject": "false" "consul.hashicorp.com/config-checksum": {{ include (print $.Template.BasePath "/client-config-configmap.yaml") . | sha256sum }} {{- if .Values.client.annotations }} @@ -169,6 +180,7 @@ spec: - name: CONSUL_DISABLE_PERM_MGMT value: "true" {{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} + {{- if not .Values.global.secretsBackend.vault.enabled }} - name: GOSSIP_KEY valueFrom: secretKeyRef: @@ -180,6 +192,7 @@ spec: key: {{ .Values.global.gossipEncryption.secretKey }} {{- end }} {{- end }} + {{- end }} {{- if (and .Values.server.enterpriseLicense.secretName .Values.server.enterpriseLicense.secretKey .Values.server.enterpriseLicense.enableLicenseAutoload (not .Values.global.acls.manageSystemACLs)) }} - name: CONSUL_LICENSE_PATH value: /consul/license/{{ .Values.server.enterpriseLicense.secretKey }} @@ -202,6 +215,10 @@ spec: - | CONSUL_FULLNAME="{{template "consul.fullname" . }}" + {{- if and .Values.global.secretsBackend.vault.enabled .Values.global.gossipEncryption.secretName }} + GOSSIP_KEY=`cat /vault/secrets/gossip.txt` + {{- end }} + {{ template "consul.extraconfig" }} exec /usr/local/bin/docker-entrypoint.sh consul agent \ diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index fe2dcff468..77fa3c68de 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -5,6 +5,9 @@ {{- if .Values.server.disableFsGroupSecurityContext }}{{ fail "server.disableFsGroupSecurityContext has been removed. Please use global.openshift.enabled instead." }}{{ end }} {{- if .Values.server.bootstrapExpect }}{{ if lt (int .Values.server.bootstrapExpect) (int .Values.server.replicas) }}{{ fail "server.bootstrapExpect cannot be less than server.replicas" }}{{ end }}{{ end }} {{- if (and (and .Values.global.tls.enabled .Values.global.tls.httpsOnly) (and .Values.global.metrics.enabled .Values.global.metrics.enableAgentMetrics))}}{{ fail "global.metrics.enableAgentMetrics cannot be enabled if TLS (HTTPS only) is enabled" }}{{ end -}} +{{- if (and .Values.global.gossipEncryption.secretName (not .Values.global.gossipEncryption.secretKey)) }}{{fail "gossipEncryption.secretKey and secretName must both be specified." }}{{ end -}} +{{- if (and (not .Values.global.gossipEncryption.secretName) .Values.global.gossipEncryption.secretKey) }}{{fail "gossipEncryption.secretKey and secretName must both be specified." }}{{ end -}} +{{- if (and .Values.global.secretsBackend.vault.enabled (not .Values.global.secretsBackend.vault.consulServerRole)) }}{{ fail "global.secretsBackend.vault.consulServerRole must be provided if global.secretsBackend.vault.enabled=true." }}{{ end -}} # StatefulSet to run the actual Consul server cluster. apiVersion: apps/v1 kind: StatefulSet @@ -46,6 +49,16 @@ spec: {{- toYaml .Values.server.extraLabels | nindent 8 }} {{- end }} annotations: + {{- if .Values.global.secretsBackend.vault.enabled }} + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": "{{ .Values.global.secretsBackend.vault.consulServerRole }}" + {{- if .Values.global.gossipEncryption.secretName }} + {{- with .Values.global.gossipEncryption }} + "vault.hashicorp.com/agent-inject-secret-gossip.txt": "{{ .secretName }}" + "vault.hashicorp.com/agent-inject-template-gossip.txt": {{ template "consul.vaultGossipTemplate" . }} + {{- end }} + {{- end }} + {{- end }} "consul.hashicorp.com/connect-inject": "false" "consul.hashicorp.com/config-checksum": {{ include (print $.Template.BasePath "/server-config-configmap.yaml") . | sha256sum }} {{- if .Values.server.annotations }} @@ -157,6 +170,7 @@ spec: - name: CONSUL_DISABLE_PERM_MGMT value: "true" {{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} + {{- if not .Values.global.secretsBackend.vault.enabled }} - name: GOSSIP_KEY valueFrom: secretKeyRef: @@ -168,6 +182,7 @@ spec: key: {{ .Values.global.gossipEncryption.secretKey }} {{- end }} {{- end }} + {{- end }} {{- if .Values.global.tls.enabled }} - name: CONSUL_HTTP_ADDR value: https://localhost:8501 @@ -192,6 +207,10 @@ spec: - | CONSUL_FULLNAME="{{template "consul.fullname" . }}" + {{- if .Values.global.secretsBackend.vault.enabled }} + GOSSIP_KEY=`cat /vault/secrets/gossip.txt` + {{- end }} + {{ template "consul.extraconfig" }} exec /usr/local/bin/docker-entrypoint.sh consul agent \ diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index 64a9d0e4c0..f83c802e32 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -602,7 +602,7 @@ load _helpers local actual=$(helm template \ -s templates/client-daemonset.yaml \ . | tee /dev/stderr | - yq '.spec.template.spec.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY") | length > 0' | tee /dev/stderr) + yq '.spec.template.spec.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY")' | tee /dev/stderr) [ "${actual}" = "" ] } @@ -1516,3 +1516,94 @@ rollingUpdate: [ "${object}" = 1 ] } + +#-------------------------------------------------------------------- +# vault integration + +@test "client/DaemonSet: fail when vault is enabled but the consulClientRole is not provided" { + cd `chart_dir` + run helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.secretsBackend.vault.consulClientRole must be provided if global.secretsBackend.vault.enabled=true" ]] +} + +@test "client/DaemonSet: vault annotations not set by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/role"] | length > 0 ' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "client/DaemonSet: vault annotations added when vault is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr) + [ "${actual}" = "foo" ] +} + +@test "client/DaemonSet: vault gossip annotations are set when gossip encryption enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.gossipEncryption.secretName=path/to/secret' \ + --set 'global.gossipEncryption.secretKey=gossip' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-gossip.txt"]' | tee /dev/stderr) + [ "${actual}" = "path/to/secret" ] + local actual="$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-gossip.txt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"path/to/secret\" -}}\n{{- .Data.data.gossip -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] +} + +@test "client/DaemonSet: GOSSIP_KEY env variable is not set and command defines GOSSIP_KEY when vault is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.gossipEncryption.secretName=a/b/c/d' \ + --set 'global.gossipEncryption.secretKey=gossip' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec' | tee /dev/stderr) + + + local actual=$(echo $object | + yq -r '.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY")' | tee /dev/stderr) + [ "${actual}" = "" ] + + local actual=$(echo $object | + yq -r '.containers[] | select(.name=="consul") | .command | any(contains("GOSSIP_KEY="))' \ + | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/test/unit/gossip-encryption-autogenerate-job.bats b/charts/consul/test/unit/gossip-encryption-autogenerate-job.bats index b78b9c231d..4b5938ab91 100644 --- a/charts/consul/test/unit/gossip-encryption-autogenerate-job.bats +++ b/charts/consul/test/unit/gossip-encryption-autogenerate-job.bats @@ -39,24 +39,14 @@ load _helpers [[ "$output" =~ "If global.gossipEncryption.autoGenerate is true, global.gossipEncryption.secretName and global.gossipEncryption.secretKey must not be set." ]] } -@test "gossipEncryptionAutogenerate/Job: fails if global.gossipEncryption.autoGenerate=true and global.gossipEncryption.secretName is set" { +@test "gossipEncryptionAutogenerate/Job: fails if global.gossipEncryption.autoGenerate=true and global.gossipEncryption.secretName+key are set" { cd `chart_dir` run helm template \ -s templates/gossip-encryption-autogenerate-job.yaml \ --set 'global.gossipEncryption.autoGenerate=true' \ --set 'global.gossipEncryption.secretName=name' \ - . - [ "$status" -eq 1 ] - [[ "$output" =~ "If global.gossipEncryption.autoGenerate is true, global.gossipEncryption.secretName and global.gossipEncryption.secretKey must not be set." ]] -} - -@test "gossipEncryptionAutogenerate/Job: fails if global.gossipEncryption.autoGenerate=true and global.gossipEncryption.secretKey is set" { - cd `chart_dir` - run helm template \ - -s templates/gossip-encryption-autogenerate-job.yaml \ - --set 'global.gossipEncryption.autoGenerate=true' \ - --set 'global.gossipEncryption.secretKey=key' \ - . + --set 'global.gossipEncryption.secretKey=name' \ + . [ "$status" -eq 1 ] [[ "$output" =~ "If global.gossipEncryption.autoGenerate is true, global.gossipEncryption.secretName and global.gossipEncryption.secretKey must not be set." ]] } diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 6418cef313..909fb647b2 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -838,7 +838,7 @@ load _helpers local actual=$(helm template \ -s templates/server-statefulset.yaml \ . | tee /dev/stderr | - yq '.spec.template.spec.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY") | length > 0' | tee /dev/stderr) + yq '.spec.template.spec.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY")' | tee /dev/stderr) [ "${actual}" = "" ] } @@ -863,25 +863,20 @@ load _helpers [ "${actual}" = "true" ] } - -@test "server/StatefulSet: gossip encryption disabled in server StatefulSet when secretName is missing" { +@test "server/StatefulSet: fail if global.gossipEncyption.gossipEncryption.secretName is set but not global.gossipEncyption.secretKey" { cd `chart_dir` - local actual=$(helm template \ + run helm template \ -s templates/server-statefulset.yaml \ - --set 'global.gossipEncryption.secretKey=bar' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY") | length > 0' | tee /dev/stderr) - [ "${actual}" = "" ] + --set 'global.gossipEncryption.secretName=bar' . + [[ "$output" =~ "gossipEncryption.secretKey and secretName must both be specified." ]] } -@test "server/StatefulSet: gossip encryption disabled in server StatefulSet when secretKey is missing" { +@test "server/StatefulSet: fail if global.gossipEncyption.gossipEncryption.secretKey is set but not global.gossipEncyption.secretName" { cd `chart_dir` - local actual=$(helm template \ + run helm template \ -s templates/server-statefulset.yaml \ - --set 'global.gossipEncryption.secretName=foo' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY") | length > 0' | tee /dev/stderr) - [ "${actual}" = "" ] + --set 'global.gossipEncryption.secretKey=bar' . + [[ "$output" =~ "gossipEncryption.secretKey and secretName must both be specified." ]] } @test "server/StatefulSet: gossip environment variable present in server StatefulSet when all config is provided" { @@ -1415,3 +1410,95 @@ load _helpers [ "${object}" = 1 ] } + +#-------------------------------------------------------------------- +# vault integration + +@test "server/StatefulSet: fail when vault is enabled but the consulServerRole is not provided" { + cd `chart_dir` + run helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.secretsBackend.vault.consulServerRole must be provided if global.secretsBackend.vault.enabled=true" ]] +} + +@test "server/StatefulSet: vault annotations not set by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/role"] | length > 0 ' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/StatefulSet: vault annotations added when vault is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr) + [ "${actual}" = "test" ] +} + +@test "server/StatefulSet: vault gossip annotations are correct when enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.gossipEncryption.secretName=path/to/secret' \ + --set 'global.gossipEncryption.secretKey=gossip' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-gossip.txt"]' | tee /dev/stderr) + [ "${actual}" = "path/to/secret" ] + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-gossip.txt"]' | tee /dev/stderr) + local actual="$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-gossip.txt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"path/to/secret\" -}}\n{{- .Data.data.gossip -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] +} + +@test "server/StatefulSet: vault no GOSSIP_KEY env variable and command defines GOSSIP_KEY" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.gossipEncryption.secretName=a/b/c/d' \ + --set 'global.gossipEncryption.secretKey=gossip' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec' | tee /dev/stderr) + + + local actual=$(echo $object | + yq -r '.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY")' | tee /dev/stderr) + [ "${actual}" = "" ] + + local actual=$(echo $object | + yq -r '.containers[] | select(.name=="consul") | .command | any(contains("GOSSIP_KEY="))' \ + | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 44b81cc327..2a04d7416c 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -117,25 +117,70 @@ global: # created by this chart. See https://kubernetes.io/docs/concepts/policy/pod-security-policy/. enablePodSecurityPolicies: false - # Configures Consul's gossip encryption key, set as a Kubernetes secret + # secretsBackend is used to configure Vault as the secrets backend for the Consul on Kubernetes installation. + # The Vault cluster needs to have the Kubernetes Auth Method, + # KV2 and PKI secrets engines enabled and have necessary secrets, + # policies and roles created prior to installing Consul. + # The Vault cluster should not have Consul as its storage backend. + # Note: When using Vault KV2 secrets engines the "data" field is implicitly required for Vault API calls, + # secretName should be in the form of "vault-kv2-mount-path/data/secret-name". + # secretKey should be in the form of "key". + secretsBackend: + vault: + # Enabling the Vault secrets backend will replace Kubernetes secrets with referenced Vault secrets. + enabled: false + + # The Vault role for the Consul server. + # The role must be connected to the Consul server's service account and + # have a policy with read capabilities for the following secrets: + # - gossip encryption key defined by `global.gossipEncryption.secretName`. + # To discover the service account name of the Consul server, run + # ``` + # helm template -s templates/server-serviceaccount.yaml charts/consul + # ``` + # and check the name of `metadata.name`. + consulServerRole: "" + + # The Vault role for the Consul client. + # The role must be connected to the Consul client's service account and + # have a policy with read capabilities for the following secrets: + # - gossip encryption key defined by `global.gossipEncryption.secretName`. + # To discover the service account name of the Consul server, run + # ``` + # helm template -s templates/client-daemonset.yaml charts/consul + # ``` + # and check the name of `metadata.name`. + consulClientRole: "" + + # Configures Consul's gossip encryption key. # (see `-encrypt` (https://consul.io/docs/agent/options#_encrypt)). # By default, gossip encryption is not enabled. The gossip encryption key may be set automatically or manually. # The recommended method is to automatically generate the key. # To automatically generate and set a gossip encryption key, set autoGenerate to true. # Values for secretName and secretKey should not be set if autoGenerate is true. # To manually generate a gossip encryption key, set secretName and secretKey and use Consul to generate - # a Kubernetes secret referencing these values. + # a key, saving this as a Kubernetes secret or Vault secret path and key. + # If `global.secretsBackend.vault.enabled=true`, be sure to add the "data" field to the secretName as required by + # the Vault KV-2 secrets engine [see example]. # # ``` # $ kubectl create secret generic consul-gossip-encryption-key --from-literal=key=$(consul keygen) # ``` + # + # Vault CLI Example: + # ``` + # $ vault kv put consul/secrets/gossip key=$(consul keygen) + # ``` + # `gossipEncryption.secretName="consul/data/secrets/gossip"` + # `gossipEncryption.secretKey="key"` + gossipEncryption: # Automatically generate a gossip encryption key and save it to a Kubernetes secret. autoGenerate: false - # secretName is the name of the Kubernetes secret that holds the gossip - # encryption key. The secret must be in the same namespace that Consul is installed into. + # secretName is the name of the Kubernetes secret or Vault secret path that holds the gossip + # encryption key. A Kubernetes secret must be in the same namespace that Consul is installed into. secretName: "" - # secretKey is the key within the Kubernetes secret that holds the gossip + # secretKey is the key within the Kubernetes secret or Vault secret key that holds the gossip # encryption key. secretKey: "" From 31586a7efdbc1410b6eab74180bd919be3e267b1 Mon Sep 17 00:00:00 2001 From: David Yu Date: Mon, 15 Nov 2021 10:45:18 -0800 Subject: [PATCH 135/418] Create federation secret with default `consul-gossip-encryption-key` secret when global.gossipEncryption.autoGenerate is set to true (#854) * adding conditional to check autogenerate * adding conditional around create federation secret flag command * add changelog --- CHANGELOG.md | 1 + .../templates/create-federation-secret-job.yaml | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb848c3487..47ad5c4cdf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ BUG FIXES: Consul destination namespace for connect or catalog sync. [[GH-846](https://github.com/hashicorp/consul-k8s/pull/846)] * Truncate Persistent Volume Claim names when namespace names are too long. [[GH-799](https://github.com/hashicorp/consul-k8s/pull/799)] * Fix issue where UI metrics would be enabled when `global.metrics=false` and `ui.metrics.enabled=-`. [[GH-841](https://github.com/hashicorp/consul-k8s/pull/841)] + * Populate the federation secret with the generated Gossip key when `global.gossipEncryption.autoGenerate` is set to true. [[GH-854](https://github.com/hashicorp/consul-k8s/pull/854)] ## 0.36.0 (November 02, 2021) diff --git a/charts/consul/templates/create-federation-secret-job.yaml b/charts/consul/templates/create-federation-secret-job.yaml index d00fde21cc..e3f0818a24 100644 --- a/charts/consul/templates/create-federation-secret-job.yaml +++ b/charts/consul/templates/create-federation-secret-job.yaml @@ -68,6 +68,13 @@ spec: items: - key: {{ .Values.global.gossipEncryption.secretKey }} path: gossip.key + {{- else if .Values.global.gossipEncryption.autoGenerate }} + - name: gossip-encryption-key + secret: + secretName: consul-gossip-encryption-key + items: + - key: key + path: gossip.key {{- end }} {{- if .Values.global.tls.enableAutoEncrypt }} @@ -107,7 +114,8 @@ spec: mountPath: /consul/tls/client/ca readOnly: true {{- end }} - {{- if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }} + {{- if (or .Values.global.gossipEncryption.autoGenerate + (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} - name: gossip-encryption-key mountPath: /consul/gossip readOnly: true @@ -119,7 +127,8 @@ spec: consul-k8s-control-plane create-federation-secret \ -log-level={{ .Values.global.logLevel }} \ -log-json={{ .Values.global.logJSON }} \ - {{- if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }} + {{- if (or .Values.global.gossipEncryption.autoGenerate (and + .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} -gossip-key-file=/consul/gossip/gossip.key \ {{- end }} {{- if .Values.global.acls.createReplicationToken }} From a0af34e02a475e282b78050a5b0d61ffbd79877d Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 15 Nov 2021 12:57:48 -0700 Subject: [PATCH 136/418] Update consul version to 1.10.4 (#861) --- CHANGELOG.md | 1 + charts/consul/Chart.yaml | 4 ++-- charts/consul/values.yaml | 2 +- control-plane/catalog/to-k8s/sink_test.go | 3 +-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47ad5c4cdf..5c75390c9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ IMPROVEMENTS: * Delete jobs, cluster roles, and cluster role bindings on `uninstall`. [[GH-820](https://github.com/hashicorp/consul-k8s/pull/820)] * Helm Chart * Add `component` labels to all resources. [[GH-840](https://github.com/hashicorp/consul-k8s/pull/840)] + * Update Consul version to 1.10.4. [[GH-861](https://github.com/hashicorp/consul-k8s/pull/861)] BUG FIXES: * Control Plane diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index 35f1b226b7..7c9857bffa 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: consul version: 0.36.0 -appVersion: 1.10.3 +appVersion: 1.10.4 kubeVersion: ">=1.17.0-0" description: Official HashiCorp Consul Chart home: https://www.consul.io @@ -13,7 +13,7 @@ annotations: artifacthub.io/prerelease: false artifacthub.io/images: | - name: consul - image: hashicorp/consul:1.10.3 + image: hashicorp/consul:1.10.4 - name: consul-k8s-control-plane image: hashicorp/consul-k8s-control-plane:0.36.0 - name: envoy diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 099b5d8c43..71b0cce751 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -85,7 +85,7 @@ global: # image: "hashicorp/consul-enterprise:1.10.0-ent" # ``` # @default: hashicorp/consul: - image: "hashicorp/consul:1.10.3" + image: "hashicorp/consul:1.10.4" # Array of objects containing image pull secret names that will be applied to each service account. # This can be used to reference image pull secrets if using a custom consul or consul-k8s-control-plane Docker image. diff --git a/control-plane/catalog/to-k8s/sink_test.go b/control-plane/catalog/to-k8s/sink_test.go index 3d5270af39..2883b1f9f3 100644 --- a/control-plane/catalog/to-k8s/sink_test.go +++ b/control-plane/catalog/to-k8s/sink_test.go @@ -150,8 +150,7 @@ func TestK8SSink_createExists(t *testing.T) { if actual == nil { r.Fatal("web not found") - } - if actual.Spec.ExternalName != "example.com." { + } else if actual.Spec.ExternalName != "example.com." { r.Fatal("modified") } }) From 183c0e0766bef984a49c814e668155c8ddf5ca90 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 16 Nov 2021 10:37:23 -0500 Subject: [PATCH 137/418] Flatten partitions tests into a single test (#859) * Flatten partitions tests into a single test * Replace config entry with CRD --- .../bases/admin-partitions/kustomization.yaml | 3 + .../partitionexports-default.yaml | 6 + .../partitionexports-secondary.yaml | 6 + .../kustomization.yaml | 5 + .../default-partition-default/patch.yaml | 14 + .../default-partition-ns1/kustomization.yaml | 5 + .../default-partition-ns1/patch.yaml | 14 + .../kustomization.yaml | 5 + .../secondary-partition-default/patch.yaml | 14 + .../kustomization.yaml | 5 + .../secondary-partition-ns1/patch.yaml | 14 + .../tests/partitions/partitions_test.go | 804 +++++------------- 12 files changed, 318 insertions(+), 577 deletions(-) create mode 100644 acceptance/tests/fixtures/bases/admin-partitions/kustomization.yaml create mode 100644 acceptance/tests/fixtures/bases/admin-partitions/partitionexports-default.yaml create mode 100644 acceptance/tests/fixtures/bases/admin-partitions/partitionexports-secondary.yaml create mode 100644 acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml create mode 100644 acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml create mode 100644 acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml create mode 100644 acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml create mode 100644 acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml create mode 100644 acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml create mode 100644 acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml create mode 100644 acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml diff --git a/acceptance/tests/fixtures/bases/admin-partitions/kustomization.yaml b/acceptance/tests/fixtures/bases/admin-partitions/kustomization.yaml new file mode 100644 index 0000000000..04a88496e8 --- /dev/null +++ b/acceptance/tests/fixtures/bases/admin-partitions/kustomization.yaml @@ -0,0 +1,3 @@ +resources: + - partitionexports-default.yaml + - partitionexports-secondary.yaml diff --git a/acceptance/tests/fixtures/bases/admin-partitions/partitionexports-default.yaml b/acceptance/tests/fixtures/bases/admin-partitions/partitionexports-default.yaml new file mode 100644 index 0000000000..718b5eae5e --- /dev/null +++ b/acceptance/tests/fixtures/bases/admin-partitions/partitionexports-default.yaml @@ -0,0 +1,6 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: PartitionExports +metadata: + name: default +spec: + services: [] diff --git a/acceptance/tests/fixtures/bases/admin-partitions/partitionexports-secondary.yaml b/acceptance/tests/fixtures/bases/admin-partitions/partitionexports-secondary.yaml new file mode 100644 index 0000000000..2f09fe87be --- /dev/null +++ b/acceptance/tests/fixtures/bases/admin-partitions/partitionexports-secondary.yaml @@ -0,0 +1,6 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: PartitionExports +metadata: + name: secondary +spec: + services: [] diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml new file mode 100644 index 0000000000..ccb255ba30 --- /dev/null +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - ../../../bases/admin-partitions + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml new file mode 100644 index 0000000000..5e836da962 --- /dev/null +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml @@ -0,0 +1,14 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: PartitionExports +metadata: + name: default +spec: + services: + - name: mesh-gateway + namespace: default + consumers: + - partition: secondary + - name: static-server + namespace: default + consumers: + - partition: secondary diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml new file mode 100644 index 0000000000..ccb255ba30 --- /dev/null +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - ../../../bases/admin-partitions + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml new file mode 100644 index 0000000000..dda2d4bfde --- /dev/null +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml @@ -0,0 +1,14 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: PartitionExports +metadata: + name: default +spec: + services: + - name: mesh-gateway + namespace: default + consumers: + - partition: secondary + - name: static-server + namespace: ns1 + consumers: + - partition: secondary diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml new file mode 100644 index 0000000000..ccb255ba30 --- /dev/null +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - ../../../bases/admin-partitions + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml new file mode 100644 index 0000000000..73ac31c6a8 --- /dev/null +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml @@ -0,0 +1,14 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: PartitionExports +metadata: + name: secondary +spec: + services: + - name: mesh-gateway + namespace: default + consumers: + - partition: default + - name: static-server + namespace: default + consumers: + - partition: default diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml new file mode 100644 index 0000000000..ccb255ba30 --- /dev/null +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - ../../../bases/admin-partitions + +patchesStrategicMerge: +- patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml new file mode 100644 index 0000000000..2e1b399797 --- /dev/null +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml @@ -0,0 +1,14 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: PartitionExports +metadata: + name: secondary +spec: + services: + - name: mesh-gateway + namespace: default + consumers: + - partition: default + - name: static-server + namespace: ns1 + consumers: + - partition: default diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 79968c7856..8f8e056784 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -23,435 +23,8 @@ const staticServerName = "static-server" const staticServerNamespace = "ns1" const staticClientNamespace = "ns2" -// Test that Connect works in a default installation. -// i.e. without ACLs because TLS is required for setting up Admin Partitions. -func TestPartitionsWithoutMesh(t *testing.T) { - env := suite.Environment() - cfg := suite.Config() - - if !cfg.EnableEnterprise { - t.Skipf("skipping this test because -enable-enterprise is not set") - } - - if !cfg.UseKind { - t.Skipf("skipping this test because Admin Partition tests are only supported in Kind for now") - } - - if cfg.EnableTransparentProxy { - t.Skipf("skipping this test because -enable-transparent-proxy is true") - } - - const defaultPartition = "default" - const secondaryPartition = "secondary" - const defaultNamespace = "default" - cases := []struct { - name string - destinationNamespace string - mirrorK8S bool - secure bool - }{ - { - "default namespace", - defaultNamespace, - false, - false, - }, - { - "default namespace; secure", - defaultNamespace, - false, - true, - }, - { - "single destination namespace", - staticServerNamespace, - false, - false, - }, - { - "single destination namespace; secure", - staticServerNamespace, - false, - true, - }, - { - "mirror k8s namespaces", - staticServerNamespace, - true, - false, - }, - { - "mirror k8s namespaces; secure", - staticServerNamespace, - true, - true, - }, - } - - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - serverClusterContext := env.DefaultContext(t) - clientClusterContext := env.Context(t, environment.SecondaryContextName) - - ctx := context.Background() - - serverHelmValues := map[string]string{ - "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta2", - - "global.adminPartitions.enabled": "true", - "global.enableConsulNamespaces": "true", - "global.tls.enabled": "true", - "global.tls.httpsOnly": strconv.FormatBool(c.secure), - "global.tls.enableAutoEncrypt": strconv.FormatBool(c.secure), - - "server.exposeGossipAndRPCPorts": "true", - - "connectInject.enabled": "true", - // When mirroringK8S is set, this setting is ignored. - "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, - "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.mirrorK8S), - "connectInject.transparentProxy.defaultEnabled": "false", - - "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), - } - - if cfg.UseKind { - serverHelmValues["global.adminPartitions.service.type"] = "NodePort" - serverHelmValues["global.adminPartitions.service.nodePort.https"] = "30000" - } - - releaseName := helpers.RandomName() - - // Install the consul cluster with servers in the default kubernetes context. - serverConsulCluster := consul.NewHelmCluster(t, serverHelmValues, serverClusterContext, cfg, releaseName) - serverConsulCluster.Create(t) - - // Get the TLS CA certificate and key secret from the server cluster and apply it to client cluster. - tlsCert := fmt.Sprintf("%s-consul-ca-cert", releaseName) - tlsKey := fmt.Sprintf("%s-consul-ca-key", releaseName) - - logger.Logf(t, "retrieving ca cert secret %s from the server cluster and applying to the client cluster", tlsCert) - caCertSecret, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, tlsCert, metav1.GetOptions{}) - caCertSecret.ResourceVersion = "" - require.NoError(t, err) - _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, caCertSecret, metav1.CreateOptions{}) - require.NoError(t, err) - - if !c.secure { - // When running in the insecure mode, auto-encrypt is disabled which requires both - // the CA cert and CA key to be available in the clients cluster. - logger.Logf(t, "retrieving ca key secret %s from the server cluster and applying to the client cluster", tlsKey) - caKeySecret, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, tlsKey, metav1.GetOptions{}) - caKeySecret.ResourceVersion = "" - require.NoError(t, err) - _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, caKeySecret, metav1.CreateOptions{}) - require.NoError(t, err) - } - - partitionToken := fmt.Sprintf("%s-consul-partitions-acl-token", releaseName) - if c.secure { - logger.Logf(t, "retrieving partition token secret %s from the server cluster and applying to the client cluster", tlsKey) - token, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionToken, metav1.GetOptions{}) - token.ResourceVersion = "" - require.NoError(t, err) - _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, token, metav1.CreateOptions{}) - require.NoError(t, err) - } - - var partitionSvcIP string - if !cfg.UseKind { - // Get the IP of the partition service to configure the external server address in the values file for the workload cluster. - partitionSecretName := fmt.Sprintf("%s-partition-secret", releaseName) - logger.Logf(t, "retrieving partition service to determine external IP for servers") - partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionSecretName, metav1.GetOptions{}) - require.NoError(t, err) - partitionSvcIP = partitionsSvc.Status.LoadBalancer.Ingress[0].IP - } else { - nodeList, err := serverClusterContext.KubernetesClient(t).CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) - require.NoError(t, err) - // Get the address of the (only) node from the Kind cluster. - partitionSvcIP = nodeList.Items[0].Status.Addresses[0].Address - } - - var k8sAuthMethodHost string - if cfg.UseKind { - // The Kubernetes AuthMethod IP for Kind is read from the endpoint for the Kubernetes service. On other clouds, - // this can be identified by reading the cluster config. - kubernetesEndpoint, err := clientClusterContext.KubernetesClient(t).CoreV1().Endpoints(defaultNamespace).Get(ctx, "kubernetes", metav1.GetOptions{}) - require.NoError(t, err) - k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) - } - - // Create client cluster. - clientHelmValues := map[string]string{ - "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta2", - "global.enabled": "false", - - "global.tls.enabled": "true", - "global.tls.httpsOnly": strconv.FormatBool(c.secure), - "global.tls.enableAutoEncrypt": strconv.FormatBool(c.secure), - - "server.exposeGossipAndRPCPorts": "true", - - "connectInject.enabled": "true", - // When mirroringK8S is set, this setting is ignored. - "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, - "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.mirrorK8S), - "connectInject.transparentProxy.defaultEnabled": "false", - - "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), - - "global.adminPartitions.enabled": "true", - "global.adminPartitions.name": secondaryPartition, - "global.enableConsulNamespaces": "true", - - "global.tls.caCert.secretName": tlsCert, - "global.tls.caCert.secretKey": "tls.crt", - - "externalServers.enabled": "true", - "externalServers.hosts[0]": partitionSvcIP, - "externalServers.tlsServerName": "server.dc1.consul", - - "client.enabled": "true", - "client.exposeGossipPorts": "true", - "client.join[0]": partitionSvcIP, - } - - if c.secure { - // setup partition token if ACLs enabled. - clientHelmValues["global.acls.bootstrapToken.secretName"] = partitionToken - clientHelmValues["global.acls.bootstrapToken.secretKey"] = "token" - clientHelmValues["externalServers.k8sAuthMethodHost"] = k8sAuthMethodHost - } else { - // provide CA key when auto-encrypt is disabled. - clientHelmValues["global.tls.caKey.secretName"] = tlsKey - clientHelmValues["global.tls.caKey.secretKey"] = "tls.key" - } - - if cfg.UseKind { - clientHelmValues["externalServers.httpsPort"] = "30000" - } - - // Install the consul cluster without servers in the client cluster kubernetes context. - clientConsulCluster := consul.NewHelmCluster(t, clientHelmValues, clientClusterContext, cfg, releaseName) - clientConsulCluster.Create(t) - - agentPodList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(clientClusterContext.KubectlOptions(t).Namespace).List(ctx, metav1.ListOptions{LabelSelector: "app=consul,component=client"}) - require.NoError(t, err) - require.Len(t, agentPodList.Items, 1) - - output, err := k8s.RunKubectlAndGetOutputE(t, clientClusterContext.KubectlOptions(t), "logs", agentPodList.Items[0].Name, "-n", clientClusterContext.KubectlOptions(t).Namespace) - require.NoError(t, err) - require.Contains(t, output, "Partition: 'secondary'") - - serverClusterStaticServerOpts := &terratestk8s.KubectlOptions{ - ContextName: serverClusterContext.KubectlOptions(t).ContextName, - ConfigPath: serverClusterContext.KubectlOptions(t).ConfigPath, - Namespace: staticServerNamespace, - } - serverClusterStaticClientOpts := &terratestk8s.KubectlOptions{ - ContextName: serverClusterContext.KubectlOptions(t).ContextName, - ConfigPath: serverClusterContext.KubectlOptions(t).ConfigPath, - Namespace: staticClientNamespace, - } - clientClusterStaticServerOpts := &terratestk8s.KubectlOptions{ - ContextName: clientClusterContext.KubectlOptions(t).ContextName, - ConfigPath: clientClusterContext.KubectlOptions(t).ConfigPath, - Namespace: staticServerNamespace, - } - clientClusterStaticClientOpts := &terratestk8s.KubectlOptions{ - ContextName: clientClusterContext.KubectlOptions(t).ContextName, - ConfigPath: clientClusterContext.KubectlOptions(t).ConfigPath, - Namespace: staticClientNamespace, - } - - logger.Logf(t, "creating namespaces %s and %s in servers cluster", staticServerNamespace, staticClientNamespace) - k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { - k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace) - }) - - k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "create", "ns", staticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { - // Note: this deletion will take longer in cases when the static-client deployment - // hasn't yet fully terminated. - k8s.RunKubectl(t, serverClusterContext.KubectlOptions(t), "delete", "ns", staticClientNamespace) - }) - - logger.Logf(t, "creating namespaces %s and %s in clients cluster", staticServerNamespace, staticClientNamespace) - k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "create", "ns", staticServerNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { - k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace) - }) - - k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "create", "ns", staticClientNamespace) - helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { - // Note: this deletion will take longer in cases when the static-client deployment - // hasn't yet fully terminated. - k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "delete", "ns", staticClientNamespace) - }) - - consulClient := serverConsulCluster.SetupConsulClient(t, c.secure) - - serverQueryServerOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: defaultPartition} - clientQueryServerOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: defaultPartition} - - serverQueryClientOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: secondaryPartition} - clientQueryClientOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: secondaryPartition} - - if !c.mirrorK8S { - serverQueryServerOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: defaultPartition} - clientQueryServerOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: defaultPartition} - serverQueryClientOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: secondaryPartition} - clientQueryClientOpts = &api.QueryOptions{Namespace: c.destinationNamespace, Partition: secondaryPartition} - } - - // Check that the ACL token is deleted. - if c.secure { - // We need to register the cleanup function before we create the deployments - // because golang will execute them in reverse order i.e. the last registered - // cleanup function will be executed first. - t.Cleanup(func() { - if c.secure { - retry.Run(t, func(r *retry.R) { - tokens, _, err := consulClient.ACL().TokenList(serverQueryServerOpts) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, staticServerName) - } - - tokens, _, err = consulClient.ACL().TokenList(clientQueryServerOpts) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, staticClientName) - } - tokens, _, err = consulClient.ACL().TokenList(serverQueryClientOpts) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, staticServerName) - } - - tokens, _, err = consulClient.ACL().TokenList(clientQueryClientOpts) - require.NoError(r, err) - for _, token := range tokens { - require.NotContains(r, token.Description, staticClientName) - } - }) - } - }) - } - - logger.Log(t, "creating static-server and static-client deployments in server cluster") - k8s.DeployKustomize(t, serverClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") - } else { - k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") - } - logger.Log(t, "creating static-server and static-client deployments in client cluster") - k8s.DeployKustomize(t, clientClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") - } else { - k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") - } - // Check that both static-server and static-client have been injected and now have 2 containers in server cluster. - for _, labelSelector := range []string{"app=static-server", "app=static-client"} { - podList, err := serverClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ - LabelSelector: labelSelector, - }) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - require.Len(t, podList.Items[0].Spec.Containers, 2) - } - - // Check that both static-server and static-client have been injected and now have 2 containers in client cluster. - for _, labelSelector := range []string{"app=static-server", "app=static-client"} { - podList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ - LabelSelector: labelSelector, - }) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - require.Len(t, podList.Items[0].Spec.Containers, 2) - } - - // Make sure that services are registered in the correct namespace. - // If mirroring is enabled, we expect services to be registered in the - // Consul namespace with the same name as their source - // Kubernetes namespace. - // If a single destination namespace is set, we expect all services - // to be registered in that destination Consul namespace. - // Server cluster. - services, _, err := consulClient.Catalog().Service(staticServerName, "", serverQueryServerOpts) - require.NoError(t, err) - require.Len(t, services, 1) - - services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryServerOpts) - require.NoError(t, err) - require.Len(t, services, 1) - - // Client cluster. - services, _, err = consulClient.Catalog().Service(staticServerName, "", serverQueryClientOpts) - require.NoError(t, err) - require.Len(t, services, 1) - - services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryClientOpts) - require.NoError(t, err) - require.Len(t, services, 1) - - if c.secure { - logger.Log(t, "checking that the connection is not successful because there's no intention") - k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") - - intention := &api.Intention{ - SourceName: staticClientName, - SourceNS: staticClientNamespace, - DestinationName: staticServerName, - DestinationNS: staticServerNamespace, - Action: api.IntentionActionAllow, - } - - // Set the destination namespace to be the same - // unless mirrorK8S is true. - if !c.mirrorK8S { - intention.SourceNS = c.destinationNamespace - intention.DestinationNS = c.destinationNamespace - } - - logger.Log(t, "creating intention") - _, err := consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: defaultPartition}) - require.NoError(t, err) - _, err = consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: secondaryPartition}) - require.NoError(t, err) - } - - logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") - - // Test that kubernetes readiness status is synced to Consul. - // Create the file so that the readiness probe of the static-server pod fails. - logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") - k8s.RunKubectl(t, serverClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") - k8s.RunKubectl(t, clientClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") - - // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry - // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. - // We are expecting a "connection reset by peer" error because in a case of health checks, - // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply - // from server, which is the case when a connection is unsuccessful due to intentions in other tests. - logger.Log(t, "checking that connection is unsuccessful") - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") - }) - } -} - -// Test that Connect works in a default installation using mesh gateways for X-Partition networking. -func TestPartitionsWithMesh(t *testing.T) { +// Test that Connect works in a default installation for X-Partition and in-partition networking. +func TestPartitions(t *testing.T) { env := suite.Environment() cfg := suite.Config() @@ -786,170 +359,247 @@ func TestPartitionsWithMesh(t *testing.T) { helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, clientClusterContext.KubectlOptions(t), kustomizeDir) }) + // This section of the tests run the in-partition networking tests. + t.Run("in-partition", func(t *testing.T) { + logger.Log(t, "test in-partition networking") + logger.Log(t, "creating static-server and static-client deployments in server cluster") + k8s.DeployKustomize(t, serverClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if c.destinationNamespace == defaultNamespace { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + } else { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + } + logger.Log(t, "creating static-server and static-client deployments in client cluster") + k8s.DeployKustomize(t, clientClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if c.destinationNamespace == defaultNamespace { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + } else { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + } + // Check that both static-server and static-client have been injected and now have 2 containers in server cluster. + for _, labelSelector := range []string{"app=static-server", "app=static-client"} { + podList, err := serverClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 2) + } - logger.Log(t, "creating static-server and static-client deployments in server cluster") - k8s.DeployKustomize(t, serverClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-partition") - } else { - k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-partition") - } - logger.Log(t, "creating static-server and static-client deployments in client cluster") - k8s.DeployKustomize(t, clientClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-default-partition") - } else { - k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-default-partition") - } - // Check that both static-server and static-client have been injected and now have 2 containers in server cluster. - for _, labelSelector := range []string{"app=static-server", "app=static-client"} { - podList, err := serverClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ - LabelSelector: labelSelector, - }) - require.NoError(t, err) - require.Len(t, podList.Items, 1) - require.Len(t, podList.Items[0].Spec.Containers, 2) - } + // Check that both static-server and static-client have been injected and now have 2 containers in client cluster. + for _, labelSelector := range []string{"app=static-server", "app=static-client"} { + podList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 2) + } - // Check that both static-server and static-client have been injected and now have 2 containers in client cluster. - for _, labelSelector := range []string{"app=static-server", "app=static-client"} { - podList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ - LabelSelector: labelSelector, - }) + // Make sure that services are registered in the correct namespace. + // If mirroring is enabled, we expect services to be registered in the + // Consul namespace with the same name as their source + // Kubernetes namespace. + // If a single destination namespace is set, we expect all services + // to be registered in that destination Consul namespace. + // Server cluster. + services, _, err := consulClient.Catalog().Service(staticServerName, "", serverQueryServerOpts) require.NoError(t, err) - require.Len(t, podList.Items, 1) - require.Len(t, podList.Items[0].Spec.Containers, 2) - } - - // Make sure that services are registered in the correct namespace. - // If mirroring is enabled, we expect services to be registered in the - // Consul namespace with the same name as their source - // Kubernetes namespace. - // If a single destination namespace is set, we expect all services - // to be registered in that destination Consul namespace. - // Server cluster. - // We are going to test that static-clients deployed in each partition can - // access the static-servers running in another partition. - // ie default -> secondary and secondary -> default. - services, _, err := consulClient.Catalog().Service(staticServerName, "", serverQueryServerOpts) - require.NoError(t, err) - require.Len(t, services, 1) + require.Len(t, services, 1) - services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryServerOpts) - require.NoError(t, err) - require.Len(t, services, 1) + services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryServerOpts) + require.NoError(t, err) + require.Len(t, services, 1) - // Client cluster. - services, _, err = consulClient.Catalog().Service(staticServerName, "", serverQueryClientOpts) - require.NoError(t, err) - require.Len(t, services, 1) + // Client cluster. + services, _, err = consulClient.Catalog().Service(staticServerName, "", serverQueryClientOpts) + require.NoError(t, err) + require.Len(t, services, 1) - services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryClientOpts) - require.NoError(t, err) - require.Len(t, services, 1) - - defaultPartitionExports := &api.PartitionExportsConfigEntry{ - Name: defaultPartition, - Services: []api.ExportedService{ - { - Name: "mesh-gateway", - Namespace: defaultNamespace, - Consumers: []api.ServiceConsumer{ - {Partition: secondaryPartition}, - }, - }, - { - Name: staticServerName, - Namespace: staticServerNamespace, - Consumers: []api.ServiceConsumer{ - {Partition: secondaryPartition}, - }, - }, - }, - } - secondaryPartitionExports := &api.PartitionExportsConfigEntry{ - Name: secondaryPartition, - Services: []api.ExportedService{ - { - Name: "mesh-gateway", - Namespace: defaultNamespace, - Consumers: []api.ServiceConsumer{ - {Partition: defaultPartition}, - }, - }, - { - Name: staticServerName, - Namespace: staticServerNamespace, - Consumers: []api.ServiceConsumer{ - {Partition: defaultPartition}, - }, - }, - }, - } + services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryClientOpts) + require.NoError(t, err) + require.Len(t, services, 1) + + if c.secure { + logger.Log(t, "checking that the connection is not successful because there's no intention") + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") + + intention := &api.Intention{ + SourceName: staticClientName, + SourceNS: staticClientNamespace, + DestinationName: staticServerName, + DestinationNS: staticServerNamespace, + Action: api.IntentionActionAllow, + } - if !c.mirrorK8S { - defaultPartitionExports.Services[1].Namespace = c.destinationNamespace - secondaryPartitionExports.Services[1].Namespace = c.destinationNamespace - } + // Set the destination namespace to be the same + // unless mirrorK8S is true. + if !c.mirrorK8S { + intention.SourceNS = c.destinationNamespace + intention.DestinationNS = c.destinationNamespace + } - logger.Log(t, "creating partition exports") - _, _, err = consulClient.ConfigEntries().Set(defaultPartitionExports, &api.WriteOptions{Partition: defaultPartition}) - require.NoError(t, err) - _, _, err = consulClient.ConfigEntries().Set(secondaryPartitionExports, &api.WriteOptions{Partition: secondaryPartition}) - require.NoError(t, err) + logger.Log(t, "creating intention") + _, err := consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: defaultPartition}) + require.NoError(t, err) + _, err = consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: secondaryPartition}) + require.NoError(t, err) + } - if c.secure { - logger.Log(t, "checking that the connection is not successful because there's no intention") - k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") - - intention := &api.ServiceIntentionsConfigEntry{ - Name: staticServerName, - Kind: api.ServiceIntentions, - Namespace: staticServerNamespace, - Sources: []*api.SourceIntention{ - { - Name: staticClientName, - Namespace: staticClientNamespace, - Action: api.IntentionActionAllow, - }, - }, + logger.Log(t, "checking that connection is successful") + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") + + // Test that kubernetes readiness status is synced to Consul. + // Create the file so that the readiness probe of the static-server pod fails. + logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") + k8s.RunKubectl(t, serverClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, clientClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + + // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry + // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. + // We are expecting a "connection reset by peer" error because in a case of health checks, + // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply + // from server, which is the case when a connection is unsuccessful due to intentions in other tests. + logger.Log(t, "checking that connection is unsuccessful") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + }) + // This section of the tests run the cross-partition networking tests. + t.Run("cross-partition", func(t *testing.T) { + logger.Log(t, "test cross-partition networking") + logger.Log(t, "creating static-server and static-client deployments in server cluster") + k8s.DeployKustomize(t, serverClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if c.destinationNamespace == defaultNamespace { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-partition") + } else { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-partition") + } + logger.Log(t, "creating static-server and static-client deployments in client cluster") + k8s.DeployKustomize(t, clientClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if c.destinationNamespace == defaultNamespace { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-default-partition") + } else { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-default-partition") + } + // Check that both static-server and static-client have been injected and now have 2 containers in server cluster. + for _, labelSelector := range []string{"app=static-server", "app=static-client"} { + podList, err := serverClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 2) } - // Set the destination namespace to be the same - // unless mirrorK8S is true. - if !c.mirrorK8S { - intention.Namespace = c.destinationNamespace - intention.Sources[0].Namespace = c.destinationNamespace + // Check that both static-server and static-client have been injected and now have 2 containers in client cluster. + for _, labelSelector := range []string{"app=static-server", "app=static-client"} { + podList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{ + LabelSelector: labelSelector, + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 2) } - logger.Log(t, "creating intention") - intention.Sources[0].Partition = secondaryPartition - _, _, err := consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: defaultPartition}) + // Make sure that services are registered in the correct namespace. + // If mirroring is enabled, we expect services to be registered in the + // Consul namespace with the same name as their source + // Kubernetes namespace. + // If a single destination namespace is set, we expect all services + // to be registered in that destination Consul namespace. + // Server cluster. + // We are going to test that static-clients deployed in each partition can + // access the static-servers running in another partition. + // ie default -> secondary and secondary -> default. + services, _, err := consulClient.Catalog().Service(staticServerName, "", serverQueryServerOpts) require.NoError(t, err) - intention.Sources[0].Partition = defaultPartition - _, _, err = consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: secondaryPartition}) + require.Len(t, services, 1) + + services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryServerOpts) require.NoError(t, err) - } + require.Len(t, services, 1) + + // Client cluster. + services, _, err = consulClient.Catalog().Service(staticServerName, "", serverQueryClientOpts) + require.NoError(t, err) + require.Len(t, services, 1) - logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") - - // Test that kubernetes readiness status is synced to Consul. - // Create the file so that the readiness probe of the static-server pod fails. - logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") - k8s.RunKubectl(t, serverClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") - k8s.RunKubectl(t, clientClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") - - // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry - // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. - // We are expecting a "connection reset by peer" error because in a case of health checks, - // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply - // from server, which is the case when a connection is unsuccessful due to intentions in other tests. - logger.Log(t, "checking that connection is unsuccessful") - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + services, _, err = consulClient.Catalog().Service(staticClientName, "", clientQueryClientOpts) + require.NoError(t, err) + require.Len(t, services, 1) + + logger.Log(t, "creating partition exports") + if c.destinationNamespace == defaultNamespace { + k8s.KubectlApplyK(t, serverClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-default") + k8s.KubectlApplyK(t, clientClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/secondary-partition-default") + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.KubectlDeleteK(t, serverClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-default") + k8s.KubectlDeleteK(t, clientClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/secondary-partition-default") + }) + } else { + k8s.KubectlApplyK(t, serverClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-ns1") + k8s.KubectlApplyK(t, clientClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/secondary-partition-ns1") + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.KubectlDeleteK(t, serverClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-ns1") + k8s.KubectlDeleteK(t, clientClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/secondary-partition-ns1") + }) + } + + if c.secure { + logger.Log(t, "checking that the connection is not successful because there's no intention") + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") + + intention := &api.ServiceIntentionsConfigEntry{ + Name: staticServerName, + Kind: api.ServiceIntentions, + Namespace: staticServerNamespace, + Sources: []*api.SourceIntention{ + { + Name: staticClientName, + Namespace: staticClientNamespace, + Action: api.IntentionActionAllow, + }, + }, + } + + // Set the destination namespace to be the same + // unless mirrorK8S is true. + if !c.mirrorK8S { + intention.Namespace = c.destinationNamespace + intention.Sources[0].Namespace = c.destinationNamespace + } + + logger.Log(t, "creating intention") + intention.Sources[0].Partition = secondaryPartition + _, _, err := consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: defaultPartition}) + require.NoError(t, err) + intention.Sources[0].Partition = defaultPartition + _, _, err = consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: secondaryPartition}) + require.NoError(t, err) + } + + logger.Log(t, "checking that connection is successful") + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") + + // Test that kubernetes readiness status is synced to Consul. + // Create the file so that the readiness probe of the static-server pod fails. + logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") + k8s.RunKubectl(t, serverClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + k8s.RunKubectl(t, clientClusterStaticServerOpts, "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + + // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry + // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. + // We are expecting a "connection reset by peer" error because in a case of health checks, + // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply + // from server, which is the case when a connection is unsuccessful due to intentions in other tests. + logger.Log(t, "checking that connection is unsuccessful") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + }) }) } } From 2bd25a7cc3b50b2f842412fd46491b04ca43d23f Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 16 Nov 2021 10:30:21 -0500 Subject: [PATCH 138/418] Update IngressGateway CRD --- acceptance/go.mod | 2 +- acceptance/go.sum | 37 ++-- .../consul/templates/crd-ingressgateways.yaml | 80 +++++++ .../api/v1alpha1/ingressgateway_types.go | 115 ++++++++-- .../api/v1alpha1/ingressgateway_types_test.go | 196 +++++++++++++++++- .../api/v1alpha1/zz_generated.deepcopy.go | 91 +++++++- .../consul.hashicorp.com_ingressgateways.yaml | 80 +++++++ control-plane/config/rbac/role.yaml | 20 -- control-plane/config/webhook/manifests.yaml | 21 -- control-plane/go.mod | 4 +- control-plane/go.sum | 21 +- 11 files changed, 574 insertions(+), 93 deletions(-) diff --git a/acceptance/go.mod b/acceptance/go.mod index 8f073c8764..7cc39ce42d 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/gruntwork-io/terratest v0.31.2 - github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb + github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf github.com/hashicorp/consul/sdk v0.8.0 github.com/stretchr/testify v1.5.1 gopkg.in/yaml.v2 v2.2.8 diff --git a/acceptance/go.sum b/acceptance/go.sum index 8bb9b7620f..d363abe258 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -225,8 +225,8 @@ github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arn github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= -github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb h1:RNuoY5+OLW+hC9FTPEf8/gXPgPo80lMjyFmS3+BUpkA= -github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf h1:AH+AORMM9SgSyOrcsvGKxsFDk57ChzqYchlGA2U3+aE= +github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -256,11 +256,11 @@ github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8 github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC7AO2g= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.5 h1:EBWvyu9tcRszt3Bxp3KNssBMP1KuHWyO51lz9+786iM= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -316,10 +316,10 @@ github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb44 github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -439,7 +439,6 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -477,7 +476,6 @@ golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -496,8 +494,10 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 h1:4qWs8cYYH6PoEFy4dfhDFgoMGkwAcETd+MmPdCPMzUc= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -509,14 +509,14 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -545,14 +545,19 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/charts/consul/templates/crd-ingressgateways.yaml b/charts/consul/templates/crd-ingressgateways.yaml index eed9f88fc9..29acc67958 100644 --- a/charts/consul/templates/crd-ingressgateways.yaml +++ b/charts/consul/templates/crd-ingressgateways.yaml @@ -82,6 +82,20 @@ spec: description: IngressService manages configuration for services that are exposed to ingress traffic. properties: + gatewayServiceTLSConfig: + description: TLS allows specifying some TLS configuration + per listener. + properties: + gatewayTLSSDSConfig: + description: SDS allows configuring TLS certificate + from an SDS service. + properties: + certResource: + type: string + clusterName: + type: string + type: object + type: object hosts: description: "Hosts is a list of hostnames which should be associated to this service on the defined listener. @@ -109,6 +123,63 @@ spec: description: Namespace is the namespace where the service is located. Namespacing is a Consul Enterprise feature. type: string + partition: + description: Partition is the admin-partition where the + service is located. Partitioning is a Consul Enterprise + feature. + type: string + requestHeaders: + description: Allow HTTP header manipulation to be configured. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that + should be appended to the request or response (i.e. + allowing duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that + should be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that + should be added to the request or response, overwriting + any existing header values of the same name. + type: object + type: object + responseHeaders: + description: HTTPHeaderModifiers is a set of rules for + HTTP header modification that should be performed by + proxies as the request passes through them. It can operate + on either request or response headers depending on the + context in which it is used. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that + should be appended to the request or response (i.e. + allowing duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that + should be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that + should be added to the request or response, overwriting + any existing header values of the same name. + type: object + type: object type: object type: array type: object @@ -120,6 +191,15 @@ spec: description: Indicates that TLS should be enabled for this gateway service. type: boolean + gatewayTLSSDSConfig: + description: SDS allows configuring TLS certificate from an SDS + service. + properties: + certResource: + type: string + clusterName: + type: string + type: object required: - enabled type: object diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index d4b6b6dfd2..b7f3a8c8df 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -61,6 +61,19 @@ type IngressGatewaySpec struct { type GatewayTLSConfig struct { // Indicates that TLS should be enabled for this gateway service. Enabled bool `json:"enabled"` + + // SDS allows configuring TLS certificate from an SDS service. + SDS *GatewayTLSSDSConfig `json:"gatewayTLSSDSConfig,omitempty"` +} + +type GatewayServiceTLSConfig struct { + // SDS allows configuring TLS certificate from an SDS service. + SDS *GatewayTLSSDSConfig `json:"gatewayTLSSDSConfig,omitempty"` +} + +type GatewayTLSSDSConfig struct { + ClusterName string `json:"clusterName,omitempty"` + CertResource string `json:"certResource,omitempty"` } // IngressListener manages the configuration for a listener on a specific port. @@ -111,6 +124,35 @@ type IngressService struct { // Namespace is the namespace where the service is located. // Namespacing is a Consul Enterprise feature. Namespace string `json:"namespace,omitempty"` + + // Partition is the admin-partition where the service is located. + // Partitioning is a Consul Enterprise feature. + Partition string `json:"partition,omitempty"` + + // TLS allows specifying some TLS configuration per listener. + TLS *GatewayServiceTLSConfig `json:"gatewayServiceTLSConfig,omitempty"` + + // Allow HTTP header manipulation to be configured. + RequestHeaders *HTTPHeaderModifiers `json:"requestHeaders,omitempty"` + ResponseHeaders *HTTPHeaderModifiers `json:"responseHeaders,omitempty"` +} + +// HTTPHeaderModifiers is a set of rules for HTTP header modification that +// should be performed by proxies as the request passes through them. It can +// operate on either request or response headers depending on the context in +// which it is used. +type HTTPHeaderModifiers struct { + // Add is a set of name -> value pairs that should be appended to the request + // or response (i.e. allowing duplicates if the same header already exists). + Add map[string]string `json:"add,omitempty"` + + // Set is a set of name -> value pairs that should be added to the request or + // response, overwriting any existing header values of the same name. + Set map[string]string `json:"set,omitempty"` + + // Remove is the set of header names that should be stripped from the request + // or response. + Remove []string `json:"remove,omitempty"` } func (in *IngressGateway) GetObjectMeta() metav1.ObjectMeta { @@ -219,11 +261,9 @@ func (in *IngressGateway) Validate(consulMeta common.ConsulMeta) error { path := field.NewPath("spec") for i, v := range in.Spec.Listeners { - errs = append(errs, v.validate(path.Child("listeners").Index(i))...) + errs = append(errs, v.validate(path.Child("listeners").Index(i), consulMeta)...) } - errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) - if len(errs) > 0 { return apierrors.NewInvalid( schema.GroupKind{Group: ConsulHashicorpGroup, Kind: ingressGatewayKubeKind}, @@ -254,6 +294,7 @@ func (in *IngressGateway) DefaultNamespaceFields(consulMeta common.ConsulMeta) { func (in GatewayTLSConfig) toConsul() capi.GatewayTLSConfig { return capi.GatewayTLSConfig{ Enabled: in.Enabled, + SDS: in.SDS.toConsul(), } } @@ -271,13 +312,47 @@ func (in IngressListener) toConsul() capi.IngressListener { func (in IngressService) toConsul() capi.IngressService { return capi.IngressService{ - Name: in.Name, - Hosts: in.Hosts, - Namespace: in.Namespace, + Name: in.Name, + Hosts: in.Hosts, + Namespace: in.Namespace, + Partition: in.Partition, + TLS: in.TLS.toConsul(), + RequestHeaders: in.RequestHeaders.toConsul(), + ResponseHeaders: in.ResponseHeaders.toConsul(), + } +} + +func (in *GatewayTLSSDSConfig) toConsul() *capi.GatewayTLSSDSConfig { + if in == nil { + return nil + } + return &capi.GatewayTLSSDSConfig{ + ClusterName: in.ClusterName, + CertResource: in.CertResource, + } +} + +func (in *GatewayServiceTLSConfig) toConsul() *capi.GatewayServiceTLSConfig { + if in == nil { + return nil + } + return &capi.GatewayServiceTLSConfig{ + SDS: in.SDS.toConsul(), } } -func (in IngressListener) validate(path *field.Path) field.ErrorList { +func (in *HTTPHeaderModifiers) toConsul() *capi.HTTPHeaderModifiers { + if in == nil { + return nil + } + return &capi.HTTPHeaderModifiers{ + Add: in.Add, + Set: in.Set, + Remove: in.Remove, + } +} + +func (in IngressListener) validate(path *field.Path, consulMeta common.ConsulMeta) field.ErrorList { var errs field.ErrorList validProtocols := []string{"tcp", "http", "http2", "grpc"} if !sliceContains(validProtocols, in.Protocol) { @@ -307,6 +382,16 @@ func (in IngressListener) validate(path *field.Path) field.ErrorList { fmt.Sprintf("hosts must be empty if name is %q", wildcardServiceName))) } + if svc.Partition != "" && !consulMeta.PartitionsEnabled { + errs = append(errs, field.Invalid(path.Child("services").Index(i).Child("partition"), + svc.Partition, `Consul Enterprise admin-partitions must be enabled to set service.partition`)) + } + + if svc.Namespace != "" && !consulMeta.NamespacesEnabled { + errs = append(errs, field.Invalid(path.Child("services").Index(i).Child("namespace"), + svc.Namespace, `Consul Enterprise namespaces must be enabled to set service.namespace`)) + } + if len(svc.Hosts) > 0 && in.Protocol == "tcp" { asJSON, _ := json.Marshal(svc.Hosts) errs = append(errs, field.Invalid(path.Child("services").Index(i).Child("hosts"), @@ -316,19 +401,3 @@ func (in IngressListener) validate(path *field.Path) field.ErrorList { } return errs } - -func (in *IngressGateway) validateNamespaces(namespacesEnabled bool) field.ErrorList { - var errs field.ErrorList - path := field.NewPath("spec") - if !namespacesEnabled { - for i, listener := range in.Spec.Listeners { - for j, service := range listener.Services { - if service.Namespace != "" { - errs = append(errs, field.Invalid(path.Child("listeners").Index(i).Child("services").Index(j).Child("namespace"), - service.Namespace, `Consul Enterprise namespaces must be enabled to set service.namespace`)) - } - } - } - } - return errs -} diff --git a/control-plane/api/v1alpha1/ingressgateway_types_test.go b/control-plane/api/v1alpha1/ingressgateway_types_test.go index 051aea39fe..d2327dace9 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types_test.go +++ b/control-plane/api/v1alpha1/ingressgateway_types_test.go @@ -56,6 +56,43 @@ func TestIngressGateway_MatchesConsul(t *testing.T) { Name: "name1", Hosts: []string{"host1_1", "host1_2"}, Namespace: "ns1", + Partition: "default", + TLS: &GatewayServiceTLSConfig{ + SDS: &GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, + }, + RequestHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, { Name: "name2", @@ -92,6 +129,43 @@ func TestIngressGateway_MatchesConsul(t *testing.T) { Name: "name1", Hosts: []string{"host1_1", "host1_2"}, Namespace: "ns1", + Partition: "default", + TLS: &capi.GatewayServiceTLSConfig{ + SDS: &capi.GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, + }, + RequestHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, { Name: "name2", @@ -183,6 +257,43 @@ func TestIngressGateway_ToConsul(t *testing.T) { Name: "name1", Hosts: []string{"host1_1", "host1_2"}, Namespace: "ns1", + Partition: "default", + TLS: &GatewayServiceTLSConfig{ + SDS: &GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, + }, + RequestHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, { Name: "name2", @@ -218,6 +329,43 @@ func TestIngressGateway_ToConsul(t *testing.T) { Name: "name1", Hosts: []string{"host1_1", "host1_2"}, Namespace: "ns1", + Partition: "default", + TLS: &capi.GatewayServiceTLSConfig{ + SDS: &capi.GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, + }, + RequestHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, { Name: "name2", @@ -258,6 +406,7 @@ func TestIngressGateway_Validate(t *testing.T) { cases := map[string]struct { input *IngressGateway namespacesEnabled bool + partitionEnabled bool expectedErrMsgs []string }{ "listener.protocol invalid": { @@ -420,6 +569,51 @@ func TestIngressGateway_Validate(t *testing.T) { }, namespacesEnabled: true, }, + "service.partition set when partitions disabled": { + input: &IngressGateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: IngressGatewaySpec{ + Listeners: []IngressListener{ + { + Protocol: "tcp", + Services: []IngressService{ + { + Name: "name", + Partition: "foo", + }, + }, + }, + }, + }, + }, + partitionEnabled: false, + expectedErrMsgs: []string{ + `spec.listeners[0].services[0].partition: Invalid value: "foo": Consul Enterprise admin-partitions must be enabled to set service.partition`, + }, + }, + "service.partition set when partitions enabled": { + input: &IngressGateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: IngressGatewaySpec{ + Listeners: []IngressListener{ + { + Protocol: "tcp", + Services: []IngressService{ + { + Name: "name", + Partition: "foo", + }, + }, + }, + }, + }, + }, + partitionEnabled: true, + }, "multiple errors": { input: &IngressGateway{ ObjectMeta: metav1.ObjectMeta{ @@ -448,7 +642,7 @@ func TestIngressGateway_Validate(t *testing.T) { for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled}) + err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled, PartitionsEnabled: testCase.partitionEnabled}) if len(testCase.expectedErrMsgs) != 0 { require.Error(t, err) for _, s := range testCase.expectedErrMsgs { diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index 04288255f1..bab52bc596 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -132,9 +132,34 @@ 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 *GatewayServiceTLSConfig) DeepCopyInto(out *GatewayServiceTLSConfig) { + *out = *in + if in.SDS != nil { + in, out := &in.SDS, &out.SDS + *out = new(GatewayTLSSDSConfig) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayServiceTLSConfig. +func (in *GatewayServiceTLSConfig) DeepCopy() *GatewayServiceTLSConfig { + if in == nil { + return nil + } + out := new(GatewayServiceTLSConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GatewayTLSConfig) DeepCopyInto(out *GatewayTLSConfig) { *out = *in + if in.SDS != nil { + in, out := &in.SDS, &out.SDS + *out = new(GatewayTLSSDSConfig) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayTLSConfig. @@ -147,6 +172,55 @@ func (in *GatewayTLSConfig) DeepCopy() *GatewayTLSConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewayTLSSDSConfig) DeepCopyInto(out *GatewayTLSSDSConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayTLSSDSConfig. +func (in *GatewayTLSSDSConfig) DeepCopy() *GatewayTLSSDSConfig { + if in == nil { + return nil + } + out := new(GatewayTLSSDSConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPHeaderModifiers) DeepCopyInto(out *HTTPHeaderModifiers) { + *out = *in + if in.Add != nil { + in, out := &in.Add, &out.Add + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Set != nil { + in, out := &in.Set, &out.Set + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Remove != nil { + in, out := &in.Remove, &out.Remove + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPHeaderModifiers. +func (in *HTTPHeaderModifiers) DeepCopy() *HTTPHeaderModifiers { + if in == nil { + return nil + } + out := new(HTTPHeaderModifiers) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HashPolicy) DeepCopyInto(out *HashPolicy) { *out = *in @@ -229,7 +303,7 @@ func (in *IngressGatewayList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IngressGatewaySpec) DeepCopyInto(out *IngressGatewaySpec) { *out = *in - out.TLS = in.TLS + in.TLS.DeepCopyInto(&out.TLS) if in.Listeners != nil { in, out := &in.Listeners, &out.Listeners *out = make([]IngressListener, len(*in)) @@ -279,6 +353,21 @@ func (in *IngressService) DeepCopyInto(out *IngressService) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = new(GatewayServiceTLSConfig) + (*in).DeepCopyInto(*out) + } + if in.RequestHeaders != nil { + in, out := &in.RequestHeaders, &out.RequestHeaders + *out = new(HTTPHeaderModifiers) + (*in).DeepCopyInto(*out) + } + if in.ResponseHeaders != nil { + in, out := &in.ResponseHeaders, &out.ResponseHeaders + *out = new(HTTPHeaderModifiers) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressService. 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 63baf9787b..68e2a01e8b 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml @@ -76,6 +76,20 @@ spec: description: IngressService manages configuration for services that are exposed to ingress traffic. properties: + gatewayServiceTLSConfig: + description: TLS allows specifying some TLS configuration + per listener. + properties: + gatewayTLSSDSConfig: + description: SDS allows configuring TLS certificate + from an SDS service. + properties: + certResource: + type: string + clusterName: + type: string + type: object + type: object hosts: description: "Hosts is a list of hostnames which should be associated to this service on the defined listener. @@ -103,6 +117,63 @@ spec: description: Namespace is the namespace where the service is located. Namespacing is a Consul Enterprise feature. type: string + partition: + description: Partition is the admin-partition where the + service is located. Partitioning is a Consul Enterprise + feature. + type: string + requestHeaders: + description: Allow HTTP header manipulation to be configured. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that + should be appended to the request or response (i.e. + allowing duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that + should be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that + should be added to the request or response, overwriting + any existing header values of the same name. + type: object + type: object + responseHeaders: + description: HTTPHeaderModifiers is a set of rules for + HTTP header modification that should be performed by + proxies as the request passes through them. It can operate + on either request or response headers depending on the + context in which it is used. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that + should be appended to the request or response (i.e. + allowing duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that + should be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that + should be added to the request or response, overwriting + any existing header values of the same name. + type: object + type: object type: object type: array type: object @@ -114,6 +185,15 @@ spec: description: Indicates that TLS should be enabled for this gateway service. type: boolean + gatewayTLSSDSConfig: + description: SDS allows configuring TLS certificate from an SDS + service. + properties: + certResource: + type: string + clusterName: + type: string + type: object required: - enabled type: object diff --git a/control-plane/config/rbac/role.yaml b/control-plane/config/rbac/role.yaml index b544a67a81..f1a46e72d3 100644 --- a/control-plane/config/rbac/role.yaml +++ b/control-plane/config/rbac/role.yaml @@ -106,26 +106,6 @@ rules: - get - patch - update -- apiGroups: - - consul.hashicorp.com - resources: - - serviceexports - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - serviceexports/status - verbs: - - get - - patch - - update - apiGroups: - consul.hashicorp.com resources: diff --git a/control-plane/config/webhook/manifests.yaml b/control-plane/config/webhook/manifests.yaml index 19b8e7ebda..8264b31887 100644 --- a/control-plane/config/webhook/manifests.yaml +++ b/control-plane/config/webhook/manifests.yaml @@ -111,27 +111,6 @@ webhooks: resources: - servicedefaults sideEffects: None -- admissionReviewVersions: - - v1beta1 - - v1 - clientConfig: - service: - name: webhook-service - namespace: system - path: /mutate-v1alpha1-service-exports - failurePolicy: Fail - name: mutate-mesh.consul.hashicorp.com - rules: - - apiGroups: - - consul.hashicorp.com - apiVersions: - - v1alpha1 - operations: - - CREATE - - UPDATE - resources: - - mesh - sideEffects: None - admissionReviewVersions: - v1beta1 - v1 diff --git a/control-plane/go.mod b/control-plane/go.mod index f37ac394a6..37e565d4e6 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/go-cmp v0.5.6 github.com/google/go-querystring v1.0.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb + github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f @@ -20,7 +20,7 @@ require ( github.com/hashicorp/go-multierror v1.1.0 github.com/hashicorp/go-sockaddr v1.0.2 // indirect github.com/hashicorp/go-uuid v1.0.2 // indirect - github.com/hashicorp/serf v0.9.5 + github.com/hashicorp/serf v0.9.6 github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect github.com/kr/text v0.2.0 github.com/mattn/go-isatty v0.0.13 // indirect diff --git a/control-plane/go.sum b/control-plane/go.sum index 523a395f69..a66634c9da 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -297,8 +297,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb h1:RNuoY5+OLW+hC9FTPEf8/gXPgPo80lMjyFmS3+BUpkA= -github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf h1:AH+AORMM9SgSyOrcsvGKxsFDk57ChzqYchlGA2U3+aE= +github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= @@ -341,14 +341,15 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.1 h1:XFSOubp8KWB+Jd2PDyaX5xUd5bhSP/+pTDZVDMzZJM8= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= +github.com/hashicorp/mdns v1.0.4 h1:sY0CMhFmjIPDMlTB+HfymFHCaYLhgifZ0QhjaYKD/UQ= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC7AO2g= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.9.5 h1:EBWvyu9tcRszt3Bxp3KNssBMP1KuHWyO51lz9+786iM= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 h1:O/pT5C1Q3mVXMyuqg7yuAWUg/jMZR1/0QTzTRdNR6Uw= github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -422,8 +423,9 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26 h1:gPxPSwALAeHJSjarOs00QjVdV9QoBvc1D2ujQUr5BzU= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0 h1:tEElEatulEHDeedTxwckzyYMA5c86fbmNIUL1hBIiTg= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= @@ -712,7 +714,9 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -783,6 +787,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= From c504b95210780b2a683fd09bde14d71851cbfede Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 16 Nov 2021 10:42:34 -0500 Subject: [PATCH 139/418] Update serviceRouter CRD with request/response headers --- .../consul/templates/crd-servicerouters.yaml | 52 ++++++++ .../api/v1alpha1/ingressgateway_types.go | 29 ----- .../api/v1alpha1/servicerouter_types.go | 5 + .../api/v1alpha1/servicerouter_types_test.go | 120 ++++++++++++++++++ control-plane/api/v1alpha1/shared_types.go | 29 +++++ .../api/v1alpha1/zz_generated.deepcopy.go | 10 ++ .../consul.hashicorp.com_servicerouters.yaml | 52 ++++++++ 7 files changed, 268 insertions(+), 29 deletions(-) diff --git a/charts/consul/templates/crd-servicerouters.yaml b/charts/consul/templates/crd-servicerouters.yaml index 01473e980d..ac8905ca2c 100644 --- a/charts/consul/templates/crd-servicerouters.yaml +++ b/charts/consul/templates/crd-servicerouters.yaml @@ -82,11 +82,63 @@ spec: This requires that either match.http.pathPrefix or match.http.pathExact be configured on this route. type: string + requestHeaders: + description: Allow HTTP header manipulation to be configured. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that + should be appended to the request or response (i.e. + allowing duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that + should be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that + should be added to the request or response, overwriting + any existing header values of the same name. + type: object + type: object requestTimeout: description: RequestTimeout is the total amount of time permitted for the entire downstream request (and retries) to be processed. type: string + responseHeaders: + description: HTTPHeaderModifiers is a set of rules for HTTP + header modification that should be performed by proxies + as the request passes through them. It can operate on + either request or response headers depending on the context + in which it is used. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that + should be appended to the request or response (i.e. + allowing duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that + should be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that + should be added to the request or response, overwriting + any existing header values of the same name. + type: object + type: object retryOnConnectFailure: description: RetryOnConnectFailure allows for connection failure errors to trigger a retry. diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index b7f3a8c8df..aa2b4e37cc 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -137,24 +137,6 @@ type IngressService struct { ResponseHeaders *HTTPHeaderModifiers `json:"responseHeaders,omitempty"` } -// HTTPHeaderModifiers is a set of rules for HTTP header modification that -// should be performed by proxies as the request passes through them. It can -// operate on either request or response headers depending on the context in -// which it is used. -type HTTPHeaderModifiers struct { - // Add is a set of name -> value pairs that should be appended to the request - // or response (i.e. allowing duplicates if the same header already exists). - Add map[string]string `json:"add,omitempty"` - - // Set is a set of name -> value pairs that should be added to the request or - // response, overwriting any existing header values of the same name. - Set map[string]string `json:"set,omitempty"` - - // Remove is the set of header names that should be stripped from the request - // or response. - Remove []string `json:"remove,omitempty"` -} - func (in *IngressGateway) GetObjectMeta() metav1.ObjectMeta { return in.ObjectMeta } @@ -341,17 +323,6 @@ func (in *GatewayServiceTLSConfig) toConsul() *capi.GatewayServiceTLSConfig { } } -func (in *HTTPHeaderModifiers) toConsul() *capi.HTTPHeaderModifiers { - if in == nil { - return nil - } - return &capi.HTTPHeaderModifiers{ - Add: in.Add, - Set: in.Set, - Remove: in.Remove, - } -} - func (in IngressListener) validate(path *field.Path, consulMeta common.ConsulMeta) field.ErrorList { var errs field.ErrorList validProtocols := []string{"tcp", "http", "http2", "grpc"} diff --git a/control-plane/api/v1alpha1/servicerouter_types.go b/control-plane/api/v1alpha1/servicerouter_types.go index a6cdf54f81..4aa42e1624 100644 --- a/control-plane/api/v1alpha1/servicerouter_types.go +++ b/control-plane/api/v1alpha1/servicerouter_types.go @@ -142,6 +142,9 @@ type ServiceRouteDestination struct { RetryOnConnectFailure bool `json:"retryOnConnectFailure,omitempty"` // RetryOnStatusCodes is a flat list of http response status codes that are eligible for retry. RetryOnStatusCodes []uint32 `json:"retryOnStatusCodes,omitempty"` + // Allow HTTP header manipulation to be configured. + RequestHeaders *HTTPHeaderModifiers `json:"requestHeaders,omitempty"` + ResponseHeaders *HTTPHeaderModifiers `json:"responseHeaders,omitempty"` } func (in *ServiceRouter) ConsulMirroringNS() string { @@ -330,6 +333,8 @@ func (in *ServiceRouteDestination) toConsul() *capi.ServiceRouteDestination { NumRetries: in.NumRetries, RetryOnConnectFailure: in.RetryOnConnectFailure, RetryOnStatusCodes: in.RetryOnStatusCodes, + RequestHeaders: in.RequestHeaders.toConsul(), + ResponseHeaders: in.ResponseHeaders.toConsul(), } } diff --git a/control-plane/api/v1alpha1/servicerouter_types_test.go b/control-plane/api/v1alpha1/servicerouter_types_test.go index 8795c0713d..5d984ddf8f 100644 --- a/control-plane/api/v1alpha1/servicerouter_types_test.go +++ b/control-plane/api/v1alpha1/servicerouter_types_test.go @@ -83,6 +83,36 @@ func TestServiceRouter_MatchesConsul(t *testing.T) { NumRetries: 1, RetryOnConnectFailure: true, RetryOnStatusCodes: []uint32{500, 400}, + RequestHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, }, }, @@ -129,6 +159,36 @@ func TestServiceRouter_MatchesConsul(t *testing.T) { NumRetries: 1, RetryOnConnectFailure: true, RetryOnStatusCodes: []uint32{500, 400}, + RequestHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, }, }, @@ -224,6 +284,36 @@ func TestServiceRouter_ToConsul(t *testing.T) { NumRetries: 1, RetryOnConnectFailure: true, RetryOnStatusCodes: []uint32{500, 400}, + RequestHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, }, }, @@ -270,6 +360,36 @@ func TestServiceRouter_ToConsul(t *testing.T) { NumRetries: 1, RetryOnConnectFailure: true, RetryOnStatusCodes: []uint32{500, 400}, + RequestHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, }, }, diff --git a/control-plane/api/v1alpha1/shared_types.go b/control-plane/api/v1alpha1/shared_types.go index c26ca5d4f0..1191614698 100644 --- a/control-plane/api/v1alpha1/shared_types.go +++ b/control-plane/api/v1alpha1/shared_types.go @@ -61,6 +61,24 @@ type MeshGateway struct { type ProxyMode string +// HTTPHeaderModifiers is a set of rules for HTTP header modification that +// should be performed by proxies as the request passes through them. It can +// operate on either request or response headers depending on the context in +// which it is used. +type HTTPHeaderModifiers struct { + // Add is a set of name -> value pairs that should be appended to the request + // or response (i.e. allowing duplicates if the same header already exists). + Add map[string]string `json:"add,omitempty"` + + // Set is a set of name -> value pairs that should be added to the request or + // response, overwriting any existing header values of the same name. + Set map[string]string `json:"set,omitempty"` + + // Remove is the set of header names that should be stripped from the request + // or response. + Remove []string `json:"remove,omitempty"` +} + func (in MeshGateway) toConsul() capi.MeshGatewayConfig { mode := capi.MeshGatewayMode(in.Mode) switch mode { @@ -147,6 +165,17 @@ func (in *ProxyMode) validate(path *field.Path) *field.Error { return nil } +func (in *HTTPHeaderModifiers) toConsul() *capi.HTTPHeaderModifiers { + if in == nil { + return nil + } + return &capi.HTTPHeaderModifiers{ + Add: in.Add, + Set: in.Set, + Remove: in.Remove, + } +} + func notInSliceMessage(slice []string) string { return fmt.Sprintf(`must be one of "%s"`, strings.Join(slice, `", "`)) } diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index bab52bc596..1cd1a2d989 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -1256,6 +1256,16 @@ func (in *ServiceRouteDestination) DeepCopyInto(out *ServiceRouteDestination) { *out = make([]uint32, len(*in)) copy(*out, *in) } + if in.RequestHeaders != nil { + in, out := &in.RequestHeaders, &out.RequestHeaders + *out = new(HTTPHeaderModifiers) + (*in).DeepCopyInto(*out) + } + if in.ResponseHeaders != nil { + in, out := &in.ResponseHeaders, &out.ResponseHeaders + *out = new(HTTPHeaderModifiers) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceRouteDestination. 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 0919eafb75..17c7c75790 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml @@ -76,11 +76,63 @@ spec: This requires that either match.http.pathPrefix or match.http.pathExact be configured on this route. type: string + requestHeaders: + description: Allow HTTP header manipulation to be configured. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that + should be appended to the request or response (i.e. + allowing duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that + should be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that + should be added to the request or response, overwriting + any existing header values of the same name. + type: object + type: object requestTimeout: description: RequestTimeout is the total amount of time permitted for the entire downstream request (and retries) to be processed. type: string + responseHeaders: + description: HTTPHeaderModifiers is a set of rules for HTTP + header modification that should be performed by proxies + as the request passes through them. It can operate on + either request or response headers depending on the context + in which it is used. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that + should be appended to the request or response (i.e. + allowing duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that + should be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that + should be added to the request or response, overwriting + any existing header values of the same name. + type: object + type: object retryOnConnectFailure: description: RetryOnConnectFailure allows for connection failure errors to trigger a retry. From 058928537fb6b2a02d8a20bec5c96997f4a19dba Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 16 Nov 2021 10:47:54 -0500 Subject: [PATCH 140/418] Update serviceSplitters with request/response headers --- .../templates/crd-servicesplitters.yaml | 52 ++++++++ .../api/v1alpha1/servicesplitter_types.go | 13 +- .../v1alpha1/servicesplitter_types_test.go | 120 ++++++++++++++++++ .../api/v1alpha1/zz_generated.deepcopy.go | 18 ++- ...consul.hashicorp.com_servicesplitters.yaml | 52 ++++++++ 5 files changed, 249 insertions(+), 6 deletions(-) diff --git a/charts/consul/templates/crd-servicesplitters.yaml b/charts/consul/templates/crd-servicesplitters.yaml index 17da91b20f..f7bb3e5246 100644 --- a/charts/consul/templates/crd-servicesplitters.yaml +++ b/charts/consul/templates/crd-servicesplitters.yaml @@ -66,6 +66,58 @@ spec: of the current namespace. If empty the current namespace is assumed. type: string + requestHeaders: + description: Allow HTTP header manipulation to be configured. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that should + be appended to the request or response (i.e. allowing + duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that should + be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that should + be added to the request or response, overwriting any existing + header values of the same name. + type: object + type: object + responseHeaders: + description: HTTPHeaderModifiers is a set of rules for HTTP + header modification that should be performed by proxies as + the request passes through them. It can operate on either + request or response headers depending on the context in which + it is used. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that should + be appended to the request or response (i.e. allowing + duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that should + be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that should + be added to the request or response, overwriting any existing + header values of the same name. + type: object + type: object service: description: Service is the service to resolve instead of the default. diff --git a/control-plane/api/v1alpha1/servicesplitter_types.go b/control-plane/api/v1alpha1/servicesplitter_types.go index 98eaadb8d4..ea41ed6b1a 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types.go +++ b/control-plane/api/v1alpha1/servicesplitter_types.go @@ -64,6 +64,9 @@ type ServiceSplit struct { // The namespace to resolve the service from instead of the current namespace. // If empty the current namespace is assumed. Namespace string `json:"namespace,omitempty"` + // Allow HTTP header manipulation to be configured. + RequestHeaders *HTTPHeaderModifiers `json:"requestHeaders,omitempty"` + ResponseHeaders *HTTPHeaderModifiers `json:"responseHeaders,omitempty"` } func (in *ServiceSplitter) GetObjectMeta() metav1.ObjectMeta { @@ -191,10 +194,12 @@ func (in ServiceSplits) toConsul() []capi.ServiceSplit { func (in ServiceSplit) toConsul() capi.ServiceSplit { return capi.ServiceSplit{ - Weight: in.Weight, - Service: in.Service, - ServiceSubset: in.ServiceSubset, - Namespace: in.Namespace, + Weight: in.Weight, + Service: in.Service, + ServiceSubset: in.ServiceSubset, + Namespace: in.Namespace, + RequestHeaders: in.RequestHeaders.toConsul(), + ResponseHeaders: in.ResponseHeaders.toConsul(), } } diff --git a/control-plane/api/v1alpha1/servicesplitter_types_test.go b/control-plane/api/v1alpha1/servicesplitter_types_test.go index aed14adba7..e37d29e9db 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types_test.go +++ b/control-plane/api/v1alpha1/servicesplitter_types_test.go @@ -50,6 +50,36 @@ func TestServiceSplitter_MatchesConsul(t *testing.T) { Service: "foo", ServiceSubset: "bar", Namespace: "baz", + RequestHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, }, }, @@ -63,6 +93,36 @@ func TestServiceSplitter_MatchesConsul(t *testing.T) { Service: "foo", ServiceSubset: "bar", Namespace: "baz", + RequestHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, }, }, @@ -125,6 +185,36 @@ func TestServiceSplitter_ToConsul(t *testing.T) { Service: "foo", ServiceSubset: "bar", Namespace: "baz", + RequestHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, }, }, @@ -138,6 +228,36 @@ func TestServiceSplitter_ToConsul(t *testing.T) { Service: "foo", ServiceSubset: "bar", Namespace: "baz", + RequestHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "foo": "bar", + "source": "dest", + }, + Set: map[string]string{ + "bar": "baz", + "key": "car", + }, + Remove: []string{ + "foo", + "bar", + "baz", + }, + }, + ResponseHeaders: &capi.HTTPHeaderModifiers{ + Add: map[string]string{ + "doo": "var", + "aource": "sest", + }, + Set: map[string]string{ + "var": "vaz", + "jey": "xar", + }, + Remove: []string{ + "doo", + "var", + "vaz", + }, + }, }, }, Meta: map[string]string{ diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index 1cd1a2d989..62039af40f 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -1442,6 +1442,16 @@ func (in *ServiceRouterSpec) DeepCopy() *ServiceRouterSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ServiceSplit) DeepCopyInto(out *ServiceSplit) { *out = *in + if in.RequestHeaders != nil { + in, out := &in.RequestHeaders, &out.RequestHeaders + *out = new(HTTPHeaderModifiers) + (*in).DeepCopyInto(*out) + } + if in.ResponseHeaders != nil { + in, out := &in.ResponseHeaders, &out.ResponseHeaders + *out = new(HTTPHeaderModifiers) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceSplit. @@ -1459,7 +1469,9 @@ func (in ServiceSplits) DeepCopyInto(out *ServiceSplits) { { in := &in *out = make(ServiceSplits, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } @@ -1538,7 +1550,9 @@ func (in *ServiceSplitterSpec) DeepCopyInto(out *ServiceSplitterSpec) { if in.Splits != nil { in, out := &in.Splits, &out.Splits *out = make(ServiceSplits, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } } 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 95ab93b617..de3d2d43fd 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml @@ -60,6 +60,58 @@ spec: of the current namespace. If empty the current namespace is assumed. type: string + requestHeaders: + description: Allow HTTP header manipulation to be configured. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that should + be appended to the request or response (i.e. allowing + duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that should + be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that should + be added to the request or response, overwriting any existing + header values of the same name. + type: object + type: object + responseHeaders: + description: HTTPHeaderModifiers is a set of rules for HTTP + header modification that should be performed by proxies as + the request passes through them. It can operate on either + request or response headers depending on the context in which + it is used. + properties: + add: + additionalProperties: + type: string + description: Add is a set of name -> value pairs that should + be appended to the request or response (i.e. allowing + duplicates if the same header already exists). + type: object + remove: + description: Remove is the set of header names that should + be stripped from the request or response. + items: + type: string + type: array + set: + additionalProperties: + type: string + description: Set is a set of name -> value pairs that should + be added to the request or response, overwriting any existing + header values of the same name. + type: object + type: object service: description: Service is the service to resolve instead of the default. From cf341468b8eb935c8418624b35827cb7c5adde88 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 16 Nov 2021 11:39:51 -0500 Subject: [PATCH 141/418] Migrate intentions from legacy intentions to config entries --- acceptance/tests/connect/connect_helper.go | 13 ++++--- .../connect/connect_inject_namespaces_test.go | 23 ++++++++----- .../ingress_gateway_namespaces_test.go | 34 ++++++++++++------- .../ingress-gateway/ingress_gateway_test.go | 13 ++++--- .../tests/mesh-gateway/mesh_gateway_test.go | 13 ++++--- .../tests/partitions/partitions_test.go | 25 ++++++++------ .../terminating_gateway_test.go | 17 ++++++---- 7 files changed, 89 insertions(+), 49 deletions(-) diff --git a/acceptance/tests/connect/connect_helper.go b/acceptance/tests/connect/connect_helper.go index 876188ea32..f59864f900 100644 --- a/acceptance/tests/connect/connect_helper.go +++ b/acceptance/tests/connect/connect_helper.go @@ -87,10 +87,15 @@ func ConnectInjectConnectivityCheck(t *testing.T, ctx environment.TestContext, c } logger.Log(t, "creating intention") - _, err := consulClient.Connect().IntentionUpsert(&api.Intention{ - SourceName: staticClientName, - DestinationName: staticServerName, - Action: api.IntentionActionAllow, + _, _, err := consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: staticServerName, + Sources: []*api.SourceIntention{ + { + Name: staticClientName, + Action: api.IntentionActionAllow, + }, + }, }, nil) require.NoError(t, err) } diff --git a/acceptance/tests/connect/connect_inject_namespaces_test.go b/acceptance/tests/connect/connect_inject_namespaces_test.go index da0c18d22d..c5dfa5604a 100644 --- a/acceptance/tests/connect/connect_inject_namespaces_test.go +++ b/acceptance/tests/connect/connect_inject_namespaces_test.go @@ -182,23 +182,28 @@ func TestConnectInjectNamespaces(t *testing.T) { k8s.CheckStaticServerConnectionFailing(t, staticClientOpts, "http://localhost:1234") } - intention := &api.Intention{ - SourceName: staticClientName, - SourceNS: staticClientNamespace, - DestinationName: staticServerName, - DestinationNS: staticServerNamespace, - Action: api.IntentionActionAllow, + intention := &api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: staticServerName, + Namespace: staticServerNamespace, + Sources: []*api.SourceIntention{ + { + Name: staticClientName, + Namespace: staticClientNamespace, + Action: api.IntentionActionAllow, + }, + }, } // Set the destination namespace to be the same // unless mirrorK8S is true. if !c.mirrorK8S { - intention.SourceNS = c.destinationNamespace - intention.DestinationNS = c.destinationNamespace + intention.Namespace = c.destinationNamespace + intention.Sources[0].Namespace = c.destinationNamespace } logger.Log(t, "creating intention") - _, err := consulClient.Connect().IntentionUpsert(intention, nil) + _, _, err := consulClient.ConfigEntries().Set(intention, nil) require.NoError(t, err) } diff --git a/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go b/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go index baa4e8bddb..f7ae5d13bc 100644 --- a/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go +++ b/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go @@ -132,12 +132,17 @@ func TestIngressGatewaySingleNamespace(t *testing.T) { // Now we create the allow intention. logger.Log(t, "creating ingress-gateway => static-server intention") - _, err = consulClient.Connect().IntentionUpsert(&api.Intention{ - SourceName: "ingress-gateway", - SourceNS: testNamespace, - DestinationName: "static-server", - DestinationNS: testNamespace, - Action: api.IntentionActionAllow, + _, _, err = consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: "static-server", + Namespace: testNamespace, + Sources: []*api.SourceIntention{ + { + Name: "ingress-gateway", + Namespace: testNamespace, + Action: api.IntentionActionAllow, + }, + }, }, nil) require.NoError(t, err) } @@ -252,12 +257,17 @@ func TestIngressGatewayNamespaceMirroring(t *testing.T) { // Now we create the allow intention. logger.Log(t, "creating ingress-gateway => static-server intention") - _, err = consulClient.Connect().IntentionUpsert(&api.Intention{ - SourceName: "ingress-gateway", - SourceNS: "default", - DestinationName: "static-server", - DestinationNS: testNamespace, - Action: api.IntentionActionAllow, + _, _, err = consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: "static-server", + Namespace: testNamespace, + Sources: []*api.SourceIntention{ + { + Name: "ingress-gateway", + Namespace: "default", + Action: api.IntentionActionAllow, + }, + }, }, nil) require.NoError(t, err) } diff --git a/acceptance/tests/ingress-gateway/ingress_gateway_test.go b/acceptance/tests/ingress-gateway/ingress_gateway_test.go index 823291e5da..b727d4332a 100644 --- a/acceptance/tests/ingress-gateway/ingress_gateway_test.go +++ b/acceptance/tests/ingress-gateway/ingress_gateway_test.go @@ -96,10 +96,15 @@ func TestIngressGateway(t *testing.T) { // Now we create the allow intention. logger.Log(t, "creating ingress-gateway => static-server intention") - _, err = consulClient.Connect().IntentionUpsert(&api.Intention{ - SourceName: "ingress-gateway", - DestinationName: "static-server", - Action: api.IntentionActionAllow, + _, _, err = consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: "static-server", + Sources: []*api.SourceIntention{ + { + Name: "ingress-gateway", + Action: api.IntentionActionAllow, + }, + }, }, nil) require.NoError(t, err) } diff --git a/acceptance/tests/mesh-gateway/mesh_gateway_test.go b/acceptance/tests/mesh-gateway/mesh_gateway_test.go index fd72db25d0..7637e03d42 100644 --- a/acceptance/tests/mesh-gateway/mesh_gateway_test.go +++ b/acceptance/tests/mesh-gateway/mesh_gateway_test.go @@ -249,10 +249,15 @@ func TestMeshGatewaySecure(t *testing.T) { k8s.DeployKustomize(t, primaryContext.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-multi-dc") logger.Log(t, "creating intention") - _, err = primaryClient.Connect().IntentionUpsert(&api.Intention{ - SourceName: staticClientName, - DestinationName: "static-server", - Action: api.IntentionActionAllow, + _, _, err = primaryClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: "static-server", + Sources: []*api.SourceIntention{ + { + Name: staticClientName, + Action: api.IntentionActionAllow, + }, + }, }, nil) require.NoError(t, err) diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 8f8e056784..576b664c34 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -425,25 +425,30 @@ func TestPartitions(t *testing.T) { k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") - intention := &api.Intention{ - SourceName: staticClientName, - SourceNS: staticClientNamespace, - DestinationName: staticServerName, - DestinationNS: staticServerNamespace, - Action: api.IntentionActionAllow, + intention := &api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: staticServerName, + Namespace: staticServerNamespace, + Sources: []*api.SourceIntention{ + { + Name: staticClientName, + Namespace: staticClientNamespace, + Action: api.IntentionActionAllow, + }, + }, } // Set the destination namespace to be the same // unless mirrorK8S is true. if !c.mirrorK8S { - intention.SourceNS = c.destinationNamespace - intention.DestinationNS = c.destinationNamespace + intention.Namespace = c.destinationNamespace + intention.Sources[0].Namespace = c.destinationNamespace } logger.Log(t, "creating intention") - _, err := consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: defaultPartition}) + _, _, err := consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: defaultPartition}) require.NoError(t, err) - _, err = consulClient.Connect().IntentionUpsert(intention, &api.WriteOptions{Partition: secondaryPartition}) + _, _, err = consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: secondaryPartition}) require.NoError(t, err) } diff --git a/acceptance/tests/terminating-gateway/terminating_gateway_test.go b/acceptance/tests/terminating-gateway/terminating_gateway_test.go index 19a7c274cd..690e231e2b 100644 --- a/acceptance/tests/terminating-gateway/terminating_gateway_test.go +++ b/acceptance/tests/terminating-gateway/terminating_gateway_test.go @@ -194,12 +194,17 @@ func assertNoConnectionAndAddIntention(t *testing.T, consulClient *api.Client, k k8s.CheckStaticServerConnectionFailing(t, k8sOptions, "http://localhost:1234") logger.Log(t, "creating static-client => static-server intention") - _, err := consulClient.Connect().IntentionUpsert(&api.Intention{ - SourceName: staticClientName, - SourceNS: sourceNS, - DestinationName: staticServerName, - DestinationNS: destinationNS, - Action: api.IntentionActionAllow, + _, _, err := consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: staticServerName, + Namespace: destinationNS, + Sources: []*api.SourceIntention{ + { + Name: staticClientName, + Namespace: sourceNS, + Action: api.IntentionActionAllow, + }, + }, }, nil) require.NoError(t, err) } From 75236bc2fec59fa9f2fb2b246eb37e76c5e764a7 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 16 Nov 2021 13:45:07 -0500 Subject: [PATCH 142/418] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c75390c9c..7021e7135c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,11 +19,15 @@ IMPROVEMENTS: * Control Plane * TLS: Support PKCS1 and PKCS8 private keys for Consul certificate authority. [[GH-843](https://github.com/hashicorp/consul-k8s/pull/843)] * Connect: Log a warning when ACLs are enabled and the default service account is used. [[GH-842](https://github.com/hashicorp/consul-k8s/pull/842)] + * Update Service Router, Service Splitter and Ingress Gateway CRD with support for RequestHeaders and ResponseHeaders. [[GH-863](https://github.com/hashicorp/consul-k8s/pull/863)] + * Update Ingress Gateway CRD with partition support for the IngressService and TLS Config. [[GH-863](https://github.com/hashicorp/consul-k8s/pull/863)] * CLI * Delete jobs, cluster roles, and cluster role bindings on `uninstall`. [[GH-820](https://github.com/hashicorp/consul-k8s/pull/820)] * Helm Chart * Add `component` labels to all resources. [[GH-840](https://github.com/hashicorp/consul-k8s/pull/840)] * Update Consul version to 1.10.4. [[GH-861](https://github.com/hashicorp/consul-k8s/pull/861)] + * Update Service Router, Service Splitter and Ingress Gateway CRD with support for RequestHeaders and ResponseHeaders. [[GH-863](https://github.com/hashicorp/consul-k8s/pull/863)] + * Update Ingress Gateway CRD with partition support for the IngressService and TLS Config. [[GH-863](https://github.com/hashicorp/consul-k8s/pull/863)] BUG FIXES: * Control Plane From 53a6403d72f7e34d3b1f3998edf3303f6cd46c21 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 16 Nov 2021 17:56:51 -0500 Subject: [PATCH 143/418] Add TLS field to Ingress Listener (#864) --- .../consul/templates/crd-ingressgateways.yaml | 19 ++++++++ .../api/v1alpha1/ingressgateway_types.go | 14 ++++-- .../api/v1alpha1/ingressgateway_types_test.go | 44 +++++++++++++++++++ .../api/v1alpha1/zz_generated.deepcopy.go | 5 +++ .../consul.hashicorp.com_ingressgateways.yaml | 19 ++++++++ 5 files changed, 98 insertions(+), 3 deletions(-) diff --git a/charts/consul/templates/crd-ingressgateways.yaml b/charts/consul/templates/crd-ingressgateways.yaml index 29acc67958..a9e2888ed7 100644 --- a/charts/consul/templates/crd-ingressgateways.yaml +++ b/charts/consul/templates/crd-ingressgateways.yaml @@ -62,6 +62,25 @@ spec: description: IngressListener manages the configuration for a listener on a specific port. properties: + gatewayTLSConfig: + description: TLS config for this listener. + properties: + enabled: + description: Indicates that TLS should be enabled for this + gateway service. + type: boolean + gatewayTLSSDSConfig: + description: SDS allows configuring TLS certificate from + an SDS service. + properties: + certResource: + type: string + clusterName: + type: string + type: object + required: + - enabled + type: object port: description: Port declares the port on which the ingress gateway should listen for traffic. diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index aa2b4e37cc..82e5026f8b 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -87,6 +87,9 @@ type IngressListener struct { // current supported values are: (tcp | http | http2 | grpc). Protocol string `json:"protocol,omitempty"` + // TLS config for this listener. + TLS *GatewayTLSConfig `json:"gatewayTLSConfig,omitempty"` + // Services declares the set of services to which the listener forwards // traffic. // @@ -223,7 +226,7 @@ func (in *IngressGateway) ToConsul(datacenter string) capi.ConfigEntry { return &capi.IngressGatewayConfigEntry{ Kind: in.ConsulKind(), Name: in.ConsulName(), - TLS: in.Spec.TLS.toConsul(), + TLS: *in.Spec.TLS.toConsul(), Listeners: listeners, Meta: meta(datacenter), } @@ -273,8 +276,11 @@ func (in *IngressGateway) DefaultNamespaceFields(consulMeta common.ConsulMeta) { } } -func (in GatewayTLSConfig) toConsul() capi.GatewayTLSConfig { - return capi.GatewayTLSConfig{ +func (in *GatewayTLSConfig) toConsul() *capi.GatewayTLSConfig { + if in == nil { + return nil + } + return &capi.GatewayTLSConfig{ Enabled: in.Enabled, SDS: in.SDS.toConsul(), } @@ -285,9 +291,11 @@ func (in IngressListener) toConsul() capi.IngressListener { for _, s := range in.Services { services = append(services, s.toConsul()) } + return capi.IngressListener{ Port: in.Port, Protocol: in.Protocol, + TLS: in.TLS.toConsul(), Services: services, } } diff --git a/control-plane/api/v1alpha1/ingressgateway_types_test.go b/control-plane/api/v1alpha1/ingressgateway_types_test.go index d2327dace9..4260b39871 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types_test.go +++ b/control-plane/api/v1alpha1/ingressgateway_types_test.go @@ -46,11 +46,22 @@ func TestIngressGateway_MatchesConsul(t *testing.T) { Spec: IngressGatewaySpec{ TLS: GatewayTLSConfig{ Enabled: true, + SDS: &GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, }, Listeners: []IngressListener{ { Port: 8888, Protocol: "tcp", + TLS: &GatewayTLSConfig{ + Enabled: true, + SDS: &GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, + }, Services: []IngressService{ { Name: "name1", @@ -119,11 +130,22 @@ func TestIngressGateway_MatchesConsul(t *testing.T) { Namespace: "foobar", TLS: capi.GatewayTLSConfig{ Enabled: true, + SDS: &capi.GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, }, Listeners: []capi.IngressListener{ { Port: 8888, Protocol: "tcp", + TLS: &capi.GatewayTLSConfig{ + Enabled: true, + SDS: &capi.GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, + }, Services: []capi.IngressService{ { Name: "name1", @@ -247,11 +269,22 @@ func TestIngressGateway_ToConsul(t *testing.T) { Spec: IngressGatewaySpec{ TLS: GatewayTLSConfig{ Enabled: true, + SDS: &GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, }, Listeners: []IngressListener{ { Port: 8888, Protocol: "tcp", + TLS: &GatewayTLSConfig{ + Enabled: true, + SDS: &GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, + }, Services: []IngressService{ { Name: "name1", @@ -319,11 +352,22 @@ func TestIngressGateway_ToConsul(t *testing.T) { Name: "name", TLS: capi.GatewayTLSConfig{ Enabled: true, + SDS: &capi.GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, }, Listeners: []capi.IngressListener{ { Port: 8888, Protocol: "tcp", + TLS: &capi.GatewayTLSConfig{ + Enabled: true, + SDS: &capi.GatewayTLSSDSConfig{ + ClusterName: "cluster1", + CertResource: "cert1", + }, + }, Services: []capi.IngressService{ { Name: "name1", diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index 62039af40f..55db5207b2 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -326,6 +326,11 @@ func (in *IngressGatewaySpec) DeepCopy() *IngressGatewaySpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IngressListener) DeepCopyInto(out *IngressListener) { *out = *in + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = new(GatewayTLSConfig) + (*in).DeepCopyInto(*out) + } if in.Services != nil { in, out := &in.Services, &out.Services *out = make([]IngressService, len(*in)) 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 68e2a01e8b..ed2114aee9 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml @@ -56,6 +56,25 @@ spec: description: IngressListener manages the configuration for a listener on a specific port. properties: + gatewayTLSConfig: + description: TLS config for this listener. + properties: + enabled: + description: Indicates that TLS should be enabled for this + gateway service. + type: boolean + gatewayTLSSDSConfig: + description: SDS allows configuring TLS certificate from + an SDS service. + properties: + certResource: + type: string + clusterName: + type: string + type: object + required: + - enabled + type: object port: description: Port declares the port on which the ingress gateway should listen for traffic. From 2c8984929ec6718a16a8e7523fe36da8d8bf3e69 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 18 Nov 2021 13:25:47 -0500 Subject: [PATCH 144/418] support 1.11.0-beta3 (#866) --- .circleci/config.yml | 4 ++-- acceptance/go.mod | 2 +- acceptance/go.sum | 4 ++-- acceptance/tests/controller/controller_namespaces_test.go | 2 +- acceptance/tests/partitions/partitions_test.go | 4 ++-- .../controller/partitionexports_controller_ent_test.go | 5 ----- control-plane/go.mod | 2 +- control-plane/go.sum | 4 ++-- 8 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cb74cea58c..cef6badbac 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,8 +9,8 @@ executors: - image: docker.mirror.hashicorp.services/circleci/golang:1.16 environment: TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.11.0-beta2 # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.11.0+ent-beta2 # Consul's enterprise version to use in tests + CONSUL_VERSION: 1.11.0-beta3 # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.0+ent-beta3 # Consul's enterprise version to use in tests control-plane-path : &control-plane-path control-plane cli-path : &cli-path cli diff --git a/acceptance/go.mod b/acceptance/go.mod index 7cc39ce42d..de665fe086 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/gruntwork-io/terratest v0.31.2 - github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf + github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f github.com/hashicorp/consul/sdk v0.8.0 github.com/stretchr/testify v1.5.1 gopkg.in/yaml.v2 v2.2.8 diff --git a/acceptance/go.sum b/acceptance/go.sum index d363abe258..998060bfec 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -225,8 +225,8 @@ github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arn github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= -github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf h1:AH+AORMM9SgSyOrcsvGKxsFDk57ChzqYchlGA2U3+aE= -github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f h1:fBBh4412td7nBzqyLkpGTH5dWycPs8p7Yg/Dy8VQjVU= +github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= diff --git a/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go index 356c21d2a5..d68b2c5414 100644 --- a/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -74,7 +74,7 @@ func TestControllerNamespaces(t *testing.T) { ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta2", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta3", "global.enableConsulNamespaces": "true", "global.adminPartitions.enabled": "true", diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 576b664c34..a9c04a3c5e 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -96,7 +96,7 @@ func TestPartitions(t *testing.T) { serverHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta2", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta3", "global.adminPartitions.enabled": "true", "global.enableConsulNamespaces": "true", @@ -192,7 +192,7 @@ func TestPartitions(t *testing.T) { // Create client cluster. clientHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta2", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta3", "global.enabled": "false", "global.tls.enabled": "true", diff --git a/control-plane/controller/partitionexports_controller_ent_test.go b/control-plane/controller/partitionexports_controller_ent_test.go index 7e8ebb2abc..888f9060e6 100644 --- a/control-plane/controller/partitionexports_controller_ent_test.go +++ b/control-plane/controller/partitionexports_controller_ent_test.go @@ -29,10 +29,7 @@ import ( // test pattern of the enterprise tests already covers a config-entry similar to partition-exports // ie a "global" configentry. Hence a separate file has been created to test this controller. -// TODO: remove skips once 1.11-beta2 image is released. - func TestPartitionExportsController_createsPartitionExports(tt *testing.T) { - tt.Skip() tt.Parallel() cases := map[string]struct { @@ -152,7 +149,6 @@ func TestPartitionExportsController_createsPartitionExports(tt *testing.T) { } func TestPartitionExportsController_updatesPartitionExports(tt *testing.T) { - tt.Skip() tt.Parallel() cases := map[string]struct { @@ -295,7 +291,6 @@ func TestPartitionExportsController_updatesPartitionExports(tt *testing.T) { } func TestPartitionExportsController_deletesPartitionExports(tt *testing.T) { - tt.Skip() tt.Parallel() cases := map[string]struct { diff --git a/control-plane/go.mod b/control-plane/go.mod index 37e565d4e6..87073d3a03 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -10,7 +10,7 @@ require ( github.com/google/go-cmp v0.5.6 github.com/google/go-querystring v1.0.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf + github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f diff --git a/control-plane/go.sum b/control-plane/go.sum index a66634c9da..179772df60 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -297,8 +297,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf h1:AH+AORMM9SgSyOrcsvGKxsFDk57ChzqYchlGA2U3+aE= -github.com/hashicorp/consul/api v1.10.1-0.20211115155114-eb21649f82bf/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f h1:fBBh4412td7nBzqyLkpGTH5dWycPs8p7Yg/Dy8VQjVU= +github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= From 914e280aa991df2f6adda7d0c4040a79959cfb16 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 18 Nov 2021 10:36:42 -0800 Subject: [PATCH 145/418] Re-enable streaming for clients (#851) * Re-enable streaming for clients --- CHANGELOG.md | 26 ++++++++++++++----- .../templates/client-config-configmap.yaml | 3 +-- .../create-federation-secret-job.yaml | 6 ++--- charts/consul/test/unit/client-daemonset.bats | 2 +- 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7021e7135c..eefcb9cd4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,5 @@ ## UNRELEASED -FEATURES: -* Helm Chart - * Add support for Consul services to utilize Consul DNS for service discovery. Set `dns.enableRedirection` to allow services to - use Consul DNS via the Consul DNS Service. [[GH-833](https://github.com/hashicorp/consul-k8s/pull/833)] -* Control Plane - * Connect: Allow services using Connect to utilize Consul DNS to perform service discovery. [[GH-833](https://github.com/hashicorp/consul-k8s/pull/833)] - BREAKING CHANGES: * Previously [UI metrics](https://www.consul.io/docs/connect/observability/ui-visualization) would be enabled when `global.metrics=false` and `ui.metrics.enabled=-`. If you are no longer seeing UI metrics, @@ -14,6 +7,24 @@ BREAKING CHANGES: * The `enterpriseLicense` section of the values file has been migrated from being under the `server` stanza to being under the `global` stanza. Migrating the contents of `server.enterpriseLicense` to `global.enterpriseLicense` will ensure the license job works. [[GH-856](https://github.com/hashicorp/consul-k8s/pull/856)] +* Consul [streaming](https://www.consul.io/docs/agent/options#use_streaming_backend) is re-enabled by default. + Streaming is broken when using multi-DC federation and Consul versions 1.10.0, 1.10.1, 1.10.2. + If you are using those versions and multi-DC federation, you must upgrade to Consul >= 1.10.3 or set: + + ```yaml + client: + extraConfig: | + {"use_streaming_backend": false} + ``` + + [[GH-851](https://github.com/hashicorp/consul-k8s/pull/851)] + +FEATURES: +* Helm Chart + * Add support for Consul services to utilize Consul DNS for service discovery. Set `dns.enableRedirection` to allow services to + use Consul DNS via the Consul DNS Service. [[GH-833](https://github.com/hashicorp/consul-k8s/pull/833)] +* Control Plane + * Connect: Allow services using Connect to utilize Consul DNS to perform service discovery. [[GH-833](https://github.com/hashicorp/consul-k8s/pull/833)] IMPROVEMENTS: * Control Plane @@ -28,6 +39,7 @@ IMPROVEMENTS: * Update Consul version to 1.10.4. [[GH-861](https://github.com/hashicorp/consul-k8s/pull/861)] * Update Service Router, Service Splitter and Ingress Gateway CRD with support for RequestHeaders and ResponseHeaders. [[GH-863](https://github.com/hashicorp/consul-k8s/pull/863)] * Update Ingress Gateway CRD with partition support for the IngressService and TLS Config. [[GH-863](https://github.com/hashicorp/consul-k8s/pull/863)] + * Re-enable streaming for Consul clients. [[GH-851](https://github.com/hashicorp/consul-k8s/pull/851)] BUG FIXES: * Control Plane diff --git a/charts/consul/templates/client-config-configmap.yaml b/charts/consul/templates/client-config-configmap.yaml index 4ba0785576..5954c1f86f 100644 --- a/charts/consul/templates/client-config-configmap.yaml +++ b/charts/consul/templates/client-config-configmap.yaml @@ -25,8 +25,7 @@ data: in the UI. */}} config.json: |- { - "check_update_interval": "0s", - "use_streaming_backend": false + "check_update_interval": "0s" } {{- end }} {{- end }} diff --git a/charts/consul/templates/create-federation-secret-job.yaml b/charts/consul/templates/create-federation-secret-job.yaml index e3f0818a24..096135dd2a 100644 --- a/charts/consul/templates/create-federation-secret-job.yaml +++ b/charts/consul/templates/create-federation-secret-job.yaml @@ -114,8 +114,7 @@ spec: mountPath: /consul/tls/client/ca readOnly: true {{- end }} - {{- if (or .Values.global.gossipEncryption.autoGenerate - (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} + {{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} - name: gossip-encryption-key mountPath: /consul/gossip readOnly: true @@ -127,8 +126,7 @@ spec: consul-k8s-control-plane create-federation-secret \ -log-level={{ .Values.global.logLevel }} \ -log-json={{ .Values.global.logJSON }} \ - {{- if (or .Values.global.gossipEncryption.autoGenerate (and - .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} + {{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} -gossip-key-file=/consul/gossip/gossip.key \ {{- end }} {{- if .Values.global.acls.createReplicationToken }} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index 2d03f2f3aa..62c27a0106 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -569,7 +569,7 @@ load _helpers --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations."consul.hashicorp.com/config-checksum"' | tee /dev/stderr) - [ "${actual}" = 1b0252854bdef3197902ee928716ebd691ef39b173a19ad0d4e883ddb0443b88 ] + [ "${actual}" = b0be8c9b3ae8692a4e393b93976c55988e95cb9d9dae96fbd8626f3f5b6c404b ] } #-------------------------------------------------------------------- From 6c1f0bd371ac0b46a7c7357ac060b0f54d3708c2 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 18 Nov 2021 13:46:18 -0500 Subject: [PATCH 146/418] v0.37.0 (#868) --- charts/consul/Chart.yaml | 4 ++-- charts/consul/values.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index 7c9857bffa..740f90d1fd 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: consul -version: 0.36.0 +version: 0.37.0 appVersion: 1.10.4 kubeVersion: ">=1.17.0-0" description: Official HashiCorp Consul Chart @@ -15,7 +15,7 @@ annotations: - name: consul image: hashicorp/consul:1.10.4 - name: consul-k8s-control-plane - image: hashicorp/consul-k8s-control-plane:0.36.0 + image: hashicorp/consul-k8s-control-plane:0.37.0 - name: envoy image: envoyproxy/envoy-alpine:v1.18.4 artifacthub.io/license: MPL-2.0 diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 71b0cce751..a6ab7223fe 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -105,7 +105,7 @@ global: # image that is used for functionality such as catalog sync. # This can be overridden per component. # @default: hashicorp/consul-k8s-control-plane: - imageK8S: "hashicorp/consul-k8s-control-plane:0.36.0" + imageK8S: "hashicorp/consul-k8s-control-plane:0.37.0" # The name of the datacenter that the agents should # register as. This can't be changed once the Consul cluster is up and running From a0d394eba3aa60ded53d7d87d7c3c85b526826fa Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Thu, 18 Nov 2021 18:55:06 +0000 Subject: [PATCH 147/418] Release v0.37.0 --- CHANGELOG.md | 2 +- cli/version/version.go | 4 ++-- control-plane/version/version.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eefcb9cd4a..8c08b775cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.37.0 (November 18, 2021) BREAKING CHANGES: * Previously [UI metrics](https://www.consul.io/docs/connect/observability/ui-visualization) would be enabled when diff --git a/cli/version/version.go b/cli/version/version.go index 8740d28984..fc910cec97 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.36.0" + Version = "0.37.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 8740d28984..fc910cec97 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.36.0" + Version = "0.37.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 929940b5ab514d59b8f9f09abe90101c1c8fc175 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Thu, 18 Nov 2021 19:17:58 +0000 Subject: [PATCH 148/418] Putting source back into Dev Mode --- CHANGELOG.md | 2 ++ cli/version/version.go | 2 +- control-plane/version/version.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c08b775cb..87da8d9f14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## UNRELEASED + ## 0.37.0 (November 18, 2021) BREAKING CHANGES: diff --git a/cli/version/version.go b/cli/version/version.go index fc910cec97..52fb3c2b9c 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index fc910cec97..52fb3c2b9c 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable From bf60c64f55693b9b5d0f78b5d5c18ad67e7a9844 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Fri, 19 Nov 2021 16:43:31 -0700 Subject: [PATCH 149/418] acceptance-tests: add a workaround to mesh gateway tests against kind 1.22 (#871) --- acceptance/tests/mesh-gateway/mesh_gateway_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/acceptance/tests/mesh-gateway/mesh_gateway_test.go b/acceptance/tests/mesh-gateway/mesh_gateway_test.go index 7637e03d42..c989535b90 100644 --- a/acceptance/tests/mesh-gateway/mesh_gateway_test.go +++ b/acceptance/tests/mesh-gateway/mesh_gateway_test.go @@ -96,6 +96,13 @@ func TestMeshGatewayDefault(t *testing.T) { secondaryConsulCluster := consul.NewHelmCluster(t, secondaryHelmValues, secondaryContext, cfg, releaseName) secondaryConsulCluster.Create(t) + if cfg.UseKind { + // This is a temporary workaround that seems to fix mesh gateway tests on kind 1.22.x. + // TODO (ishustava): we need to investigate this further and remove once we've found the issue. + k8s.RunKubectl(t, primaryContext.KubectlOptions(t), "rollout", "restart", fmt.Sprintf("sts/%s-consul-server", releaseName)) + k8s.RunKubectl(t, primaryContext.KubectlOptions(t), "rollout", "status", fmt.Sprintf("sts/%s-consul-server", releaseName)) + } + primaryClient := primaryConsulCluster.SetupConsulClient(t, false) secondaryClient := secondaryConsulCluster.SetupConsulClient(t, false) @@ -225,6 +232,13 @@ func TestMeshGatewaySecure(t *testing.T) { secondaryConsulCluster := consul.NewHelmCluster(t, secondaryHelmValues, secondaryContext, cfg, releaseName) secondaryConsulCluster.Create(t) + if cfg.UseKind { + // This is a temporary workaround that seems to fix mesh gateway tests on kind 1.22.x. + // TODO (ishustava): we need to investigate this further and remove once we've found the issue. + k8s.RunKubectl(t, primaryContext.KubectlOptions(t), "rollout", "restart", fmt.Sprintf("sts/%s-consul-server", releaseName)) + k8s.RunKubectl(t, primaryContext.KubectlOptions(t), "rollout", "status", fmt.Sprintf("sts/%s-consul-server", releaseName)) + } + primaryClient := primaryConsulCluster.SetupConsulClient(t, true) secondaryClient := secondaryConsulCluster.SetupConsulClient(t, true) From 9c515aaf4397e8f81a66b1137240adc0c9317e4d Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Wed, 24 Nov 2021 13:52:24 -0700 Subject: [PATCH 150/418] Add configuration for the vault Connect CA provider (#872) --- acceptance/framework/helpers/helpers.go | 4 +- .../fixtures/bases/intention/intention.yaml | 10 + .../bases/intention/kustomization.yaml | 2 + acceptance/tests/vault/vault_test.go | 125 +++++++--- .../templates/server-config-configmap.yaml | 30 +++ .../test/unit/server-config-configmap.bats | 227 ++++++++++++++++++ charts/consul/values.yaml | 37 +++ 7 files changed, 406 insertions(+), 29 deletions(-) create mode 100644 acceptance/tests/fixtures/bases/intention/intention.yaml create mode 100644 acceptance/tests/fixtures/bases/intention/kustomization.yaml diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index f173aeea6f..1c40112e7d 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "github.com/gruntwork-io/terratest/modules/helm" "os" "os/signal" "strings" @@ -12,6 +11,8 @@ import ( "testing" "time" + "github.com/gruntwork-io/terratest/modules/helm" + terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" "github.com/gruntwork-io/terratest/modules/random" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" @@ -85,6 +86,7 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac retry.RunWith(counter, t, func(r *retry.R) { pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) require.NoError(r, err) + require.NotEmpty(r, pods.Items) var notReadyPods []string for _, pod := range pods.Items { diff --git a/acceptance/tests/fixtures/bases/intention/intention.yaml b/acceptance/tests/fixtures/bases/intention/intention.yaml new file mode 100644 index 0000000000..c7bf26dac2 --- /dev/null +++ b/acceptance/tests/fixtures/bases/intention/intention.yaml @@ -0,0 +1,10 @@ +apiVersion: consul.hashicorp.com/v1alpha1 +kind: ServiceIntentions +metadata: + name: client-to-server +spec: + destination: + name: static-server + sources: + - name: static-client + action: allow diff --git a/acceptance/tests/fixtures/bases/intention/kustomization.yaml b/acceptance/tests/fixtures/bases/intention/kustomization.yaml new file mode 100644 index 0000000000..8d15c05511 --- /dev/null +++ b/acceptance/tests/fixtures/bases/intention/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - intention.yaml \ No newline at end of file diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 67b81f1884..94d09f1492 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -4,34 +4,50 @@ import ( "crypto/rand" "encoding/base64" "fmt" + "testing" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/vault" "github.com/stretchr/testify/require" - "testing" ) -// generateGossipSecret generates a random 32 byte secret returned as a base64 encoded string. -func generateGossipSecret() (string, error) { - // This code was copied from Consul's Keygen command: - // https://github.com/hashicorp/consul/blob/d652cc86e3d0322102c2b5e9026c6a60f36c17a5/command/keygen/keygen.go +const ( + gossipPolicy = ` +path "consul/data/secret/gossip" { + capabilities = ["read"] +}` - key := make([]byte, 32) - n, err := rand.Reader.Read(key) - if err != nil { - return "", fmt.Errorf("error reading random data: %s", err) - } - if n != 32 { - return "", fmt.Errorf("couldn't read enough entropy") - } + // connectCAPolicy allows Consul to bootstrap all certificates for the service mesh in Vault. + // Adapted from https://www.consul.io/docs/connect/ca/vault#consul-managed-pki-paths. + connectCAPolicy = ` +path "/sys/mounts" { + capabilities = [ "read" ] +} - return base64.StdEncoding.EncodeToString(key), nil +path "/sys/mounts/connect_root" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +path "/sys/mounts/connect_inter" { + capabilities = [ "create", "read", "update", "delete", "list" ] } -// Installs Vault, bootstraps it with secrets, policies, and Kube Auth Method -// then creates a gossip encryption secret and uses this to bootstrap Consul. -func TestVault_BootstrapConsulGossipEncryptionKey(t *testing.T) { +path "/connect_root/*" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +path "/connect_inter/*" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} +` +) + +// TestVault installs Vault, bootstraps it with secrets, policies, and Kube Auth Method. +// It then configures Consul to use vault as the backend and checks that it works. +func TestVault(t *testing.T) { cfg := suite.Config() ctx := suite.Environment().DefaultContext(t) @@ -48,16 +64,20 @@ func TestVault_BootstrapConsulGossipEncryptionKey(t *testing.T) { vaultClient := vaultCluster.VaultClient(t) // Create the Vault Policy for the gossip key. - logger.Log(t, "Creating the gossip policy") - rules := ` -path "consul/data/secret/gossip" { - capabilities = ["read"] -}` - err := vaultClient.Sys().PutPolicy("consul-gossip", rules) + logger.Log(t, "Creating policies") + err := vaultClient.Sys().PutPolicy("consul-gossip", gossipPolicy) + require.NoError(t, err) + + err = vaultClient.Sys().PutPolicy("connect-ca", connectCAPolicy) require.NoError(t, err) - // Create the Auth Roles for consul-server + consul-client. - logger.Log(t, "Creating the consul-server and consul-client-roles") + // Create the Auth Roles for consul-server and consul-client. + // Auth roles bind policies to Kubernetes service accounts, which + // then enables the Vault agent init container to call 'vault login' + // with the Kubernetes auth method to obtain a Vault token. + // Please see https://www.vaultproject.io/docs/auth/kubernetes#configuration + // for more details. + logger.Log(t, "Creating the consul-server and consul-client roles") params := map[string]interface{}{ "bound_service_account_names": consulClientServiceAccountName, "bound_service_account_namespaces": "default", @@ -70,7 +90,7 @@ path "consul/data/secret/gossip" { params = map[string]interface{}{ "bound_service_account_names": consulServerServiceAccountName, "bound_service_account_namespaces": "default", - "policies": "consul-gossip", + "policies": "consul-gossip,connect-ca", "ttl": "24h", } _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-server", params) @@ -88,17 +108,23 @@ path "consul/data/secret/gossip" { } _, err = vaultClient.Logical().Write("consul/data/secret/gossip", params) require.NoError(t, err) - consulHelmValues := map[string]string{ + "global.image": "docker.mirror.hashicorp.services/hashicorpdev/consul:latest", + "server.enabled": "true", "server.replicas": "1", "connectInject.enabled": "true", + "controller.enabled": "true", "global.secretsBackend.vault.enabled": "true", "global.secretsBackend.vault.consulServerRole": "consul-server", "global.secretsBackend.vault.consulClientRole": "consul-client", + "global.secretsBackend.vault.connectCA.address": fmt.Sprintf("http://%s-vault:8200", vaultReleaseName), + "global.secretsBackend.vault.connectCA.rootPKIPath": "connect_root", + "global.secretsBackend.vault.connectCA.intermediatePKIPath": "connect_inter", + "global.acls.manageSystemACLs": "true", "global.tls.enabled": "true", "global.gossipEncryption.secretName": "consul/data/secret/gossip", @@ -113,6 +139,49 @@ path "consul/data/secret/gossip" { consulClient := consulCluster.SetupConsulClient(t, true) keys, err := consulClient.Operator().KeyringList(nil) require.NoError(t, err) - // We use keys[0] because KeyringList returns a list of keyrings for each dc, in this case there is only 1 dc. + // There are two identical keys for LAN and WAN since there is only 1 dc. + require.Len(t, keys, 2) require.Equal(t, 1, keys[0].PrimaryKeys[gossipKey]) + + // Confirm that the Vault Connect CA has been bootstrapped correctly. + caConfig, _, err := consulClient.Connect().CAGetConfig(nil) + require.NoError(t, err) + require.Equal(t, caConfig.Provider, "vault") + + // Deploy two services and check that they can talk to each other. + logger.Log(t, "creating static-server and static-client deployments") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if cfg.EnableTransparentProxy { + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + } else { + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + } + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.KubectlDeleteK(t, ctx.KubectlOptions(t), "../fixtures/bases/intention") + }) + k8s.KubectlApplyK(t, ctx.KubectlOptions(t), "../fixtures/bases/intention") + + logger.Log(t, "checking that connection is successful") + if cfg.EnableTransparentProxy { + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://static-server") + } else { + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://localhost:1234") + } +} + +// generateGossipSecret generates a random 32 byte secret returned as a base64 encoded string. +func generateGossipSecret() (string, error) { + // This code was copied from Consul's Keygen command: + // https://github.com/hashicorp/consul/blob/d652cc86e3d0322102c2b5e9026c6a60f36c17a5/command/keygen/keygen.go + + key := make([]byte, 32) + n, err := rand.Reader.Read(key) + if err != nil { + return "", fmt.Errorf("error reading random data: %s", err) + } + if n != 32 { + return "", fmt.Errorf("couldn't read enough entropy") + } + + return base64.StdEncoding.EncodeToString(key), nil } diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index 6faf60b4b9..2b8f07dc6b 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -11,6 +11,36 @@ metadata: heritage: {{ .Release.Service }} release: {{ .Release.Name }} data: + {{- $vaultConnectCAEnabled := and .Values.global.secretsBackend.vault.connectCA.address .Values.global.secretsBackend.vault.connectCA.rootPKIPath .Values.global.secretsBackend.vault.connectCA.intermediatePKIPath -}} + {{- if and .Values.global.secretsBackend.vault.enabled $vaultConnectCAEnabled }} + {{- with .Values.global.secretsBackend.vault }} + connect-ca-config.json: | + { + "connect": [ + { + "ca_config": [ + { + "address": "{{ .connectCA.address }}", + "intermediate_pki_path": "{{ .connectCA.intermediatePKIPath }}", + "root_pki_path": "{{ .connectCA.rootPKIPath }}", + "auth_method": { + "type": "kubernetes", + "params": { + "role": "{{.consulServerRole}}" + } + } + } + ], + "ca_provider": "vault" + } + ] + } + {{- if .connectCA.additionalConfig }} + additional-connect-ca-config.json: | +{{ tpl .connectCA.additionalConfig $ | trimAll "\"" | indent 4 }} + {{- end }} + {{- end }} + {{- end }} extra-from-values.json: |- {{ tpl .Values.server.extraConfig . | trimAll "\"" | indent 4 }} {{- if .Values.global.acls.manageSystemACLs }} diff --git a/charts/consul/test/unit/server-config-configmap.bats b/charts/consul/test/unit/server-config-configmap.bats index 25a08da37c..8245fb215e 100755 --- a/charts/consul/test/unit/server-config-configmap.bats +++ b/charts/consul/test/unit/server-config-configmap.bats @@ -179,3 +179,230 @@ load _helpers yq -r '.data["acl-config.json"]' | yq -r '.acl.enable_token_replication' | tee /dev/stderr) [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# Vault Connect CA + +@test "server/ConfigMap: doesn't add connect CA config by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled but vault address, root and int PKI paths are not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and vault address is set, but root and int PKI paths are not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and root pki path is set, but vault address and int PKI paths are not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and int path is set, but vault address and root PKI paths are not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and root and int paths are set, but vault address is not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and root path and address are set, but int path is not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't add connect CA config when vault is enabled and int path and address are set, but root path is not set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.intPKIPath=int' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.intPKIPath=int' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: adds connect CA config when vault is enabled and connect CA are configured" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"]' | tee /dev/stderr) + [ "${actual}" = '"{\n \"connect\": [\n {\n \"ca_config\": [\n {\n \"address\": \"example.com\",\n \"intermediate_pki_path\": \"int\",\n \"root_pki_path\": \"root\",\n \"auth_method\": {\n \"type\": \"kubernetes\",\n \"params\": {\n \"role\": \"foo\"\n }\n }\n }\n ],\n \"ca_provider\": \"vault\"\n }\n ]\n}\n"' ] + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"]' | tee /dev/stderr) + [ "${actual}" = '"{}\n"' ] +} + +@test "server/ConfigMap: can set additional connect CA config" { + cd `chart_dir` + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + --set 'global.secretsBackend.vault.connectCA.additionalConfig="{\"hello\": \"world\"}"' \ + . | tee /dev/stderr | + yq '.data["additional-connect-ca-config.json"]' | tee /dev/stderr) + [ "${actual}" = '"{\"hello\": \"world\"}\n"' ] +} \ No newline at end of file diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 2a04d7416c..480e46bee5 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -152,6 +152,43 @@ global: # and check the name of `metadata.name`. consulClientRole: "" + # Configuration for the Vault Connect CA provider. + # The provider will be configured to use the Vault Kubernetes auth method + # and therefore requires the role provided by `global.secretsBackend.vault.consulServerRole` + # to have permissions to the root and intermediate PKI paths. + # Please see https://www.consul.io/docs/connect/ca/vault#vault-acl-policies + # for information on how to configure the Vault policies. + connectCA: + # The address of the Vault server. + address: "" + + # The path to a PKI secrets engine for the root certificate. + # Please see https://www.consul.io/docs/connect/ca/vault#rootpkipath. + rootPKIPath: "" + + # The path to a PKI secrets engine for the generated intermediate certificate. + # Please see https://www.consul.io/docs/connect/ca/vault#intermediatepkipath. + intermediatePKIPath: "" + + # Additional Connect CA configuration in JSON format. + # Please see https://www.consul.io/docs/connect/ca/vault#common-ca-config-options + # for additional configuration options. + # + # Example: + # + # ```yaml + # additionalConfig: | + # { + # "connect": [{ + # "ca_config": [{ + # "leaf_cert_ttl": "36h" + # }] + # }] + # } + # ``` + additionalConfig: | + {} + # Configures Consul's gossip encryption key. # (see `-encrypt` (https://consul.io/docs/agent/options#_encrypt)). # By default, gossip encryption is not enabled. The gossip encryption key may be set automatically or manually. From c68d7952057eac47f370e92002d610f1bf3beaeb Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Mon, 29 Nov 2021 11:20:58 -0600 Subject: [PATCH 151/418] add cd chart_dir so tests can be run from root level (#882) --- charts/consul/test/unit/ui-ingress.bats | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/charts/consul/test/unit/ui-ingress.bats b/charts/consul/test/unit/ui-ingress.bats index 3a4e1b6bd1..f26d181d2b 100755 --- a/charts/consul/test/unit/ui-ingress.bats +++ b/charts/consul/test/unit/ui-ingress.bats @@ -69,6 +69,7 @@ load _helpers # --kube-version "1.18" \ # . | tee /dev/stderr | # yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -89,6 +90,7 @@ load _helpers # --kube-version "1.18" \ # . | tee /dev/stderr | # yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -110,6 +112,7 @@ load _helpers # --kube-version "1.18" \ # . | tee /dev/stderr | # yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -132,6 +135,7 @@ load _helpers # --kube-version "1.18" \ # . | tee /dev/stderr | # yq -r '.spec.rules[0].http.paths[1].backend.servicePort' | tee /dev/stderr) + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -207,6 +211,7 @@ load _helpers # pathtype @test "ui/Ingress: default PathType Prefix" { + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -218,6 +223,7 @@ load _helpers } @test "ui/Ingress: set PathType ImplementationSpecific" { + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ From 8bdc5e692b4657a2bd603cfda432462409ae1008 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Wed, 24 Nov 2021 09:47:48 -0800 Subject: [PATCH 152/418] update pipeline steps to build using go 1.17 --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index cef6badbac..f84aed3235 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ orbs: executors: go: docker: - - image: docker.mirror.hashicorp.services/circleci/golang:1.16 + - image: docker.mirror.hashicorp.services/circleci/golang:1.17 environment: TEST_RESULTS: /tmp/test-results # path to where test results are saved CONSUL_VERSION: 1.11.0-beta3 # Consul's OSS version to use in tests @@ -30,9 +30,9 @@ commands: - run: name: Install gotestsum, kind, kubectl, and helm command: | - wget https://golang.org/dl/go1.16.5.linux-amd64.tar.gz - sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.16.5.linux-amd64.tar.gz - rm go1.16.5.linux-amd64.tar.gz + wget https://golang.org/dl/go1.17.3.linux-amd64.tar.gz + sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.3.linux-amd64.tar.gz + rm go1.17.3.linux-amd64.tar.gz echo 'export PATH=$PATH:/usr/local/go/bin' >> $BASH_ENV wget https://github.com/gotestyourself/gotestsum/releases/download/v1.6.4/gotestsum_1.6.4_linux_amd64.tar.gz From 537ea8e629e5eae10d9dbd758501517a8f060552 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Wed, 24 Nov 2021 09:54:03 -0800 Subject: [PATCH 153/418] run go fmt with 1.17 locally since prev commit was failing fmt in a go 1.17 environment --- control-plane/api/v1alpha1/zz_generated.deepcopy.go | 1 + .../catalog/to-consul/consul_node_services_client_ent_test.go | 1 + control-plane/catalog/to-consul/syncer_ent_test.go | 1 + control-plane/connect-inject/endpoints_controller_ent_test.go | 1 + control-plane/connect-inject/handler_ent_test.go | 1 + control-plane/controller/configentry_controller_ent_test.go | 1 + control-plane/controller/partitionexports_controller_ent_test.go | 1 + control-plane/namespaces/namespaces_test.go | 1 + control-plane/subcommand/connect-init/command_ent_test.go | 1 + control-plane/subcommand/consul-sidecar/command_ent_test.go | 1 + control-plane/subcommand/partition-init/command_ent_test.go | 1 + control-plane/subcommand/server-acl-init/command_ent_test.go | 1 + control-plane/subcommand/sync-catalog/command_ent_test.go | 1 + 13 files changed, 13 insertions(+) diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index 55db5207b2..2bf2f86b4e 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated // Code generated by controller-gen. DO NOT EDIT. diff --git a/control-plane/catalog/to-consul/consul_node_services_client_ent_test.go b/control-plane/catalog/to-consul/consul_node_services_client_ent_test.go index 42c68efdfe..e93fae516b 100644 --- a/control-plane/catalog/to-consul/consul_node_services_client_ent_test.go +++ b/control-plane/catalog/to-consul/consul_node_services_client_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package catalog diff --git a/control-plane/catalog/to-consul/syncer_ent_test.go b/control-plane/catalog/to-consul/syncer_ent_test.go index c6b9941f23..0d5ce60140 100644 --- a/control-plane/catalog/to-consul/syncer_ent_test.go +++ b/control-plane/catalog/to-consul/syncer_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package catalog diff --git a/control-plane/connect-inject/endpoints_controller_ent_test.go b/control-plane/connect-inject/endpoints_controller_ent_test.go index 4b75426346..fe1a5cfd29 100644 --- a/control-plane/connect-inject/endpoints_controller_ent_test.go +++ b/control-plane/connect-inject/endpoints_controller_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package connectinject diff --git a/control-plane/connect-inject/handler_ent_test.go b/control-plane/connect-inject/handler_ent_test.go index f99cde6f0e..9bc6249df4 100644 --- a/control-plane/connect-inject/handler_ent_test.go +++ b/control-plane/connect-inject/handler_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package connectinject diff --git a/control-plane/controller/configentry_controller_ent_test.go b/control-plane/controller/configentry_controller_ent_test.go index 09b8d4c06d..eb4ae505fe 100644 --- a/control-plane/controller/configentry_controller_ent_test.go +++ b/control-plane/controller/configentry_controller_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package controller_test diff --git a/control-plane/controller/partitionexports_controller_ent_test.go b/control-plane/controller/partitionexports_controller_ent_test.go index 888f9060e6..4313a871a4 100644 --- a/control-plane/controller/partitionexports_controller_ent_test.go +++ b/control-plane/controller/partitionexports_controller_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package controller_test diff --git a/control-plane/namespaces/namespaces_test.go b/control-plane/namespaces/namespaces_test.go index 4e0c25884e..5540e8dec5 100644 --- a/control-plane/namespaces/namespaces_test.go +++ b/control-plane/namespaces/namespaces_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package namespaces diff --git a/control-plane/subcommand/connect-init/command_ent_test.go b/control-plane/subcommand/connect-init/command_ent_test.go index 83f456cb2e..ea61f755e9 100644 --- a/control-plane/subcommand/connect-init/command_ent_test.go +++ b/control-plane/subcommand/connect-init/command_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package connectinit diff --git a/control-plane/subcommand/consul-sidecar/command_ent_test.go b/control-plane/subcommand/consul-sidecar/command_ent_test.go index ed20e1eb76..de0de853a1 100644 --- a/control-plane/subcommand/consul-sidecar/command_ent_test.go +++ b/control-plane/subcommand/consul-sidecar/command_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package consulsidecar diff --git a/control-plane/subcommand/partition-init/command_ent_test.go b/control-plane/subcommand/partition-init/command_ent_test.go index 39e031a8b7..0da70e454c 100644 --- a/control-plane/subcommand/partition-init/command_ent_test.go +++ b/control-plane/subcommand/partition-init/command_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package partition_init diff --git a/control-plane/subcommand/server-acl-init/command_ent_test.go b/control-plane/subcommand/server-acl-init/command_ent_test.go index 26842e8d6b..5d7c6e3262 100644 --- a/control-plane/subcommand/server-acl-init/command_ent_test.go +++ b/control-plane/subcommand/server-acl-init/command_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package serveraclinit diff --git a/control-plane/subcommand/sync-catalog/command_ent_test.go b/control-plane/subcommand/sync-catalog/command_ent_test.go index 80af158ea4..3475a3daeb 100644 --- a/control-plane/subcommand/sync-catalog/command_ent_test.go +++ b/control-plane/subcommand/sync-catalog/command_ent_test.go @@ -1,3 +1,4 @@ +//go:build enterprise // +build enterprise package synccatalog From d39f62c70b2671ab68130cd940e849f9dcbbb904 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Wed, 24 Nov 2021 13:03:46 -0800 Subject: [PATCH 154/418] update minimum go version for all 3 modules The control-plane module go fmt with 1.17 will error if you only ran go fmt with 1.16, so the minimum working version should be bumped to 1.17. The other 2 modules were bumped to 1.17 for consistency. The go.mod files themselves changed because in go 1.17 the indirect imports are in a separate section. --- charts/go.mod | 2 +- cli/go.mod | 147 ++++++++++++++++++++++++++++++++++++++++--- control-plane/go.mod | 118 +++++++++++++++++++++++++++++----- 3 files changed, 243 insertions(+), 24 deletions(-) diff --git a/charts/go.mod b/charts/go.mod index b5195323c1..950a1e55be 100644 --- a/charts/go.mod +++ b/charts/go.mod @@ -1,3 +1,3 @@ module github.com/hashicorp/consul-k8s/charts -go 1.16 +go 1.17 diff --git a/cli/go.mod b/cli/go.mod index cbb00dadc1..3bb781f2e2 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -1,35 +1,164 @@ module github.com/hashicorp/consul-k8s/cli -go 1.16 +go 1.17 require ( github.com/bgentry/speakeasy v0.1.0 github.com/cenkalti/backoff v2.2.1+incompatible github.com/fatih/color v1.9.0 - github.com/golang/protobuf v1.5.2 // indirect github.com/hashicorp/consul-k8s/charts v0.0.0-00010101000000-000000000000 github.com/hashicorp/go-hclog v0.16.2 - github.com/hashicorp/go-multierror v1.1.0 // indirect github.com/kr/text v0.2.0 - github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.12 github.com/mitchellh/cli v1.1.2 - github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/olekukonko/tablewriter v0.0.4 github.com/posener/complete v1.1.1 github.com/stretchr/testify v1.7.0 - go.starlark.net v0.0.0-20200707032745-474f21a9602d // indirect - golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect - google.golang.org/grpc v1.33.1 // indirect helm.sh/helm/v3 v3.6.1 k8s.io/api v0.21.2 k8s.io/apimachinery v0.21.2 k8s.io/cli-runtime v0.21.0 k8s.io/client-go v0.21.2 - rsc.io/letsencrypt v0.0.3 // indirect sigs.k8s.io/yaml v1.2.0 ) +require ( + cloud.google.com/go v0.54.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.12 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.5 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.0 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/BurntSushi/toml v0.3.1 // indirect + github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver v1.5.0 // indirect + github.com/Masterminds/semver/v3 v3.1.1 // indirect + github.com/Masterminds/sprig v2.22.0+incompatible // indirect + github.com/Masterminds/sprig/v3 v3.2.2 // indirect + github.com/Masterminds/squirrel v1.5.0 // indirect + github.com/Microsoft/go-winio v0.4.16 // indirect + github.com/Microsoft/hcsshim v0.8.14 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect + github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 // indirect + github.com/containerd/containerd v1.4.4 // indirect + github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7 // indirect + github.com/cyphar/filepath-securejoin v0.2.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deislabs/oras v0.11.1 // indirect + github.com/docker/cli v20.10.5+incompatible // indirect + github.com/docker/distribution v2.7.1+incompatible // indirect + github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible // indirect + github.com/docker/docker-credential-helpers v0.6.3 // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916 // indirect + github.com/docker/go-units v0.4.0 // indirect + github.com/evanphx/json-patch v4.9.0+incompatible // indirect + github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect + github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect + github.com/go-errors/errors v1.0.1 // indirect + github.com/go-logr/logr v0.4.0 // indirect + github.com/go-openapi/jsonpointer v0.19.3 // indirect + github.com/go-openapi/jsonreference v0.19.3 // indirect + github.com/go-openapi/spec v0.19.5 // indirect + github.com/go-openapi/swag v0.19.5 // indirect + github.com/gobwas/glob v0.2.3 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/btree v1.0.0 // indirect + github.com/google/go-cmp v0.5.5 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/googleapis/gnostic v0.4.1 // indirect + github.com/gorilla/mux v1.7.3 // indirect + github.com/gosuri/uitable v0.0.4 // indirect + github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-multierror v1.1.0 // indirect + github.com/hashicorp/golang-lru v0.5.1 // indirect + github.com/huandu/xstrings v1.3.2 // indirect + github.com/imdario/mergo v0.3.11 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jmoiron/sqlx v1.3.1 // indirect + github.com/json-iterator/go v1.1.10 // indirect + github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect + github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect + github.com/lib/pq v1.10.0 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/mailru/easyjson v0.7.0 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-runewidth v0.0.7 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/mitchellh/copystructure v1.1.1 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/reflectwalk v1.0.1 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/morikuni/aec v1.0.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/runc v0.1.1 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/client_golang v1.7.1 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.10.0 // indirect + github.com/prometheus/procfs v0.2.0 // indirect + github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 // indirect + github.com/russross/blackfriday v1.5.2 // indirect + github.com/shopspring/decimal v1.2.0 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/cobra v1.1.3 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect + go.opencensus.io v0.22.3 // indirect + go.starlark.net v0.0.0-20200707032745-474f21a9602d // indirect + golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect + golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 // indirect + golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect + golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + golang.org/x/text v0.3.4 // indirect + golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect + google.golang.org/appengine v1.6.5 // indirect + google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect + google.golang.org/grpc v1.33.1 // indirect + google.golang.org/protobuf v1.26.0 // indirect + gopkg.in/gorp.v1 v1.7.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + k8s.io/apiextensions-apiserver v0.21.0 // indirect + k8s.io/apiserver v0.21.0 // indirect + k8s.io/component-base v0.21.0 // indirect + k8s.io/klog/v2 v2.8.0 // indirect + k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 // indirect + k8s.io/kubectl v0.21.0 // indirect + k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect + rsc.io/letsencrypt v0.0.3 // indirect + sigs.k8s.io/kustomize/api v0.8.5 // indirect + sigs.k8s.io/kustomize/kyaml v0.10.15 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.0 // indirect +) + // This replace directive is to avoid having to manually bump the version of the charts module upon changes to the Helm // chart. When the CLI compiles, all changes to the local charts directory are picked up automatically. This directive // works because of the monorepo setup, where the charts module and CLI module are in the same repository. Otherwise, diff --git a/control-plane/go.mod b/control-plane/go.mod index 87073d3a03..6f1d560066 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -1,34 +1,21 @@ module github.com/hashicorp/consul-k8s/control-plane require ( - github.com/armon/go-metrics v0.3.9 // indirect github.com/cenkalti/backoff v2.1.1+incompatible github.com/deckarep/golang-set v1.7.1 - github.com/digitalocean/godo v1.10.0 // indirect - github.com/fatih/color v1.12.0 // indirect github.com/go-logr/logr v0.4.0 github.com/google/go-cmp v0.5.6 - github.com/google/go-querystring v1.0.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f github.com/hashicorp/consul/sdk v0.8.0 - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f github.com/hashicorp/go-hclog v0.16.1 - github.com/hashicorp/go-immutable-radix v1.3.0 // indirect - github.com/hashicorp/go-msgpack v0.5.5 // indirect github.com/hashicorp/go-multierror v1.1.0 - github.com/hashicorp/go-sockaddr v1.0.2 // indirect - github.com/hashicorp/go-uuid v1.0.2 // indirect github.com/hashicorp/serf v0.9.6 - github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect github.com/kr/text v0.2.0 - github.com/mattn/go-isatty v0.0.13 // indirect github.com/mitchellh/cli v1.1.0 github.com/mitchellh/go-homedir v1.1.0 - github.com/mitchellh/go-testing-interface v1.14.0 // indirect github.com/mitchellh/mapstructure v1.4.1 - github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/testify v1.7.0 go.uber.org/zap v1.19.0 golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac @@ -40,4 +27,107 @@ require ( sigs.k8s.io/controller-runtime v0.10.2 ) -go 1.16 +require ( + cloud.google.com/go v0.54.0 // indirect + github.com/Azure/azure-sdk-for-go v44.0.0+incompatible // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.18 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect + github.com/Azure/go-autorest/autorest/azure/auth v0.5.0 // indirect + github.com/Azure/go-autorest/autorest/azure/cli v0.4.0 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect + github.com/Azure/go-autorest/autorest/validation v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/armon/go-metrics v0.3.9 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/aws/aws-sdk-go v1.25.41 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/bgentry/speakeasy v0.1.0 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661 // indirect + github.com/digitalocean/godo v1.10.0 // indirect + github.com/dimchansky/utfbom v1.1.0 // indirect + github.com/evanphx/json-patch v4.11.0+incompatible // indirect + github.com/fatih/color v1.12.0 // indirect + github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/go-logr/zapr v0.4.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-querystring v1.0.0 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/googleapis/gax-go/v2 v2.0.5 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect + github.com/gophercloud/gophercloud v0.1.0 // indirect + github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.0 // indirect + github.com/hashicorp/go-msgpack v0.5.5 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/hashicorp/golang-lru v0.5.1 // indirect + github.com/hashicorp/mdns v1.0.4 // indirect + github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect + github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect + github.com/json-iterator/go v1.1.11 // indirect + github.com/linode/linodego v0.7.1 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.13 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/miekg/dns v1.1.41 // indirect + github.com/mitchellh/go-testing-interface v1.14.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 // indirect + github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/posener/complete v1.2.3 // indirect + github.com/prometheus/client_golang v1.11.0 // indirect + github.com/prometheus/client_model v0.2.0 // indirect + github.com/prometheus/common v0.26.0 // indirect + github.com/prometheus/procfs v0.6.0 // indirect + github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.2.0 // indirect + github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible // indirect + github.com/vmware/govmomi v0.18.0 // indirect + go.opencensus.io v0.22.3 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect + golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect + golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + golang.org/x/text v0.3.6 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/api v0.20.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect + google.golang.org/grpc v1.38.0 // indirect + google.golang.org/protobuf v1.26.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/resty.v1 v1.12.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/apiextensions-apiserver v0.22.2 // indirect + k8s.io/component-base v0.22.2 // indirect + k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect + k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect +) + +go 1.17 From 35ac863e486d3c27125ef0c4d28c69f56d4ca6a3 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Wed, 24 Nov 2021 13:07:46 -0800 Subject: [PATCH 155/418] update acceptance test go module to 1.17 for consistency across all modules --- acceptance/go.mod | 60 ++++++++++++++++++++++++++++++++++++++++++++++- acceptance/go.sum | 3 --- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/acceptance/go.mod b/acceptance/go.mod index de665fe086..06a2492b0f 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -1,6 +1,6 @@ module github.com/hashicorp/consul-k8s/acceptance -go 1.14 +go 1.17 require ( github.com/gruntwork-io/terratest v0.31.2 @@ -12,3 +12,61 @@ require ( k8s.io/apimachinery v0.19.3 k8s.io/client-go v0.19.3 ) + +require ( + cloud.google.com/go v0.51.0 // indirect + github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect + github.com/aws/aws-sdk-go v1.27.1 // indirect + github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect + github.com/evanphx/json-patch v4.9.0+incompatible // indirect + github.com/fatih/color v1.9.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect + github.com/go-logr/logr v0.2.0 // indirect + github.com/go-sql-driver/mysql v1.4.1 // indirect + github.com/gogo/protobuf v1.3.1 // indirect + github.com/golang/protobuf v1.4.2 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/uuid v1.1.1 // indirect + github.com/googleapis/gnostic v0.4.1 // indirect + github.com/gruntwork-io/gruntwork-cli v0.7.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.1 // indirect + github.com/hashicorp/go-hclog v0.12.0 // indirect + github.com/hashicorp/go-immutable-radix v1.0.0 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/golang-lru v0.5.3 // indirect + github.com/hashicorp/serf v0.9.6 // indirect + github.com/imdario/mergo v0.3.7 // indirect + github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect + github.com/json-iterator/go v1.1.10 // indirect + github.com/mattn/go-colorable v0.1.6 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.1.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pquerna/otp v1.2.0 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/urfave/cli v1.22.2 // indirect + golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect + golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 // indirect + golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect + golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 // indirect + golang.org/x/text v0.3.6 // indirect + golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect + google.golang.org/appengine v1.6.5 // indirect + google.golang.org/protobuf v1.24.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + k8s.io/klog/v2 v2.2.0 // indirect + k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 // indirect + k8s.io/utils v0.0.0-20200729134348-d5654de09c73 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.0.1 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect +) diff --git a/acceptance/go.sum b/acceptance/go.sum index 998060bfec..a2fc4174b4 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -120,7 +120,6 @@ github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkg github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1 h1:yY9rWGoXv1U5pl4gxqlULARMQD7x0QG85lqEXTWysik= github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= -github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= @@ -133,7 +132,6 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -510,7 +508,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= From 503d7d82503ac431d9ee02bc918325347f1ac095 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Mon, 29 Nov 2021 16:22:19 -0800 Subject: [PATCH 156/418] remove old build directive Since the minimum supported go version is 1.17, we can remove build directives compatible with older versions. For more info see: https://stackoverflow.com/questions/68360688/whats-the-difference-between-gobuild-and-build-directives?noredirect=1&lq=1 --- control-plane/api/v1alpha1/zz_generated.deepcopy.go | 1 - .../catalog/to-consul/consul_node_services_client_ent_test.go | 1 - control-plane/catalog/to-consul/syncer_ent_test.go | 1 - control-plane/connect-inject/endpoints_controller_ent_test.go | 1 - control-plane/connect-inject/handler_ent_test.go | 1 - control-plane/controller/configentry_controller_ent_test.go | 1 - control-plane/controller/partitionexports_controller_ent_test.go | 1 - control-plane/namespaces/namespaces_test.go | 1 - control-plane/subcommand/connect-init/command_ent_test.go | 1 - control-plane/subcommand/consul-sidecar/command_ent_test.go | 1 - control-plane/subcommand/partition-init/command_ent_test.go | 1 - control-plane/subcommand/server-acl-init/command_ent_test.go | 1 - control-plane/subcommand/sync-catalog/command_ent_test.go | 1 - 13 files changed, 13 deletions(-) diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index 2bf2f86b4e..eb7b167895 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated // Code generated by controller-gen. DO NOT EDIT. diff --git a/control-plane/catalog/to-consul/consul_node_services_client_ent_test.go b/control-plane/catalog/to-consul/consul_node_services_client_ent_test.go index e93fae516b..ac570948f5 100644 --- a/control-plane/catalog/to-consul/consul_node_services_client_ent_test.go +++ b/control-plane/catalog/to-consul/consul_node_services_client_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package catalog diff --git a/control-plane/catalog/to-consul/syncer_ent_test.go b/control-plane/catalog/to-consul/syncer_ent_test.go index 0d5ce60140..2cc206f908 100644 --- a/control-plane/catalog/to-consul/syncer_ent_test.go +++ b/control-plane/catalog/to-consul/syncer_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package catalog diff --git a/control-plane/connect-inject/endpoints_controller_ent_test.go b/control-plane/connect-inject/endpoints_controller_ent_test.go index fe1a5cfd29..7d333783c8 100644 --- a/control-plane/connect-inject/endpoints_controller_ent_test.go +++ b/control-plane/connect-inject/endpoints_controller_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package connectinject diff --git a/control-plane/connect-inject/handler_ent_test.go b/control-plane/connect-inject/handler_ent_test.go index 9bc6249df4..e35fd7aaad 100644 --- a/control-plane/connect-inject/handler_ent_test.go +++ b/control-plane/connect-inject/handler_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package connectinject diff --git a/control-plane/controller/configentry_controller_ent_test.go b/control-plane/controller/configentry_controller_ent_test.go index eb4ae505fe..11bdaa33bb 100644 --- a/control-plane/controller/configentry_controller_ent_test.go +++ b/control-plane/controller/configentry_controller_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package controller_test diff --git a/control-plane/controller/partitionexports_controller_ent_test.go b/control-plane/controller/partitionexports_controller_ent_test.go index 4313a871a4..02ed8bf31a 100644 --- a/control-plane/controller/partitionexports_controller_ent_test.go +++ b/control-plane/controller/partitionexports_controller_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package controller_test diff --git a/control-plane/namespaces/namespaces_test.go b/control-plane/namespaces/namespaces_test.go index 5540e8dec5..8cd3d316fd 100644 --- a/control-plane/namespaces/namespaces_test.go +++ b/control-plane/namespaces/namespaces_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package namespaces diff --git a/control-plane/subcommand/connect-init/command_ent_test.go b/control-plane/subcommand/connect-init/command_ent_test.go index ea61f755e9..50b52f44e2 100644 --- a/control-plane/subcommand/connect-init/command_ent_test.go +++ b/control-plane/subcommand/connect-init/command_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package connectinit diff --git a/control-plane/subcommand/consul-sidecar/command_ent_test.go b/control-plane/subcommand/consul-sidecar/command_ent_test.go index de0de853a1..c41e73842b 100644 --- a/control-plane/subcommand/consul-sidecar/command_ent_test.go +++ b/control-plane/subcommand/consul-sidecar/command_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package consulsidecar diff --git a/control-plane/subcommand/partition-init/command_ent_test.go b/control-plane/subcommand/partition-init/command_ent_test.go index 0da70e454c..8ed91cec14 100644 --- a/control-plane/subcommand/partition-init/command_ent_test.go +++ b/control-plane/subcommand/partition-init/command_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package partition_init diff --git a/control-plane/subcommand/server-acl-init/command_ent_test.go b/control-plane/subcommand/server-acl-init/command_ent_test.go index 5d7c6e3262..af240e4960 100644 --- a/control-plane/subcommand/server-acl-init/command_ent_test.go +++ b/control-plane/subcommand/server-acl-init/command_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package serveraclinit diff --git a/control-plane/subcommand/sync-catalog/command_ent_test.go b/control-plane/subcommand/sync-catalog/command_ent_test.go index 3475a3daeb..4e5ba14e93 100644 --- a/control-plane/subcommand/sync-catalog/command_ent_test.go +++ b/control-plane/subcommand/sync-catalog/command_ent_test.go @@ -1,5 +1,4 @@ //go:build enterprise -// +build enterprise package synccatalog From 0bb6a44739c4771c9c6636507538ce8be65bfc29 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Mon, 29 Nov 2021 17:48:46 -0800 Subject: [PATCH 157/418] add changelog and update contributing guide for go version (#883) --- CHANGELOG.md | 1 + CONTRIBUTING.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 87da8d9f14..ffed0d9f64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ BREAKING CHANGES: ``` [[GH-851](https://github.com/hashicorp/consul-k8s/pull/851)] +* Update minimum go version for project to 1.17 [[GH-878](https://github.com/hashicorp/consul-k8s/pull/878)] FEATURES: * Helm Chart diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ec4aaf9192..f63ebdf5b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,7 +28,7 @@ ### Building and running `consul-k8s-control-plane` -To build and install the control plane binary `consul-k8s` locally, Go version 1.11.4+ is required because this repository uses go modules and go 1.11.4 introduced changes to checksumming of modules to correct a symlink problem. +To build and install the control plane binary `consul-k8s` locally, Go version 1.17.0+ is required. You will also need to install the Docker engine: - [Docker for Mac](https://docs.docker.com/engine/installation/mac/) From 98585af86a2a8c5418127e49f1eed3c2f30824f1 Mon Sep 17 00:00:00 2001 From: NicoletaPopoviciu <87660255+NicoletaPopoviciu@users.noreply.github.com> Date: Tue, 30 Nov 2021 12:48:09 -0500 Subject: [PATCH 158/418] Precheck to verify the correct license secret exists when using an ent image. (#875) * added checkValidEnterprise to check and validate an enterprise installation Co-authored-by: Iryna Shustava Co-authored-by: Nitya Dhanushkodi --- CHANGELOG.md | 4 +++ cli/cmd/install/install.go | 49 +++++++++++++++++++++++++++++++++ cli/cmd/install/install_test.go | 36 ++++++++++++++++++++++++ 3 files changed, 89 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffed0d9f64..5671956afd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## UNRELEASED +IMPROVEMENTS: +* CLI + * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] + ## 0.37.0 (November 18, 2021) BREAKING CHANGES: diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index 689fbbcc3e..f1e0b8c496 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -3,6 +3,7 @@ package install import ( "errors" "fmt" + k8serrors "k8s.io/apimachinery/pkg/api/errors" "os" "strings" "sync" @@ -174,6 +175,20 @@ func (c *Command) init() { c.Init() } +type helmValues struct { + Global globalValues `yaml:"global"` +} + +type globalValues struct { + Image string `yaml:"image"` + EnterpriseLicense enterpriseLicense `yaml:"enterpriseLicense"` +} + +type enterpriseLicense struct { + SecretName string `yaml:"secretName"` + SecretKey string `yaml:"secretKey"` +} + func (c *Command) Run(args []string) int { c.once.Do(c.init) @@ -267,6 +282,22 @@ func (c *Command) Run(args []string) int { return 1 } + var v helmValues + err = yaml.Unmarshal(valuesYaml, &v) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // If an enterprise license secret was provided check that the secret exists + // and that the enterprise Consul image is set. + if v.Global.EnterpriseLicense.SecretName != "" { + if err := c.checkValidEnterprise(v.Global.EnterpriseLicense.SecretName, v.Global.Image); err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + } + // Print out the installation summary. if !c.flagAutoApprove { c.UI.Output("Consul Installation Summary", terminal.WithHeaderStyle()) @@ -501,3 +532,21 @@ func validLabel(s string) bool { } return true } + +// checkValidEnterprise checks and validates an enterprise installation. +// When an enterprise license secret is provided, check that the secret exists +// in the "consul" namespace, and that the enterprise Consul image is provided. +func (c *Command) checkValidEnterprise(secretName string, image string) error { + + _, err := c.kubernetes.CoreV1().Secrets(c.flagNamespace).Get(c.Ctx, secretName, metav1.GetOptions{}) + if k8serrors.IsNotFound(err) { + return fmt.Errorf("enterprise license secret %q is not found in the %q namespace; please make sure that the secret exists in the %q namespace", secretName, c.flagNamespace, c.flagNamespace) + } else if err != nil { + return fmt.Errorf("error getting the enterprise license secret %q in the %q namespace: %s", secretName, c.flagNamespace, err) + } + if !strings.Contains(image, "-ent") { + return fmt.Errorf("enterprise Consul image is not provided when enterprise license secret is set: %s", image) + } + c.UI.Output("Valid enterprise Consul image and secret found.", terminal.WithSuccessStyle()) + return nil +} diff --git a/cli/cmd/install/install_test.go b/cli/cmd/install/install_test.go index 0680cc032d..661a2282ac 100644 --- a/cli/cmd/install/install_test.go +++ b/cli/cmd/install/install_test.go @@ -187,3 +187,39 @@ func getInitializedCommand(t *testing.T) *Command { c.init() return c } + +func TestCheckValidEnterprise(t *testing.T) { + c := getInitializedCommand(t) + c.kubernetes = fake.NewSimpleClientset() + secret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-secret", + }, + } + secret2 := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "consul-secret2", + }, + } + + // Enterprise secret and image are valid. + c.kubernetes.CoreV1().Secrets("consul").Create(context.Background(), secret, metav1.CreateOptions{}) + err := c.checkValidEnterprise(secret.Name, "consul-enterprise:-ent") + require.NoError(t, err) + + // Enterprise secret provided but not an enterprise image. + err = c.checkValidEnterprise(secret.Name, "consul:") + require.Error(t, err) + require.Contains(t, err.Error(), "enterprise Consul image is not provided") + + // Enterprise secret does not exist. + err = c.checkValidEnterprise("consul-unrelated-secret", "consul-enterprise:-ent") + require.Error(t, err) + require.Contains(t, err.Error(), "please make sure that the secret exists") + + // Enterprise secret exists in a different namespace. + c.kubernetes.CoreV1().Secrets("unrelated").Create(context.Background(), secret2, metav1.CreateOptions{}) + err = c.checkValidEnterprise(secret2.Name, "consul-enterprise:-ent") + require.Error(t, err) + require.Contains(t, err.Error(), "please make sure that the secret exists") +} From 86637f66e7695b845334dfbb42c91f4fd68f13d8 Mon Sep 17 00:00:00 2001 From: David Yu Date: Tue, 30 Nov 2021 10:00:17 -0800 Subject: [PATCH 159/418] CHANGELOG: Move go 1.17 bump to UNRELEASED (#884) --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5671956afd..0bd710d7b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## UNRELEASED +BREAKING CHANGES: +* Update minimum go version for project to 1.17 [[GH-878](https://github.com/hashicorp/consul-k8s/pull/878)] + IMPROVEMENTS: * CLI * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] @@ -24,7 +27,6 @@ BREAKING CHANGES: ``` [[GH-851](https://github.com/hashicorp/consul-k8s/pull/851)] -* Update minimum go version for project to 1.17 [[GH-878](https://github.com/hashicorp/consul-k8s/pull/878)] FEATURES: * Helm Chart From e895995266923598304a26e16bc3261068e9fb53 Mon Sep 17 00:00:00 2001 From: Saad Jamal <85898851+sadjamz@users.noreply.github.com> Date: Tue, 30 Nov 2021 13:44:14 -0800 Subject: [PATCH 160/418] cli: Create Secrets With A Label (#835) Every-time a secret is created, add a label "managed-by" which is equal to "consul-k8s". On uninstall, only delete those secrets with said label. Co-authored-by: Thomas Eckert Co-authored-by: Nitya Dhanushkodi --- CHANGELOG.md | 1 + acceptance/go.mod | 49 ++-- acceptance/go.sum | 212 +++++++++++++--- cli/cmd/common/utils.go | 5 + cli/cmd/install/install.go | 8 +- cli/cmd/install/install_test.go | 5 +- cli/cmd/uninstall/uninstall.go | 19 +- cli/cmd/uninstall/uninstall_test.go | 8 +- cli/go.mod | 138 ++++++---- cli/go.sum | 239 ++++++++++++++---- .../subcommand/acl-init/command_test.go | 10 +- control-plane/subcommand/common/common.go | 5 + .../create-federation-secret/command.go | 1 + .../create-federation-secret/command_test.go | 9 +- .../gossip-encryption-autogenerate/command.go | 1 + .../server-acl-init/command_test.go | 9 +- .../server-acl-init/connect_inject_test.go | 4 +- .../server-acl-init/create_or_update.go | 3 +- .../subcommand/server-acl-init/servers.go | 3 +- control-plane/subcommand/tls-init/command.go | 10 + .../webhook-cert-manager/command.go | 7 + .../webhook-cert-manager/command_test.go | 9 +- 22 files changed, 567 insertions(+), 188 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bd710d7b1..11988f4b27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ BREAKING CHANGES: IMPROVEMENTS: * CLI * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] + * Add a label "managed-by" to every secret the control-plane creates. Only delete said secrets on an uninstall. [[GH-835](https://github.com/hashicorp/consul-k8s/pull/835)] ## 0.37.0 (November 18, 2021) diff --git a/acceptance/go.mod b/acceptance/go.mod index 06a2492b0f..8a22b898e7 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -6,32 +6,32 @@ require ( github.com/gruntwork-io/terratest v0.31.2 github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f github.com/hashicorp/consul/sdk v0.8.0 - github.com/stretchr/testify v1.5.1 - gopkg.in/yaml.v2 v2.2.8 - k8s.io/api v0.19.3 - k8s.io/apimachinery v0.19.3 - k8s.io/client-go v0.19.3 + github.com/stretchr/testify v1.7.0 + gopkg.in/yaml.v2 v2.4.0 + k8s.io/api v0.22.2 + k8s.io/apimachinery v0.22.2 + k8s.io/client-go v0.22.2 ) require ( - cloud.google.com/go v0.51.0 // indirect + cloud.google.com/go v0.54.0 // indirect github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect github.com/aws/aws-sdk-go v1.27.1 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect - github.com/evanphx/json-patch v4.9.0+incompatible // indirect + github.com/evanphx/json-patch v4.11.0+incompatible // indirect github.com/fatih/color v1.9.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect - github.com/go-logr/logr v0.2.0 // indirect + github.com/go-logr/logr v0.4.0 // indirect github.com/go-sql-driver/mysql v1.4.1 // indirect - github.com/gogo/protobuf v1.3.1 // indirect - github.com/golang/protobuf v1.4.2 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-cmp v0.5.5 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.1.1 // indirect - github.com/googleapis/gnostic v0.4.1 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect github.com/gruntwork-io/gruntwork-cli v0.7.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-hclog v0.12.0 // indirect @@ -41,11 +41,12 @@ require ( github.com/hashicorp/serf v0.9.6 // indirect github.com/imdario/mergo v0.3.7 // indirect github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect - github.com/json-iterator/go v1.1.10 // indirect + github.com/json-iterator/go v1.1.11 // indirect github.com/mattn/go-colorable v0.1.6 // indirect github.com/mattn/go-isatty v0.0.12 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.1.2 // indirect + github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -55,18 +56,20 @@ require ( github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/urfave/cli v1.22.2 // indirect - golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect - golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 // indirect + golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect + golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 // indirect + golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect golang.org/x/text v0.3.6 // indirect - golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect google.golang.org/appengine v1.6.5 // indirect - google.golang.org/protobuf v1.24.0 // indirect + google.golang.org/protobuf v1.26.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/klog/v2 v2.2.0 // indirect - k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 // indirect - k8s.io/utils v0.0.0-20200729134348-d5654de09c73 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.0.1 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/klog/v2 v2.9.0 // indirect + k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect + k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect sigs.k8s.io/yaml v1.2.0 // indirect ) diff --git a/acceptance/go.sum b/acceptance/go.sum index a2fc4174b4..1c81c79d35 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -5,12 +5,23 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= @@ -22,12 +33,14 @@ github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8 github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= @@ -44,6 +57,7 @@ github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQ github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -63,6 +77,7 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1 h1:MXnqY6SlWySaZAqNnXThOvjRFdiiOuKtC6i7baFdNdU= @@ -95,6 +110,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -111,7 +127,6 @@ github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avu github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -126,12 +141,16 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -139,12 +158,15 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 h1:skJKxRtNmevLqnayafdLe2AsenqRupVmzZSqrvb5caU= github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -162,36 +184,46 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -201,20 +233,26 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -259,7 +297,6 @@ github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -275,24 +312,26 @@ github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBv github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -326,6 +365,8 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -338,17 +379,25 @@ github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8m github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= @@ -408,6 +457,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -416,8 +466,9 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -428,11 +479,14 @@ github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44 github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -447,15 +501,22 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -464,12 +525,18 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -486,16 +553,25 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1 h1:4qWs8cYYH6PoEFy4dfhDFgoMGkwAcETd+MmPdCPMzUc= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -508,6 +584,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -529,26 +606,43 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44 h1:Bli41pIlzTzf3KEY06n+xnzK/BESIg2ze4Pgfh/aI8c= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -558,8 +652,9 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -583,15 +678,31 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= @@ -600,7 +711,12 @@ google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNV google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -615,8 +731,18 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -625,6 +751,7 @@ google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -633,16 +760,18 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -657,24 +786,34 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= -k8s.io/api v0.19.3 h1:GN6ntFnv44Vptj/b+OnMW7FmzkpDoIDLZRvKX3XH9aU= k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= +k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apimachinery v0.19.3 h1:bpIQXlKjB4cB/oNpnNnV+BybGPR7iP5oYpsOTEJ4hgc= k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= +k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= -k8s.io/client-go v0.19.3 h1:ctqR1nQ52NUs6LpI0w+a5U+xjYwflFwA13OJKcicMxg= k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= +k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= @@ -687,26 +826,33 @@ k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= -sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/cli/cmd/common/utils.go b/cli/cmd/common/utils.go index 95fafb013e..2cff8eccec 100644 --- a/cli/cmd/common/utils.go +++ b/cli/cmd/common/utils.go @@ -21,6 +21,11 @@ const ( valuesFileName = "values.yaml" templatesDirName = "templates" TopLevelChartDirName = "consul" + + // CLILabelKey and CLILabelValue are added to each secret on creation so the CLI knows + // which key to delete on an uninstall. + CLILabelKey = "managed-by" + CLILabelValue = "consul-k8s" ) // ReadChartFiles reads the chart files from the embedded file system, and loads their contents into diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index f1e0b8c496..001c1d3c2a 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" - "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart/loader" helmCLI "helm.sh/helm/v3/pkg/cli" @@ -416,17 +415,18 @@ func (c *Command) checkForPreviousPVCs() error { // checkForPreviousSecrets checks for the bootstrap token and returns an error if found. func (c *Command) checkForPreviousSecrets() error { - secrets, err := c.kubernetes.CoreV1().Secrets("").List(c.Ctx, metav1.ListOptions{}) + secrets, err := c.kubernetes.CoreV1().Secrets("").List(c.Ctx, metav1.ListOptions{LabelSelector: common.CLILabelKey + "=" + common.CLILabelValue}) if err != nil { return fmt.Errorf("error listing secrets: %s", err) } for _, secret := range secrets.Items { // future TODO: also check for federation secret - if strings.Contains(secret.Name, "consul-bootstrap-acl-token") { - return fmt.Errorf("found consul-acl-bootstrap-token secret from previous installations: %q in namespace %q. To delete, run kubectl delete secret %s --namespace %s", + if secret.ObjectMeta.Labels[common.CLILabelKey] == common.CLILabelValue { + return fmt.Errorf("found Consul secret from previous installation: %q in namespace %q. To delete, run kubectl delete secret %s --namespace %s", secret.Name, secret.Namespace, secret.Name, secret.Namespace) } } + c.UI.Output("No previous secrets found", terminal.WithSuccessStyle()) return nil } diff --git a/cli/cmd/install/install_test.go b/cli/cmd/install/install_test.go index 661a2282ac..f9e4028d05 100644 --- a/cli/cmd/install/install_test.go +++ b/cli/cmd/install/install_test.go @@ -53,13 +53,14 @@ func TestCheckForPreviousSecrets(t *testing.T) { c.kubernetes = fake.NewSimpleClientset() secret := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-consul-bootstrap-acl-token", + Name: "test-consul-bootstrap-acl-token", + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, } c.kubernetes.CoreV1().Secrets("default").Create(context.Background(), secret, metav1.CreateOptions{}) err := c.checkForPreviousSecrets() require.Error(t, err) - require.Contains(t, err.Error(), "found consul-acl-bootstrap-token secret from previous installations: \"test-consul-bootstrap-acl-token\" in namespace \"default\". To delete, run kubectl delete secret test-consul-bootstrap-acl-token --namespace default") + require.Contains(t, err.Error(), "found Consul secret from previous installation") // Clear out the client and make sure the check now passes. c.kubernetes = fake.NewSimpleClientset() diff --git a/cli/cmd/uninstall/uninstall.go b/cli/cmd/uninstall/uninstall.go index 0e85ea4eef..11d68aab7b 100644 --- a/cli/cmd/uninstall/uninstall.go +++ b/cli/cmd/uninstall/uninstall.go @@ -3,7 +3,6 @@ package uninstall import ( "fmt" "os" - "strings" "sync" "time" @@ -380,10 +379,11 @@ func (c *Command) deletePVCs(foundReleaseName, foundReleaseNamespace string) err return nil } -// deleteSecrets deletes any secrets that have foundReleaseName in their name. +// deleteSecrets deletes any secrets that have the label "managed-by" set to "consul-k8s". func (c *Command) deleteSecrets(foundReleaseName, foundReleaseNamespace string) error { - var secretNames []string - secrets, err := c.kubernetes.CoreV1().Secrets(foundReleaseNamespace).List(c.Ctx, metav1.ListOptions{}) + secrets, err := c.kubernetes.CoreV1().Secrets(foundReleaseNamespace).List(c.Ctx, metav1.ListOptions{ + LabelSelector: common.CLILabelKey + "=" + common.CLILabelValue, + }) if err != nil { return fmt.Errorf("deleteSecrets: %s", err) } @@ -391,14 +391,13 @@ func (c *Command) deleteSecrets(foundReleaseName, foundReleaseNamespace string) c.UI.Output("No Consul secrets found.", terminal.WithSuccessStyle()) return nil } + var secretNames []string for _, secret := range secrets.Items { - if strings.HasPrefix(secret.Name, foundReleaseName) { - err := c.kubernetes.CoreV1().Secrets(foundReleaseNamespace).Delete(c.Ctx, secret.Name, metav1.DeleteOptions{}) - if err != nil { - return fmt.Errorf("deleteSecrets: error deleting Secret %q: %s", secret.Name, err) - } - secretNames = append(secretNames, secret.Name) + err := c.kubernetes.CoreV1().Secrets(foundReleaseNamespace).Delete(c.Ctx, secret.Name, metav1.DeleteOptions{}) + if err != nil { + return fmt.Errorf("deleteSecrets: error deleting Secret %q: %s", secret.Name, err) } + secretNames = append(secretNames, secret.Name) } if len(secretNames) > 0 { for _, secret := range secretNames { diff --git a/cli/cmd/uninstall/uninstall_test.go b/cli/cmd/uninstall/uninstall_test.go index 6e46f51506..faf3a132c1 100644 --- a/cli/cmd/uninstall/uninstall_test.go +++ b/cli/cmd/uninstall/uninstall_test.go @@ -63,7 +63,8 @@ func TestDeleteSecrets(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "consul-test-secret1", Labels: map[string]string{ - "release": "consul", + "release": "consul", + common.CLILabelKey: common.CLILabelValue, }, }, } @@ -93,8 +94,9 @@ func TestDeleteSecrets(t *testing.T) { require.NoError(t, err) secrets, err := c.kubernetes.CoreV1().Secrets("default").List(context.Background(), metav1.ListOptions{}) require.NoError(t, err) - require.Len(t, secrets.Items, 1) - require.Equal(t, secrets.Items[0].Name, secret3.Name) + + // Only secret1 should have been deleted, secret2 and secret 3 persist since it doesn't have the label. + require.Len(t, secrets.Items, 2) } func TestDeleteServiceAccounts(t *testing.T) { diff --git a/cli/go.mod b/cli/go.mod index 3bb781f2e2..f0c0e8ae7f 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -3,33 +3,48 @@ module github.com/hashicorp/consul-k8s/cli go 1.17 require ( + github.com/armon/go-radix v1.0.0 // indirect github.com/bgentry/speakeasy v0.1.0 github.com/cenkalti/backoff v2.2.1+incompatible - github.com/fatih/color v1.9.0 + github.com/fatih/color v1.12.0 + github.com/google/go-cmp v0.5.6 // indirect github.com/hashicorp/consul-k8s/charts v0.0.0-00010101000000-000000000000 github.com/hashicorp/go-hclog v0.16.2 + github.com/hashicorp/go-multierror v1.1.0 // indirect + github.com/imdario/mergo v0.3.12 // indirect github.com/kr/text v0.2.0 - github.com/mattn/go-isatty v0.0.12 + github.com/mattn/go-isatty v0.0.13 github.com/mitchellh/cli v1.1.2 github.com/olekukonko/tablewriter v0.0.4 - github.com/posener/complete v1.1.1 + github.com/onsi/gomega v1.15.0 // indirect + github.com/posener/complete v1.2.3 github.com/stretchr/testify v1.7.0 + go.starlark.net v0.0.0-20200707032745-474f21a9602d // indirect + golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect + google.golang.org/appengine v1.6.7 // indirect helm.sh/helm/v3 v3.6.1 - k8s.io/api v0.21.2 - k8s.io/apimachinery v0.21.2 + k8s.io/api v0.22.2 + k8s.io/apiextensions-apiserver v0.22.2 // indirect + k8s.io/apimachinery v0.22.2 k8s.io/cli-runtime v0.21.0 - k8s.io/client-go v0.21.2 + k8s.io/client-go v0.22.2 + rsc.io/letsencrypt v0.0.3 // indirect sigs.k8s.io/yaml v1.2.0 ) require ( cloud.google.com/go v0.54.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/Azure/azure-sdk-for-go v44.0.0+incompatible // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.12 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.5 // indirect + github.com/Azure/go-autorest/autorest v0.11.18 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect + github.com/Azure/go-autorest/autorest/azure/auth v0.5.0 // indirect + github.com/Azure/go-autorest/autorest/azure/cli v0.4.0 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect - github.com/Azure/go-autorest/logger v0.2.0 // indirect + github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect + github.com/Azure/go-autorest/autorest/validation v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/BurntSushi/toml v0.3.1 // indirect github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect @@ -43,8 +58,10 @@ require ( github.com/Microsoft/hcsshim v0.8.14 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect - github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect + github.com/armon/go-metrics v0.3.9 // indirect + github.com/armon/go-radix v1.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect + github.com/aws/aws-sdk-go v1.27.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 // indirect @@ -53,6 +70,9 @@ require ( github.com/cyphar/filepath-securejoin v0.2.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deislabs/oras v0.11.1 // indirect + github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba // indirect + github.com/digitalocean/godo v1.10.0 // indirect + github.com/dimchansky/utfbom v1.1.0 // indirect github.com/docker/cli v20.10.5+incompatible // indirect github.com/docker/distribution v2.7.1+incompatible // indirect github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible // indirect @@ -60,103 +80,131 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/evanphx/json-patch v4.9.0+incompatible // indirect + github.com/evanphx/json-patch v4.11.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect - github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect + github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect github.com/go-errors/errors v1.0.1 // indirect github.com/go-logr/logr v0.4.0 // indirect - github.com/go-openapi/jsonpointer v0.19.3 // indirect - github.com/go-openapi/jsonreference v0.19.3 // indirect + github.com/go-logr/zapr v0.4.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.5 // indirect github.com/go-openapi/spec v0.19.5 // indirect - github.com/go-openapi/swag v0.19.5 // indirect + github.com/go-openapi/swag v0.19.14 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/btree v1.0.0 // indirect - github.com/google/go-cmp v0.5.5 // indirect + github.com/google/btree v1.0.1 // indirect + github.com/google/go-cmp v0.5.6 // indirect + github.com/google/go-querystring v1.0.0 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.1.2 // indirect - github.com/googleapis/gnostic v0.4.1 // indirect + github.com/googleapis/gax-go/v2 v2.0.5 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect + github.com/gophercloud/gophercloud v0.1.0 // indirect github.com/gorilla/mux v1.7.3 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb // indirect github.com/hashicorp/errwrap v1.0.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f // indirect + github.com/hashicorp/go-immutable-radix v1.3.0 // indirect github.com/hashicorp/go-multierror v1.1.0 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.1 // indirect + github.com/hashicorp/mdns v1.0.1 // indirect + github.com/hashicorp/serf v0.9.5 // indirect + github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 // indirect github.com/huandu/xstrings v1.3.2 // indirect - github.com/imdario/mergo v0.3.11 // indirect + github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect github.com/jmoiron/sqlx v1.3.1 // indirect - github.com/json-iterator/go v1.1.10 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect + github.com/json-iterator/go v1.1.11 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/mailru/easyjson v0.7.0 // indirect + github.com/linode/linodego v0.7.1 // indirect + github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-runewidth v0.0.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/miekg/dns v1.1.26 // indirect github.com/mitchellh/copystructure v1.1.1 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect + github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v0.1.1 // indirect + github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.7.1 // indirect + github.com/prometheus/client_golang v1.11.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.10.0 // indirect - github.com/prometheus/procfs v0.2.0 // indirect + github.com/prometheus/common v0.26.0 // indirect + github.com/prometheus/procfs v0.6.0 // indirect + github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 // indirect github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 // indirect github.com/russross/blackfriday v1.5.2 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect + github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.1.3 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible // indirect + github.com/vmware/govmomi v0.18.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect go.opencensus.io v0.22.3 // indirect - go.starlark.net v0.0.0-20200707032745-474f21a9602d // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + go.uber.org/zap v1.19.0 // indirect golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect - golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 // indirect + golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect - golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.4 // indirect - golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect - google.golang.org/appengine v1.6.5 // indirect - google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect - google.golang.org/grpc v1.33.1 // indirect + golang.org/x/text v0.3.6 // indirect + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + google.golang.org/api v0.20.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect + google.golang.org/grpc v1.38.0 // indirect google.golang.org/protobuf v1.26.0 // indirect gopkg.in/gorp.v1 v1.7.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/resty.v1 v1.12.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect - k8s.io/apiextensions-apiserver v0.21.0 // indirect - k8s.io/apiserver v0.21.0 // indirect - k8s.io/component-base v0.21.0 // indirect - k8s.io/klog/v2 v2.8.0 // indirect - k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/apiextensions-apiserver v0.22.2 // indirect + k8s.io/apiserver v0.22.2 // indirect + k8s.io/component-base v0.22.2 // indirect + k8s.io/klog/v2 v2.9.0 // indirect + k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect k8s.io/kubectl v0.21.0 // indirect - k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect - rsc.io/letsencrypt v0.0.3 // indirect + k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect + sigs.k8s.io/controller-runtime v0.10.2 // indirect sigs.k8s.io/kustomize/api v0.8.5 // indirect sigs.k8s.io/kustomize/kyaml v0.10.15 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect ) // This replace directive is to avoid having to manually bump the version of the charts module upon changes to the Helm diff --git a/cli/go.sum b/cli/go.sum index bd14d14daa..6ee5e7cf6a 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -25,21 +25,26 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE= github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= -github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= +github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -88,14 +93,17 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -105,6 +113,7 @@ github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQ github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -128,6 +137,8 @@ github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= @@ -140,7 +151,11 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 h1:qWj4qVYZ95vLWwqyNJCQg7rDsG5wPdze0UaPolH7DUk= github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= @@ -165,6 +180,7 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -221,25 +237,32 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= +github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -252,6 +275,7 @@ github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -270,13 +294,15 @@ github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -299,8 +325,9 @@ github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= @@ -309,6 +336,7 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gobuffalo/envy v1.7.1 h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8= github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= @@ -322,6 +350,7 @@ github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kE github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godror/godror v0.13.3/go.mod h1:2ouUT4kdhUBk7TAkHWD4SN0CdI0pgEQbo8FVHhbSKWg= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -337,8 +366,9 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -358,13 +388,15 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -372,8 +404,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -392,8 +425,10 @@ github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo= @@ -411,9 +446,11 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWet github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -436,14 +473,12 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= @@ -451,8 +486,9 @@ github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= @@ -464,15 +500,21 @@ github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXL github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -507,8 +549,9 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -519,9 +562,9 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= +github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -557,8 +600,9 @@ github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY7 github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -572,6 +616,7 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= @@ -583,6 +628,9 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -594,12 +642,18 @@ github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FW github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -638,8 +692,9 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -647,8 +702,9 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -663,8 +719,9 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -672,11 +729,13 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -708,6 +767,7 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -732,6 +792,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -750,6 +811,7 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -768,6 +830,7 @@ github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6Ut github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= @@ -779,8 +842,16 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -791,17 +862,33 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.starlark.net v0.0.0-20200707032745-474f21a9602d h1:uFqwFYlX7d5ZSp+IqhXxct0SybXrTzEBDvb2CkEhPBs= go.starlark.net v0.0.0-20200707032745-474f21a9602d/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -844,6 +931,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -853,6 +941,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -885,10 +974,17 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -902,8 +998,9 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -928,6 +1025,7 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -935,6 +1033,7 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -948,16 +1047,24 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -969,14 +1076,17 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1003,6 +1113,7 @@ golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1022,8 +1133,10 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1046,8 +1159,9 @@ google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1068,9 +1182,13 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4 google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1085,8 +1203,12 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1109,7 +1231,6 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= @@ -1126,6 +1247,7 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1133,8 +1255,10 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= @@ -1150,43 +1274,51 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= -k8s.io/api v0.21.2 h1:vz7DqmRsXTCSa6pNxXwQ1IYeAZgdIsua+DZU+o+SX3Y= -k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU= -k8s.io/apiextensions-apiserver v0.21.0 h1:Nd4uBuweg6ImzbxkC1W7xUNZcCV/8Vt10iTdTIVF3hw= +k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= +k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/apiextensions-apiserver v0.21.0/go.mod h1:gsQGNtGkc/YoDG9loKI0V+oLZM4ljRPjc/sql5tmvzc= +k8s.io/apiextensions-apiserver v0.22.2 h1:zK7qI8Ery7j2CaN23UCFaC1hj7dMiI87n01+nKuewd4= +k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= -k8s.io/apimachinery v0.21.2 h1:vezUc/BHqWlQDnZ+XkrpXSmnANSLbpnlpwo0Lhk0gpc= -k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM= -k8s.io/apiserver v0.21.0 h1:1hWMfsz+cXxB77k6/y0XxWxwl6l9OF26PC9QneUVn1Q= +k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= +k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg= +k8s.io/apiserver v0.22.2 h1:TdIfZJc6YNhu2WxeAOWq1TvukHF0Sfx0+ln4XK9qnL4= +k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= k8s.io/cli-runtime v0.21.0 h1:/V2Kkxtf6x5NI2z+Sd/mIrq4FQyQ8jzZAUD6N5RnN7Y= k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo= k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= -k8s.io/client-go v0.21.2 h1:Q1j4L/iMN4pTw6Y4DWppBoUxgKO8LbffEMVEV00MUp0= -k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA= +k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= +k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= k8s.io/code-generator v0.21.0/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= -k8s.io/component-base v0.21.0 h1:tLLGp4BBjQaCpS/KiuWh7m2xqvAdsxLm4ATxHSe5Zpg= +k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw= +k8s.io/component-base v0.22.2 h1:vNIvE0AIrLhjX8drH0BgCNJcR4QZxMXcJzBsDplDx9M= +k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= k8s.io/component-helpers v0.21.0/go.mod h1:tezqefP7lxfvJyR+0a+6QtVrkZ/wIkyMLK4WcQ3Cj8U= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= +k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kubectl v0.21.0 h1:WZXlnG/yjcE4LWO2g6ULjFxtzK6H1TKzsfaBFuVIhNg= k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks= k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/letsencrypt v0.0.3 h1:H7xDfhkaFFSYEJlKeq38RwX2jYcnTeHuDQyT+mMNMwM= rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/kustomize/api v0.8.5 h1:bfCXGXDAbFbb/Jv5AhMj2BB8a5VAJuuQ5/KU69WtDjQ= sigs.k8s.io/kustomize/api v0.8.5/go.mod h1:M377apnKT5ZHJS++6H4rQoCHmWtt6qTpp3mbe7p6OLY= sigs.k8s.io/kustomize/cmd/config v0.9.7/go.mod h1:MvXCpHs77cfyxRmCNUQjIqCmZyYsbn5PyQpWiq44nW0= @@ -1194,8 +1326,9 @@ sigs.k8s.io/kustomize/kustomize/v4 v4.0.5/go.mod h1:C7rYla7sI8EnxHE/xEhRBSHMNfcL sigs.k8s.io/kustomize/kyaml v0.10.15 h1:dSLgG78KyaxN4HylPXdK+7zB3k7sW6q3IcCmcfKA+aI= sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/control-plane/subcommand/acl-init/command_test.go b/control-plane/subcommand/acl-init/command_test.go index 441f858a25..0a3a7ab8bf 100644 --- a/control-plane/subcommand/acl-init/command_test.go +++ b/control-plane/subcommand/acl-init/command_test.go @@ -7,6 +7,7 @@ import ( "path/filepath" "testing" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" "github.com/mitchellh/cli" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" @@ -31,7 +32,8 @@ func TestRun_TokenSinkFile(t *testing.T) { context.Background(), &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: secretName, + Name: secretName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ "token": []byte(token), @@ -72,7 +74,8 @@ func TestRun_TokenSinkFileErr(t *testing.T) { context.Background(), &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: secretName, + Name: secretName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ "token": []byte(token), @@ -118,7 +121,8 @@ func TestRun_TokenSinkFileTwice(t *testing.T) { context.Background(), &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: secretName, + Name: secretName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ "token": []byte(token), diff --git a/control-plane/subcommand/common/common.go b/control-plane/subcommand/common/common.go index 4dc2783683..bd60b5822c 100644 --- a/control-plane/subcommand/common/common.go +++ b/control-plane/subcommand/common/common.go @@ -26,6 +26,11 @@ const ( // ACLTokenSecretKey is the key that we store the ACL tokens in when we // create Kubernetes secrets. ACLTokenSecretKey = "token" + + // CLILabelKey and CLILabelValue are added to each secret on creation so the CLI knows + // which secrets to delete on an uninstall. + CLILabelKey = "managed-by" + CLILabelValue = "consul-k8s" ) // Logger returns an hclog instance with log level set and JSON logging enabled/disabled, or an error if level is invalid. diff --git a/control-plane/subcommand/create-federation-secret/command.go b/control-plane/subcommand/create-federation-secret/command.go index 860c5386b7..c62d3a0b32 100644 --- a/control-plane/subcommand/create-federation-secret/command.go +++ b/control-plane/subcommand/create-federation-secret/command.go @@ -128,6 +128,7 @@ func (c *Command) Run(args []string) int { ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-federation", c.flagResourcePrefix), Namespace: c.flagK8sNamespace, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Type: "Opaque", Data: make(map[string][]byte), diff --git a/control-plane/subcommand/create-federation-secret/command_test.go b/control-plane/subcommand/create-federation-secret/command_test.go index b3adcc6afd..607599a27e 100644 --- a/control-plane/subcommand/create-federation-secret/command_test.go +++ b/control-plane/subcommand/create-federation-secret/command_test.go @@ -213,7 +213,8 @@ func TestRun_ReplicationTokenMissingExpectedKey(t *testing.T) { context.Background(), &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "prefix-" + common.ACLReplicationTokenName + "-acl-token", + Name: "prefix-" + common.ACLReplicationTokenName + "-acl-token", + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, }, metav1.CreateOptions{}) @@ -391,7 +392,8 @@ func TestRun_ACLs_K8SNamespaces_ResourcePrefixes(tt *testing.T) { context.Background(), &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: c.resourcePrefix + "-acl-replication-acl-token", + Name: c.resourcePrefix + "-acl-replication-acl-token", + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ common.ACLTokenSecretKey: []byte(replicationToken), @@ -786,7 +788,8 @@ func TestRun_ReplicationSecretDelay(t *testing.T) { context.Background(), &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: "prefix-" + common.ACLReplicationTokenName + "-acl-token", + Name: "prefix-" + common.ACLReplicationTokenName + "-acl-token", + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ common.ACLTokenSecretKey: []byte(replicationToken), diff --git a/control-plane/subcommand/gossip-encryption-autogenerate/command.go b/control-plane/subcommand/gossip-encryption-autogenerate/command.go index 0383bc8f08..3668a20c35 100644 --- a/control-plane/subcommand/gossip-encryption-autogenerate/command.go +++ b/control-plane/subcommand/gossip-encryption-autogenerate/command.go @@ -111,6 +111,7 @@ func (c *Command) Run(args []string) int { ObjectMeta: metav1.ObjectMeta{ Name: c.flagSecretName, Namespace: c.flagNamespace, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ c.flagSecretKey: []byte(gossipSecret), diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index e15e8db3cf..0336ba366d 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -1611,7 +1611,8 @@ func TestRun_AlreadyBootstrapped(t *testing.T) { context.Background(), &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: resourcePrefix + "-bootstrap-acl-token", + Name: resourcePrefix + "-bootstrap-acl-token", + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ "token": []byte("old-token"), @@ -2299,7 +2300,8 @@ func setUpK8sServiceAccount(t *testing.T, k8s *fake.Clientset, namespace string) secretName := resourcePrefix + "-connect-injector-authmethod-svc-account" secret := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: secretName, + Name: secretName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ "ca.crt": caCertBytes, @@ -2312,7 +2314,8 @@ func setUpK8sServiceAccount(t *testing.T, k8s *fake.Clientset, namespace string) // Create the second secret of a different type otherSecret := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: resourcePrefix + "-some-other-secret", + Name: resourcePrefix + "-some-other-secret", + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{}, Type: v1.SecretTypeDockercfg, diff --git a/control-plane/subcommand/server-acl-init/connect_inject_test.go b/control-plane/subcommand/server-acl-init/connect_inject_test.go index 556148acc4..3dde30ae2b 100644 --- a/control-plane/subcommand/server-acl-init/connect_inject_test.go +++ b/control-plane/subcommand/server-acl-init/connect_inject_test.go @@ -4,6 +4,7 @@ import ( "context" "testing" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" @@ -54,7 +55,8 @@ func TestCommand_createAuthMethodTmpl_SecretNotFound(t *testing.T) { // Create a secret of non service-account-token type (we're using the opaque type). secret := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: secretName, + Name: secretName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{}, Type: v1.SecretTypeOpaque, diff --git a/control-plane/subcommand/server-acl-init/create_or_update.go b/control-plane/subcommand/server-acl-init/create_or_update.go index 404426ebfa..a17d78c6e3 100644 --- a/control-plane/subcommand/server-acl-init/create_or_update.go +++ b/control-plane/subcommand/server-acl-init/create_or_update.go @@ -86,7 +86,8 @@ func (c *Command) createACL(name, rules string, localToken bool, dc string, isPr func() error { secret := &apiv1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: secretName, + Name: secretName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ common.ACLTokenSecretKey: []byte(token), diff --git a/control-plane/subcommand/server-acl-init/servers.go b/control-plane/subcommand/server-acl-init/servers.go index 844fc5c03d..0f0ab8a0d1 100644 --- a/control-plane/subcommand/server-acl-init/servers.go +++ b/control-plane/subcommand/server-acl-init/servers.go @@ -102,7 +102,8 @@ func (c *Command) bootstrapACLs(firstServerAddr string, scheme string, bootToken func() error { secret := &apiv1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: bootTokenSecretName, + Name: bootTokenSecretName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ common.ACLTokenSecretKey: []byte(bootstrapToken), diff --git a/control-plane/subcommand/tls-init/command.go b/control-plane/subcommand/tls-init/command.go index f40a900226..7a038b79b2 100644 --- a/control-plane/subcommand/tls-init/command.go +++ b/control-plane/subcommand/tls-init/command.go @@ -136,6 +136,7 @@ func (c *Command) Run(args []string) int { ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-ca-cert", c.flagNamePrefix), Namespace: c.flagK8sNamespace, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ corev1.TLSCertKey: []byte(ca), @@ -152,6 +153,7 @@ func (c *Command) Run(args []string) int { ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%s-ca-key", c.flagNamePrefix), Namespace: c.flagK8sNamespace, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ corev1.TLSPrivateKeyKey: []byte(pk), @@ -237,6 +239,7 @@ func (c *Command) Run(args []string) int { ObjectMeta: metav1.ObjectMeta{ Namespace: c.flagK8sNamespace, Name: fmt.Sprintf("%s-server-cert", c.flagNamePrefix), + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ corev1.TLSCertKey: []byte(serverCert), @@ -253,6 +256,13 @@ func (c *Command) Run(args []string) int { corev1.TLSCertKey: []byte(serverCert), corev1.TLSPrivateKeyKey: []byte(serverKey), } + + if serverCertSecret.ObjectMeta.Labels == nil { + serverCertSecret.ObjectMeta.Labels = map[string]string{common.CLILabelKey: common.CLILabelValue} + } else { + serverCertSecret.ObjectMeta.Labels[common.CLILabelKey] = common.CLILabelValue + } + c.log.Info("updating server certificate and private key secret") _, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Update(c.ctx, serverCertSecret, metav1.UpdateOptions{}) if err != nil { diff --git a/control-plane/subcommand/webhook-cert-manager/command.go b/control-plane/subcommand/webhook-cert-manager/command.go index 6c044f06c6..2f69889975 100644 --- a/control-plane/subcommand/webhook-cert-manager/command.go +++ b/control-plane/subcommand/webhook-cert-manager/command.go @@ -249,6 +249,7 @@ func (c *Command) reconcileCertificates(ctx context.Context, clientset kubernete UID: deployment.UID, }, }, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, Data: map[string][]byte{ corev1.TLSCertKey: bundle.Cert, @@ -279,6 +280,12 @@ func (c *Command) reconcileCertificates(ctx context.Context, clientset kubernete return nil } + if certSecret.ObjectMeta.Labels == nil { + certSecret.ObjectMeta.Labels = map[string]string{common.CLILabelKey: common.CLILabelValue} + } else { + certSecret.ObjectMeta.Labels[common.CLILabelKey] = common.CLILabelValue + } + certSecret.Data[corev1.TLSCertKey] = bundle.Cert certSecret.Data[corev1.TLSPrivateKeyKey] = bundle.Key // Update the Owner Reference on an existing secret in case the secret diff --git a/control-plane/subcommand/webhook-cert-manager/command_test.go b/control-plane/subcommand/webhook-cert-manager/command_test.go index 7df7029241..434db47958 100644 --- a/control-plane/subcommand/webhook-cert-manager/command_test.go +++ b/control-plane/subcommand/webhook-cert-manager/command_test.go @@ -277,7 +277,8 @@ func TestRun_SecretExists(t *testing.T) { secretOne := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: secretOneName, + Name: secretOneName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, StringData: map[string]string{ v1.TLSCertKey: "cert-1", @@ -287,7 +288,8 @@ func TestRun_SecretExists(t *testing.T) { } secretTwo := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: secretTwoName, + Name: secretTwoName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, StringData: map[string]string{ v1.TLSCertKey: "cert-2", @@ -402,7 +404,8 @@ func TestRun_SecretUpdates(t *testing.T) { secret1 := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: secretOne, + Name: secretOne, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, }, StringData: map[string]string{ v1.TLSCertKey: "cert-1", From 84f1a8eb93cbd0d0d1b635895089851c67b28acd Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Wed, 1 Dec 2021 11:17:25 -0700 Subject: [PATCH 161/418] Support Vault server running with TLS (#874) * Change vault cluster in acceptance tests to only run with TLS. All tests will run against vault with TLS because that is the use case we think will be the most valuable for users to test * Support adding Vault CA as a secret to pods that will be using vault agent. We need to add two annotations to pods: * vault.hashicorp.com/agent-extra-secret with the value of the vault CA secret name. The secret will be mounted to vault agent at /vault/custom path. See docs here * vault.hashicorp.com/ca-cert - with the path of the ca file inside the vault agent container. This should be /vault/custom/ * Most pods will only need those annotations. The server pods also need the Vault CA secret to be mounted as a volume because it needs the CA to be on the file system for the vault connect CA provider. --- acceptance/framework/helpers/helpers.go | 4 +- acceptance/framework/vault/vault_cluster.go | 264 ++++++++-- acceptance/go.mod | 11 +- acceptance/go.sum | 492 ++++++++++++++++-- acceptance/tests/vault/vault_test.go | 16 +- charts/consul/templates/client-daemonset.yaml | 4 + .../templates/server-config-configmap.yaml | 5 +- .../consul/templates/server-statefulset.yaml | 17 + charts/consul/test/unit/client-daemonset.bats | 68 +++ .../test/unit/server-config-configmap.bats | 68 +++ .../consul/test/unit/server-statefulset.bats | 117 ++++- charts/consul/values.yaml | 9 + 12 files changed, 954 insertions(+), 121 deletions(-) diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index 1c40112e7d..7ed784d838 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -77,7 +77,7 @@ func CheckForPriorInstallations(t *testing.T, client kubernetes.Interface, optio func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespace, podLabelSelector string) { t.Helper() - logger.Log(t, "Waiting for pods to be ready.") + logger.Logf(t, "Waiting for pods with label %q to be ready.", podLabelSelector) // Wait up to 15m. // On Azure, volume provisioning can sometimes take close to 5 min, @@ -101,7 +101,7 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac logger.Log(t, "Finished waiting for pods to be ready.") } -// Sets up a goroutine that will wait for interrupt signals +// SetupInterruptHandler sets up a goroutine that will wait for interrupt signals // and call cleanup function when it catches it. func SetupInterruptHandler(cleanup func()) { c := make(chan os.Signal, 1) diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index 01e3141e1f..9287d57035 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -1,6 +1,7 @@ package vault import ( + "context" "fmt" "testing" "time" @@ -13,33 +14,30 @@ import ( "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/control-plane/helper/cert" "github.com/hashicorp/consul/sdk/testutil/retry" vapi "github.com/hashicorp/vault/api" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) const ( - vaultNS = "default" - vaultPodLabel = "app.kubernetes.io/instance=" - vaultRootToken = "abcd1234" + releaseLabel = "app.kubernetes.io/instance=" ) -// VaultCluster +// VaultCluster represents a vault installation. type VaultCluster struct { - ctx environment.TestContext - namespace string + ctx environment.TestContext - vaultHelmOptions *helm.Options - vaultReleaseName string - vaultClient *vapi.Client + helmOptions *helm.Options + releaseName string + vaultClient *vapi.Client kubectlOptions *terratestk8s.KubectlOptions - values map[string]string kubernetesClient kubernetes.Interface - kubeConfig string - kubeContext string noCleanupOnFailure bool debugDirectory string @@ -47,21 +45,14 @@ type VaultCluster struct { } // NewVaultCluster creates a VaultCluster which will be used to install Vault using Helm. -func NewVaultCluster( - t *testing.T, - helmValues map[string]string, - ctx environment.TestContext, - cfg *config.TestConfig, - releaseName string, -) *VaultCluster { +func NewVaultCluster(t *testing.T, ctx environment.TestContext, cfg *config.TestConfig, releaseName string) *VaultCluster { logger := terratestLogger.New(logger.TestLogger{}) kopts := ctx.KubectlOptions(t) - kopts.Namespace = vaultNS vaultHelmOpts := &helm.Options{ - SetValues: defaultVaultValues(), + SetValues: defaultHelmValues(releaseName), KubectlOptions: kopts, Logger: logger, } @@ -75,35 +66,34 @@ func NewVaultCluster( return &VaultCluster{ ctx: ctx, - vaultHelmOptions: vaultHelmOpts, + helmOptions: vaultHelmOpts, kubectlOptions: kopts, - namespace: cfg.KubeNamespace, - values: helmValues, kubernetesClient: ctx.KubernetesClient(t), - kubeConfig: cfg.Kubeconfig, - kubeContext: cfg.KubeContext, noCleanupOnFailure: cfg.NoCleanupOnFailure, debugDirectory: cfg.DebugDirectory, logger: logger, - vaultReleaseName: releaseName, + releaseName: releaseName, } } // VaultClient returns the vault client. func (v *VaultCluster) VaultClient(t *testing.T) *vapi.Client { return v.vaultClient } -// Setup Vault Client returns a Vault Client. -// TODO: We need to support Vault with TLS enabled. +// SetupVaultClient sets up and returns a Vault Client. func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { t.Helper() + if v.vaultClient != nil { + return v.vaultClient + } + config := vapi.DefaultConfig() localPort := terratestk8s.GetAvailablePort(t) remotePort := 8200 // use non-secure by default - serverPod := fmt.Sprintf("%s-vault-0", v.vaultReleaseName) + serverPod := fmt.Sprintf("%s-vault-0", v.releaseName) tunnel := terratestk8s.NewTunnelWithLogger( - v.vaultHelmOptions.KubectlOptions, + v.helmOptions.KubectlOptions, terratestk8s.ResourceTypePod, serverPod, localPort, @@ -122,7 +112,10 @@ func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { tunnel.Close() }) - config.Address = fmt.Sprintf("http://127.0.0.1:%d", localPort) + config.Address = fmt.Sprintf("https://127.0.0.1:%d", localPort) + // We don't need to verify TLS for localhost traffic. + err := config.ConfigureTLS(&vapi.TLSConfig{Insecure: true}) + require.NoError(t, err) vaultClient, err := vapi.NewClient(config) require.NoError(t, err) return vaultClient @@ -132,7 +125,6 @@ func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { func (v *VaultCluster) bootstrap(t *testing.T, ctx environment.TestContext) { v.vaultClient = v.SetupVaultClient(t) - v.vaultClient.SetToken(vaultRootToken) // Enable the KV-V2 Secrets engine. err := v.vaultClient.Sys().Mount("consul", &vapi.MountInput{ @@ -146,18 +138,28 @@ func (v *VaultCluster) bootstrap(t *testing.T, ctx environment.TestContext) { // Enable Kube Auth. err = v.vaultClient.Sys().EnableAuthWithOptions("kubernetes", &vapi.EnableAuthOptions{ - Type: "kubernetes", - Config: vapi.MountConfigInput{}, + Type: "kubernetes", }) if err != nil { t.Fatal("unable to enable kube auth", "err", err) } - // We need to kubectl exec this one on the vault server: - // This is taken from https://learn.hashicorp.com/tutorials/vault/kubernetes-google-cloud-gke?in=vault/kubernetes#configure-kubernetes-authentication - cmdString := fmt.Sprintf("VAULT_TOKEN=%s vault write auth/kubernetes/config disable_iss_validation=\"true\" token_reviewer_jwt=\"$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\" kubernetes_host=\"https://${KUBERNETES_PORT_443_TCP_ADDR}:443\" kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", vaultRootToken) v.logger.Logf(t, "updating vault kube auth config") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "-i", fmt.Sprintf("%s-vault-0", v.vaultReleaseName), "--", "sh", "-c", cmdString) + + // To configure the auth method, we need to read the token and the ca cert from the Vault's server + // service account token. + namespace := v.helmOptions.KubectlOptions.Namespace + sa, err := v.kubernetesClient.CoreV1().ServiceAccounts(namespace).Get(context.Background(), fmt.Sprintf("%s-vault", v.releaseName), metav1.GetOptions{}) + require.NoError(t, err) + require.Len(t, sa.Secrets, 1) + tokenSecret, err := v.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), sa.Secrets[0].Name, metav1.GetOptions{}) + require.NoError(t, err) + _, err = v.vaultClient.Logical().Write("auth/kubernetes/config", map[string]interface{}{ + "token_reviewer_jwt": tokenSecret.StringData["token"], + "kubernetes_ca_cert": tokenSecret.StringData["ca.crt"], + "kubernetes_host": "https://kubernetes.default.svc", + }) + require.NoError(t, err) } // Create installs Vault via Helm and then calls bootstrap to initialize it. @@ -171,13 +173,19 @@ func (v *VaultCluster) Create(t *testing.T, ctx environment.TestContext) { }) // Fail if there are any existing installations of the Helm chart. - helpers.CheckForPriorInstallations(t, v.kubernetesClient, v.vaultHelmOptions, "", fmt.Sprintf("%s=%s", vaultPodLabel, v.vaultReleaseName)) + helpers.CheckForPriorInstallations(t, v.kubernetesClient, v.helmOptions, "", v.releaseLabelSelector()) + + v.createTLSCerts(t) // Install Vault. - helm.Install(t, v.vaultHelmOptions, "hashicorp/vault", v.vaultReleaseName) + helm.Install(t, v.helmOptions, "hashicorp/vault", v.releaseName) + + v.initAndUnseal(t) + // Wait for the injector and vault server pods to become Ready. - helpers.WaitForAllPodsToBeReady(t, v.kubernetesClient, v.vaultHelmOptions.KubectlOptions.Namespace, fmt.Sprintf("%s=%s", vaultPodLabel, v.vaultReleaseName)) - // Now call bootstrap() + helpers.WaitForAllPodsToBeReady(t, v.kubernetesClient, v.helmOptions.KubectlOptions.Namespace, v.releaseLabelSelector()) + + // Now call bootstrap(). v.bootstrap(t, ctx) } @@ -185,20 +193,170 @@ func (v *VaultCluster) Create(t *testing.T, ctx environment.TestContext) { func (v *VaultCluster) Destroy(t *testing.T) { t.Helper() - k8s.WritePodsDebugInfoIfFailed(t, v.kubectlOptions, v.debugDirectory, "release="+v.vaultReleaseName) + k8s.WritePodsDebugInfoIfFailed(t, v.kubectlOptions, v.debugDirectory, v.releaseLabelSelector()) // Ignore the error returned by the helm delete here so that we can // always idempotently clean up resources in the cluster. - _ = helm.DeleteE(t, v.vaultHelmOptions, v.vaultReleaseName, true) - // We do not need to do any PVC deletion in vault dev mode. + _ = helm.DeleteE(t, v.helmOptions, v.releaseName, true) + + err := v.kubernetesClient.CoreV1().PersistentVolumeClaims(v.helmOptions.KubectlOptions.Namespace).DeleteCollection(context.Background(), + metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: v.releaseLabelSelector()}) + require.NoError(t, err) } -func defaultVaultValues() map[string]string { +func defaultHelmValues(releaseName string) map[string]string { + certSecret := certSecretName(releaseName) + caSecret := CASecretName(releaseName) + + serverConfig := fmt.Sprintf(` + listener "tcp" { + address = "[::]:8200" + cluster_address = "[::]:8201" + tls_cert_file = "/vault/userconfig/%s/tls.crt" + tls_key_file = "/vault/userconfig/%s/tls.key" + tls_client_ca_file = "/vault/userconfig/%s/tls.crt" + } + + storage "file" { + path = "/vault/data" + }`, certSecret, certSecret, caSecret) + return map[string]string{ - "server.replicas": "1", - "server.dev.enabled": "true", - "server.dev.devRootToken": vaultRootToken, - "server.bootstrapExpect": "1", - "injector.enabled": "true", - "global.enabled": "true", + "global.tlsDisable": "false", + "server.extraEnvironmentVars.VAULT_CACERT": fmt.Sprintf("/vault/userconfig/%s/tls.crt", caSecret), + "server.extraVolumes[0].name": caSecret, + "server.extraVolumes[0].type": "secret", + "server.extraVolumes[1].name": certSecret, + "server.extraVolumes[1].type": "secret", + "server.standalone.enabled": "true", + "server.standalone.config": serverConfig, + "injector.enabled": "true", } } + +// certSecretName returns the Kubernetes secret name of the certificate and key +// for the Vault server. +func certSecretName(releaseName string) string { + return fmt.Sprintf("%s-vault-server-tls", releaseName) +} + +// CASecretName returns the Kubernetes secret name of the CA for the Vault server. +func CASecretName(releaseName string) string { + return fmt.Sprintf("%s-vault-ca", releaseName) +} + +// Address is the in-cluster API address of the Vault server. +func (v *VaultCluster) Address() string { + return fmt.Sprintf("https://%s-vault:8200", v.releaseName) +} + +// releaseLabelSelector returns label selector that selects all pods +// from a Vault installation. +func (v *VaultCluster) releaseLabelSelector() string { + return fmt.Sprintf("%s=%s", releaseLabel, v.releaseName) +} + +// createTLSCerts generates a self-signed CA and uses it to generate +// certificate and key for the Vault server. It then saves those as +// Kubernetes secrets. +func (v *VaultCluster) createTLSCerts(t *testing.T) { + v.logger.Logf(t, "generating Vault TLS certificates") + + namespace := v.helmOptions.KubectlOptions.Namespace + + // Generate CA and cert and create secrets for them. + signer, _, caPem, caCertTmpl, err := cert.GenerateCA("Vault CA") + require.NoError(t, err) + vaultService := fmt.Sprintf("%s-vault", v.releaseName) + certSANs := []string{ + vaultService, + fmt.Sprintf("%s.default", vaultService), + fmt.Sprintf("%s.default.svc", vaultService), + } + certPem, keyPem, err := cert.GenerateCert("Vault server", 24*time.Hour, caCertTmpl, signer, certSANs) + require.NoError(t, err) + + t.Cleanup(func() { + if !v.noCleanupOnFailure { + // We're ignoring error here because secret deletion is best-effort. + _ = v.kubernetesClient.CoreV1().Secrets(namespace).Delete(context.Background(), certSecretName(v.releaseName), metav1.DeleteOptions{}) + _ = v.kubernetesClient.CoreV1().Secrets(namespace).Delete(context.Background(), CASecretName(v.releaseName), metav1.DeleteOptions{}) + } + }) + + _, err = v.kubernetesClient.CoreV1().Secrets(namespace).Create(context.Background(), &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: certSecretName(v.releaseName), + }, + Data: map[string][]byte{ + corev1.TLSCertKey: []byte(certPem), + corev1.TLSPrivateKeyKey: []byte(keyPem), + }, + Type: corev1.SecretTypeTLS, + }, metav1.CreateOptions{}) + require.NoError(t, err) + + _, err = v.kubernetesClient.CoreV1().Secrets(namespace).Create(context.Background(), &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: CASecretName(v.releaseName), + Namespace: namespace, + }, + Data: map[string][]byte{ + corev1.TLSCertKey: []byte(caPem), + }, + Type: corev1.SecretTypeOpaque, + }, metav1.CreateOptions{}) + require.NoError(t, err) +} + +// initAndUnseal initializes and unseals Vault. +// Once initialized, it saves the Vault root token into a Kubernetes secret. +func (v *VaultCluster) initAndUnseal(t *testing.T) { + v.logger.Logf(t, "initializing and unsealing Vault") + + namespace := v.helmOptions.KubectlOptions.Namespace + retrier := &retry.Timer{Timeout: 2 * time.Minute, Wait: 1 * time.Second} + retry.RunWith(retrier, t, func(r *retry.R) { + // Wait for vault server pod to be running so that we can create Vault client without errors. + serverPod, err := v.kubernetesClient.CoreV1().Pods(namespace).Get(context.Background(), fmt.Sprintf("%s-vault-0", v.releaseName), metav1.GetOptions{}) + require.NoError(r, err) + require.Equal(r, serverPod.Status.Phase, corev1.PodRunning) + + // Set up the client so that we can make API calls to initialize and unseal. + v.vaultClient = v.SetupVaultClient(t) + + // Initialize Vault with 1 secret share. We don't need to + // more key shares for this test installation. + initResp, err := v.vaultClient.Sys().Init(&vapi.InitRequest{ + SecretShares: 1, + SecretThreshold: 1, + }) + require.NoError(r, err) + v.vaultClient.SetToken(initResp.RootToken) + + // Unseal Vault with the unseal key we got when initialized it. + // There should be one unseal key since we're only using one secret share. + _, err = v.vaultClient.Sys().Unseal(initResp.KeysB64[0]) + require.NoError(r, err) + }) + + v.logger.Logf(t, "successfully initialized and unsealed Vault") + + rootTokenSecret := fmt.Sprintf("%s-vault-root-token", v.releaseName) + v.logger.Logf(t, "saving Vault root token to %q Kubernetes secret", rootTokenSecret) + + helpers.Cleanup(t, v.noCleanupOnFailure, func() { + _ = v.kubernetesClient.CoreV1().Secrets(namespace).Delete(context.Background(), rootTokenSecret, metav1.DeleteOptions{}) + }) + _, err := v.kubernetesClient.CoreV1().Secrets(namespace).Create(context.Background(), &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: rootTokenSecret, + Namespace: namespace, + }, + Data: map[string][]byte{ + "token": []byte(v.vaultClient.Token()), + }, + Type: corev1.SecretTypeOpaque, + }, metav1.CreateOptions{}) + require.NoError(t, err) +} diff --git a/acceptance/go.mod b/acceptance/go.mod index f3ae49e46d..4993a3b5df 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -4,12 +4,13 @@ go 1.14 require ( github.com/gruntwork-io/terratest v0.31.2 - github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c + github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51 + github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/vault/api v1.2.0 github.com/stretchr/testify v1.7.0 - gopkg.in/yaml.v2 v2.2.8 - k8s.io/api v0.19.3 - k8s.io/apimachinery v0.19.3 - k8s.io/client-go v0.19.3 + gopkg.in/yaml.v2 v2.4.0 + k8s.io/api v0.22.2 + k8s.io/apimachinery v0.22.2 + k8s.io/client-go v0.22.2 ) diff --git a/acceptance/go.sum b/acceptance/go.sum index 21beaba9f1..c7e67332e3 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -6,29 +6,47 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v44.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.0/go.mod h1:QRTvSZQpxqm8mSErhnbI+tANIBAKP7B+UIE2z4ypUO0= github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= @@ -41,10 +59,12 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935 github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -55,39 +75,56 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.0/go.mod h1:zXjbSimjXTd7vOpY8B0/2LpvNvDoXBuplAD+gJD3GYs= -github.com/armon/go-metrics v0.3.3 h1:a9F4rlj7EWWrbj7BYw8J8+x+ZZkJeqzNyRk8hdPF+ro= github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= +github.com/armon/go-metrics v0.3.9 h1:O2sNqxBdvq8Eq5xmzljcYzAORli6RWCvEym4cJf9m18= +github.com/armon/go-metrics v0.3.9/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.30.27 h1:9gPjZWVDSoQrBO2AvqrWObS6KAZByfEJxQoCYo4ZfK0= github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= +github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= 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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -96,7 +133,12 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -108,15 +150,19 @@ github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -124,11 +170,17 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/digitalocean/godo v1.7.5/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= +github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= @@ -141,7 +193,6 @@ github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avu github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -157,21 +208,30 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= +github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -179,73 +239,100 @@ github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 h1:skJKxRtNmevLqnayafdLe2AsenqRupVmzZSqrvb5caU= github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8= github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= @@ -254,51 +341,74 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arnQQLM4RH+CYs= github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= -github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c h1:7hQzN7YHI2XscCNqPVW5pORQSwJWdFgObnwXNFdEJI8= -github.com/hashicorp/consul/api v1.10.1-0.20211025235848-5c24ed61a89c/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= +github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51 h1:Km6RYuAsJVVu3gipkTWF1SVYuvSJrksBtT89rO4hcdA= +github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51/go.mod h1:+Ay3RL0eZdI0wgT193r+EJTOk9cSn1WUlvBvk6Lfnmo= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f h1:fBBh4412td7nBzqyLkpGTH5dWycPs8p7Yg/Dy8VQjVU= +github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f/go.mod h1:D4eo8/CN92vm9/9UDG+ldX1/fMFa4kpl8qzyTolus8o= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc= github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.0 h1:8exGP7ego3OmkfksihtSouGMZ+hQrhxx+FVELeXpVPE= +github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= -github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 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= @@ -309,6 +419,7 @@ github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= 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= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= @@ -327,6 +438,7 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= @@ -334,47 +446,67 @@ github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= -github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC7AO2g= -github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.5 h1:EBWvyu9tcRszt3Bxp3KNssBMP1KuHWyO51lz9+786iM= -github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f/go.mod h1:euTFbi2YJgwcju3imEt919lhJKF68nN1cQPq3aA+kBE= github.com/hashicorp/vault/api v1.2.0 h1:ysGFc6XRGbv05NsWPzuO5VTv68Lj8jtwATxRLFOpP9s= github.com/hashicorp/vault/api v1.2.0/go.mod h1:dAjw0T5shMnrfH7Q/Mst+LrcTKvStZBVs1PICEDpUqY= github.com/hashicorp/vault/sdk v0.1.14-0.20200519221530-14615acda45f/go.mod h1:WX57W2PwkrOPQ6rVQk+dy5/htHIaB4aBM70EwKThu10= github.com/hashicorp/vault/sdk v0.2.1 h1:S4O6Iv/dyKlE9AUTXGa7VOvZmsCvg36toPKgV4f2P4M= github.com/hashicorp/vault/sdk v0.2.1/go.mod h1:WfUiO1vYzfBkz1TmoE4ZGU7HD0T0Cl/rZwaxjBkgN4U= +github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= +github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -385,41 +517,54 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= +github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.31 h1:sJFOl9BgwbYAWOGEwr61FU28pqsBNdpRBnhGXtO06Oo= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= +github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.0 h1:/x0XQ6h+3U3nAyk1yx+bHPURrKa9sVVvYbuqZ7pIAtI= +github.com/mitchellh/go-testing-interface v1.14.0/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -428,6 +573,9 @@ github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7p github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -439,20 +587,35 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.0-20180130162743-b8a9be070da4/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -460,7 +623,9 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -484,24 +649,38 @@ github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/zerolog v1.4.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -513,21 +692,35 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sean-/conswriter v0.0.0-20180208195008-f5ae3917a627/go.mod h1:7zjs06qF79/FKAJpBvFx3P8Ww4UTIMAe+lpNXDHziac= +github.com/sean-/pager v0.0.0-20180208200047-666be9bf53b5/go.mod h1:BeybITEsBEg6qbIiqJ6/Bqeq25bCLbL7YFmpaFfJDuM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -536,6 +729,9 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= @@ -545,10 +741,16 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -556,19 +758,51 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -583,16 +817,24 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -602,13 +844,19 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f h1:J5lckAjkw6qYlOZNj90mLYNTEKDvWeuc1yieZ8qUzUE= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -623,21 +871,36 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -649,8 +912,11 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -671,42 +937,77 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo= +golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -717,6 +1018,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -732,16 +1034,37 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200113040837-eac381796e91 h1:OOkytthzFBKHY5EfEgLUabprb0LtJVkQtNxAQ02+UE4= golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= @@ -750,13 +1073,19 @@ google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNV google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -765,12 +1094,26 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -779,8 +1122,13 @@ google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRn google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -790,22 +1138,25 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -818,61 +1169,92 @@ gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= -k8s.io/api v0.19.3 h1:GN6ntFnv44Vptj/b+OnMW7FmzkpDoIDLZRvKX3XH9aU= +k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= +k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= +k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apimachinery v0.19.3 h1:bpIQXlKjB4cB/oNpnNnV+BybGPR7iP5oYpsOTEJ4hgc= +k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= +k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= -k8s.io/client-go v0.19.3 h1:ctqR1nQ52NUs6LpI0w+a5U+xjYwflFwA13OJKcicMxg= +k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= +k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= +k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= -k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 h1:+WnxoVtG8TMiudHBSEtrVL1egv36TkkJm+bA8AxicmQ= +k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg= +k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/controller-runtime v0.10.2/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= -sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 94d09f1492..4b63dc8b65 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -56,7 +56,7 @@ func TestVault(t *testing.T) { consulClientServiceAccountName := fmt.Sprintf("%s-consul-client", consulReleaseName) consulServerServiceAccountName := fmt.Sprintf("%s-consul-server", consulReleaseName) - vaultCluster := vault.NewVaultCluster(t, nil, ctx, cfg, vaultReleaseName) + vaultCluster := vault.NewVaultCluster(t, ctx, cfg, vaultReleaseName) vaultCluster.Create(t, ctx) // Vault is now installed in the cluster. @@ -108,11 +108,16 @@ func TestVault(t *testing.T) { } _, err = vaultClient.Logical().Write("consul/data/secret/gossip", params) require.NoError(t, err) + + vaultCASecret := vault.CASecretName(vaultReleaseName) consulHelmValues := map[string]string{ "global.image": "docker.mirror.hashicorp.services/hashicorpdev/consul:latest", - "server.enabled": "true", - "server.replicas": "1", + "server.enabled": "true", + "server.replicas": "1", + "server.extraVolumes[0].type": "secret", + "server.extraVolumes[0].name": vaultCASecret, + "server.extraVolumes[0].load": "false", "connectInject.enabled": "true", "controller.enabled": "true", @@ -121,7 +126,10 @@ func TestVault(t *testing.T) { "global.secretsBackend.vault.consulServerRole": "consul-server", "global.secretsBackend.vault.consulClientRole": "consul-client", - "global.secretsBackend.vault.connectCA.address": fmt.Sprintf("http://%s-vault:8200", vaultReleaseName), + "global.secretsBackend.vault.ca.secretName": vaultCASecret, + "global.secretsBackend.vault.ca.secretKey": "tls.crt", + + "global.secretsBackend.vault.connectCA.address": vaultCluster.Address(), "global.secretsBackend.vault.connectCA.rootPKIPath": "connect_root", "global.secretsBackend.vault.connectCA.intermediatePKIPath": "connect_inter", diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index af213f9e4e..468af38fda 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -41,6 +41,10 @@ spec: {{- if .Values.global.secretsBackend.vault.enabled }} "vault.hashicorp.com/agent-inject": "true" "vault.hashicorp.com/role": "{{ .Values.global.secretsBackend.vault.consulClientRole }}" + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" + "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + {{- end }} {{- if .Values.global.gossipEncryption.secretName }} {{- with .Values.global.gossipEncryption }} "vault.hashicorp.com/agent-inject-secret-gossip.txt": "{{ .secretName }}" diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index 2b8f07dc6b..27b65887b7 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -21,12 +21,15 @@ data: "ca_config": [ { "address": "{{ .connectCA.address }}", + {{- if and .ca.secretName .ca.secretKey }} + "ca_file": "/consul/vault-ca/tls.crt", + {{- end }} "intermediate_pki_path": "{{ .connectCA.intermediatePKIPath }}", "root_pki_path": "{{ .connectCA.rootPKIPath }}", "auth_method": { "type": "kubernetes", "params": { - "role": "{{.consulServerRole}}" + "role": "{{ .consulServerRole }}" } } } diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 77fa3c68de..5a3afeea4d 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -52,6 +52,10 @@ spec: {{- if .Values.global.secretsBackend.vault.enabled }} "vault.hashicorp.com/agent-inject": "true" "vault.hashicorp.com/role": "{{ .Values.global.secretsBackend.vault.consulServerRole }}" + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" + "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + {{- end }} {{- if .Values.global.gossipEncryption.secretName }} {{- with .Values.global.gossipEncryption }} "vault.hashicorp.com/agent-inject-secret-gossip.txt": "{{ .secretName }}" @@ -120,6 +124,14 @@ spec: secret: secretName: {{ .Values.server.enterpriseLicense.secretName }} {{- end }} + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + - name: vault-ca + secret: + secretName: {{ .Values.global.secretsBackend.vault.ca.secretName }} + items: + - key: {{ .Values.global.secretsBackend.vault.ca.secretKey }} + path: tls.crt + {{- end }} {{- range .Values.server.extraVolumes }} - name: userconfig-{{ .name }} {{ .type }}: @@ -298,6 +310,11 @@ spec: readOnly: true mountPath: /consul/userconfig/{{ .name }} {{- end }} + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + - name: vault-ca + mountPath: /consul/vault-ca/ + readOnly: true + {{- end }} ports: {{- if (or (not .Values.global.tls.enabled) (not .Values.global.tls.httpsOnly)) }} - name: http diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index f83c802e32..73483651db 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1607,3 +1607,71 @@ rollingUpdate: | tee /dev/stderr) [ "${actual}" = "true" ] } + +@test "client/DaemonSet: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "client/DaemonSet: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "client/DaemonSet: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "client/DaemonSet: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} diff --git a/charts/consul/test/unit/server-config-configmap.bats b/charts/consul/test/unit/server-config-configmap.bats index 8245fb215e..bb52f7e33f 100755 --- a/charts/consul/test/unit/server-config-configmap.bats +++ b/charts/consul/test/unit/server-config-configmap.bats @@ -405,4 +405,72 @@ load _helpers . | tee /dev/stderr | yq '.data["additional-connect-ca-config.json"]' | tee /dev/stderr) [ "${actual}" = '"{\"hello\": \"world\"}\n"' ] +} + +@test "server/ConfigMap: doesn't set Vault CA cert in connect CA config by default" { + cd `chart_dir` + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | contains("\"ca_file\": \"/consul/vault-ca/tls.crt\"")' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't set Vault CA cert in connect CA config when vault CA secret name is set but secret key is not" { + cd `chart_dir` + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | contains("\"ca_file\": \"/consul/vault-ca/tls.crt\"")' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't set Vault CA cert in connect CA config when vault CA secret key is set but secret name is not" { + cd `chart_dir` + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | contains("\"ca_file\": \"/consul/vault-ca/tls.crt\"")' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: doesn't set Vault CA cert in connect CA config when both vault CA secret name and key are set" { + cd `chart_dir` + + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq '.data["connect-ca-config.json"] | contains("\"ca_file\": \"/consul/vault-ca/tls.crt\"")' | tee /dev/stderr) + [ "${actual}" = "true" ] } \ No newline at end of file diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 909fb647b2..9a180f5d98 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -1492,7 +1492,6 @@ load _helpers . | tee /dev/stderr | yq -r '.spec.template.spec' | tee /dev/stderr) - local actual=$(echo $object | yq -r '.containers[] | select(.name=="consul") | .env[] | select(.name == "GOSSIP_KEY")' | tee /dev/stderr) [ "${actual}" = "" ] @@ -1502,3 +1501,119 @@ load _helpers | tee /dev/stderr) [ "${actual}" = "true" ] } + +@test "server/StatefulSet: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check that the volume is defined. + local actual=$(echo $object | + yq -r '.spec.volumes[] | select(.name=="vault-ca")' | tee /dev/stderr) + [ "${actual}" = "" ] + + # Check that the volume mount is added. + local actual=$(echo $object | + yq -r '.spec.containers[] | select(.name=="consul").volumeMounts[] | select(.name=="vault-ca")' \ + | tee /dev/stderr) + [ "${actual}" = "" ] + + # Check that Vault agent annotations are added. + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "server/StatefulSet: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check that the volume is defined. + local actual=$(echo $object | + yq -r '.spec.volumes[] | select(.name=="vault-ca")' | tee /dev/stderr) + [ "${actual}" = "" ] + + # Check that the volume mount is added. + local actual=$(echo $object | + yq -r '.spec.containers[] | select(.name=="consul").volumeMounts[] | select(.name=="vault-ca")' \ + | tee /dev/stderr) + [ "${actual}" = "" ] + + # Check that Vault agent annotations are added. + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "server/StatefulSet: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check that the volume is defined. + local actual=$(echo $object | + yq -r '.spec.volumes[] | select(.name=="vault-ca")' | tee /dev/stderr) + [ "${actual}" = "" ] + + # Check that the volume mount is added. + local actual=$(echo $object | + yq -r '.spec.containers[] | select(.name=="consul").volumeMounts[] | select(.name=="vault-ca")' \ + | tee /dev/stderr) + [ "${actual}" = "" ] + + # Check that Vault agent annotations are added. + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "server/StatefulSet: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check that the volume is defined. + local actual=$(echo $object | + yq -r '.spec.volumes[] | select(.name=="vault-ca").secret.secretName' | tee /dev/stderr) + [ "${actual}" = "ca" ] + + # Check that the volume mount is added. + local actual=$(echo $object | + yq -r '.spec.containers[] | select(.name=="consul").volumeMounts[] | select(.name=="vault-ca")' \ + | tee /dev/stderr) + [ "${actual}" != "" ] + + # Check that Vault agent annotations are added. + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 480e46bee5..ec6b29c2e7 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -152,6 +152,15 @@ global: # and check the name of `metadata.name`. consulClientRole: "" + # Configuration for Vault server CA certificate. This certificate will be mounted + # to any pod where Vault agent needs to run. + ca: + # secretName is the name of the Kubernetes secret that holds the Vault CA certificate. + # A Kubernetes secret must be in the same namespace that Consul is installed into. + secretName: "" + # secretKey is the key within the Kubernetes secret that holds the Vault CA certificate. + secretKey: "" + # Configuration for the Vault Connect CA provider. # The provider will be configured to use the Vault Kubernetes auth method # and therefore requires the role provided by `global.secretsBackend.vault.consulServerRole` From 1af9eda0b967263ccdca038cbf264cb70e9248f2 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Wed, 1 Dec 2021 11:19:34 -0700 Subject: [PATCH 162/418] Add a workaround to check that the ACL token is replicated to other Consul servers (#887) Fixes #862 A consul client may reach out to a follower instead of a leader to resolve the token during the call to get services. This is because clients talk to servers in the stale consistency mode to decrease the load on the servers (see https://www.consul.io/docs/architecture/consensus#stale). In that case, it's possible that the token isn't replicated to that server instance yet. The client will then get an "ACL not found" error and subsequently cache this not found response. Then our call to get services from the agent will keep hitting the same "ACL not found" error until the cache entry expires (determined by the `acl_token_ttl` which defaults to 30 seconds). This is not great because it will delay app start up time by 30 seconds in most cases (if you are running 3 servers, then the probability of ending up on a follower is close to 2/3). To help with that, we try to first read the token in the stale consistency mode until we get a successful response. This should not take more than 100ms because raft replication should in most cases take less than that (see https://www.consul.io/docs/install/performance#read-write-tuning) but we set the timeout to 2s to be sure. Note though that this workaround does not eliminate this problem completely. It's still possible for this call and the next call to reach different servers and those servers to have different states from each other. For example, get token call can reach a leader and succeed, while the call to get services can go to a follower that is still behind the leader and get an "ACL not found" error. However, this is a pretty unlikely case because clients have sticky connections to a server, and those connections get rebalanced only every 2-3min. And so, this workaround should work in a vast majority of cases. --- CHANGELOG.md | 4 + .../subcommand/connect-init/command.go | 46 ++++++++ .../subcommand/connect-init/command_test.go | 109 +++++++++++++++++- 3 files changed, 157 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11988f4b27..dd3780d5d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ IMPROVEMENTS: * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] * Add a label "managed-by" to every secret the control-plane creates. Only delete said secrets on an uninstall. [[GH-835](https://github.com/hashicorp/consul-k8s/pull/835)] +BUG FIXES: +* Control Plane: + * Add a workaround to check that the ACL token is replicated to other Consul servers. [[GH-862](https://github.com/hashicorp/consul-k8s/issues/862)] + ## 0.37.0 (November 18, 2021) BREAKING CHANGES: diff --git a/control-plane/subcommand/connect-init/command.go b/control-plane/subcommand/connect-init/command.go index e7487fb9e1..18271e6b05 100644 --- a/control-plane/subcommand/connect-init/command.go +++ b/control-plane/subcommand/connect-init/command.go @@ -26,6 +26,9 @@ const ( numLoginRetries = 3 // The number of times to attempt to read this service (120s). defaultServicePollingRetries = 120 + + raftReplicationTimeout = 2 * time.Second + tokenReadPollingInterval = 100 * time.Millisecond ) type Command struct { @@ -155,6 +158,49 @@ func (c *Command) Run(args []string) int { return 1 } c.logger.Info("Consul login complete") + + // A workaround to check that the ACL token is replicated to other Consul servers. + // + // A consul client may reach out to a follower instead of a leader to resolve the token during the + // call to get services below. This is because clients talk to servers in the stale consistency mode + // to decrease the load on the servers (see https://www.consul.io/docs/architecture/consensus#stale). + // In that case, it's possible that the token isn't replicated + // to that server instance yet. The client will then get an "ACL not found" error + // and subsequently cache this not found response. Then our call below + // to get services from the agent will keep hitting the same "ACL not found" error + // until the cache entry expires (determined by the `acl_token_ttl` which defaults to 30 seconds). + // This is not great because it will delay app start up time by 30 seconds in most cases + // (if you are running 3 servers, then the probability of ending up on a follower is close to 2/3). + // + // To help with that, we try to first read the token in the stale consistency mode until we + // get a successful response. This should not take more than 100ms because raft replication + // should in most cases take less than that (see https://www.consul.io/docs/install/performance#read-write-tuning) + // but we set the timeout to 2s to be sure. + // + // Note though that this workaround does not eliminate this problem completely. It's still possible + // for this call and the next call to reach different servers and those servers to have different + // states from each other. + // For example, this call can reach a leader and succeed, while the call below can go to a follower + // that is still behind the leader and get an "ACL not found" error. + // However, this is a pretty unlikely case because + // clients have sticky connections to a server, and those connections get rebalanced only every 2-3min. + // And so, this workaround should work in a vast majority of cases. + c.logger.Info("Checking that the ACL token exists when reading it in the stale consistency mode") + // Use raft timeout and polling interval to determine the number of retries. + numTokenReadRetries := uint64(raftReplicationTimeout.Milliseconds() / tokenReadPollingInterval.Milliseconds()) + err = backoff.Retry(func() error { + _, _, err := consulClient.ACL().TokenReadSelf(&api.QueryOptions{AllowStale: true}) + if err != nil { + c.logger.Error("Unable to read ACL token; retrying", "err", err) + } + return err + }, backoff.WithMaxRetries(backoff.NewConstantBackOff(tokenReadPollingInterval), numTokenReadRetries)) + if err != nil { + c.logger.Error("Unable to read ACL token from a Consul server; "+ + "please check that your server cluster is healthy", "err", err) + return 1 + } + c.logger.Info("Successfully read ACL token from the server") } // Now wait for the service to be registered. Do this by querying the Agent for a service diff --git a/control-plane/subcommand/connect-init/command_test.go b/control-plane/subcommand/connect-init/command_test.go index 704c7356a6..ff847bf0fb 100644 --- a/control-plane/subcommand/connect-init/command_test.go +++ b/control-plane/subcommand/connect-init/command_test.go @@ -592,6 +592,10 @@ func TestRun_FailsWithBadServerResponses(t *testing.T) { if r != nil && r.URL.Path == "/v1/acl/login" && r.Method == "POST" { w.Write([]byte(c.loginResponse)) } + // Token read request. + if r != nil && r.URL.Path == "/v1/acl/token/self" && r.Method == "GET" { + w.Write([]byte(testTokenReadSelfResponse)) + } // Agent Services get. if r != nil && r.URL.Path == "/v1/agent/services" && r.Method == "GET" { servicesGetCounter++ @@ -600,7 +604,7 @@ func TestRun_FailsWithBadServerResponses(t *testing.T) { })) defer consulServer.Close() - // Setup the Command. + // Set up the Command. ui := cli.NewMockUi() cmd := Command{ UI: ui, @@ -663,6 +667,10 @@ func TestRun_LoginWithRetries(t *testing.T) { w.Write([]byte(testLoginResponse)) } } + // Token read request. + if r != nil && r.URL.Path == "/v1/acl/token/self" && r.Method == "GET" { + w.Write([]byte(testTokenReadSelfResponse)) + } // Agent Services get. if r != nil && r.URL.Path == "/v1/agent/services" && r.Method == "GET" { w.Write([]byte(testServiceListResponse)) @@ -702,6 +710,79 @@ func TestRun_LoginWithRetries(t *testing.T) { } } +// Test that we check token exists when reading it in the stale consistency mode. +func TestRun_EnsureTokenExists(t *testing.T) { + t.Parallel() + + cases := map[string]struct { + neverSucceed bool + }{ + "succeed after first retry": {neverSucceed: false}, + "never succeed": {neverSucceed: true}, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + // Create a fake input bearer token file and an output file. + bearerFile := common.WriteTempFile(t, "bearerTokenFile") + tokenFile := common.WriteTempFile(t, "") + proxyFile := common.WriteTempFile(t, "") + + // Start the mock Consul server. + counter := 0 + consulServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // ACL Login. + if r != nil && r.URL.Path == "/v1/acl/login" && r.Method == "POST" { + w.Write([]byte(testLoginResponse)) + } + // Token read request. + if r != nil && + r.URL.Path == "/v1/acl/token/self" && + r.Method == "GET" && + r.URL.Query().Has("stale") { + + // Fail the first request but succeed on the next. + if counter == 0 || c.neverSucceed { + counter++ + w.WriteHeader(http.StatusForbidden) + w.Write([]byte("ACL not found")) + } else { + w.Write([]byte(testTokenReadSelfResponse)) + } + } + // Agent Services get. + if r != nil && r.URL.Path == "/v1/agent/services" && r.Method == "GET" { + w.Write([]byte(testServiceListResponse)) + } + })) + defer consulServer.Close() + + serverURL, err := url.Parse(consulServer.URL) + require.NoError(t, err) + + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + tokenSinkFile: tokenFile, + bearerTokenFile: bearerFile, + proxyIDFile: proxyFile, + } + code := cmd.Run([]string{ + "-pod-name", testPodName, + "-pod-namespace", testPodNamespace, + "-acl-auth-method", test.AuthMethod, + "-service-account-name", testServiceAccountName, + "-http-addr", serverURL.String()}) + if c.neverSucceed { + require.Equal(t, 1, code) + } else { + require.Equal(t, 0, code) + require.Equal(t, 1, counter) + } + }) + } +} + const ( metaKeyPodName = "pod-name" metaKeyKubeNS = "k8s-namespace" @@ -710,7 +791,7 @@ const ( testPodName = "counting-pod" testServiceAccountName = "counting" - // sample response from https://consul.io/api-docs/acl#sample-response + // Sample response from https://consul.io/api-docs/acl#sample-response. testLoginResponse = `{ "AccessorID": "926e2bd2-b344-d91b-0c83-ae89f372cd9b", "SecretID": "b78d37c7-0ca7-5f4d-99ee-6d9975ce4586", @@ -734,6 +815,30 @@ const ( "ModifyIndex": 36 }` + // Sample response from https://www.consul.io/api-docs/acl/tokens#read-self-token. + testTokenReadSelfResponse = ` +{ + "AccessorID": "6a1253d2-1785-24fd-91c2-f8e78c745511", + "SecretID": "45a3bd52-07c7-47a4-52fd-0745e0cfe967", + "Description": "Agent token for 'node1'", + "Policies": [ + { + "ID": "165d4317-e379-f732-ce70-86278c4558f7", + "Name": "node1-write" + }, + { + "ID": "e359bd81-baca-903e-7e64-1ccd9fdc78f5", + "Name": "node-read" + } + ], + "Local": false, + "CreateTime": "2018-10-24T12:25:06.921933-04:00", + "Hash": "UuiRkOQPRCvoRZHRtUxxbrmwZ5crYrOdZ0Z1FTFbTbA=", + "CreateIndex": 59, + "ModifyIndex": 59 +} +` + testServiceListResponse = `{ "counting-counting": { "ID": "counting-counting", From 9c55e45be80c6297413d6e4436c5d6c7d98faf49 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 1 Dec 2021 13:36:12 -0500 Subject: [PATCH 163/418] Ignore services in endpoint controller using `consul.hashicorp.com/service-ignore` (#858) * connect-ignore deregisters or ignores service endpoint * Add some comments as a clean up * Refactor deregisterServiceOnAllAgents to return the same as Reconcile * Add a warning in connect-init about running multiple services which point to the same pod. * Add a line break before the multiservice warning * Move labelConnectIgnore to annotations * Inline the check on hasBeenInjected * Refactor address mapping to a function * Test mapAddresses * connect-ignore -> service-ignore * Clarify Reconcile comment * Add CHANGELOG entry * Stub out test * Stub out isRegistered * Just a baby grammar fix * Undo deregister refactor * Pull the deregistration back into the normal path * Extend test cases for mapAddresses * Move the stubbed out test down * Add comment to deregistration process * Fix connect ignore to service ignore * Test service-ignore * Delete isRegistered * Update control-plane/connect-inject/endpoints_controller.go Co-authored-by: Kyle Schochenmaier * Update control-plane/connect-inject/endpoints_controller.go Co-authored-by: Kyle Schochenmaier * Update control-plane/subcommand/connect-init/command.go Co-authored-by: Kyle Schochenmaier * Update CHANGELOG.md Co-authored-by: Kyle Schochenmaier * Use strconv.ParseBool on label value * Separate error for multiple Consul services registered. * Update control-plane/connect-inject/endpoints_controller_test.go Co-authored-by: Iryna Shustava * Split out isLabeledIgnore * Rework test to not run Reconcile twice * Clean up space on CHANGELOG * Add logging when an endpoint is getting ignored * Fix comment on service ignore test * Add proxy service to test * Update control-plane/subcommand/connect-init/command.go Co-authored-by: Kyle Schochenmaier Co-authored-by: Kyle Schochenmaier Co-authored-by: Iryna Shustava --- CHANGELOG.md | 2 + control-plane/connect-inject/annotations.go | 4 + .../connect-inject/endpoints_controller.go | 63 ++++-- .../endpoints_controller_test.go | 211 ++++++++++++++++++ .../subcommand/connect-init/command.go | 6 + 5 files changed, 266 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd3780d5d4..ddf6aee220 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,9 @@ BREAKING CHANGES: IMPROVEMENTS: * CLI * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] +* Control Plane * Add a label "managed-by" to every secret the control-plane creates. Only delete said secrets on an uninstall. [[GH-835](https://github.com/hashicorp/consul-k8s/pull/835)] + * Add support for labeling a Kubernetes service with `consul.hashicorp.com/service-ignore` to prevent services from being registered in Consul. [[GH-858](https://github.com/hashicorp/consul-k8s/pull/858)] BUG FIXES: * Control Plane: diff --git a/control-plane/connect-inject/annotations.go b/control-plane/connect-inject/annotations.go index ccc9ab6341..c8bf650e08 100644 --- a/control-plane/connect-inject/annotations.go +++ b/control-plane/connect-inject/annotations.go @@ -122,6 +122,10 @@ const ( // webhook/handler. annotationOriginalPod = "consul.hashicorp.com/original-pod" + // labelServiceIgnore is a label that can be added to a service to prevent it from being + // registered with Consul. + labelServiceIgnore = "consul.hashicorp.com/service-ignore" + // injected is used as the annotation value for annotationInjected. injected = "injected" diff --git a/control-plane/connect-inject/endpoints_controller.go b/control-plane/connect-inject/endpoints_controller.go index 4e6a2b73ba..78b1748d4b 100644 --- a/control-plane/connect-inject/endpoints_controller.go +++ b/control-plane/connect-inject/endpoints_controller.go @@ -6,6 +6,7 @@ import ( "fmt" "net" "regexp" + "strconv" "strings" mapset "github.com/deckarep/golang-set" @@ -117,10 +118,13 @@ type EndpointsController struct { context.Context } +// Reconcile reads the state of an Endpoints object for a Kubernetes Service and reconciles Consul services which +// correspond to the Kubernetes Service. These events are driven by changes to the Pods backing the Kube service. func (r *EndpointsController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { var errs error var serviceEndpoints corev1.Endpoints + // Ignore the request if the namespace of the endpoint is not allowed. if shouldIgnore(req.Namespace, r.DenyK8sNamespacesSet, r.AllowK8sNamespacesSet) { return ctrl.Result{}, nil } @@ -137,15 +141,22 @@ func (r *EndpointsController) Reconcile(ctx context.Context, req ctrl.Request) ( if k8serrors.IsNotFound(err) { // Deregister all instances in Consul for this service. The function deregisterServiceOnAllAgents handles // the case where the Consul service name is different from the Kubernetes service name. - if err = r.deregisterServiceOnAllAgents(ctx, req.Name, req.Namespace, nil, endpointPods); err != nil { - return ctrl.Result{}, err - } - return ctrl.Result{}, nil + err = r.deregisterServiceOnAllAgents(ctx, req.Name, req.Namespace, nil, endpointPods) + return ctrl.Result{}, err } else if err != nil { r.Log.Error(err, "failed to get Endpoints", "name", req.Name, "ns", req.Namespace) return ctrl.Result{}, err } + // If the endpoints object has the label "consul.hashicorp.com/service-ignore" set to true, deregister all instances in Consul for this service. + // It is possible that the endpoints object has never been registered, in which case deregistration is a no-op. + if isLabeledIgnore(serviceEndpoints.Labels) { + // We always deregister the service to handle the case where a user has registered the service, then added the label later. + r.Log.Info("Ignoring endpoint labeled with `consul.hashicorp.com/service-ignore: \"true\"`", "name", req.Name, "namespace", req.Namespace) + err = r.deregisterServiceOnAllAgents(ctx, req.Name, req.Namespace, nil, endpointPods) + return ctrl.Result{}, err + } + r.Log.Info("retrieved", "name", serviceEndpoints.Name, "ns", serviceEndpoints.Namespace) // endpointAddressMap stores every IP that corresponds to a Pod in the Endpoints object. It is used to compare @@ -154,17 +165,7 @@ func (r *EndpointsController) Reconcile(ctx context.Context, req ctrl.Request) ( // Register all addresses of this Endpoints object as service instances in Consul. for _, subset := range serviceEndpoints.Subsets { - // Combine all addresses to a map, with a value indicating whether an address is ready or not. - allAddresses := make(map[corev1.EndpointAddress]string) - for _, readyAddress := range subset.Addresses { - allAddresses[readyAddress] = api.HealthPassing - } - - for _, notReadyAddress := range subset.NotReadyAddresses { - allAddresses[notReadyAddress] = api.HealthCritical - } - - for address, healthStatus := range allAddresses { + for address, healthStatus := range mapAddresses(subset) { if address.TargetRef != nil && address.TargetRef.Kind == "Pod" { endpointPods.Add(address.TargetRef.Name) if err := r.registerServicesAndHealthCheck(ctx, serviceEndpoints, address, healthStatus, endpointAddressMap); err != nil { @@ -200,7 +201,7 @@ func (r *EndpointsController) SetupWithManager(mgr ctrl.Manager) error { ).Complete(r) } -// registerServicesAndHealthCheck creates Consul registrations for the service and proxy and register them with Consul. +// registerServicesAndHealthCheck creates Consul registrations for the service and proxy and registers them with Consul. // It also upserts a Kubernetes health check for the service based on whether the endpoint address is ready. func (r *EndpointsController) registerServicesAndHealthCheck(ctx context.Context, serviceEndpoints corev1.Endpoints, address corev1.EndpointAddress, healthStatus string, endpointAddressMap map[string]bool) error { // Get pod associated with this address. @@ -726,6 +727,7 @@ func (r *EndpointsController) deregisterServiceOnAllAgents(ctx context.Context, } } } + return nil } @@ -1004,10 +1006,31 @@ func (r *EndpointsController) consulNamespace(namespace string) string { // hasBeenInjected checks the value of the status annotation and returns true if the Pod has been injected. func hasBeenInjected(pod corev1.Pod) bool { - if anno, ok := pod.Annotations[keyInjectStatus]; ok { - if anno == injected { - return true - } + if anno, ok := pod.Annotations[keyInjectStatus]; ok && anno == injected { + return true } return false } + +// mapAddresses combines all addresses to a mapping of address to its health status. +func mapAddresses(addresses corev1.EndpointSubset) map[corev1.EndpointAddress]string { + m := make(map[corev1.EndpointAddress]string) + for _, readyAddress := range addresses.Addresses { + m[readyAddress] = api.HealthPassing + } + + for _, notReadyAddress := range addresses.NotReadyAddresses { + m[notReadyAddress] = api.HealthCritical + } + + return m +} + +// isLabeledIgnore checks the value of the label `consul.hashicorp.com/service-ignore` and returns true if the +// label exists and is "truthy". Otherwise, it returns false. +func isLabeledIgnore(labels map[string]string) bool { + value, labelExists := labels[labelServiceIgnore] + shouldIgnore, err := strconv.ParseBool(value) + + return shouldIgnore && labelExists && err == nil +} diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index 5f1a0dadd8..de021ec198 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -2717,6 +2717,149 @@ func TestReconcileDeleteEndpoint(t *testing.T) { } } +// TestReconcileIgnoresServiceIgnoreLabel tests that the endpoints controller correctly ignores services +// with the service-ignore label and deregisters services previously registered if the service-ignore +// label is added. +func TestReconcileIgnoresServiceIgnoreLabel(t *testing.T) { + t.Parallel() + nodeName := "test-node" + serviceName := "service-ignored" + namespace := "default" + + cases := map[string]struct { + svcInitiallyRegistered bool + serviceLabels map[string]string + expectedNumSvcInstances int + }{ + "Registered endpoint with label is deregistered.": { + svcInitiallyRegistered: true, + serviceLabels: map[string]string{ + labelServiceIgnore: "true", + }, + expectedNumSvcInstances: 0, + }, + "Not registered endpoint with label is never registered": { + svcInitiallyRegistered: false, + serviceLabels: map[string]string{ + labelServiceIgnore: "true", + }, + expectedNumSvcInstances: 0, + }, + "Registered endpoint without label is unaffected": { + svcInitiallyRegistered: true, + serviceLabels: map[string]string{}, + expectedNumSvcInstances: 1, + }, + "Not registered endpoint without label is registered": { + svcInitiallyRegistered: false, + serviceLabels: map[string]string{}, + expectedNumSvcInstances: 1, + }, + } + + for name, tt := range cases { + t.Run(name, func(t *testing.T) { + // Set up the fake Kubernetes client with an endpoint, pod, consul client, and the default namespace. + endpoint := &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: serviceName, + Namespace: namespace, + Labels: tt.serviceLabels, + }, + Subsets: []corev1.EndpointSubset{ + { + Addresses: []corev1.EndpointAddress{ + { + IP: "1.2.3.4", + NodeName: &nodeName, + TargetRef: &corev1.ObjectReference{ + Kind: "Pod", + Name: "pod1", + Namespace: namespace, + }, + }, + }, + }, + }, + } + pod1 := createPod("pod1", "1.2.3.4", true, true) + fakeClientPod := createPod("fake-consul-client", "127.0.0.1", false, true) + fakeClientPod.Labels = map[string]string{"component": "client", "app": "consul", "release": "consul"} + ns := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}} + k8sObjects := []runtime.Object{endpoint, pod1, fakeClientPod, &ns} + fakeClient := fake.NewClientBuilder().WithRuntimeObjects(k8sObjects...).Build() + + // Create test Consul server. + consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.NodeName = nodeName }) + require.NoError(t, err) + defer consul.Stop() + consul.WaitForServiceIntentions(t) + cfg := &api.Config{Address: consul.HTTPAddr} + consulClient, err := api.NewClient(cfg) + require.NoError(t, err) + addr := strings.Split(consul.HTTPAddr, ":") + consulPort := addr[1] + + // Set up the initial Consul services. + if tt.svcInitiallyRegistered { + err = consulClient.Agent().ServiceRegister(&api.AgentServiceRegistration{ + ID: "pod1-" + serviceName, + Name: serviceName, + Port: 0, + Address: "1.2.3.4", + Meta: map[string]string{ + "k8s-namespace": namespace, + "k8s-service-name": serviceName, + "managed-by": "consul-k8s-endpoints-controller", + "pod-name": "pod1", + }, + }) + require.NoError(t, err) + err = consulClient.Agent().ServiceRegister(&api.AgentServiceRegistration{ + ID: "pod1-sidecar-proxy-" + serviceName, + Name: serviceName + "-sidecar-proxy", + Port: 0, + Meta: map[string]string{ + "k8s-namespace": namespace, + "k8s-service-name": serviceName, + "managed-by": "consul-k8s-endpoints-controller", + "pod-name": "pod1", + }, + }) + require.NoError(t, err) + } + + // Create the endpoints controller. + ep := &EndpointsController{ + Client: fakeClient, + Log: logrtest.TestLogger{T: t}, + ConsulClient: consulClient, + ConsulPort: consulPort, + ConsulScheme: "http", + AllowK8sNamespacesSet: mapset.NewSetWith("*"), + DenyK8sNamespacesSet: mapset.NewSetWith(), + ReleaseName: "consul", + ReleaseNamespace: namespace, + ConsulClientCfg: cfg, + } + + // Run the reconcile process to deregister the service if it was registered before. + namespacedName := types.NamespacedName{Namespace: namespace, Name: serviceName} + resp, err := ep.Reconcile(context.Background(), ctrl.Request{NamespacedName: namespacedName}) + require.NoError(t, err) + require.False(t, resp.Requeue) + + // Check that the correct number of services are registered with Consul. + serviceInstances, _, err := consulClient.Catalog().Service(serviceName, "", nil) + require.NoError(t, err) + require.Len(t, serviceInstances, tt.expectedNumSvcInstances) + proxyServiceInstances, _, err := consulClient.Catalog().Service(serviceName+"-sidecar-proxy", "", nil) + require.NoError(t, err) + require.Len(t, proxyServiceInstances, tt.expectedNumSvcInstances) + }) + } +} + func TestFilterAgentPods(t *testing.T) { t.Parallel() cases := map[string]struct { @@ -4761,6 +4904,74 @@ func TestGetTokenMetaFromDescription(t *testing.T) { } } +func TestMapAddresses(t *testing.T) { + t.Parallel() + cases := map[string]struct { + addresses corev1.EndpointSubset + expected map[corev1.EndpointAddress]string + }{ + "ready and not ready addresses": { + addresses: corev1.EndpointSubset{ + Addresses: []corev1.EndpointAddress{ + {Hostname: "host1"}, + {Hostname: "host2"}, + }, + NotReadyAddresses: []corev1.EndpointAddress{ + {Hostname: "host3"}, + {Hostname: "host4"}, + }, + }, + expected: map[corev1.EndpointAddress]string{ + {Hostname: "host1"}: api.HealthPassing, + {Hostname: "host2"}: api.HealthPassing, + {Hostname: "host3"}: api.HealthCritical, + {Hostname: "host4"}: api.HealthCritical, + }, + }, + "ready addresses only": { + addresses: corev1.EndpointSubset{ + Addresses: []corev1.EndpointAddress{ + {Hostname: "host1"}, + {Hostname: "host2"}, + {Hostname: "host3"}, + {Hostname: "host4"}, + }, + NotReadyAddresses: []corev1.EndpointAddress{}, + }, + expected: map[corev1.EndpointAddress]string{ + {Hostname: "host1"}: api.HealthPassing, + {Hostname: "host2"}: api.HealthPassing, + {Hostname: "host3"}: api.HealthPassing, + {Hostname: "host4"}: api.HealthPassing, + }, + }, + "not ready addresses only": { + addresses: corev1.EndpointSubset{ + Addresses: []corev1.EndpointAddress{}, + NotReadyAddresses: []corev1.EndpointAddress{ + {Hostname: "host1"}, + {Hostname: "host2"}, + {Hostname: "host3"}, + {Hostname: "host4"}, + }, + }, + expected: map[corev1.EndpointAddress]string{ + {Hostname: "host1"}: api.HealthCritical, + {Hostname: "host2"}: api.HealthCritical, + {Hostname: "host3"}: api.HealthCritical, + {Hostname: "host4"}: api.HealthCritical, + }, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + actual := mapAddresses(c.addresses) + require.Equal(t, c.expected, actual) + }) + } +} + func createPod(name, ip string, inject bool, managedByEndpointsController bool) *corev1.Pod { pod := &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ diff --git a/control-plane/subcommand/connect-init/command.go b/control-plane/subcommand/connect-init/command.go index 18271e6b05..3d30710107 100644 --- a/control-plane/subcommand/connect-init/command.go +++ b/control-plane/subcommand/connect-init/command.go @@ -225,6 +225,12 @@ func (c *Command) Run(args []string) int { c.logger.Info("Check to ensure a Kubernetes service has been created for this application." + " If your pod is not starting also check the connect-inject deployment logs.") } + if len(serviceList) > 2 { + c.logger.Error("There are multiple Consul services registered for this pod when there must only be one." + + " Check if there are multiple Kubernetes services selecting this pod and add the label" + + " `consul.hashicorp.com/service-ignore: \"true\"` to all services except the one used by Consul for handling requests.") + } + return fmt.Errorf("did not find correct number of services: %d", len(serviceList)) } for _, svc := range serviceList { From 68c89ac7ef5fe53a3bb52eb56fba56e9cd6228a9 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 2 Dec 2021 10:27:41 -0500 Subject: [PATCH 164/418] Do not mount consul-ca-cert to partition init if externalServers.useSystemRoots is true (#885) * Do not mount consul-ca-cert to partition init if externalServers.useSystemRoots is true * Update CHANGELOG --- CHANGELOG.md | 4 ++ .../consul/templates/partition-init-job.yaml | 12 +++-- charts/consul/test/unit/client-daemonset.bats | 2 + .../consul/test/unit/partition-init-job.bats | 54 +++++++++++++++++++ 4 files changed, 67 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddf6aee220..1165ade1f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ BUG FIXES: * Control Plane: * Add a workaround to check that the ACL token is replicated to other Consul servers. [[GH-862](https://github.com/hashicorp/consul-k8s/issues/862)] +BUG FIXES: +* Helm Chart + * Admin Partitions **(Consul Enterprise only)**: Do not mount Consul CA certs to partition-init job if `externalServers.useSystemRoots` is `true`. [[GH-885](https://github.com/hashicorp/consul-k8s/pull/885)] + ## 0.37.0 (November 18, 2021) BREAKING CHANGES: diff --git a/charts/consul/templates/partition-init-job.yaml b/charts/consul/templates/partition-init-job.yaml index 3bdfa58a23..fe5f26fd86 100644 --- a/charts/consul/templates/partition-init-job.yaml +++ b/charts/consul/templates/partition-init-job.yaml @@ -1,6 +1,7 @@ {{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} -{{- if (and .Values.global.adminPartitions.enabled (not $serverEnabled)) }} +{{- if (and .Values.global.adminPartitions.enabled (not $serverEnabled) (ne .Values.global.adminPartitions.name "default")) }} {{- template "consul.reservedNamesFailer" (list .Values.global.adminPartitions.name "global.adminPartitions.name") }} +{{- if and (not .Values.externalServers.enabled) (ne .Values.global.adminPartitions.name "default") }}{{ fail "externalServers.enabled needs to be true and configured to create a non-default partition." }}{{ end -}} apiVersion: batch/v1 kind: Job metadata: @@ -31,6 +32,7 @@ spec: restartPolicy: Never serviceAccountName: {{ template "consul.fullname" . }}-partition-init {{- if .Values.global.tls.enabled }} + {{- if not .Values.externalServers.useSystemRoots }} volumes: - name: consul-ca-cert secret: @@ -43,6 +45,7 @@ spec: - key: {{ default "tls.crt" .Values.global.tls.caCert.secretKey }} path: tls.crt {{- end }} + {{- end }} containers: - name: partition-init-job image: {{ .Values.global.imageK8S }} @@ -59,17 +62,17 @@ spec: key: {{ .Values.global.acls.bootstrapToken.secretKey }} {{- end }} {{- if .Values.global.tls.enabled }} + {{- if not .Values.externalServers.useSystemRoots }} volumeMounts: - name: consul-ca-cert mountPath: /consul/tls/ca readOnly: true {{- end }} + {{- end }} command: - "/bin/sh" - "-ec" - | - CONSUL_FULLNAME="{{template "consul.fullname" . }}" - consul-k8s-control-plane partition-init \ -log-level={{ .Values.global.logLevel }} \ -log-json={{ .Values.global.logJSON }} \ @@ -82,9 +85,8 @@ spec: {{- if .Values.global.tls.enabled }} -use-https \ + {{- if not .Values.externalServers.useSystemRoots }} -consul-ca-cert=/consul/tls/ca/tls.crt \ - {{- if not .Values.externalServers.enabled }} - -server-port=8501 \ {{- end }} {{- if .Values.externalServers.tlsServerName }} -consul-tls-server-name={{ .Values.externalServers.tlsServerName }} \ diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index 62c27a0106..20b5aac856 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1446,6 +1446,8 @@ rollingUpdate: --set 'global.adminPartitions.enabled=true' \ --set 'global.adminPartitions.name=test' \ --set 'server.enabled=false' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=bar' \ . | tee /dev/stderr | yq -c -r '.spec.template.spec.containers[0].command | join(" ") | contains("partition = \"test\"")' | tee /dev/stderr) [ "${actual}" = "true" ] diff --git a/charts/consul/test/unit/partition-init-job.bats b/charts/consul/test/unit/partition-init-job.bats index 5dc60e9888..ca1a9a6d37 100644 --- a/charts/consul/test/unit/partition-init-job.bats +++ b/charts/consul/test/unit/partition-init-job.bats @@ -15,6 +15,9 @@ load _helpers -s templates/partition-init-job.yaml \ --set 'global.adminPartitions.enabled=true' \ --set 'server.enabled=false' \ + --set 'global.adminPartitions.name=bar' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=foo' \ . | tee /dev/stderr | yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] @@ -29,6 +32,15 @@ load _helpers . } +@test "partitionInit/Job: disabled with global.adminPartitions.enabled=true and adminPartition.name = default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'server.enabled=false' \ + . +} + @test "partitionInit/Job: disabled with global.adminPartitions.enabled=true and global.enabled = true" { cd `chart_dir` assert_empty helm template \ @@ -47,6 +59,18 @@ load _helpers . } +@test "partitionInit/Job: fails if externalServers.enabled = false with non-default adminPartition" { + cd `chart_dir` + run helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=bar' \ + --set 'server.enabled=false' \ + --set 'externalServers.enabled=false' . + [ "$status" -eq 1 ] + [[ "$output" =~ "externalServers.enabled needs to be true and configured to create a non-default partition." ]] +} + #-------------------------------------------------------------------- # global.tls.enabled @@ -57,6 +81,9 @@ load _helpers --set 'global.enabled=false' \ --set 'global.adminPartitions.enabled=true' \ --set 'global.tls.enabled=true' \ + --set 'global.adminPartitions.name=bar' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=foo' \ . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].command' | tee /dev/stderr) @@ -71,12 +98,34 @@ load _helpers [ "${actual}" = "true" ] } +@test "partitionInit/Job: does not set consul ca cert or server-port when .externalServers.useSystemRoots is true" { + cd `chart_dir` + local command=$(helm template \ + -s templates/partition-init-job.yaml \ + --set 'global.enabled=false' \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=bar' \ + --set 'global.tls.enabled=true' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=foo' \ + --set 'externalServers.useSystemRoots=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].command' | tee /dev/stderr) + + local actual + actual=$(echo $command | jq -r '. | any(contains("-consul-ca-cert=/consul/tls/ca/tls.crt"))' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + @test "partitionInit/Job: can overwrite CA secret with the provided one" { cd `chart_dir` local ca_cert_volume=$(helm template \ -s templates/partition-init-job.yaml \ --set 'global.enabled=false' \ --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=bar' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.caCert.secretName=foo-ca-cert' \ --set 'global.tls.caCert.secretKey=key' \ @@ -104,6 +153,9 @@ load _helpers -s templates/partition-init-job.yaml \ --set 'global.enabled=false' \ --set 'global.adminPartitions.enabled=true' \ + --set 'global.adminPartitions.name=bar' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=foo' \ --set 'global.acls.bootstrapToken.secretName=partition-token' \ --set 'global.acls.bootstrapToken.secretKey=token' \ . | tee /dev/stderr | @@ -142,6 +194,8 @@ reservedNameTest() { run helm template \ -s templates/partition-init-job.yaml \ --set 'global.enabled=false' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=foo' \ --set 'global.adminPartitions.enabled=true' \ --set "global.adminPartitions.name=$name" . From 5ba979b3fcd09bda5bccf1b991f9d6181b2e543c Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Thu, 2 Dec 2021 13:12:21 -0600 Subject: [PATCH 165/418] add a makefile target for parallel bats (#888) --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 481a58a142..90839e82fa 100644 --- a/Makefile +++ b/Makefile @@ -11,3 +11,7 @@ copy-crds-to-chart: # Deletes AWS resources left behind after failed acceptance tests. ci.aws-acceptance-test-cleanup: @cd hack/aws-acceptance-test-cleanup; go run ./... -auto-approve + +# Run bats tests in parallel from the root of the repository. +bats-tests: + bats --jobs 4 charts/consul/test/unit From 9ddce21d3922cd9492f3b5d2a5980b66432ef551 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Mon, 6 Dec 2021 10:10:18 -0800 Subject: [PATCH 166/418] Revert go.mod changes in CLI from PR #835 (#900) The cloud acceptance tests for the CLI have been failing (but passing in Kind) since merging 835. After reverting the whole PR and testing with several parts of that PR, it looks like the code itself wasn't causing issues, but rather the extensive go.mod updates. Those updates were not necessary for the PR (I was able to run go mod tidy with no changes), so I'm reverting those here so the tests will pass again. --- cli/go.mod | 138 ++++++++++--------------------- cli/go.sum | 239 ++++++++++++----------------------------------------- 2 files changed, 98 insertions(+), 279 deletions(-) diff --git a/cli/go.mod b/cli/go.mod index f0c0e8ae7f..3bb781f2e2 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -3,48 +3,33 @@ module github.com/hashicorp/consul-k8s/cli go 1.17 require ( - github.com/armon/go-radix v1.0.0 // indirect github.com/bgentry/speakeasy v0.1.0 github.com/cenkalti/backoff v2.2.1+incompatible - github.com/fatih/color v1.12.0 - github.com/google/go-cmp v0.5.6 // indirect + github.com/fatih/color v1.9.0 github.com/hashicorp/consul-k8s/charts v0.0.0-00010101000000-000000000000 github.com/hashicorp/go-hclog v0.16.2 - github.com/hashicorp/go-multierror v1.1.0 // indirect - github.com/imdario/mergo v0.3.12 // indirect github.com/kr/text v0.2.0 - github.com/mattn/go-isatty v0.0.13 + github.com/mattn/go-isatty v0.0.12 github.com/mitchellh/cli v1.1.2 github.com/olekukonko/tablewriter v0.0.4 - github.com/onsi/gomega v1.15.0 // indirect - github.com/posener/complete v1.2.3 + github.com/posener/complete v1.1.1 github.com/stretchr/testify v1.7.0 - go.starlark.net v0.0.0-20200707032745-474f21a9602d // indirect - golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect - google.golang.org/appengine v1.6.7 // indirect helm.sh/helm/v3 v3.6.1 - k8s.io/api v0.22.2 - k8s.io/apiextensions-apiserver v0.22.2 // indirect - k8s.io/apimachinery v0.22.2 + k8s.io/api v0.21.2 + k8s.io/apimachinery v0.21.2 k8s.io/cli-runtime v0.21.0 - k8s.io/client-go v0.22.2 - rsc.io/letsencrypt v0.0.3 // indirect + k8s.io/client-go v0.21.2 sigs.k8s.io/yaml v1.2.0 ) require ( cloud.google.com/go v0.54.0 // indirect - github.com/Azure/azure-sdk-for-go v44.0.0+incompatible // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.18 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect - github.com/Azure/go-autorest/autorest/azure/auth v0.5.0 // indirect - github.com/Azure/go-autorest/autorest/azure/cli v0.4.0 // indirect + github.com/Azure/go-autorest/autorest v0.11.12 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.5 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect - github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect - github.com/Azure/go-autorest/autorest/validation v0.3.0 // indirect - github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/logger v0.2.0 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/BurntSushi/toml v0.3.1 // indirect github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect @@ -58,10 +43,8 @@ require ( github.com/Microsoft/hcsshim v0.8.14 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect - github.com/armon/go-metrics v0.3.9 // indirect - github.com/armon/go-radix v1.0.0 // indirect + github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 // indirect github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect - github.com/aws/aws-sdk-go v1.27.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 // indirect @@ -70,9 +53,6 @@ require ( github.com/cyphar/filepath-securejoin v0.2.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/deislabs/oras v0.11.1 // indirect - github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba // indirect - github.com/digitalocean/godo v1.10.0 // indirect - github.com/dimchansky/utfbom v1.1.0 // indirect github.com/docker/cli v20.10.5+incompatible // indirect github.com/docker/distribution v2.7.1+incompatible // indirect github.com/docker/docker v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible // indirect @@ -80,131 +60,103 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/evanphx/json-patch v4.11.0+incompatible // indirect + github.com/evanphx/json-patch v4.9.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect - github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect + github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect github.com/go-errors/errors v1.0.1 // indirect github.com/go-logr/logr v0.4.0 // indirect - github.com/go-logr/zapr v0.4.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.5 // indirect + github.com/go-openapi/jsonpointer v0.19.3 // indirect + github.com/go-openapi/jsonreference v0.19.3 // indirect github.com/go-openapi/spec v0.19.5 // indirect - github.com/go-openapi/swag v0.19.14 // indirect + github.com/go-openapi/swag v0.19.5 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/btree v1.0.1 // indirect - github.com/google/go-cmp v0.5.6 // indirect - github.com/google/go-querystring v1.0.0 // indirect + github.com/google/btree v1.0.0 // indirect + github.com/google/go-cmp v0.5.5 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.1.2 // indirect - github.com/googleapis/gax-go/v2 v2.0.5 // indirect - github.com/googleapis/gnostic v0.5.5 // indirect - github.com/gophercloud/gophercloud v0.1.0 // indirect + github.com/googleapis/gnostic v0.4.1 // indirect github.com/gorilla/mux v1.7.3 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect - github.com/hashicorp/consul/api v1.10.1-0.20211101164201-d47b7311b8bb // indirect github.com/hashicorp/errwrap v1.0.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f // indirect - github.com/hashicorp/go-immutable-radix v1.3.0 // indirect github.com/hashicorp/go-multierror v1.1.0 // indirect - github.com/hashicorp/go-rootcerts v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.1 // indirect - github.com/hashicorp/mdns v1.0.1 // indirect - github.com/hashicorp/serf v0.9.5 // indirect - github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443 // indirect github.com/huandu/xstrings v1.3.2 // indirect - github.com/imdario/mergo v0.3.12 // indirect + github.com/imdario/mergo v0.3.11 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect github.com/jmoiron/sqlx v1.3.1 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f // indirect - github.com/json-iterator/go v1.1.11 // indirect + github.com/json-iterator/go v1.1.10 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/linode/linodego v0.7.1 // indirect - github.com/mailru/easyjson v0.7.6 // indirect + github.com/mailru/easyjson v0.7.0 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-runewidth v0.0.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect - github.com/miekg/dns v1.1.26 // indirect github.com/mitchellh/copystructure v1.1.1 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect - github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect + github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.1 // indirect github.com/opencontainers/runc v0.1.1 // indirect - github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.11.0 // indirect + github.com/prometheus/client_golang v1.7.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.26.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect - github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 // indirect + github.com/prometheus/common v0.10.0 // indirect + github.com/prometheus/procfs v0.2.0 // indirect github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 // indirect github.com/russross/blackfriday v1.5.2 // indirect github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect - github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.1.3 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible // indirect - github.com/vmware/govmomi v0.18.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect go.opencensus.io v0.22.3 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.19.0 // indirect + go.starlark.net v0.0.0-20200707032745-474f21a9602d // indirect golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect - golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect + golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect + golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.6 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - google.golang.org/api v0.20.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect - google.golang.org/grpc v1.38.0 // indirect + golang.org/x/text v0.3.4 // indirect + golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect + google.golang.org/appengine v1.6.5 // indirect + google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect + google.golang.org/grpc v1.33.1 // indirect google.golang.org/protobuf v1.26.0 // indirect gopkg.in/gorp.v1 v1.7.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/resty.v1 v1.12.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/apiextensions-apiserver v0.22.2 // indirect - k8s.io/apiserver v0.22.2 // indirect - k8s.io/component-base v0.22.2 // indirect - k8s.io/klog/v2 v2.9.0 // indirect - k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + k8s.io/apiextensions-apiserver v0.21.0 // indirect + k8s.io/apiserver v0.21.0 // indirect + k8s.io/component-base v0.21.0 // indirect + k8s.io/klog/v2 v2.8.0 // indirect + k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 // indirect k8s.io/kubectl v0.21.0 // indirect - k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect - sigs.k8s.io/controller-runtime v0.10.2 // indirect + k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect + rsc.io/letsencrypt v0.0.3 // indirect sigs.k8s.io/kustomize/api v0.8.5 // indirect sigs.k8s.io/kustomize/kyaml v0.10.15 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.0 // indirect ) // This replace directive is to avoid having to manually bump the version of the charts module upon changes to the Helm diff --git a/cli/go.sum b/cli/go.sum index 6ee5e7cf6a..bd14d14daa 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -25,26 +25,21 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE= github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= -github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= +github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= -github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= -github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= -github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -93,17 +88,14 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= @@ -113,7 +105,6 @@ github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQ github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -137,8 +128,6 @@ github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= @@ -151,11 +140,7 @@ github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmE github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= -github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59 h1:qWj4qVYZ95vLWwqyNJCQg7rDsG5wPdze0UaPolH7DUk= github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM= @@ -180,7 +165,6 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -237,32 +221,25 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= -github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= -github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= +github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= -github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -275,7 +252,6 @@ github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -294,15 +270,13 @@ github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= +github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= -github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -325,9 +299,8 @@ github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= -github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= @@ -336,7 +309,6 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= github.com/gobuffalo/envy v1.7.1 h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8= github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= @@ -350,7 +322,6 @@ github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kE github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godror/godror v0.13.3/go.mod h1:2ouUT4kdhUBk7TAkHWD4SN0CdI0pgEQbo8FVHhbSKWg= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= @@ -366,9 +337,8 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -388,15 +358,13 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -404,9 +372,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -425,10 +392,8 @@ github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= -github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= -github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo= @@ -446,11 +411,9 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWet github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -473,12 +436,14 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= @@ -486,9 +451,8 @@ github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= @@ -500,21 +464,15 @@ github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXL github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -549,9 +507,8 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -562,9 +519,9 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= -github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= @@ -600,9 +557,8 @@ github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY7 github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= -github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= -github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -616,7 +572,6 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= @@ -628,9 +583,6 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -642,18 +594,12 @@ github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FW github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= -github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -692,9 +638,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -702,9 +647,8 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -719,9 +663,8 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -729,13 +672,11 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= @@ -767,7 +708,6 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -792,7 +732,6 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -811,7 +750,6 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -830,7 +768,6 @@ github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6Ut github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE= @@ -842,16 +779,8 @@ github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wK go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= -go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= -go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= -go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -862,33 +791,17 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= -go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.starlark.net v0.0.0-20200707032745-474f21a9602d h1:uFqwFYlX7d5ZSp+IqhXxct0SybXrTzEBDvb2CkEhPBs= go.starlark.net v0.0.0-20200707032745-474f21a9602d/go.mod h1:f0znQkUKRrkk36XxWbGjMqQM8wGv/xHBVE2qc3B5oFU= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -931,7 +844,6 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -941,7 +853,6 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -974,17 +885,10 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= -golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -998,9 +902,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1025,7 +928,6 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1033,7 +935,6 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1047,24 +948,16 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -1076,17 +969,14 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1113,7 +1003,6 @@ golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1133,10 +1022,8 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1159,9 +1046,8 @@ google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1182,13 +1068,9 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4 google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1203,12 +1085,8 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1231,6 +1109,7 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= @@ -1247,7 +1126,6 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1255,10 +1133,8 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= @@ -1274,51 +1150,43 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= -k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= -k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= +k8s.io/api v0.21.2 h1:vz7DqmRsXTCSa6pNxXwQ1IYeAZgdIsua+DZU+o+SX3Y= +k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU= +k8s.io/apiextensions-apiserver v0.21.0 h1:Nd4uBuweg6ImzbxkC1W7xUNZcCV/8Vt10iTdTIVF3hw= k8s.io/apiextensions-apiserver v0.21.0/go.mod h1:gsQGNtGkc/YoDG9loKI0V+oLZM4ljRPjc/sql5tmvzc= -k8s.io/apiextensions-apiserver v0.22.2 h1:zK7qI8Ery7j2CaN23UCFaC1hj7dMiI87n01+nKuewd4= -k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= -k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= -k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= +k8s.io/apimachinery v0.21.2 h1:vezUc/BHqWlQDnZ+XkrpXSmnANSLbpnlpwo0Lhk0gpc= +k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM= +k8s.io/apiserver v0.21.0 h1:1hWMfsz+cXxB77k6/y0XxWxwl6l9OF26PC9QneUVn1Q= k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg= -k8s.io/apiserver v0.22.2 h1:TdIfZJc6YNhu2WxeAOWq1TvukHF0Sfx0+ln4XK9qnL4= -k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= k8s.io/cli-runtime v0.21.0 h1:/V2Kkxtf6x5NI2z+Sd/mIrq4FQyQ8jzZAUD6N5RnN7Y= k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo= k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= -k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= -k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= +k8s.io/client-go v0.21.2 h1:Q1j4L/iMN4pTw6Y4DWppBoUxgKO8LbffEMVEV00MUp0= +k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA= k8s.io/code-generator v0.21.0/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= -k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= +k8s.io/component-base v0.21.0 h1:tLLGp4BBjQaCpS/KiuWh7m2xqvAdsxLm4ATxHSe5Zpg= k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw= -k8s.io/component-base v0.22.2 h1:vNIvE0AIrLhjX8drH0BgCNJcR4QZxMXcJzBsDplDx9M= -k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= k8s.io/component-helpers v0.21.0/go.mod h1:tezqefP7lxfvJyR+0a+6QtVrkZ/wIkyMLK4WcQ3Cj8U= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= -k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kubectl v0.21.0 h1:WZXlnG/yjcE4LWO2g6ULjFxtzK6H1TKzsfaBFuVIhNg= k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks= k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= -k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/letsencrypt v0.0.3 h1:H7xDfhkaFFSYEJlKeq38RwX2jYcnTeHuDQyT+mMNMwM= rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/kustomize/api v0.8.5 h1:bfCXGXDAbFbb/Jv5AhMj2BB8a5VAJuuQ5/KU69WtDjQ= sigs.k8s.io/kustomize/api v0.8.5/go.mod h1:M377apnKT5ZHJS++6H4rQoCHmWtt6qTpp3mbe7p6OLY= sigs.k8s.io/kustomize/cmd/config v0.9.7/go.mod h1:MvXCpHs77cfyxRmCNUQjIqCmZyYsbn5PyQpWiq44nW0= @@ -1326,9 +1194,8 @@ sigs.k8s.io/kustomize/kustomize/v4 v4.0.5/go.mod h1:C7rYla7sI8EnxHE/xEhRBSHMNfcL sigs.k8s.io/kustomize/kyaml v0.10.15 h1:dSLgG78KyaxN4HylPXdK+7zB3k7sW6q3IcCmcfKA+aI= sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From e0f3b71702a9083798d417ae17cb7857eb4c4b00 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Mon, 6 Dec 2021 14:26:29 -0500 Subject: [PATCH 167/418] Fail if partitions enabled with federation (#892) * Fail if both adminPartitions and wan federation are enabled. * Update CHANGELOG and fix indentation. --- CHANGELOG.md | 13 +++++++------ charts/consul/templates/client-daemonset.yaml | 1 + charts/consul/templates/server-statefulset.yaml | 1 + charts/consul/test/unit/client-daemonset.bats | 12 ++++++++++++ charts/consul/test/unit/server-statefulset.bats | 15 +++++++++++++++ 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1165ade1f4..873d49b793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,21 @@ ## UNRELEASED BREAKING CHANGES: -* Update minimum go version for project to 1.17 [[GH-878](https://github.com/hashicorp/consul-k8s/pull/878)] +* Control Plane + * Update minimum go version for project to 1.17 [[GH-878](https://github.com/hashicorp/consul-k8s/pull/878)] IMPROVEMENTS: * CLI - * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] + * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] * Control Plane - * Add a label "managed-by" to every secret the control-plane creates. Only delete said secrets on an uninstall. [[GH-835](https://github.com/hashicorp/consul-k8s/pull/835)] + * Add a label "managed-by" to every secret the control-plane creates. Only delete said secrets on an uninstall. [[GH-835](https://github.com/hashicorp/consul-k8s/pull/835)] * Add support for labeling a Kubernetes service with `consul.hashicorp.com/service-ignore` to prevent services from being registered in Consul. [[GH-858](https://github.com/hashicorp/consul-k8s/pull/858)] +* Helm Chart + * Fail an installation/upgrade if WAN federation and Admin Partitions are both enabled. [[GH-892](https://github.com/hashicorp/consul-k8s/issues/892)] BUG FIXES: * Control Plane: - * Add a workaround to check that the ACL token is replicated to other Consul servers. [[GH-862](https://github.com/hashicorp/consul-k8s/issues/862)] - -BUG FIXES: + * Add a workaround to check that the ACL token is replicated to other Consul servers. [[GH-862](https://github.com/hashicorp/consul-k8s/issues/862)] * Helm Chart * Admin Partitions **(Consul Enterprise only)**: Do not mount Consul CA certs to partition-init job if `externalServers.useSystemRoots` is `true`. [[GH-885](https://github.com/hashicorp/consul-k8s/pull/885)] diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index c98265480d..3b03c17fa8 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -2,6 +2,7 @@ {{- if (and (and .Values.global.tls.enabled .Values.global.tls.httpsOnly) (and .Values.global.metrics.enabled .Values.global.metrics.enableAgentMetrics))}}{{ fail "global.metrics.enableAgentMetrics cannot be enabled if TLS (HTTPS only) is enabled" }}{{ end -}} {{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} {{- if (and .Values.global.adminPartitions.enabled $serverEnabled (ne .Values.global.adminPartitions.name "default"))}}{{ fail "global.adminPartitions.name has to be \"default\" in the server cluster" }}{{ end -}} +{{- if and .Values.global.federation.enabled .Values.global.adminPartitions.enabled }}{{ fail "If global.federation.enabled is true, global.adminPartitions.enabled must be false because they are mutually exclusive" }}{{ end }} # DaemonSet to run the Consul clients on every node. apiVersion: apps/v1 kind: DaemonSet diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 2380486793..af43a146e3 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -1,4 +1,5 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} +{{- if and .Values.global.federation.enabled .Values.global.adminPartitions.enabled }}{{ fail "If global.federation.enabled is true, global.adminPartitions.enabled must be false because they are mutually exclusive" }}{{ end }} {{- if and .Values.global.federation.enabled (not .Values.global.tls.enabled) }}{{ fail "If global.federation.enabled is true, global.tls.enabled must be true because federation is only supported with TLS enabled" }}{{ end }} {{- if and .Values.global.federation.enabled (not .Values.meshGateway.enabled) }}{{ fail "If global.federation.enabled is true, meshGateway.enabled must be true because mesh gateways are required for federation" }}{{ end }} {{- if and .Values.server.serverCert.secretName (not .Values.global.tls.caCert.secretName) }}{{ fail "If server.serverCert.secretName is provided, global.tls.caCert must also be provided" }}{{ end }} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index 20b5aac856..848243c8f8 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1465,6 +1465,18 @@ rollingUpdate: [[ "$output" =~ "global.adminPartitions.name has to be \"default\" in the server cluster" ]] } +@test "client/DaemonSet: federation and admin partitions cannot be enabled together" { + cd `chart_dir` + run helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.federation.enabled=true' \ + . + + [ "$status" -eq 1 ] + [[ "$output" =~ "If global.federation.enabled is true, global.adminPartitions.enabled must be false because they are mutually exclusive" ]] +} + #-------------------------------------------------------------------- # extraContainers diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index e11018f279..95a36423bd 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -52,6 +52,21 @@ load _helpers [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# admin-partitions + +@test "server/StatefulSet: federation and admin partitions cannot be enabled together" { + cd `chart_dir` + run helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.adminPartitions.enabled=true' \ + --set 'global.federation.enabled=true' \ + . + + [ "$status" -eq 1 ] + [[ "$output" =~ "If global.federation.enabled is true, global.adminPartitions.enabled must be false because they are mutually exclusive" ]] +} + #-------------------------------------------------------------------- # image From d08821b58b9e3a9a16a169dcc78491f3c4bca7df Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Mon, 6 Dec 2021 15:04:58 -0800 Subject: [PATCH 168/418] Change error handling when scraping metrics (#551) * If Envoy returns an error then also respond with a 500 in our merged metrics response so that Prometheus will know that we had an error, not that there are no metrics. * If the service metrics return with a non-2xx status code then don't include the response body in the merged metrics. This will stop issues where users accidentally turn on metrics merging but they don't have an exporter and so their metrics endpoint returns 404. I could have responded with a 500 in this case in order to indicate that there is an error, however I think it's more likely that users are accidentally turning on metrics merging and the error indication is accomplished via a new metric (see below). * Append a new metric that indicates the success of the service scraping. This can be used for alerting by users since the response code of the service metrics response is discarded: * success: consul_metrics_merging_service_metrics_success 1 * fail: consul_metrics_merging_service_metrics_success 0 * modify logging to use key/value pairs * Fixes #546 --- CHANGELOG.md | 4 + .../subcommand/consul-sidecar/command.go | 80 +++++++++++--- .../subcommand/consul-sidecar/command_test.go | 100 +++++++++++------- 3 files changed, 131 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 873d49b793..d977798e5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ BREAKING CHANGES: * Control Plane * Update minimum go version for project to 1.17 [[GH-878](https://github.com/hashicorp/consul-k8s/pull/878)] + * Add boolean metric to merged metrics response `consul_merged_service_metrics_success` to indicate if service metrics were + scraped successfully. [[GH-551](https://github.com/hashicorp/consul-k8s/pull/551)] IMPROVEMENTS: * CLI @@ -16,6 +18,8 @@ IMPROVEMENTS: BUG FIXES: * Control Plane: * Add a workaround to check that the ACL token is replicated to other Consul servers. [[GH-862](https://github.com/hashicorp/consul-k8s/issues/862)] + * Return 500 on prometheus response if unable to get metrics from Envoy. [[GH-551](https://github.com/hashicorp/consul-k8s/pull/551)] + * Don't include body of failed service metrics calls in merged metrics response. [[GH-551](https://github.com/hashicorp/consul-k8s/pull/551)] * Helm Chart * Admin Partitions **(Consul Enterprise only)**: Do not mount Consul CA certs to partition-init job if `externalServers.useSystemRoots` is `true`. [[GH-885](https://github.com/hashicorp/consul-k8s/pull/885)] diff --git a/control-plane/subcommand/consul-sidecar/command.go b/control-plane/subcommand/consul-sidecar/command.go index dcb05199ba..b6ff0d9d39 100644 --- a/control-plane/subcommand/consul-sidecar/command.go +++ b/control-plane/subcommand/consul-sidecar/command.go @@ -21,8 +21,13 @@ import ( "github.com/mitchellh/cli" ) -const metricsServerShutdownTimeout = 5 * time.Second -const envoyMetricsAddr = "http://127.0.0.1:19000/stats/prometheus" +const ( + metricsServerShutdownTimeout = 5 * time.Second + envoyMetricsAddr = "http://127.0.0.1:19000/stats/prometheus" + // prometheusServiceMetricsSuccessKey is the key of the prometheus metric used to + // indicate if service metrics were scraped successfully. + prometheusServiceMetricsSuccessKey = "consul_merged_service_metrics_success" +) type Command struct { UI cli.Ui @@ -240,27 +245,36 @@ func (c *Command) createMergedMetricsServer() *http.Server { mergedMetricsServerAddr := fmt.Sprintf("127.0.0.1:%s", c.flagMergedMetricsPort) server := &http.Server{Addr: mergedMetricsServerAddr, Handler: mux} + // http.Client satisfies the metricsGetter interface. // The default http.Client timeout is indefinite, so adding a timeout makes // sure that requests don't hang. client := &http.Client{ Timeout: time.Second * 10, } - // http.Client satisfies the metricsGetter interface. - c.envoyMetricsGetter = client - c.serviceMetricsGetter = client + + // During tests these may already be set to mocks. + if c.envoyMetricsGetter == nil { + c.envoyMetricsGetter = client + } + if c.serviceMetricsGetter == nil { + c.serviceMetricsGetter = client + } return server } // mergedMetricsHandler has the logic to append both Envoy and service metrics // together, logging if it's unsuccessful at either. +// If the Envoy scrape fails, we respond with a 500 code which follows the Prometheus +// exporter guidelines. If the service scrape fails, we respond with a 200 so +// that the Envoy metrics are still scraped. +// We also include a metric line in each response indicating the success or +// failure of the service metric scraping. func (c *Command) mergedMetricsHandler(rw http.ResponseWriter, _ *http.Request) { - envoyMetrics, err := c.envoyMetricsGetter.Get(envoyMetricsAddr) if err != nil { - // If there is an error scraping Envoy, we want the handler to return - // without writing anything to the response, and log the error. - c.logger.Error(fmt.Sprintf("Error scraping Envoy proxy metrics: %s", err.Error())) + c.logger.Error("Error scraping Envoy proxy metrics", "err", err) + http.Error(rw, fmt.Sprintf("Error scraping Envoy proxy metrics: %s", err), http.StatusInternalServerError) return } @@ -273,18 +287,22 @@ func (c *Command) mergedMetricsHandler(rw http.ResponseWriter, _ *http.Request) }() envoyMetricsBody, err := ioutil.ReadAll(envoyMetrics.Body) if err != nil { - c.logger.Error(fmt.Sprintf("Couldn't read Envoy proxy metrics: %s", err.Error())) + c.logger.Error("Could not read Envoy proxy metrics", "err", err) + http.Error(rw, fmt.Sprintf("Could not read Envoy proxy metrics: %s", err), http.StatusInternalServerError) return } - _, err = rw.Write(envoyMetricsBody) - if err != nil { - c.logger.Error(fmt.Sprintf("Error writing envoy metrics body: %s", err.Error())) + if non2xxCode(envoyMetrics.StatusCode) { + c.logger.Error("Received non-2xx status code scraping Envoy proxy metrics", "code", envoyMetrics.StatusCode, "response", string(envoyMetricsBody)) + http.Error(rw, fmt.Sprintf("Received non-2xx status code scraping Envoy proxy metrics: %d: %s", envoyMetrics.StatusCode, string(envoyMetricsBody)), http.StatusInternalServerError) + return } + writeResponse(rw, envoyMetricsBody, "envoy metrics", c.logger) serviceMetricsAddr := fmt.Sprintf("http://127.0.0.1:%s%s", c.flagServiceMetricsPort, c.flagServiceMetricsPath) serviceMetrics, err := c.serviceMetricsGetter.Get(serviceMetricsAddr) if err != nil { - c.logger.Warn(fmt.Sprintf("Error scraping service metrics: %s", err.Error())) + c.logger.Warn("Error scraping service metrics", "err", err) + writeResponse(rw, serviceMetricSuccess(false), "service metrics success", c.logger) // Since we've already written the Envoy metrics to the response, we can // return at this point if we were unable to get service metrics. return @@ -300,12 +318,25 @@ func (c *Command) mergedMetricsHandler(rw http.ResponseWriter, _ *http.Request) }() serviceMetricsBody, err := ioutil.ReadAll(serviceMetrics.Body) if err != nil { - c.logger.Error(fmt.Sprintf("Couldn't read service metrics: %s", err.Error())) + c.logger.Error("Could not read service metrics", "err", err) + writeResponse(rw, serviceMetricSuccess(false), "service metrics success", c.logger) return } - _, err = rw.Write(serviceMetricsBody) + if non2xxCode(serviceMetrics.StatusCode) { + c.logger.Error("Received non-2xx status code scraping service metrics", "code", serviceMetrics.StatusCode, "response", string(serviceMetricsBody)) + writeResponse(rw, serviceMetricSuccess(false), "service metrics success", c.logger) + return + } + writeResponse(rw, serviceMetricsBody, "service metrics", c.logger) + writeResponse(rw, serviceMetricSuccess(true), "service metrics success", c.logger) +} + +// writeResponse is a helper method to write resp to rw and log if there is an error writing. +// respName is the name of this response that will be used in the error log. +func writeResponse(rw http.ResponseWriter, resp []byte, respName string, logger hclog.Logger) { + _, err := rw.Write(resp) if err != nil { - c.logger.Error(fmt.Sprintf("Error writing service metrics body: %s", err.Error())) + logger.Error(fmt.Sprintf("Error writing %s: %s", respName, err.Error())) } } @@ -339,6 +370,21 @@ func (c *Command) validateFlags() error { return nil } +// non2xxCode returns true if code is not in the range of 200-299 inclusive. +func non2xxCode(code int) bool { + return code < 200 || code >= 300 +} + +// serviceMetricSuccess returns a prometheus metric line indicating +// the success of the metrics merging. +func serviceMetricSuccess(success bool) []byte { + boolAsInt := 0 + if success { + boolAsInt = 1 + } + return []byte(fmt.Sprintf("%s %d\n", prometheusServiceMetricsSuccessKey, boolAsInt)) +} + // parseConsulFlags creates Consul client command flags // from command's HTTP flags and returns them as an array of strings. func (c *Command) parseConsulFlags() []string { diff --git a/control-plane/subcommand/consul-sidecar/command_test.go b/control-plane/subcommand/consul-sidecar/command_test.go index 6ee55f8ea0..370b4afd8f 100644 --- a/control-plane/subcommand/consul-sidecar/command_test.go +++ b/control-plane/subcommand/consul-sidecar/command_test.go @@ -214,50 +214,88 @@ func TestRunSignalHandlingAllProcessesEnabled(t *testing.T) { } } -type envoyMetrics struct { +type mockEnvoyMetricsGetter struct { + respStatusCode int } -func (em *envoyMetrics) Get(url string) (resp *http.Response, err error) { +func (em *mockEnvoyMetricsGetter) Get(_ string) (resp *http.Response, err error) { response := &http.Response{} + response.StatusCode = em.respStatusCode response.Body = ioutil.NopCloser(bytes.NewReader([]byte("envoy metrics\n"))) return response, nil } -type serviceMetrics struct { - url string +// mockServiceMetricsGetter +type mockServiceMetricsGetter struct { + // reqURL is the last URL that was passed to Get(url) + reqURL string + + // respStatusCode is the status code to use for the response. + respStatusCode int } -func (sm *serviceMetrics) Get(url string) (resp *http.Response, err error) { +func (sm *mockServiceMetricsGetter) Get(url string) (resp *http.Response, err error) { + // Record the URL that we were called with. + sm.reqURL = url + response := &http.Response{} response.Body = ioutil.NopCloser(bytes.NewReader([]byte("service metrics\n"))) - sm.url = url + response.StatusCode = sm.respStatusCode + return response, nil } func TestMergedMetricsServer(t *testing.T) { cases := []struct { - name string - runEnvoyMetricsServer bool - runServiceMetricsServer bool - expectedOutput string + name string + envoyMetricsGetter *mockEnvoyMetricsGetter + serviceMetricsGetter *mockServiceMetricsGetter + expectedStatusCode int + expectedOutput string }{ { - name: "happy path: envoy and service metrics are merged", - runEnvoyMetricsServer: true, - runServiceMetricsServer: true, - expectedOutput: "envoy metrics\nservice metrics\n", + name: "happy path: envoy and service metrics are merged", + envoyMetricsGetter: &mockEnvoyMetricsGetter{ + respStatusCode: 200, + }, + serviceMetricsGetter: &mockServiceMetricsGetter{ + respStatusCode: 200, + }, + expectedStatusCode: 200, + expectedOutput: "envoy metrics\nservice metrics\nconsul_merged_service_metrics_success 1\n", }, { - name: "no service metrics", - runEnvoyMetricsServer: true, - runServiceMetricsServer: false, - expectedOutput: "envoy metrics\n", + name: "service metrics non-200", + envoyMetricsGetter: &mockEnvoyMetricsGetter{ + respStatusCode: 200, + }, + serviceMetricsGetter: &mockServiceMetricsGetter{ + respStatusCode: 404, + }, + expectedStatusCode: 200, + expectedOutput: "envoy metrics\nconsul_merged_service_metrics_success 0\n", }, { - name: "no envoy metrics", - runEnvoyMetricsServer: false, - runServiceMetricsServer: true, - expectedOutput: "", + name: "envoy metrics non-200", + envoyMetricsGetter: &mockEnvoyMetricsGetter{ + respStatusCode: 404, + }, + serviceMetricsGetter: &mockServiceMetricsGetter{ + respStatusCode: 200, + }, + expectedStatusCode: 500, + expectedOutput: "Received non-2xx status code scraping Envoy proxy metrics: 404: envoy metrics\n\n", + }, + { + name: "envoy and service metrics non-200", + envoyMetricsGetter: &mockEnvoyMetricsGetter{ + respStatusCode: 500, + }, + serviceMetricsGetter: &mockServiceMetricsGetter{ + respStatusCode: 500, + }, + expectedStatusCode: 500, + expectedOutput: "Received non-2xx status code scraping Envoy proxy metrics: 500: envoy metrics\n\n", }, } @@ -272,21 +310,11 @@ func TestMergedMetricsServer(t *testing.T) { flagServiceMetricsPort: fmt.Sprint(randomPorts[1]), flagServiceMetricsPath: "/metrics", logger: hclog.Default(), + envoyMetricsGetter: c.envoyMetricsGetter, + serviceMetricsGetter: c.serviceMetricsGetter, } server := cmd.createMergedMetricsServer() - - // Override the cmd's envoyMetricsGetter and serviceMetricsGetter - // with stubs. - em := &envoyMetrics{} - sm := &serviceMetrics{} - if c.runEnvoyMetricsServer { - cmd.envoyMetricsGetter = em - } - if c.runServiceMetricsServer { - cmd.serviceMetricsGetter = sm - } - go func() { _ = server.ListenAndServe() }() @@ -304,8 +332,8 @@ func TestMergedMetricsServer(t *testing.T) { // Verify the correct service metrics url was used. The service // metrics endpoint is only called if the Envoy metrics endpoint // call succeeds. - if c.runServiceMetricsServer && c.runEnvoyMetricsServer { - require.Equal(r, fmt.Sprintf("http://127.0.0.1:%d%s", randomPorts[1], "/metrics"), sm.url) + if c.envoyMetricsGetter.respStatusCode == 200 { + require.Equal(r, fmt.Sprintf("http://127.0.0.1:%d%s", randomPorts[1], "/metrics"), c.serviceMetricsGetter.reqURL) } }) }) From 738d80eb2912feb1153eed96fefbf614479b9858 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Mon, 6 Dec 2021 18:45:03 -0600 Subject: [PATCH 169/418] Server TLS bootstrapping (#881) * Support Vault server running with TLS (#874) * Change vault cluster in acceptance tests to only run with TLS. All tests will run against vault with TLS because that is the use case we think will be the most valuable for users to test * Support adding Vault CA as a secret to pods that will be using vault agent. We need to add two annotations to pods: * vault.hashicorp.com/agent-extra-secret with the value of the vault CA secret name. The secret will be mounted to vault agent at /vault/custom path. See docs here * vault.hashicorp.com/ca-cert - with the path of the ca file inside the vault agent container. This should be /vault/custom/ * Most pods will only need those annotations. The server pods also need the Vault CA secret to be mounted as a volume because it needs the CA to be on the file system for the vault connect CA provider. * add terminating and ingress gateways TLS support (#894) * Support TLS with vault for the server-acl-init job (#889) * Support TLS with Vault for the sync catalog deployment (#890) * Support server TLS with vault for the client snapshot agent deployment (#891) Co-authored-by: Iryna Shustava Co-authored-by: Luke Kysow <1034429+lkysow@users.noreply.github.com> --- acceptance/framework/vault/vault_cluster.go | 17 ++- acceptance/tests/vault/vault_test.go | 84 ++++++++++- charts/consul/templates/_helpers.tpl | 36 +++++ charts/consul/templates/client-daemonset.yaml | 19 ++- .../client-snapshot-agent-deployment.yaml | 11 ++ .../templates/connect-inject-deployment.yaml | 11 ++ .../templates/controller-deployment.yaml | 11 ++ .../ingress-gateways-deployment.yaml | 11 ++ .../consul/templates/server-acl-init-job.yaml | 19 ++- .../consul/templates/server-statefulset.yaml | 31 +++- .../templates/sync-catalog-deployment.yaml | 11 ++ .../terminating-gateways-deployment.yaml | 11 ++ .../templates/tls-init-cleanup-job.yaml | 2 + .../tls-init-cleanup-podsecuritypolicy.yaml | 2 + .../templates/tls-init-cleanup-role.yaml | 2 + .../tls-init-cleanup-rolebinding.yaml | 2 + .../tls-init-cleanup-serviceaccount.yaml | 2 + charts/consul/templates/tls-init-job.yaml | 2 + .../templates/tls-init-podsecuritypolicy.yaml | 2 + charts/consul/templates/tls-init-role.yaml | 2 + .../templates/tls-init-rolebinding.yaml | 2 + .../templates/tls-init-serviceaccount.yaml | 2 + charts/consul/test/unit/client-daemonset.bats | 124 ++++++++++++++++ .../client-snapshot-agent-deployment.bats | 124 ++++++++++++++++ .../test/unit/connect-inject-deployment.bats | 131 +++++++++++++++- .../test/unit/controller-deployment.bats | 130 ++++++++++++++++ charts/consul/test/unit/helpers.bats | 23 +++ .../unit/ingress-gateways-deployment.bats | 125 ++++++++++++++++ .../consul/test/unit/server-acl-init-job.bats | 133 +++++++++++++++++ .../consul/test/unit/server-statefulset.bats | 140 ++++++++++++++++-- .../test/unit/sync-catalog-deployment.bats | 123 +++++++++++++++ .../unit/terminating-gateways-deployment.bats | 124 ++++++++++++++++ .../test/unit/tls-init-cleanup-job.bats | 17 +++ .../tls-init-cleanup-podsecuritypolicy.bats | 17 +++ .../test/unit/tls-init-cleanup-role.bats | 17 +++ .../unit/tls-init-cleanup-rolebinding.bats | 17 +++ .../unit/tls-init-cleanup-serviceaccount.bats | 17 +++ charts/consul/test/unit/tls-init-job.bats | 17 +++ .../test/unit/tls-init-podsecuritypolicy.bats | 17 +++ charts/consul/test/unit/tls-init-role.bats | 17 +++ .../test/unit/tls-init-rolebinding.bats | 17 +++ .../test/unit/tls-init-serviceaccount.bats | 16 ++ charts/consul/test/unit/ui-ingress.bats | 6 + charts/consul/values.yaml | 43 ++++-- 44 files changed, 1641 insertions(+), 46 deletions(-) diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index 9287d57035..b0f444f85e 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -131,18 +131,20 @@ func (v *VaultCluster) bootstrap(t *testing.T, ctx environment.TestContext) { Type: "kv-v2", Config: vapi.MountConfigInput{}, }) - if err != nil { - t.Fatal("unable to mount kv-v2 secrets engine", "err", err) - } - // TODO: add the PKI Secrets Engine when we have a need for it. + require.NoError(t, err) + + // Enable the PKI Secrets engine. + err = v.vaultClient.Sys().Mount("pki", &vapi.MountInput{ + Type: "pki", + Config: vapi.MountConfigInput{}, + }) + require.NoError(t, err) // Enable Kube Auth. err = v.vaultClient.Sys().EnableAuthWithOptions("kubernetes", &vapi.EnableAuthOptions{ Type: "kubernetes", }) - if err != nil { - t.Fatal("unable to enable kube auth", "err", err) - } + require.NoError(t, err) v.logger.Logf(t, "updating vault kube auth config") @@ -230,6 +232,7 @@ func defaultHelmValues(releaseName string) map[string]string { "server.standalone.enabled": "true", "server.standalone.config": serverConfig, "injector.enabled": "true", + "ui.enabled": "true", } } diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 4b63dc8b65..e19e196c84 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -43,6 +43,14 @@ path "/connect_inter/*" { capabilities = [ "create", "read", "update", "delete", "list" ] } ` + serverTLSPolicy = ` +path "pki/issue/consul-server" { + capabilities = ["create", "update"] +}` + caPolicy = ` +path "pki/cert/ca" { + capabilities = ["read"] +}` ) // TestVault installs Vault, bootstraps it with secrets, policies, and Kube Auth Method. @@ -50,6 +58,7 @@ path "/connect_inter/*" { func TestVault(t *testing.T) { cfg := suite.Config() ctx := suite.Environment().DefaultContext(t) + ns := ctx.KubectlOptions(t).Namespace consulReleaseName := helpers.RandomName() vaultReleaseName := helpers.RandomName() @@ -68,6 +77,7 @@ func TestVault(t *testing.T) { err := vaultClient.Sys().PutPolicy("consul-gossip", gossipPolicy) require.NoError(t, err) + // Create the Vault Policy for the connect-ca. err = vaultClient.Sys().PutPolicy("connect-ca", connectCAPolicy) require.NoError(t, err) @@ -80,7 +90,7 @@ func TestVault(t *testing.T) { logger.Log(t, "Creating the consul-server and consul-client roles") params := map[string]interface{}{ "bound_service_account_names": consulClientServiceAccountName, - "bound_service_account_namespaces": "default", + "bound_service_account_namespaces": ns, "policies": "consul-gossip", "ttl": "24h", } @@ -89,13 +99,24 @@ func TestVault(t *testing.T) { params = map[string]interface{}{ "bound_service_account_names": consulServerServiceAccountName, - "bound_service_account_namespaces": "default", - "policies": "consul-gossip,connect-ca", + "bound_service_account_namespaces": ns, + "policies": "consul-gossip,connect-ca,consul-server", "ttl": "24h", } _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-server", params) require.NoError(t, err) + // Create the CA role that all components will use to fetch the Server CA certs. + params = map[string]interface{}{ + "bound_service_account_names": "*", + "bound_service_account_namespaces": ns, + "policies": "consul-ca", + "ttl": "24h", + } + _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-ca", params) + require.NoError(t, err) + + // Generate the gossip secret. gossipKey, err := generateGossipSecret() require.NoError(t, err) @@ -110,7 +131,39 @@ func TestVault(t *testing.T) { require.NoError(t, err) vaultCASecret := vault.CASecretName(vaultReleaseName) + + // Bootstrap TLS by creating the CA infrastructure required for Consul server TLS and also create the `consul-server` PKI role. + // Using https://learn.hashicorp.com/tutorials/consul/vault-pki-consul-secure-tls. + // Generate the root CA. + params = map[string]interface{}{ + "common_name": "dc1.consul", + "ttl": "24h", + } + _, err = vaultClient.Logical().Write("pki/root/generate/internal", params) + require.NoError(t, err) + + // Create the Vault PKI Role. + name := consulReleaseName + "-consul" + allowedDomains := fmt.Sprintf("dc1.consul,%s-server,%s-server.%s,%s-server.%s.svc", name, name, ns, name, ns) + params = map[string]interface{}{ + "allowed_domains": allowedDomains, + "allow_bare_domains": "true", + "allow_localhost": "true", + "allow_subdomains": "true", + "generate_lease": "true", + "max_ttl": "1h", + } + _, err = vaultClient.Logical().Write("pki/roles/consul-server", params) + require.NoError(t, err) + + // Create the server and ca policies + err = vaultClient.Sys().PutPolicy("consul-server", serverTLSPolicy) + require.NoError(t, err) + err = vaultClient.Sys().PutPolicy("consul-ca", caPolicy) + require.NoError(t, err) + consulHelmValues := map[string]string{ + // TODO: Update the global image once 1.11 is GA. "global.image": "docker.mirror.hashicorp.services/hashicorpdev/consul:latest", "server.enabled": "true", @@ -118,13 +171,16 @@ func TestVault(t *testing.T) { "server.extraVolumes[0].type": "secret", "server.extraVolumes[0].name": vaultCASecret, "server.extraVolumes[0].load": "false", + "global.datacenter": "dc1", - "connectInject.enabled": "true", - "controller.enabled": "true", + "connectInject.enabled": "true", + "connectInject.replicas": "1", + "controller.enabled": "true", "global.secretsBackend.vault.enabled": "true", "global.secretsBackend.vault.consulServerRole": "consul-server", "global.secretsBackend.vault.consulClientRole": "consul-client", + "global.secretsBackend.vault.consulCARole": "consul-ca", "global.secretsBackend.vault.ca.secretName": vaultCASecret, "global.secretsBackend.vault.ca.secretKey": "tls.crt", @@ -137,6 +193,24 @@ func TestVault(t *testing.T) { "global.tls.enabled": "true", "global.gossipEncryption.secretName": "consul/data/secret/gossip", "global.gossipEncryption.secretKey": "gossip", + + "ingressGateways.enabled": "true", + "ingressGateways.defaults.replicas": "1", + "terminatingGateways.enabled": "true", + "terminatingGateways.defaults.replicas": "1", + + "server.serverCert.secretName": "pki/issue/consul-server", + "global.tls.caCert.secretName": "pki/cert/ca", + "global.tls.httpsOnly": "false", + "global.tls.enableAutoEncrypt": "true", + + // For sync catalog, it is sufficient to check that the deployment is running and ready + // because we only care that get-auto-encrypt-client-ca init container was able + // to talk to the Consul server using the CA from Vault. For this reason, + // we don't need any services to be synced in either direction. + "syncCatalog.enabled": "true", + "syncCatalog.toConsul": "false", + "syncCatalog.toK8S": "false", } logger.Log(t, "Installing Consul") consulCluster := consul.NewHelmCluster(t, consulHelmValues, ctx, cfg, consulReleaseName) diff --git a/charts/consul/templates/_helpers.tpl b/charts/consul/templates/_helpers.tpl index 07ced2d778..8b9f1e836d 100644 --- a/charts/consul/templates/_helpers.tpl +++ b/charts/consul/templates/_helpers.tpl @@ -21,6 +21,36 @@ as well as the global.name setting. {{ "{{" }}- {{ printf ".Data.data.%s" .secretKey }} -{{ "}}" }} {{ "{{" }}- end -{{ "}}" }} {{- end -}} + +{{- define "consul.serverTLSCATemplate" -}} + | + {{ "{{" }}- with secret "{{ .Values.global.tls.caCert.secretName }}" -{{ "}}" }} + {{ "{{" }}- .Data.certificate -{{ "}}" }} + {{ "{{" }}- end -{{ "}}" }} +{{- end -}} + +{{- define "consul.serverTLSCertTemplate" -}} + | + {{ "{{" }}- with secret "{{ .Values.server.serverCert.secretName }}" "{{ printf "common_name=server.%s.%s" .Values.global.datacenter .Values.global.domain }}" + "ttl=1h" "alt_names={{ include "consul.serverTLSAltNames" . }}" "ip_sans=127.0.0.1" -{{ "}}" }} + {{ "{{" }}- .Data.certificate -{{ "}}" }} + {{ "{{" }}- end -{{ "}}" }} +{{- end -}} + +{{- define "consul.serverTLSKeyTemplate" -}} + | + {{ "{{" }}- with secret "{{ .Values.server.serverCert.secretName }}" "{{ printf "common_name=server.%s.%s" .Values.global.datacenter .Values.global.domain }}" + "ttl=1h" "alt_names={{ include "consul.serverTLSAltNames" . }}" "ip_sans=127.0.0.1" -{{ "}}" }} + {{ "{{" }}- .Data.private_key -{{ "}}" }} + {{ "{{" }}- end -{{ "}}" }} +{{- end -}} + +{{- define "consul.serverTLSAltNames" -}} +{{- $name := include "consul.fullname" . -}} +{{- $ns := .Release.Namespace -}} +{{ printf "localhost,%s-server,*.%s-server,*.%s-server.%s,*.%s-server.%s.svc,*.server.%s.%s" $name $name $name $ns $name $ns (.Values.global.datacenter ) (.Values.global.domain) }} +{{- end -}} + {{/* Sets up the extra-from-values config file passed to consul and then uses sed to do any necessary substitution for HOST_IP/POD_IP/HOSTNAME. Useful for dogstats telemetry. The output file @@ -108,13 +138,19 @@ This template is for an init container. {{- else }} -server-addr={{ template "consul.fullname" . }}-server \ -server-port=8501 \ + {{- if .Values.global.secretsBackend.vault.enabled }} + -ca-file=/vault/secrets/serverca.crt + {{- else }} -ca-file=/consul/tls/ca/tls.crt {{- end }} + {{- end }} volumeMounts: {{- if not (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots) }} + {{- if not .Values.global.secretsBackend.vault.enabled }} - name: consul-ca-cert mountPath: /consul/tls/ca {{- end }} + {{- end }} - name: consul-auto-encrypt-ca-cert mountPath: /consul/tls/client/ca resources: diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index 468af38fda..2fb04423fc 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -3,6 +3,9 @@ {{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} {{- if (and .Values.global.adminPartitions.enabled $serverEnabled (ne .Values.global.adminPartitions.name "default"))}}{{ fail "global.adminPartitions.name has to be \"default\" in the server cluster" }}{{ end -}} {{- if (and (not .Values.global.secretsBackend.vault.consulClientRole) .Values.global.secretsBackend.vault.enabled) }}{{ fail "global.secretsBackend.vault.consulClientRole must be provided if global.secretsBackend.vault.enabled=true." }}{{ end -}} +{{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.tls.caCert.secretName)) }}{{ fail "global.tls.caCert.secretName must be provided if global.tls.enabled=true and global.secretsBackend.vault.enabled=true." }}{{ end -}} +{{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.tls.enableAutoEncrypt)) }}{{ fail "global.tls.enableAutoEncrypt must be true if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" }}{{ end -}} +{{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.secretsBackend.vault.consulCARole)) }}{{ fail "global.secretsBackend.vault.consulCARole must be provided if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" }}{{ end -}} # DaemonSet to run the Consul clients on every node. apiVersion: apps/v1 kind: DaemonSet @@ -47,10 +50,14 @@ spec: {{- end }} {{- if .Values.global.gossipEncryption.secretName }} {{- with .Values.global.gossipEncryption }} - "vault.hashicorp.com/agent-inject-secret-gossip.txt": "{{ .secretName }}" + "vault.hashicorp.com/agent-inject-secret-gossip.txt": {{ .secretName }} "vault.hashicorp.com/agent-inject-template-gossip.txt": {{ template "consul.vaultGossipTemplate" . }} {{- end }} {{- end }} + {{- if .Values.global.tls.enabled }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} + {{- end }} {{- end }} "consul.hashicorp.com/connect-inject": "false" "consul.hashicorp.com/config-checksum": {{ include (print $.Template.BasePath "/client-config-configmap.yaml") . | sha256sum }} @@ -104,6 +111,7 @@ spec: configMap: name: {{ template "consul.fullname" . }}-client-config {{- if .Values.global.tls.enabled }} + {{- if not .Values.global.secretsBackend.vault.enabled }} - name: consul-ca-cert secret: {{- if .Values.global.tls.caCert.secretName }} @@ -132,6 +140,7 @@ spec: medium: "Memory" {{- end }} {{- end }} + {{- end }} {{- range .Values.client.extraVolumes }} - name: userconfig-{{ .name }} {{ .type }}: @@ -235,7 +244,11 @@ spec: {{- end }} -hcl='leave_on_terminate = true' \ {{- if .Values.global.tls.enabled }} + {{- if .Values.global.secretsBackend.vault.enabled }} + -hcl='ca_file = "/vault/secrets/serverca.crt"' \ + {{- else }} -hcl='ca_file = "/consul/tls/ca/tls.crt"' \ + {{- end }} {{- if .Values.global.tls.enableAutoEncrypt }} -hcl='auto_encrypt = {tls = true}' \ -hcl="auto_encrypt = {ip_san = [\"$HOST_IP\",\"$POD_IP\"]}" \ @@ -304,6 +317,7 @@ spec: - name: config mountPath: /consul/config {{- if .Values.global.tls.enabled }} + {{- if not .Values.global.secretsBackend.vault.enabled }} - name: consul-ca-cert mountPath: /consul/tls/ca readOnly: true @@ -313,6 +327,7 @@ spec: readOnly: true {{- end }} {{- end }} + {{- end }} {{- range .Values.client.extraVolumes }} - name: userconfig-{{ .name }} readOnly: true @@ -446,6 +461,7 @@ spec: mv {{ .Values.global.datacenter }}-client-{{ .Values.global.domain }}-0.pem tls.crt mv {{ .Values.global.datacenter }}-client-{{ .Values.global.domain }}-0-key.pem tls.key volumeMounts: + {{- if not .Values.global.secretsBackend.vault.enabled }} - name: consul-client-cert mountPath: /consul/tls/client - name: consul-ca-cert @@ -454,6 +470,7 @@ spec: - name: consul-ca-key mountPath: /consul/tls/ca/key readOnly: true + {{- end }} resources: requests: memory: "50Mi" diff --git a/charts/consul/templates/client-snapshot-agent-deployment.yaml b/charts/consul/templates/client-snapshot-agent-deployment.yaml index 864c2125d1..7a8c679084 100644 --- a/charts/consul/templates/client-snapshot-agent-deployment.yaml +++ b/charts/consul/templates/client-snapshot-agent-deployment.yaml @@ -27,6 +27,17 @@ spec: component: client-snapshot-agent annotations: "consul.hashicorp.com/connect-inject": "false" + {{- if (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) }} + "vault.hashicorp.com/agent-init-first": "true" + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" + "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + {{- end }} + {{- end }} spec: {{- if .Values.client.tolerations }} tolerations: diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index f3f9f9a754..32717e2286 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -36,6 +36,17 @@ spec: component: connect-injector annotations: "consul.hashicorp.com/connect-inject": "false" + {{- if (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) }} + "vault.hashicorp.com/agent-init-first": "true" + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" + "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + {{- end }} + {{- end }} spec: serviceAccountName: {{ template "consul.fullname" . }}-connect-injector-webhook-svc-account containers: diff --git a/charts/consul/templates/controller-deployment.yaml b/charts/consul/templates/controller-deployment.yaml index 151c08b1e8..5caf5e6a48 100644 --- a/charts/consul/templates/controller-deployment.yaml +++ b/charts/consul/templates/controller-deployment.yaml @@ -30,6 +30,17 @@ spec: component: controller annotations: "consul.hashicorp.com/connect-inject": "false" + {{- if (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) }} + "vault.hashicorp.com/agent-init-first": "true" + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" + "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + {{- end }} + {{- end }} spec: {{- if or .Values.global.acls.manageSystemACLs (and .Values.global.tls.enabled .Values.global.tls.enableAutoEncrypt) }} initContainers: diff --git a/charts/consul/templates/ingress-gateways-deployment.yaml b/charts/consul/templates/ingress-gateways-deployment.yaml index 36671fb2b8..5b8c8dc4b7 100644 --- a/charts/consul/templates/ingress-gateways-deployment.yaml +++ b/charts/consul/templates/ingress-gateways-deployment.yaml @@ -55,6 +55,17 @@ spec: component: ingress-gateway ingress-gateway-name: {{ template "consul.fullname" $root }}-{{ .name }} annotations: + {{- if (and $root.Values.global.secretsBackend.vault.enabled $root.Values.global.tls.enabled) }} + "vault.hashicorp.com/agent-init-first": "true" + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": {{ $root.Values.global.secretsBackend.vault.consulCARole }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ $root.Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" $root }} + {{- if and $root.Values.global.secretsBackend.vault.ca.secretName $root.Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": {{ $root.Values.global.secretsBackend.vault.ca.secretName }} + "vault.hashicorp.com/ca-cert": /vault/custom/{{ $root.Values.global.secretsBackend.vault.ca.secretKey }} + {{- end }} + {{- end }} "consul.hashicorp.com/connect-inject": "false" {{- if (and $root.Values.global.metrics.enabled $root.Values.global.metrics.enableGatewayMetrics) }} "prometheus.io/scrape": "true" diff --git a/charts/consul/templates/server-acl-init-job.yaml b/charts/consul/templates/server-acl-init-job.yaml index 07b9ab8e6b..bc303e2607 100644 --- a/charts/consul/templates/server-acl-init-job.yaml +++ b/charts/consul/templates/server-acl-init-job.yaml @@ -33,12 +33,23 @@ spec: component: server-acl-init annotations: "consul.hashicorp.com/connect-inject": "false" + {{- if (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) }} + "vault.hashicorp.com/agent-pre-populate-only": "true" + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" + "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + {{- end }} + {{- end }} spec: restartPolicy: Never serviceAccountName: {{ template "consul.fullname" . }}-server-acl-init {{- if (or .Values.global.tls.enabled (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey)) }} volumes: - {{- if .Values.global.tls.enabled }} + {{- if and .Values.global.tls.enabled (not .Values.global.secretsBackend.vault.enabled) }} - name: consul-ca-cert secret: {{- if .Values.global.tls.caCert.secretName }} @@ -76,7 +87,7 @@ spec: fieldPath: metadata.namespace {{- if (or .Values.global.tls.enabled (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey)) }} volumeMounts: - {{- if .Values.global.tls.enabled }} + {{- if and .Values.global.tls.enabled (not .Values.global.secretsBackend.vault.enabled) }} - name: consul-ca-cert mountPath: /consul/tls/ca readOnly: true @@ -118,8 +129,12 @@ spec: {{- if .Values.global.tls.enabled }} -use-https \ {{- if not (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots) }} + {{- if .Values.global.secretsBackend.vault.enabled }} + -consul-ca-cert=/vault/secrets/serverca.crt \ + {{- else }} -consul-ca-cert=/consul/tls/ca/tls.crt \ {{- end }} + {{- end }} {{- if not .Values.externalServers.enabled }} -server-port=8501 \ {{- end }} diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 5a3afeea4d..a73c56e40d 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -8,6 +8,10 @@ {{- if (and .Values.global.gossipEncryption.secretName (not .Values.global.gossipEncryption.secretKey)) }}{{fail "gossipEncryption.secretKey and secretName must both be specified." }}{{ end -}} {{- if (and (not .Values.global.gossipEncryption.secretName) .Values.global.gossipEncryption.secretKey) }}{{fail "gossipEncryption.secretKey and secretName must both be specified." }}{{ end -}} {{- if (and .Values.global.secretsBackend.vault.enabled (not .Values.global.secretsBackend.vault.consulServerRole)) }}{{ fail "global.secretsBackend.vault.consulServerRole must be provided if global.secretsBackend.vault.enabled=true." }}{{ end -}} +{{- if (and .Values.server.serverCert.secretName (not .Values.global.tls.caCert.secretName)) }}{{ fail "If server.serverCert.secretName is provided, global.tls.caCert.secretName must also be provided" }}{{ end }} +{{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.tls.caCert.secretName)) }}{{ fail "global.tls.caCert.secretName must be provided if global.tls.enabled=true and global.secretsBackend.vault.enabled=true." }}{{ end -}} +{{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.tls.enableAutoEncrypt)) }}{{ fail "global.tls.enableAutoEncrypt must be true if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" }}{{ end -}} +{{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.secretsBackend.vault.consulCARole)) }}{{ fail "global.secretsBackend.vault.consulCARole must be provided if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" }}{{ end -}} # StatefulSet to run the actual Consul server cluster. apiVersion: apps/v1 kind: StatefulSet @@ -53,8 +57,8 @@ spec: "vault.hashicorp.com/agent-inject": "true" "vault.hashicorp.com/role": "{{ .Values.global.secretsBackend.vault.consulServerRole }}" {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} - "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" - "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + "vault.hashicorp.com/agent-extra-secret": {{ .Values.global.secretsBackend.vault.ca.secretName }} + "vault.hashicorp.com/ca-cert": /vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }} {{- end }} {{- if .Values.global.gossipEncryption.secretName }} {{- with .Values.global.gossipEncryption }} @@ -62,6 +66,14 @@ spec: "vault.hashicorp.com/agent-inject-template-gossip.txt": {{ template "consul.vaultGossipTemplate" . }} {{- end }} {{- end }} + {{- if .Values.server.serverCert.secretName }} + "vault.hashicorp.com/agent-inject-secret-servercert.crt": {{ .Values.server.serverCert.secretName }} + "vault.hashicorp.com/agent-inject-template-servercert.crt": {{ include "consul.serverTLSCertTemplate" . }} + "vault.hashicorp.com/agent-inject-secret-servercert.key": {{ .Values.server.serverCert.secretName }} + "vault.hashicorp.com/agent-inject-template-servercert.key": {{ include "consul.serverTLSKeyTemplate" . }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ include "consul.serverTLSCATemplate" . }} + {{- end }} {{- end }} "consul.hashicorp.com/connect-inject": "false" "consul.hashicorp.com/config-checksum": {{ include (print $.Template.BasePath "/server-config-configmap.yaml") . | sha256sum }} @@ -100,7 +112,7 @@ spec: - name: config configMap: name: {{ template "consul.fullname" . }}-server-config - {{- if .Values.global.tls.enabled }} + {{- if (and .Values.global.tls.enabled (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-ca-cert secret: {{- if .Values.global.tls.caCert.secretName }} @@ -219,7 +231,7 @@ spec: - | CONSUL_FULLNAME="{{template "consul.fullname" . }}" - {{- if .Values.global.secretsBackend.vault.enabled }} + {{- if and .Values.global.secretsBackend.vault.enabled .Values.global.gossipEncryption.secretName }} GOSSIP_KEY=`cat /vault/secrets/gossip.txt` {{- end }} @@ -230,9 +242,15 @@ spec: -bind=0.0.0.0 \ -bootstrap-expect={{ if .Values.server.bootstrapExpect }}{{ .Values.server.bootstrapExpect }}{{ else }}{{ .Values.server.replicas }}{{ end }} \ {{- if .Values.global.tls.enabled }} + {{- if .Values.global.secretsBackend.vault.enabled }} + -hcl='ca_file = "/vault/secrets/serverca.crt"' \ + -hcl='cert_file = "/vault/secrets/servercert.crt"' \ + -hcl='key_file = "/vault/secrets/servercert.key"' \ + {{- else }} -hcl='ca_file = "/consul/tls/ca/tls.crt"' \ -hcl='cert_file = "/consul/tls/server/tls.crt"' \ -hcl='key_file = "/consul/tls/server/tls.key"' \ + {{- end }} {{- if .Values.global.tls.enableAutoEncrypt }} -hcl='auto_encrypt = {allow_tls = true}' \ {{- end }} @@ -292,7 +310,7 @@ spec: mountPath: /consul/data - name: config mountPath: /consul/config - {{- if .Values.global.tls.enabled }} + {{- if (and .Values.global.tls.enabled (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-ca-cert mountPath: /consul/tls/ca/ readOnly: true @@ -368,8 +386,7 @@ spec: - "-ec" - | {{- if .Values.global.tls.enabled }} - curl \ - --cacert /consul/tls/ca/tls.crt \ + curl -k \ https://127.0.0.1:8501/v1/status/leader \ {{- else }} curl http://127.0.0.1:8500/v1/status/leader \ diff --git a/charts/consul/templates/sync-catalog-deployment.yaml b/charts/consul/templates/sync-catalog-deployment.yaml index 50a847b354..696a8d4c77 100644 --- a/charts/consul/templates/sync-catalog-deployment.yaml +++ b/charts/consul/templates/sync-catalog-deployment.yaml @@ -31,6 +31,17 @@ spec: {{- end }} annotations: "consul.hashicorp.com/connect-inject": "false" + {{- if (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) }} + "vault.hashicorp.com/agent-init-first": "true" + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" + "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + {{- end }} + {{- end }} spec: serviceAccountName: {{ template "consul.fullname" . }}-sync-catalog {{- if .Values.global.tls.enabled }} diff --git a/charts/consul/templates/terminating-gateways-deployment.yaml b/charts/consul/templates/terminating-gateways-deployment.yaml index a53743918d..f99d9f1c26 100644 --- a/charts/consul/templates/terminating-gateways-deployment.yaml +++ b/charts/consul/templates/terminating-gateways-deployment.yaml @@ -53,6 +53,17 @@ spec: component: terminating-gateway terminating-gateway-name: {{ template "consul.fullname" $root }}-{{ .name }} annotations: + {{- if (and $root.Values.global.secretsBackend.vault.enabled $root.Values.global.tls.enabled) }} + "vault.hashicorp.com/agent-init-first": "true" + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": {{ $root.Values.global.secretsBackend.vault.consulCARole }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ $root.Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" $root }} + {{- if and $root.Values.global.secretsBackend.vault.ca.secretName $root.Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": {{ $root.Values.global.secretsBackend.vault.ca.secretName }} + "vault.hashicorp.com/ca-cert": /vault/custom/{{ $root.Values.global.secretsBackend.vault.ca.secretKey }} + {{- end }} + {{- end }} "consul.hashicorp.com/connect-inject": "false" {{- if (and $root.Values.global.metrics.enabled $root.Values.global.metrics.enableGatewayMetrics) }} "prometheus.io/scrape": "true" diff --git a/charts/consul/templates/tls-init-cleanup-job.yaml b/charts/consul/templates/tls-init-cleanup-job.yaml index dc658d733d..ad95cbed16 100644 --- a/charts/consul/templates/tls-init-cleanup-job.yaml +++ b/charts/consul/templates/tls-init-cleanup-job.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} +{{- if not .Values.global.secretsBackend.vault.enabled }} # tls-init-cleanup job deletes Kubernetes secrets created by tls-init apiVersion: batch/v1 kind: Job @@ -62,3 +63,4 @@ spec: cpu: "50m" {{- end }} {{- end }} +{{- end }} diff --git a/charts/consul/templates/tls-init-cleanup-podsecuritypolicy.yaml b/charts/consul/templates/tls-init-cleanup-podsecuritypolicy.yaml index c8dc00f62d..360b23c4ff 100644 --- a/charts/consul/templates/tls-init-cleanup-podsecuritypolicy.yaml +++ b/charts/consul/templates/tls-init-cleanup-podsecuritypolicy.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and (and .Values.global.tls.enabled .Values.global.enablePodSecurityPolicies) (not .Values.server.serverCert.secretName)) }} +{{- if not .Values.global.secretsBackend.vault.enabled }} apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: @@ -38,3 +39,4 @@ spec: readOnlyRootFilesystem: false {{- end }} {{- end }} +{{- end }} diff --git a/charts/consul/templates/tls-init-cleanup-role.yaml b/charts/consul/templates/tls-init-cleanup-role.yaml index 3922144997..27a324eeac 100644 --- a/charts/consul/templates/tls-init-cleanup-role.yaml +++ b/charts/consul/templates/tls-init-cleanup-role.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} +{{- if not .Values.global.secretsBackend.vault.enabled }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: @@ -36,3 +37,4 @@ rules: {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/charts/consul/templates/tls-init-cleanup-rolebinding.yaml b/charts/consul/templates/tls-init-cleanup-rolebinding.yaml index c02f4d2e40..444d1ecf1a 100644 --- a/charts/consul/templates/tls-init-cleanup-rolebinding.yaml +++ b/charts/consul/templates/tls-init-cleanup-rolebinding.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} +{{- if not .Values.global.secretsBackend.vault.enabled }} apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: @@ -22,3 +23,4 @@ subjects: name: {{ template "consul.fullname" . }}-tls-init-cleanup {{- end }} {{- end }} +{{- end }} diff --git a/charts/consul/templates/tls-init-cleanup-serviceaccount.yaml b/charts/consul/templates/tls-init-cleanup-serviceaccount.yaml index f26d14122f..ca8924e579 100644 --- a/charts/consul/templates/tls-init-cleanup-serviceaccount.yaml +++ b/charts/consul/templates/tls-init-cleanup-serviceaccount.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} +{{- if not .Values.global.secretsBackend.vault.enabled }} apiVersion: v1 kind: ServiceAccount metadata: @@ -21,3 +22,4 @@ imagePullSecrets: {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/charts/consul/templates/tls-init-job.yaml b/charts/consul/templates/tls-init-job.yaml index 019513c897..ecb166c8fc 100644 --- a/charts/consul/templates/tls-init-job.yaml +++ b/charts/consul/templates/tls-init-job.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} +{{- if not .Values.global.secretsBackend.vault.enabled }} # tls-init job generate Consul cluster CA and certificates for the Consul servers # and creates Kubernetes secrets for them. apiVersion: batch/v1 @@ -102,3 +103,4 @@ spec: cpu: "50m" {{- end }} {{- end }} +{{- end }} diff --git a/charts/consul/templates/tls-init-podsecuritypolicy.yaml b/charts/consul/templates/tls-init-podsecuritypolicy.yaml index 4f188bd819..2d03ac748c 100644 --- a/charts/consul/templates/tls-init-podsecuritypolicy.yaml +++ b/charts/consul/templates/tls-init-podsecuritypolicy.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and (and .Values.global.tls.enabled .Values.global.enablePodSecurityPolicies) (not .Values.server.serverCert.secretName)) }} +{{- if not .Values.global.secretsBackend.vault.enabled }} apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: @@ -38,3 +39,4 @@ spec: readOnlyRootFilesystem: false {{- end }} {{- end }} +{{- end }} diff --git a/charts/consul/templates/tls-init-role.yaml b/charts/consul/templates/tls-init-role.yaml index 5a27d8b44b..6ee785807f 100644 --- a/charts/consul/templates/tls-init-role.yaml +++ b/charts/consul/templates/tls-init-role.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} +{{- if not .Values.global.secretsBackend.vault.enabled }} apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: @@ -33,3 +34,4 @@ rules: {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/charts/consul/templates/tls-init-rolebinding.yaml b/charts/consul/templates/tls-init-rolebinding.yaml index 3ac92e7316..9d83e9075c 100644 --- a/charts/consul/templates/tls-init-rolebinding.yaml +++ b/charts/consul/templates/tls-init-rolebinding.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} +{{- if not .Values.global.secretsBackend.vault.enabled }} apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: @@ -22,3 +23,4 @@ subjects: name: {{ template "consul.fullname" . }}-tls-init {{- end }} {{- end }} +{{- end }} diff --git a/charts/consul/templates/tls-init-serviceaccount.yaml b/charts/consul/templates/tls-init-serviceaccount.yaml index e8b2d94ab1..06efeddcf4 100644 --- a/charts/consul/templates/tls-init-serviceaccount.yaml +++ b/charts/consul/templates/tls-init-serviceaccount.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and .Values.global.tls.enabled (not .Values.server.serverCert.secretName)) }} +{{- if not .Values.global.secretsBackend.vault.enabled }} apiVersion: v1 kind: ServiceAccount metadata: @@ -21,3 +22,4 @@ imagePullSecrets: {{- end }} {{- end }} {{- end }} +{{- end }} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index 73483651db..03f4de7d43 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1531,6 +1531,65 @@ rollingUpdate: [[ "$output" =~ "global.secretsBackend.vault.consulClientRole must be provided if global.secretsBackend.vault.enabled=true" ]] } +@test "client/DaemonSet: fail when vault, tls are enabled but no caCert provided" { + cd `chart_dir` + run helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.tls.enabled=true' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.tls.caCert.secretName must be provided if global.tls.enabled=true and global.secretsBackend.vault.enabled=true." ]] +} + +@test "client/DaemonSet: fail when vault, tls are enabled with a serverCert but no autoencrypt" { + cd `chart_dir` + run helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.enabled=true' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.tls.enableAutoEncrypt must be true if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" ]] +} + +@test "client/DaemonSet: fail when vault is enabled with tls but autoencrypt is disabled" { + cd `chart_dir` + run helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.server.serverCert.secretName=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.tls.enableAutoEncrypt must be true if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" ]] +} + +@test "client/DaemonSet: fail when vault is enabled with tls but no consulCARole is provided" { + cd `chart_dir` + run helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.server.serverCert.secretName=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.enabled=true' . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.secretsBackend.vault.consulCARole must be provided if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" ]] +} + @test "client/DaemonSet: vault annotations not set by default" { cd `chart_dir` local object=$(helm template \ @@ -1553,6 +1612,7 @@ rollingUpdate: --set 'global.secretsBackend.vault.enabled=true' \ --set 'global.secretsBackend.vault.consulClientRole=foo' \ --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ . | tee /dev/stderr | yq -r '.spec.template.metadata' | tee /dev/stderr) @@ -1571,6 +1631,7 @@ rollingUpdate: --set 'global.secretsBackend.vault.enabled=true' \ --set 'global.secretsBackend.vault.consulClientRole=test' \ --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ --set 'global.gossipEncryption.secretName=path/to/secret' \ --set 'global.gossipEncryption.secretKey=gossip' \ . | tee /dev/stderr | @@ -1592,6 +1653,7 @@ rollingUpdate: --set 'global.secretsBackend.vault.enabled=true' \ --set 'global.secretsBackend.vault.consulClientRole=test' \ --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ --set 'global.gossipEncryption.secretName=a/b/c/d' \ --set 'global.gossipEncryption.secretKey=gossip' \ . | tee /dev/stderr | @@ -1675,3 +1737,65 @@ rollingUpdate: local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') [ "${actual}" = "/vault/custom/tls.crt" ] } + +@test "client/DaemonSet: vault tls annotations are set when tls is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual="$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr)" + [ "${actual}" = "pki_int/cert/ca" ] + + local actual="$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"pki_int/cert/ca\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] +} + +@test "client/DaemonSet: tls related volumes not attached and command is modified correctly when tls is enabled with vault" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=pki_int/ca/pem' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec' | tee /dev/stderr) + + + local actual=$(echo $object | + yq -r '.volumes[] | select(.name == "consul-ca-cert") | length > 0' | tee /dev/stderr) + [ "${actual}" = "" ] + + local actual=$(echo $object | + yq -r '.volumes[] | select(.name == "consul-ca-key") | length > 0' | tee /dev/stderr) + [ "${actual}" = "" ] + + local actual=$(echo $object | + yq -r '.containers[0].volumeMounts[] | select(.name == "consul-client-cert")' | tee /dev/stderr) + [ "${actual}" = "" ] + + local actual=$(echo $object | + yq -r '.containers[0].volumeMounts[] | select(.name == "consul-ca-key")' | tee /dev/stderr) + [ "${actual}" = "" ] + + local actual=$(echo $object | + yq -r '.containers[0].command | any(contains("ca_file = \"/vault/secrets/serverca.crt\""))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} \ No newline at end of file diff --git a/charts/consul/test/unit/client-snapshot-agent-deployment.bats b/charts/consul/test/unit/client-snapshot-agent-deployment.bats index 07d96a68bf..22dc6c9855 100644 --- a/charts/consul/test/unit/client-snapshot-agent-deployment.bats +++ b/charts/consul/test/unit/client-snapshot-agent-deployment.bats @@ -458,3 +458,127 @@ exec /bin/consul snapshot agent \' yq -r -c '.spec.template.spec.containers[0].env[] | select(.name == "CONSUL_LICENSE_PATH")' | tee /dev/stderr) [ "${actual}" = "" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "client/SnapshotAgentDeployment: configures server CA to come from vault when vault is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check annotations + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-init-first"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr) + [ "${actual}" = "carole" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr) + [ "${actual}" = "foo" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr) + [ "${actual}" = $'{{- with secret \"foo\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' ] +} + +@test "client/SnapshotAgentDeployment: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "client/SnapshotAgentDeployment: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "client/SnapshotAgentDeployment: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "client/SnapshotAgentDeployment: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} diff --git a/charts/consul/test/unit/connect-inject-deployment.bats b/charts/consul/test/unit/connect-inject-deployment.bats index 75df185d3f..8730a2b21e 100755 --- a/charts/consul/test/unit/connect-inject-deployment.bats +++ b/charts/consul/test/unit/connect-inject-deployment.bats @@ -1512,4 +1512,133 @@ EOF yq '.spec.replicas' | tee /dev/stderr) [ "${actual}" = "3" ] -} \ No newline at end of file +} + +#-------------------------------------------------------------------- +# Vault + +@test "connectInject/Deployment: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "connectInject/Deployment: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "connectInject/Deployment: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "connectInject/Deployment: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} + +@test "connectInject/Deployment: vault tls annotations are set when tls is enabled" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=bar' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"pki_int/cert/ca\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr)" + [ "${actual}" = "pki_int/cert/ca" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-init-first"]' | tee /dev/stderr)" + [ "${actual}" = "true" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr)" + [ "${actual}" = "true" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr)" + [ "${actual}" = "test" ] +} diff --git a/charts/consul/test/unit/controller-deployment.bats b/charts/consul/test/unit/controller-deployment.bats index 158c6edaaa..29cd9a1026 100644 --- a/charts/consul/test/unit/controller-deployment.bats +++ b/charts/consul/test/unit/controller-deployment.bats @@ -550,3 +550,133 @@ load _helpers [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# Vault + +@test "controller/Deployment: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/controller-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "controller/Deployment: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/controller-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "controller/Deployment: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/controller-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "controller/Deployment: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/controller-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} + +@test "controller/Deployment: vault tls annotations are set when tls is enabled" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/controller-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=bar' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"pki_int/cert/ca\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr)" + [ "${actual}" = "pki_int/cert/ca" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-init-first"]' | tee /dev/stderr)" + [ "${actual}" = "true" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr)" + [ "${actual}" = "true" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr)" + [ "${actual}" = "test" ] +} + + diff --git a/charts/consul/test/unit/helpers.bats b/charts/consul/test/unit/helpers.bats index 235338adc6..75e90165a9 100644 --- a/charts/consul/test/unit/helpers.bats +++ b/charts/consul/test/unit/helpers.bats @@ -270,3 +270,26 @@ load _helpers [ "${actual}" = "" ] } + +@test "helper/consul.getAutoEncryptClientCA: uses the correct -ca-file when vault is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/tests/test-runner.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.caCert.secretName=pki_int/ca/pem' \ + --set 'server.enabled=false' \ + . | tee /dev/stderr | + yq '.spec.initContainers[] | select(.name == "get-auto-encrypt-client-ca")' | tee /dev/stderr) + + actual=$(echo $object | jq '.command | join(" ") | contains("-ca-file=/vault/secrets/serverca.crt")') + [ "${actual}" = "true" ] + + actual=$(echo $object | jq '.volumeMounts[] | select(.name == "consul-ca-cert")') + [ "${actual}" = "" ] +} diff --git a/charts/consul/test/unit/ingress-gateways-deployment.bats b/charts/consul/test/unit/ingress-gateways-deployment.bats index c4b623e4be..ee1ac5f303 100644 --- a/charts/consul/test/unit/ingress-gateways-deployment.bats +++ b/charts/consul/test/unit/ingress-gateways-deployment.bats @@ -1485,3 +1485,128 @@ EOF local actual=$(echo $object | yq '.[2] | length > 0' | tee /dev/stderr) [ "${actual}" = "false" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "ingressGateway/Deployment: vault tls annotations are set when tls is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check annotations + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-init-first"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr) + [ "${actual}" = "carole" ] + + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr) + [ "${actual}" = "foo" ] + + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr) + [ "${actual}" = $'{{- with secret \"foo\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' ] +} + +@test "ingressGateway/Deployment: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + + +@test "ingressGateway/Deployment: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "ingressGateway/Deployment: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "ingressGateway/Deployment: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} \ No newline at end of file diff --git a/charts/consul/test/unit/server-acl-init-job.bats b/charts/consul/test/unit/server-acl-init-job.bats index a0ae9a34c5..117f77d37d 100644 --- a/charts/consul/test/unit/server-acl-init-job.bats +++ b/charts/consul/test/unit/server-acl-init-job.bats @@ -593,6 +593,139 @@ load _helpers [ "${actual}" = "key" ] } +@test "serverACLInit/Job: configures server CA to come from vault when vault is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.server.serverCert.secretName=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check annotations + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-pre-populate-only"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr) + [ "${actual}" = "carole" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr) + [ "${actual}" = "foo" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr) + [ "${actual}" = $'{{- with secret \"foo\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' ] + + # Check that the consul-ca-cert volume is not attached + local actual=$(echo $object | jq -r '.spec.volumes') + [ "${actual}" = "null" ] + + local actual=$(echo $object | jq -r '.spec.containers[] | select(.name="post-install-job").volumeMounts') + [ "${actual}" = "null" ] +} + +@test "serverACLInit/Job: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.server.serverCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "serverACLInit/Job: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.server.serverCert.secretName=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "serverACLInit/Job: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.server.serverCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "serverACLInit/Job: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.server.serverCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} + #-------------------------------------------------------------------- # namespaces diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 9a180f5d98..9ff08dbd85 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -818,7 +818,7 @@ load _helpers #-------------------------------------------------------------------- # global.openshift.enabled & client.containerSecurityContext -@test "client/DaemonSet: container level securityContexts are not set when global.openshift.enabled=true" { +@test "server/StatefulSet: container level securityContexts are not set when global.openshift.enabled=true" { cd `chart_dir` local manifest=$(helm template \ -s templates/server-statefulset.yaml \ @@ -1036,16 +1036,6 @@ load _helpers [ "${actual}" = "true" ] } -@test "server/StatefulSet: CA certificate is specified when TLS is enabled" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-statefulset.yaml \ - --set 'global.tls.enabled=true' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].readinessProbe.exec.command | join(" ") | contains("--cacert /consul/tls/ca/tls.crt")' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - @test "server/StatefulSet: HTTP is disabled in agent when httpsOnly is enabled" { cd `chart_dir` local actual=$(helm template \ @@ -1424,6 +1414,63 @@ load _helpers [[ "$output" =~ "global.secretsBackend.vault.consulServerRole must be provided if global.secretsBackend.vault.enabled=true" ]] } +@test "server/StatefulSet: fail when vault is enabled with tls but autoencrypt is disabled" { + cd `chart_dir` + run helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.server.serverCert.secretName=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.tls.enableAutoEncrypt must be true if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" ]] +} + +@test "server/StatefulSet: fail when vault, tls are enabled but no caCert provided" { + cd `chart_dir` + run helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.tls.enabled=true' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.tls.caCert.secretName must be provided if global.tls.enabled=true and global.secretsBackend.vault.enabled=true." ]] +} + +@test "server/StatefulSet: fail when vault, tls are enabled with a serverCert but no autoencrypt" { + cd `chart_dir` + run helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.enabled=true' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.tls.enableAutoEncrypt must be true if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" ]] +} + +@test "server/StatefulSet: fail when vault is enabled with tls but no consulCARole is provided" { + cd `chart_dir` + run helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.server.serverCert.secretName=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.enabled=true' . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.secretsBackend.vault.consulCARole must be provided if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" ]] +} + @test "server/StatefulSet: vault annotations not set by default" { cd `chart_dir` local object=$(helm template \ @@ -1617,3 +1664,74 @@ load _helpers local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') [ "${actual}" = "/vault/custom/tls.crt" ] } + +@test "server/StatefulSet: vault tls annotations are set when tls is enabled and command modified correctly" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc2' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual="$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr)" + [ "${actual}" = "pki_int/cert/ca" ] + + local actual="$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"pki_int/cert/ca\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + local actual="$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-servercert.crt"]' | tee /dev/stderr)" + [ "${actual}" = "pki_int/issue/test" ] + + local actual=$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-servercert.crt"]' | tee /dev/stderr) + local expected=$'{{- with secret \"pki_int/issue/test\" \"common_name=server.dc2.consul\"\n\"ttl=1h\" \"alt_names=localhost,RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server.default,*.RELEASE-NAME-consul-server.default.svc,*.server.dc2.consul\" \"ip_sans=127.0.0.1\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + local actual="$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-servercert.key"]' | tee /dev/stderr)" + [ "${actual}" = "pki_int/issue/test" ] + + local actual="$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-servercert.key"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"pki_int/issue/test\" \"common_name=server.dc2.consul\"\n\"ttl=1h\" \"alt_names=localhost,RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server.default,*.RELEASE-NAME-consul-server.default.svc,*.server.dc2.consul\" \"ip_sans=127.0.0.1\" -}}\n{{- .Data.private_key -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + local actual=$(echo $object | + yq -r '.spec.containers[0].command | any(contains("ca_file = \"/vault/secrets/serverca.crt\""))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "server/StatefulSet: tls related volumes not attached when tls is enabled on vault" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.volumes[] | select(.name == "consul-ca-cert") | length > 0' | tee /dev/stderr) + [ "${actual}" = "" ] + + local actual=$(echo $object | + yq -r '.containers[0].volumeMounts[] | select(.name == "consul-ca-key")' | tee /dev/stderr) + [ "${actual}" = "" ] +} diff --git a/charts/consul/test/unit/sync-catalog-deployment.bats b/charts/consul/test/unit/sync-catalog-deployment.bats index 904ac699ce..f69937c886 100755 --- a/charts/consul/test/unit/sync-catalog-deployment.bats +++ b/charts/consul/test/unit/sync-catalog-deployment.bats @@ -978,3 +978,126 @@ load _helpers [ "${actual}" = "true" ] } +#-------------------------------------------------------------------- +# Vault + +@test "syncCatalog/Deployment: configures server CA to come from vault when vault is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/sync-catalog-deployment.yaml \ + --set 'syncCatalog.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check annotations + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-init-first"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr) + [ "${actual}" = "carole" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr) + [ "${actual}" = "foo" ] + local actual + actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr) + [ "${actual}" = $'{{- with secret \"foo\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' ] +} + +@test "syncCatalog/Deployment: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/sync-catalog-deployment.yaml \ + --set 'syncCatalog.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "syncCatalog/Deployment: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/sync-catalog-deployment.yaml \ + --set 'syncCatalog.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "syncCatalog/Deployment: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/sync-catalog-deployment.yaml \ + --set 'syncCatalog.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "syncCatalog/Deployment: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/sync-catalog-deployment.yaml \ + --set 'syncCatalog.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} diff --git a/charts/consul/test/unit/terminating-gateways-deployment.bats b/charts/consul/test/unit/terminating-gateways-deployment.bats index 5a36e639be..e0bbdcd0a4 100644 --- a/charts/consul/test/unit/terminating-gateways-deployment.bats +++ b/charts/consul/test/unit/terminating-gateways-deployment.bats @@ -1295,3 +1295,127 @@ EOF local actual=$(echo $object | yq '.[2] | length > 0' | tee /dev/stderr) [ "${actual}" = "false" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "terminatingGateway/Deployment: configures server CA to come from vault when vault is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/terminating-gateways-deployment.yaml \ + --set 'terminatingGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check annotations + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-init-first"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr) + [ "${actual}" = "carole" ] + + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr) + [ "${actual}" = "foo" ] + + local actual=$(echo $object | jq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr) + [ "${actual}" = $'{{- with secret \"foo\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' ] +} + +@test "terminatingGateway/Deployment: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/terminating-gateways-deployment.yaml \ + --set 'terminatingGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "terminatingGateway/Deployment: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/terminating-gateways-deployment.yaml \ + --set 'terminatingGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "terminatingGateway/Deployment: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/terminating-gateways-deployment.yaml \ + --set 'terminatingGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "terminatingGateway/Deployment: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/terminating-gateways-deployment.yaml \ + --set 'terminatingGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} diff --git a/charts/consul/test/unit/tls-init-cleanup-job.bats b/charts/consul/test/unit/tls-init-cleanup-job.bats index d75abf7d6d..76da65bfe5 100644 --- a/charts/consul/test/unit/tls-init-cleanup-job.bats +++ b/charts/consul/test/unit/tls-init-cleanup-job.bats @@ -58,3 +58,20 @@ load _helpers yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "tlsInitCleanup/Job: disabled with global.secretsBackend.vault.enabled=true and global.tls.enabled=true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-cleanup-job.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . +} diff --git a/charts/consul/test/unit/tls-init-cleanup-podsecuritypolicy.bats b/charts/consul/test/unit/tls-init-cleanup-podsecuritypolicy.bats index 34d747aecb..72d1812c69 100644 --- a/charts/consul/test/unit/tls-init-cleanup-podsecuritypolicy.bats +++ b/charts/consul/test/unit/tls-init-cleanup-podsecuritypolicy.bats @@ -47,3 +47,20 @@ load _helpers yq -s 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "tlsInitCleanup/PodSecurityPolicy: disabled with global.secretsBackend.vault.enabled=true and global.tls.enabled=true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-cleanup-podsecuritypolicy.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . +} diff --git a/charts/consul/test/unit/tls-init-cleanup-role.bats b/charts/consul/test/unit/tls-init-cleanup-role.bats index ad3ca7bbe6..cfcf5be7ba 100644 --- a/charts/consul/test/unit/tls-init-cleanup-role.bats +++ b/charts/consul/test/unit/tls-init-cleanup-role.bats @@ -70,3 +70,20 @@ load _helpers [ "${actual}" = "RELEASE-NAME-consul-tls-init-cleanup" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "tlsInitCleanup/Role: disabled with global.secretsBackend.vault.enabled=true and global.tls.enabled=true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-cleanup-role.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . +} diff --git a/charts/consul/test/unit/tls-init-cleanup-rolebinding.bats b/charts/consul/test/unit/tls-init-cleanup-rolebinding.bats index 5fd3632ed4..07cd485852 100644 --- a/charts/consul/test/unit/tls-init-cleanup-rolebinding.bats +++ b/charts/consul/test/unit/tls-init-cleanup-rolebinding.bats @@ -58,3 +58,20 @@ load _helpers yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "tlsInitCleanup/RoleBinding: disabled with global.secretsBackend.vault.enabled=true and global.tls.enabled=true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-cleanup-rolebinding.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . +} diff --git a/charts/consul/test/unit/tls-init-cleanup-serviceaccount.bats b/charts/consul/test/unit/tls-init-cleanup-serviceaccount.bats index d2a89e4e48..283c1ad73f 100644 --- a/charts/consul/test/unit/tls-init-cleanup-serviceaccount.bats +++ b/charts/consul/test/unit/tls-init-cleanup-serviceaccount.bats @@ -79,3 +79,20 @@ load _helpers yq -r '.imagePullSecrets[1].name' | tee /dev/stderr) [ "${actual}" = "my-secret2" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "tlsInitCleanup/ServiceAccount: disabled with global.secretsBackend.vault.enabled=true and global.tls.enabled=true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-cleanup-serviceaccount.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . +} diff --git a/charts/consul/test/unit/tls-init-job.bats b/charts/consul/test/unit/tls-init-job.bats index 9c751fa3d8..8db52fcfbd 100644 --- a/charts/consul/test/unit/tls-init-job.bats +++ b/charts/consul/test/unit/tls-init-job.bats @@ -115,3 +115,20 @@ load _helpers actual=$(echo $spec | jq -r '.containers[0].command | join(" ") | contains("consul tls ca create")' | tee /dev/stderr) [ "${actual}" = "false" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "tlsInit/Job: disabled with global.secretsBackend.vault.enabled=true and global.tls.enabled=true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-job.yaml \ + --set 'global.tls.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . +} diff --git a/charts/consul/test/unit/tls-init-podsecuritypolicy.bats b/charts/consul/test/unit/tls-init-podsecuritypolicy.bats index 5ec0729d05..459097a9db 100644 --- a/charts/consul/test/unit/tls-init-podsecuritypolicy.bats +++ b/charts/consul/test/unit/tls-init-podsecuritypolicy.bats @@ -47,3 +47,20 @@ load _helpers yq -s 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "tlsInit/PodSecurityPolicy: disabled with global.secretsBackend.vault.enabled=true and global.tls.enabled=true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-podsecuritypolicy.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . +} diff --git a/charts/consul/test/unit/tls-init-role.bats b/charts/consul/test/unit/tls-init-role.bats index fe601be911..12af5ed2d0 100644 --- a/charts/consul/test/unit/tls-init-role.bats +++ b/charts/consul/test/unit/tls-init-role.bats @@ -70,3 +70,20 @@ load _helpers [ "${actual}" = "RELEASE-NAME-consul-tls-init" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "tlsInit/Role: disabled with global.secretsBackend.vault.enabled=true and global.tls.enabled=true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-role.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . +} diff --git a/charts/consul/test/unit/tls-init-rolebinding.bats b/charts/consul/test/unit/tls-init-rolebinding.bats index cac2a97f53..3085d4b85b 100644 --- a/charts/consul/test/unit/tls-init-rolebinding.bats +++ b/charts/consul/test/unit/tls-init-rolebinding.bats @@ -58,3 +58,20 @@ load _helpers yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# Vault + +@test "tlsInit/RoleBinding: disabled with global.secretsBackend.vault.enabled=true and global.tls.enabled=true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-rolebinding.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . +} diff --git a/charts/consul/test/unit/tls-init-serviceaccount.bats b/charts/consul/test/unit/tls-init-serviceaccount.bats index 9eb3560ba7..3acf6f281e 100644 --- a/charts/consul/test/unit/tls-init-serviceaccount.bats +++ b/charts/consul/test/unit/tls-init-serviceaccount.bats @@ -80,3 +80,19 @@ load _helpers [ "${actual}" = "my-secret2" ] } +#-------------------------------------------------------------------- +# Vault + +@test "tlsInit/ServiceAccount: disabled with global.secretsBackend.vault.enabled=true and global.tls.enabled=true" { + cd `chart_dir` + assert_empty helm template \ + -s templates/tls-init-serviceaccount.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . +} diff --git a/charts/consul/test/unit/ui-ingress.bats b/charts/consul/test/unit/ui-ingress.bats index 3a4e1b6bd1..f26d181d2b 100755 --- a/charts/consul/test/unit/ui-ingress.bats +++ b/charts/consul/test/unit/ui-ingress.bats @@ -69,6 +69,7 @@ load _helpers # --kube-version "1.18" \ # . | tee /dev/stderr | # yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -89,6 +90,7 @@ load _helpers # --kube-version "1.18" \ # . | tee /dev/stderr | # yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -110,6 +112,7 @@ load _helpers # --kube-version "1.18" \ # . | tee /dev/stderr | # yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -132,6 +135,7 @@ load _helpers # --kube-version "1.18" \ # . | tee /dev/stderr | # yq -r '.spec.rules[0].http.paths[1].backend.servicePort' | tee /dev/stderr) + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -207,6 +211,7 @@ load _helpers # pathtype @test "ui/Ingress: default PathType Prefix" { + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -218,6 +223,7 @@ load _helpers } @test "ui/Ingress: set PathType ImplementationSpecific" { + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index ec6b29c2e7..adc1edb6e0 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -118,10 +118,11 @@ global: enablePodSecurityPolicies: false # secretsBackend is used to configure Vault as the secrets backend for the Consul on Kubernetes installation. - # The Vault cluster needs to have the Kubernetes Auth Method, - # KV2 and PKI secrets engines enabled and have necessary secrets, - # policies and roles created prior to installing Consul. - # The Vault cluster should not have Consul as its storage backend. + # The Vault cluster needs to have the Kubernetes Auth Method, KV2 and PKI secrets engines enabled + # and have necessary secrets, policies and roles created prior to installing Consul. + # The Vault cluster *must* not have the Consul cluster installed by this Helm chart as its storage backend. + # It can have Consul as its storage backend as long as that Consul cluster is not running on this Kubernetes cluster + # and is being managed separately from this Helm installation. # Note: When using Vault KV2 secrets engines the "data" field is implicitly required for Vault API calls, # secretName should be in the form of "vault-kv2-mount-path/data/secret-name". # secretKey should be in the form of "key". @@ -152,6 +153,12 @@ global: # and check the name of `metadata.name`. consulClientRole: "" + # The Vault role for all Consul components to read the ServerTLS CA Certificate (unauthenticated). + # The role should be connected to the service accounts of all Consul components, or alternatively `*` since it + # will be used only against the `pki/cert/ca` endpoint which is unauthenticated. A policy must be created which grants + # read capabilities to `global.tls.caCert.secretName`, which is usually `pki/cert/ca`. + consulCARole: "" + # Configuration for Vault server CA certificate. This certificate will be mounted # to any pod where Vault agent needs to run. ca: @@ -206,7 +213,7 @@ global: # Values for secretName and secretKey should not be set if autoGenerate is true. # To manually generate a gossip encryption key, set secretName and secretKey and use Consul to generate # a key, saving this as a Kubernetes secret or Vault secret path and key. - # If `global.secretsBackend.vault.enabled=true`, be sure to add the "data" field to the secretName as required by + # If `global.secretsBackend.vault.enabled=true`, be sure to add the "data" component of the secretName path as required by # the Vault KV-2 secrets engine [see example]. # # ``` @@ -274,15 +281,19 @@ global: # both clients and servers and to only accept HTTPS connections. httpsOnly: true - # A Kubernetes secret containing the certificate of the CA to use for - # TLS communication within the Consul cluster. If you have generated the CA yourself - # with the consul CLI, you could use the following command to create the secret + # A secret containing the certificate of the CA to use for TLS communication within the Consul cluster. + # If you have generated the CA yourself with the consul CLI, you could use the following command to create the secret # in Kubernetes: # # ```bash # kubectl create secret generic consul-ca-cert \ # --from-file='tls.crt=./consul-agent-ca.pem' # ``` + # If you are using Vault as a secrets backend with TLS, `caCert.secretName` must be provided and should reference + # the CA path for your PKI secrets engine. This should be of the form `pki/cert/ca` where `pki` is the mount point of your PKI secrets engine. + # A read policy must be created and associated with the CA cert path for `global.tls.caCert.secretName`. + # This will be consumed by the `global.secretsBackend.vault.consulCARole` role by all Consul components. + # When using Vault the secretKey is not used. caCert: # The name of the Kubernetes secret. secretName: null @@ -470,10 +481,11 @@ server: # Manages license autoload. Required in Consul 1.10.0+, 1.9.7+ and 1.8.12+. enableLicenseAutoload: true - # A Kubernetes secret containing a certificate & key for the server agents to use + # A secret containing a certificate & key for the server agents to use # for TLS communication within the Consul cluster. Cert needs to be provided with # additional DNS name SANs so that it will work within the Kubernetes cluster: # + # Kubernetes Secrets backend: # ```bash # consul tls cert create -server -days=730 -domain=consul -ca=consul-agent-ca.pem \ # -key=consul-agent-ca-key.pem -dc={{datacenter}} \ @@ -485,8 +497,7 @@ server: # -additional-dnsname="server.{{datacenter}}.{{domain}}" # ``` # - # If you have generated the - # server-cert yourself with the consul CLI, you could use the following command + # If you have generated the server-cert yourself with the consul CLI, you could use the following command # to create the secret in Kubernetes: # # ```bash @@ -494,8 +505,16 @@ server: # --from-file='tls.crt=./dc1-server-consul-0.pem' # --from-file='tls.key=./dc1-server-consul-0-key.pem' # ``` + # + # Vault Secrets backend: + # If you are using Vault as a secrets backend, a Vault Policy must be created which allows `["create", "update"]` + # capabilities on the PKI issuing endpoint, which is usually of the form `pki/issue/consul-server`. + # Please see the following guide for steps to generate a compatible certificate: + # https://learn.hashicorp.com/tutorials/consul/vault-pki-consul-secure-tls + # Note: when using TLS, both the `server.serverCert` and `global.tls.caCert` which points to the CA endpoint of this PKI engine + # must be provided. serverCert: - # The name of the Kubernetes secret. + # The name of the Kubernetes secret or Vault secret path containing the PEM encoded server certificate. secretName: null # Exposes the servers' gossip and RPC ports as hostPorts. To enable a client From 8107dd1f3b0cb33c7a814a5233c9e7412e599df8 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Mon, 6 Dec 2021 19:30:21 -0600 Subject: [PATCH 170/418] mod tidy --- acceptance/go.mod | 56 ++++++++++++++++++------- acceptance/go.sum | 104 +++++++++++++++++++++++----------------------- 2 files changed, 92 insertions(+), 68 deletions(-) diff --git a/acceptance/go.mod b/acceptance/go.mod index e86a0091d8..c43c0816aa 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -5,6 +5,7 @@ go 1.17 require ( github.com/gruntwork-io/terratest v0.31.2 github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51 + github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/vault/api v1.2.0 github.com/stretchr/testify v1.7.0 @@ -16,57 +17,82 @@ require ( require ( cloud.google.com/go v0.54.0 // indirect - github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect - github.com/aws/aws-sdk-go v1.27.1 // indirect + github.com/armon/go-metrics v0.3.9 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/aws/aws-sdk-go v1.30.27 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect + github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/evanphx/json-patch v4.11.0+incompatible // indirect - github.com/fatih/color v1.9.0 // indirect + github.com/fatih/color v1.12.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect github.com/go-logr/logr v0.4.0 // indirect - github.com/go-sql-driver/mysql v1.4.1 // indirect + github.com/go-sql-driver/mysql v1.5.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/go-cmp v0.5.5 // indirect + github.com/golang/snappy v0.0.1 // indirect + github.com/google/go-cmp v0.5.6 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/uuid v1.1.2 // indirect github.com/googleapis/gnostic v0.5.5 // indirect github.com/gruntwork-io/gruntwork-cli v0.7.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.1 // indirect - github.com/hashicorp/go-hclog v0.12.0 // indirect - github.com/hashicorp/go-immutable-radix v1.0.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v0.16.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.0.1 // indirect + github.com/hashicorp/go-retryablehttp v0.6.6 // indirect github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/hashicorp/go-version v1.2.0 // indirect github.com/hashicorp/golang-lru v0.5.3 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/serf v0.9.6 // indirect - github.com/imdario/mergo v0.3.7 // indirect - github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect + github.com/hashicorp/vault/sdk v0.2.1 // indirect + github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jmespath/go-jmespath v0.3.0 // indirect github.com/json-iterator/go v1.1.11 // indirect - github.com/mattn/go-colorable v0.1.6 // indirect - github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.13 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.1.2 // indirect + github.com/mitchellh/go-testing-interface v1.14.0 // indirect + github.com/mitchellh/mapstructure v1.4.2 // indirect + github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/oklog/run v1.0.0 // indirect + github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pquerna/otp v1.2.0 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/urfave/cli v1.22.2 // indirect + go.uber.org/atomic v1.7.0 // indirect golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 // indirect + golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect golang.org/x/text v0.3.6 // indirect golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - google.golang.org/appengine v1.6.5 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect + google.golang.org/grpc v1.38.0 // indirect google.golang.org/protobuf v1.26.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/square/go-jose.v2 v2.5.1 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect k8s.io/klog/v2 v2.9.0 // indirect k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect diff --git a/acceptance/go.sum b/acceptance/go.sum index a2cdcd5bba..de7c95fae2 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -223,12 +223,12 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk= github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= @@ -313,14 +313,14 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= @@ -332,10 +332,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= @@ -388,10 +387,10 @@ github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51 github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51/go.mod h1:+Ay3RL0eZdI0wgT193r+EJTOk9cSn1WUlvBvk6Lfnmo= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f h1:fBBh4412td7nBzqyLkpGTH5dWycPs8p7Yg/Dy8VQjVU= -github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f h1:fBBh4412td7nBzqyLkpGTH5dWycPs8p7Yg/Dy8VQjVU= github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -457,11 +456,16 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= +github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= +github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f/go.mod h1:euTFbi2YJgwcju3imEt919lhJKF68nN1cQPq3aA+kBE= github.com/hashicorp/vault/api v1.2.0 h1:ysGFc6XRGbv05NsWPzuO5VTv68Lj8jtwATxRLFOpP9s= @@ -472,11 +476,6 @@ github.com/hashicorp/vault/sdk v0.2.1/go.mod h1:WfUiO1vYzfBkz1TmoE4ZGU7HD0T0Cl/r github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= -github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= @@ -559,6 +558,7 @@ github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJc github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= @@ -586,10 +586,10 @@ github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -605,17 +605,16 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20180130162743-b8a9be070da4/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -625,20 +624,18 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -765,11 +762,11 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -829,6 +826,7 @@ go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -884,6 +882,7 @@ golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -914,17 +913,17 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -941,13 +940,13 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -996,30 +995,29 @@ golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 h1:RqytpXGR1iVNX7psjB3ff8y7sNFinVFvkx1c8SjBkio= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= @@ -1089,11 +1087,11 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1142,12 +1140,12 @@ google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1177,12 +1175,12 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1232,15 +1230,15 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= +k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= +k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= -k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= -k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= @@ -1291,13 +1289,13 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/controller-runtime v0.10.2/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= From 09f0ac2964e328f6e87cb92c22d07b2ffc72d38c Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Mon, 6 Dec 2021 20:20:43 -0600 Subject: [PATCH 171/418] fix merge error --- charts/consul/values.yaml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 857abbf501..c8239f4f78 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -481,21 +481,6 @@ server: # @type: int bootstrapExpect: null - # [Enterprise Only] This value refers to a Kubernetes secret that you have created - # that contains your enterprise license. It is required if you are using an - # enterprise binary. Defining it here applies it to your cluster once a leader - # has been elected. If you are not using an enterprise image or if you plan to - # introduce the license key via another route, then set these fields to null. - # Note: the job to apply license runs on both Helm installs and upgrades. - enterpriseLicense: - # The name of the Kubernetes secret that holds the enterprise license. - # The secret must be in the same namespace that Consul is installed into. - secretName: null - # The key within the Kubernetes secret that holds the enterprise license. - secretKey: null - # Manages license autoload. Required in Consul 1.10.0+, 1.9.7+ and 1.8.12+. - enableLicenseAutoload: true - # A secret containing a certificate & key for the server agents to use # for TLS communication within the Consul cluster. Cert needs to be provided with # additional DNS name SANs so that it will work within the Kubernetes cluster: From ea85df12eb3da7a283ae9558058ffbdd60def957 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Mon, 6 Dec 2021 21:08:27 -0600 Subject: [PATCH 172/418] add changelog entries --- CHANGELOG.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d977798e5c..f48138a1c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,72 @@ BREAKING CHANGES: * Control Plane * Update minimum go version for project to 1.17 [[GH-878](https://github.com/hashicorp/consul-k8s/pull/878)] - * Add boolean metric to merged metrics response `consul_merged_service_metrics_success` to indicate if service metrics were - scraped successfully. [[GH-551](https://github.com/hashicorp/consul-k8s/pull/551)] + * Add boolean metric to merged metrics response `consul_merged_service_metrics_success` to indicate if service metrics + were scraped successfully. [[GH-551](https://github.com/hashicorp/consul-k8s/pull/551)] IMPROVEMENTS: +* Vault as a Secrets Backend + * Add support for Vault as a secrets backend for Gossip Encryption, Server TLS certs and Service Mesh TLS certificates, + removing the existing usage of Kubernetes Secrets for the respective secrets. [[GH-904](https://github.com/hashicorp/consul-k8s/pull/904/)] + * Consul 1.11+ is required. + * Vault 1.19+ is required and Vault-K8s 0.14+ must be installed with the Vault Agent Injector (`injector.enabled=true`) + and must be configured to talk to the Vault server installation from the Kubernetes cluster that Consul is installed. + * `global.tls.enableAutoEncryption=true` is required for TLS support. + * If TLS is enabled in Vault `global.secretsBackend.vault.ca` must be provided and should reference a Kube secret + which holds a copy of the Vault CA cert. + +To enable the Vault Secrets backend for the Consul cluster use the following config: + +```yaml +global: + image: hashicorp/consul:1.11.0 + + # Gossip Encryption. + gossipEncryption: + secretName="consul/data/secrets/gossip" + secretKey="key" + + tls: + enabled: true + enableAutoEncryption: true + + # Server CA certificate. + caCert: + secretName: "pki/cert/ca" + + # Vault configuration. + secretsBackend: + vault: + enabled: true + + # Vault Auth Roles. + consulServerRole: "consul-server" + consulClientRole: "consul-client" + consulCARole: "consul-ca" + + # If Vault TLS is enabled. + ca: + secretName: "vault-CA-cert" + secretKey: "tls.crt" + + # Connect CA configuration. + connectCA: + address: "https://vault:8200" + rootPKIPath: "connect_root" + intermediatePKIPath: "connect_inter" + +# Server TLS Certificates. +server: + serverCert: + secretName: "pki/issue/consul-server" + extraVolumes: + - name: "vault-CA-cert" + type: "secret" + load: false +``` +Note: See `values.yaml` and [Consul - Vault documentation](https://www.consul.io/docs/k8s/installation/vault/index.mdx) +for additional information on required Vault policies and configurations. + * CLI * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] * Control Plane From 2e9da0da16e70877df338b48465d7fe63c4d44e5 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Tue, 7 Dec 2021 06:59:46 -0800 Subject: [PATCH 173/418] cli: allow enterprise images to be named without the string "-ent" (#903) In a case where users might have a Consul enterprise image that may not contain the string "-ent" in the name, we don't want to fail the installation. This is a fairly common case, so we've removed the check. --- cli/cmd/install/install.go | 15 ++++++--------- cli/cmd/install/install_test.go | 13 ++++--------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index 001c1d3c2a..44b1bca41f 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -3,12 +3,13 @@ package install import ( "errors" "fmt" - k8serrors "k8s.io/apimachinery/pkg/api/errors" "os" "strings" "sync" "time" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + consulChart "github.com/hashicorp/consul-k8s/charts" "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" @@ -179,7 +180,6 @@ type helmValues struct { } type globalValues struct { - Image string `yaml:"image"` EnterpriseLicense enterpriseLicense `yaml:"enterpriseLicense"` } @@ -291,7 +291,7 @@ func (c *Command) Run(args []string) int { // If an enterprise license secret was provided check that the secret exists // and that the enterprise Consul image is set. if v.Global.EnterpriseLicense.SecretName != "" { - if err := c.checkValidEnterprise(v.Global.EnterpriseLicense.SecretName, v.Global.Image); err != nil { + if err := c.checkValidEnterprise(v.Global.EnterpriseLicense.SecretName); err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 } @@ -535,8 +535,8 @@ func validLabel(s string) bool { // checkValidEnterprise checks and validates an enterprise installation. // When an enterprise license secret is provided, check that the secret exists -// in the "consul" namespace, and that the enterprise Consul image is provided. -func (c *Command) checkValidEnterprise(secretName string, image string) error { +// in the "consul" namespace. +func (c *Command) checkValidEnterprise(secretName string) error { _, err := c.kubernetes.CoreV1().Secrets(c.flagNamespace).Get(c.Ctx, secretName, metav1.GetOptions{}) if k8serrors.IsNotFound(err) { @@ -544,9 +544,6 @@ func (c *Command) checkValidEnterprise(secretName string, image string) error { } else if err != nil { return fmt.Errorf("error getting the enterprise license secret %q in the %q namespace: %s", secretName, c.flagNamespace, err) } - if !strings.Contains(image, "-ent") { - return fmt.Errorf("enterprise Consul image is not provided when enterprise license secret is set: %s", image) - } - c.UI.Output("Valid enterprise Consul image and secret found.", terminal.WithSuccessStyle()) + c.UI.Output("Valid enterprise Consul secret found.", terminal.WithSuccessStyle()) return nil } diff --git a/cli/cmd/install/install_test.go b/cli/cmd/install/install_test.go index f9e4028d05..ba6608d256 100644 --- a/cli/cmd/install/install_test.go +++ b/cli/cmd/install/install_test.go @@ -203,24 +203,19 @@ func TestCheckValidEnterprise(t *testing.T) { }, } - // Enterprise secret and image are valid. + // Enterprise secret is valid. c.kubernetes.CoreV1().Secrets("consul").Create(context.Background(), secret, metav1.CreateOptions{}) - err := c.checkValidEnterprise(secret.Name, "consul-enterprise:-ent") + err := c.checkValidEnterprise(secret.Name) require.NoError(t, err) - // Enterprise secret provided but not an enterprise image. - err = c.checkValidEnterprise(secret.Name, "consul:") - require.Error(t, err) - require.Contains(t, err.Error(), "enterprise Consul image is not provided") - // Enterprise secret does not exist. - err = c.checkValidEnterprise("consul-unrelated-secret", "consul-enterprise:-ent") + err = c.checkValidEnterprise("consul-unrelated-secret") require.Error(t, err) require.Contains(t, err.Error(), "please make sure that the secret exists") // Enterprise secret exists in a different namespace. c.kubernetes.CoreV1().Secrets("unrelated").Create(context.Background(), secret2, metav1.CreateOptions{}) - err = c.checkValidEnterprise(secret2.Name, "consul-enterprise:-ent") + err = c.checkValidEnterprise(secret2.Name) require.Error(t, err) require.Contains(t, err.Error(), "please make sure that the secret exists") } From c1df868522c876b07d1382efc1b9a2d58b5be114 Mon Sep 17 00:00:00 2001 From: Niklas Wagner Date: Tue, 12 Oct 2021 16:17:15 +0200 Subject: [PATCH 174/418] Add support for ingressClassName Signed-off-by: Niklas Wagner --- charts/consul/templates/ui-ingress.yaml | 7 +++++-- charts/consul/test/unit/ui-ingress.bats | 22 ++++++++++++++++++++++ charts/consul/values.yaml | 3 ++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/charts/consul/templates/ui-ingress.yaml b/charts/consul/templates/ui-ingress.yaml index 28d3069768..b91e780415 100644 --- a/charts/consul/templates/ui-ingress.yaml +++ b/charts/consul/templates/ui-ingress.yaml @@ -5,7 +5,7 @@ This is because while networks.k8s.io/v1 was introduced in Kubernetes v1.15+, the Ingress resource was promoted to v1 only in Kubernetes v1.19+. This ensures the correct API version is chosen that supports the Ingress resource. */}} -{{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "19" ) }} +{{- if semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion }} apiVersion: networking.k8s.io/v1 {{- else }} apiVersion: networking.k8s.io/v1beta1 @@ -25,9 +25,12 @@ metadata: {{ tpl .Values.ui.ingress.annotations . | nindent 4 | trim }} {{- end }} spec: + {{- if and .Values.ui.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ui.ingress.className }} + {{- end }} rules: {{ $global := .Values.global }} - {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "19" ) }} + {{- if semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion }} {{- range .Values.ui.ingress.hosts }} - host: {{ .host | quote }} http: diff --git a/charts/consul/test/unit/ui-ingress.bats b/charts/consul/test/unit/ui-ingress.bats index f26d181d2b..e44eac5b7f 100755 --- a/charts/consul/test/unit/ui-ingress.bats +++ b/charts/consul/test/unit/ui-ingress.bats @@ -234,3 +234,25 @@ load _helpers yq -r '.spec.rules[0].http.paths[0].pathType' | tee /dev/stderr) [ "${actual}" = "ImplementationSpecific" ] } + +#-------------------------------------------------------------------- +# ingressClassName + +@test "ui/Ingress: no ingressClassName by default" { + local actual=$(helm template \ + -s templates/ui-ingress.yaml \ + --set 'ui.ingress.enabled=true' \ + . | tee /dev/stderr | + yq -r '.spec.ingressClassName' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + +@test "ui/Ingress: no ingressClassName by default" { + local actual=$(helm template \ + -s templates/ui-ingress.yaml \ + --set 'ui.ingress.enabled=true' \ + --set 'ui.ingress.ingressClassName=nginx' \ + . | tee /dev/stderr | + yq -r '.spec.ingressClassName' | tee /dev/stderr) + [ "${actual}" = "nginx" ] +} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index a6ab7223fe..ebc0a05dc4 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -1220,7 +1220,8 @@ ui: ingress: # This will create an Ingress resource for the Consul UI. # @type: boolean - enabled: false + enabled: true + className: "" # pathType override - see: https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types pathType: Prefix From adc71cac3b4378fd43b89e219d5ee9fabc549668 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Tue, 7 Dec 2021 14:28:11 -0600 Subject: [PATCH 175/418] Apply suggestions from code review Co-authored-by: Luke Kysow <1034429+lkysow@users.noreply.github.com> --- CHANGELOG.md | 72 +++++++-------------------------------- charts/consul/values.yaml | 9 +++-- 2 files changed, 18 insertions(+), 63 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f48138a1c2..151a3c5cfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,70 +6,22 @@ BREAKING CHANGES: * Add boolean metric to merged metrics response `consul_merged_service_metrics_success` to indicate if service metrics were scraped successfully. [[GH-551](https://github.com/hashicorp/consul-k8s/pull/551)] -IMPROVEMENTS: -* Vault as a Secrets Backend - * Add support for Vault as a secrets backend for Gossip Encryption, Server TLS certs and Service Mesh TLS certificates, +FEATURES: +* Vault as a Secrets Backend: Add support for Vault as a secrets backend for Gossip Encryption, Server TLS certs and Service Mesh TLS certificates, removing the existing usage of Kubernetes Secrets for the respective secrets. [[GH-904](https://github.com/hashicorp/consul-k8s/pull/904/)] - * Consul 1.11+ is required. - * Vault 1.19+ is required and Vault-K8s 0.14+ must be installed with the Vault Agent Injector (`injector.enabled=true`) - and must be configured to talk to the Vault server installation from the Kubernetes cluster that Consul is installed. + + See the [Consul Kubernetes and Vault documentation](https://www.consul.io/docs/k8s/installation/vault) + for full install instructions. + + Requirements: + * Consul 1.11+ + * Vault 1.19+ and Vault-K8s 0.14+ must be installed with the Vault Agent Injector enabled (`injector.enabled=true`) + into the Kubernetes cluster that Consul is installed into. * `global.tls.enableAutoEncryption=true` is required for TLS support. - * If TLS is enabled in Vault `global.secretsBackend.vault.ca` must be provided and should reference a Kube secret + * If TLS is enabled in Vault, `global.secretsBackend.vault.ca` must be provided and should reference a Kube secret which holds a copy of the Vault CA cert. -To enable the Vault Secrets backend for the Consul cluster use the following config: - -```yaml -global: - image: hashicorp/consul:1.11.0 - - # Gossip Encryption. - gossipEncryption: - secretName="consul/data/secrets/gossip" - secretKey="key" - - tls: - enabled: true - enableAutoEncryption: true - - # Server CA certificate. - caCert: - secretName: "pki/cert/ca" - - # Vault configuration. - secretsBackend: - vault: - enabled: true - - # Vault Auth Roles. - consulServerRole: "consul-server" - consulClientRole: "consul-client" - consulCARole: "consul-ca" - - # If Vault TLS is enabled. - ca: - secretName: "vault-CA-cert" - secretKey: "tls.crt" - - # Connect CA configuration. - connectCA: - address: "https://vault:8200" - rootPKIPath: "connect_root" - intermediatePKIPath: "connect_inter" - -# Server TLS Certificates. -server: - serverCert: - secretName: "pki/issue/consul-server" - extraVolumes: - - name: "vault-CA-cert" - type: "secret" - load: false -``` -Note: See `values.yaml` and [Consul - Vault documentation](https://www.consul.io/docs/k8s/installation/vault/index.mdx) -for additional information on required Vault policies and configurations. - -* CLI +IMPROVEMENTS: * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] * Control Plane * Add a label "managed-by" to every secret the control-plane creates. Only delete said secrets on an uninstall. [[GH-835](https://github.com/hashicorp/consul-k8s/pull/835)] diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index c8239f4f78..bcf6d088ad 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -120,7 +120,10 @@ global: # secretsBackend is used to configure Vault as the secrets backend for the Consul on Kubernetes installation. # The Vault cluster needs to have the Kubernetes Auth Method, KV2 and PKI secrets engines enabled # and have necessary secrets, policies and roles created prior to installing Consul. - # The Vault cluster *must* not have the Consul cluster installed by this Helm chart as its storage backend. + # See https://www.consul.io/docs/k8s/installation/vault for full instructions. + # + # The Vault cluster *must* not have the Consul cluster installed by this Helm chart as its storage backend + # as that would cause a circular dependency. # It can have Consul as its storage backend as long as that Consul cluster is not running on this Kubernetes cluster # and is being managed separately from this Helm installation. # Note: When using Vault KV2 secrets engines the "data" field is implicitly required for Vault API calls, @@ -137,7 +140,7 @@ global: # - gossip encryption key defined by `global.gossipEncryption.secretName`. # To discover the service account name of the Consul server, run # ``` - # helm template -s templates/server-serviceaccount.yaml charts/consul + # helm template -s templates/server-serviceaccount.yaml hashicorp/consul # ``` # and check the name of `metadata.name`. consulServerRole: "" @@ -153,7 +156,7 @@ global: # and check the name of `metadata.name`. consulClientRole: "" - # The Vault role for all Consul components to read the ServerTLS CA Certificate (unauthenticated). + # The Vault role for all Consul components to read the Consul's server's CA Certificate (unauthenticated). # The role should be connected to the service accounts of all Consul components, or alternatively `*` since it # will be used only against the `pki/cert/ca` endpoint which is unauthenticated. A policy must be created which grants # read capabilities to `global.tls.caCert.secretName`, which is usually `pki/cert/ca`. From 6c510cc81f656466eaadb17015a803178a7be369 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 7 Dec 2021 15:29:49 -0500 Subject: [PATCH 176/418] Reset ui ingress default to false --- charts/consul/values.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index ebc0a05dc4..c637b927a6 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -1220,8 +1220,10 @@ ui: ingress: # This will create an Ingress resource for the Consul UI. # @type: boolean - enabled: true - className: "" + enabled: false + + # Optionally set the ingressClassName. + ingressClassName: "" # pathType override - see: https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types pathType: Prefix From 737b970b83225d62764b8a6affd3fec0cf401f13 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 7 Dec 2021 15:30:11 -0500 Subject: [PATCH 177/418] Test ingress UI with different Kube versions --- charts/consul/templates/ui-ingress.yaml | 8 +- charts/consul/test/unit/ui-ingress.bats | 121 +++++++++++++++--------- 2 files changed, 82 insertions(+), 47 deletions(-) diff --git a/charts/consul/templates/ui-ingress.yaml b/charts/consul/templates/ui-ingress.yaml index b91e780415..7b6e6bab4f 100644 --- a/charts/consul/templates/ui-ingress.yaml +++ b/charts/consul/templates/ui-ingress.yaml @@ -5,7 +5,7 @@ This is because while networks.k8s.io/v1 was introduced in Kubernetes v1.15+, the Ingress resource was promoted to v1 only in Kubernetes v1.19+. This ensures the correct API version is chosen that supports the Ingress resource. */}} -{{- if semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion }} +{{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "19" ) }} apiVersion: networking.k8s.io/v1 {{- else }} apiVersion: networking.k8s.io/v1beta1 @@ -25,12 +25,12 @@ metadata: {{ tpl .Values.ui.ingress.annotations . | nindent 4 | trim }} {{- end }} spec: - {{- if and .Values.ui.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} - ingressClassName: {{ .Values.ui.ingress.className }} + {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "18" ) }} + ingressClassName: {{ .Values.ui.ingress.ingressClassName }} {{- end }} rules: {{ $global := .Values.global }} - {{- if semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion }} + {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "19" ) }} {{- range .Values.ui.ingress.hosts }} - host: {{ .host | quote }} http: diff --git a/charts/consul/test/unit/ui-ingress.bats b/charts/consul/test/unit/ui-ingress.bats index e44eac5b7f..aaa4e56653 100755 --- a/charts/consul/test/unit/ui-ingress.bats +++ b/charts/consul/test/unit/ui-ingress.bats @@ -59,59 +59,73 @@ load _helpers [ "${actual}" = "foo.com" ] } -@test "ui/Ingress: exposes single port 80 when global.tls.enabled=false" { -# todo: test for Kube versions < 1.19 when helm supports --kube-version flag (https://github.com/helm/helm/pull/9040) -# local actual=$(helm template \ -# -s templates/ui-ingress.yaml \ -# --set 'ui.ingress.enabled=true' \ -# --set 'global.tls.enabled=false' \ -# --set 'ui.ingress.hosts[0].host=foo.com' \ -# --kube-version "1.18" \ -# . | tee /dev/stderr | -# yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) +@test "ui/Ingress: exposes single port 80 when global.tls.enabled=false when Kube version < 1.19" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/ui-ingress.yaml \ + --set 'ui.ingress.enabled=true' \ + --set 'global.tls.enabled=false' \ + --set 'ui.ingress.hosts[0].host=foo.com' \ + --kube-version "1.18" \ + . | tee /dev/stderr | + yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) + [ "${actual}" = "80" ] +} + +@test "ui/Ingress: exposes single port 80 when global.tls.enabled=false when Kube version >= 1.19" { cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ --set 'global.tls.enabled=false' \ --set 'ui.ingress.hosts[0].host=foo.com' \ + --kube-version "1.19" \ . | tee /dev/stderr | yq -r '.spec.rules[0].http.paths[0].backend.service.port.number' | tee /dev/stderr) [ "${actual}" = "80" ] } -@test "ui/Ingress: exposes single port 443 when global.tls.enabled=true and global.tls.httpsOnly=true" { -# todo: test for Kube versions < 1.19 when helm supports --kube-version flag (https://github.com/helm/helm/pull/9040) -# local actual=$(helm template \ -# -s templates/ui-ingress.yaml \ -# --set 'ui.ingress.enabled=true' \ -# --set 'global.tls.enabled=true' \ -# --set 'ui.ingress.hosts[0].host=foo.com' \ -# --kube-version "1.18" \ -# . | tee /dev/stderr | -# yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) +@test "ui/Ingress: exposes single port 443 when global.tls.enabled=true and global.tls.httpsOnly=true when Kube version < 1.19" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/ui-ingress.yaml \ + --set 'ui.ingress.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'ui.ingress.hosts[0].host=foo.com' \ + --kube-version "1.18" \ + . | tee /dev/stderr | + yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) + [ "${actual}" = "443" ] +} + +@test "ui/Ingress: exposes single port 443 when global.tls.enabled=true and global.tls.httpsOnly=true when Kube version >= 1.19" { cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ --set 'global.tls.enabled=true' \ --set 'ui.ingress.hosts[0].host=foo.com' \ + --kube-version "1.19" \ . | tee /dev/stderr | yq -r '.spec.rules[0].http.paths[0].backend.service.port.number' | tee /dev/stderr) [ "${actual}" = "443" ] } -@test "ui/Ingress: exposes the port 80 when global.tls.enabled=true and global.tls.httpsOnly=false" { -# todo: test for Kube versions < 1.19 when helm supports --kube-version flag (https://github.com/helm/helm/pull/9040) -# local actual=$(helm template \ -# -s templates/ui-ingress.yaml \ -# --set 'ui.ingress.enabled=true' \ -# --set 'global.tls.enabled=true' \ -# --set 'global.tls.httpsOnly=false' \ -# --set 'ui.ingress.hosts[0].host=foo.com' \ -# --kube-version "1.18" \ -# . | tee /dev/stderr | -# yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) +@test "ui/Ingress: exposes the port 80 when global.tls.enabled=true and global.tls.httpsOnly=false when Kube version < 1.19" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/ui-ingress.yaml \ + --set 'ui.ingress.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.httpsOnly=false' \ + --set 'ui.ingress.hosts[0].host=foo.com' \ + --kube-version "1.18" \ + . | tee /dev/stderr | + yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) + [ "${actual}" = "80" ] +} + +@test "ui/Ingress: exposes the port 80 when global.tls.enabled=true and global.tls.httpsOnly=false when Kube version >= 1.19" { cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ @@ -119,22 +133,27 @@ load _helpers --set 'global.tls.enabled=true' \ --set 'global.tls.httpsOnly=false' \ --set 'ui.ingress.hosts[0].host=foo.com' \ + --kube-version "1.19" \ . | tee /dev/stderr | yq -r '.spec.rules[0].http.paths[0].backend.service.port.number' | tee /dev/stderr) [ "${actual}" = "80" ] } -@test "ui/Ingress: exposes the port 443 when global.tls.enabled=true and global.tls.httpsOnly=false" { -# todo: test for Kube versions < 1.19 when helm supports --kube-version flag (https://github.com/helm/helm/pull/9040) -# local actual=$(helm template \ -# -s templates/ui-ingress.yaml \ -# --set 'ui.ingress.enabled=true' \ -# --set 'global.tls.enabled=true' \ -# --set 'global.tls.httpsOnly=false' \ -# --set 'ui.ingress.hosts[0].host=foo.com' \ -# --kube-version "1.18" \ -# . | tee /dev/stderr | -# yq -r '.spec.rules[0].http.paths[1].backend.servicePort' | tee /dev/stderr) +@test "ui/Ingress: exposes the port 443 when global.tls.enabled=true and global.tls.httpsOnly=false when Kube version < 1.19" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/ui-ingress.yaml \ + --set 'ui.ingress.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.httpsOnly=false' \ + --set 'ui.ingress.hosts[0].host=foo.com' \ + --kube-version "1.18" \ + . | tee /dev/stderr | + yq -r '.spec.rules[0].http.paths[1].backend.servicePort' | tee /dev/stderr) + [ "${actual}" = "443" ] +} + +@test "ui/Ingress: exposes the port 443 when global.tls.enabled=true and global.tls.httpsOnly=false when Kube version >= 1.19" { cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ @@ -142,6 +161,7 @@ load _helpers --set 'global.tls.enabled=true' \ --set 'global.tls.httpsOnly=false' \ --set 'ui.ingress.hosts[0].host=foo.com' \ + --kube-version "1.19" \ . | tee /dev/stderr | yq -r '.spec.rules[0].http.paths[1].backend.service.port.number' | tee /dev/stderr) [ "${actual}" = "443" ] @@ -239,6 +259,7 @@ load _helpers # ingressClassName @test "ui/Ingress: no ingressClassName by default" { + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -247,7 +268,8 @@ load _helpers [ "${actual}" = "null" ] } -@test "ui/Ingress: no ingressClassName by default" { +@test "ui/Ingress: can set ingressClassName" { + cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ @@ -256,3 +278,16 @@ load _helpers yq -r '.spec.ingressClassName' | tee /dev/stderr) [ "${actual}" = "nginx" ] } + +@test "ui/Ingress: cannot set ingressClassName for Kube version < 1.18" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/ui-ingress.yaml \ + --set 'ui.ingress.enabled=true' \ + --set 'ui.ingress.ingressClassName=nginx' \ + --kube-version "1.17" \ + . | tee /dev/stderr | + yq -r '.spec.ingressClassName' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + From 5df000415132a5f1732a8ed60ea9f7d427798cc1 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Tue, 7 Dec 2021 14:30:35 -0600 Subject: [PATCH 178/418] Apply suggestions from code review Co-authored-by: Luke Kysow <1034429+lkysow@users.noreply.github.com> --- charts/consul/values.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index bcf6d088ad..6c5f200320 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -126,6 +126,7 @@ global: # as that would cause a circular dependency. # It can have Consul as its storage backend as long as that Consul cluster is not running on this Kubernetes cluster # and is being managed separately from this Helm installation. + # # Note: When using Vault KV2 secrets engines the "data" field is implicitly required for Vault API calls, # secretName should be in the form of "vault-kv2-mount-path/data/secret-name". # secretKey should be in the form of "key". From 5a728f4b08360272ebb2514014f360184cef3d32 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 7 Dec 2021 15:34:56 -0500 Subject: [PATCH 179/418] Add Changelog entry for ingressClassName --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d977798e5c..e31b3eb46c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ IMPROVEMENTS: * Add support for labeling a Kubernetes service with `consul.hashicorp.com/service-ignore` to prevent services from being registered in Consul. [[GH-858](https://github.com/hashicorp/consul-k8s/pull/858)] * Helm Chart * Fail an installation/upgrade if WAN federation and Admin Partitions are both enabled. [[GH-892](https://github.com/hashicorp/consul-k8s/issues/892)] + * Add support for setting `ingressClassName` for UI. [[GH-909](https://github.com/hashicorp/consul-k8s/pull/909)] BUG FIXES: * Control Plane: From aea9efea5638e7d560ffa34ec03f3663d0d7d2ec Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 7 Dec 2021 13:22:34 -0800 Subject: [PATCH 180/418] Add docs about choosing storage class (#907) --- charts/consul/values.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 6c5f200320..709e3c2b46 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -556,6 +556,8 @@ server: # storage classes, the PersistentVolumeClaims would need to be manually created. # A `null` value will use the Kubernetes cluster's default StorageClass. If a default # StorageClass does not exist, you will need to create one. + # See https://www.consul.io/docs/install/performance#read-write-tuning for considerations around choosing a + # performant storage class. # @type: string storageClass: null From 6408674e418ec49e1b57567a3642e32446e11353 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 8 Dec 2021 12:36:35 -0500 Subject: [PATCH 181/418] Rename to exported services (#902) * Rename partitionExports to exportedServices - Update anonymous token job to not run in non-default partitions. The current implementation breaks against the latest consul version. * Update consul API where exportedservices are renamed. --- CHANGELOG.md | 5 + acceptance/go.mod | 2 +- acceptance/go.sum | 4 +- .../controller/controller_namespaces_test.go | 26 +-- .../bases/admin-partitions/kustomization.yaml | 3 - .../exportedservices-default.yaml} | 2 +- .../kustomization.yaml | 2 + .../exportedservices-secondary.yaml} | 2 +- .../kustomization.yaml | 2 + .../kustomization.yaml | 2 +- .../default-partition-default/patch.yaml | 2 +- .../default-partition-ns1/kustomization.yaml | 2 +- .../default-partition-ns1/patch.yaml | 2 +- .../kustomization.yaml | 2 +- .../secondary-partition-default/patch.yaml | 2 +- .../kustomization.yaml | 2 +- .../secondary-partition-ns1/patch.yaml | 2 +- ...tionexports.yaml => exportedservices.yaml} | 2 +- .../cases/crds-ent/kustomization.yaml | 2 +- .../tests/partitions/partitions_test.go | 6 +- .../templates/controller-clusterrole.yaml | 4 +- ...ntroller-mutatingwebhookconfiguration.yaml | 21 +++ ...exports.yaml => crd-exportedservices.yaml} | 14 +- ...exports.bats => crd-exportedservices.bats} | 8 +- control-plane/PROJECT | 2 +- control-plane/api/common/common.go | 2 +- ...rts_types.go => exportedservices_types.go} | 72 ++++---- ...test.go => exportedservices_types_test.go} | 130 +++++++------- ...webhook.go => exportedservices_webhook.go} | 14 +- ...st.go => exportedservices_webhook_test.go} | 46 ++--- .../api/v1alpha1/zz_generated.deepcopy.go | 163 +++++++++--------- .../config/certmanager/certificate.yaml | 26 --- .../config/certmanager/kustomization.yaml | 5 - .../config/certmanager/kustomizeconfig.yaml | 16 -- ...onsul.hashicorp.com_exportedservices.yaml} | 14 +- control-plane/config/crd/kustomization.yaml | 45 ----- control-plane/config/crd/kustomizeconfig.yaml | 17 -- .../cainjection_in_ingressgateways.yaml | 8 - .../patches/cainjection_in_proxydefaults.yaml | 8 - .../cainjection_in_servicedefaults.yaml | 8 - .../cainjection_in_serviceintentions.yaml | 8 - .../cainjection_in_serviceresolvers.yaml | 8 - .../cainjection_in_servicerouters.yaml | 8 - .../cainjection_in_servicesplitters.yaml | 8 - .../cainjection_in_terminatinggateways.yaml | 8 - .../patches/webhook_in_ingressgateways.yaml | 17 -- .../patches/webhook_in_partitionexports.yaml | 17 -- .../crd/patches/webhook_in_proxydefaults.yaml | 17 -- .../patches/webhook_in_servicedefaults.yaml | 17 -- .../patches/webhook_in_serviceintentions.yaml | 17 -- .../patches/webhook_in_serviceresolvers.yaml | 17 -- .../patches/webhook_in_servicerouters.yaml | 17 -- .../patches/webhook_in_servicesplitters.yaml | 17 -- .../webhook_in_terminatinggateways.yaml | 17 -- .../config/default/kustomization.yaml | 74 -------- .../default/manager_auth_proxy_patch.yaml | 25 --- .../config/default/manager_webhook_patch.yaml | 23 --- .../default/webhookcainjection_patch.yaml | 8 - .../config/manager/kustomization.yaml | 9 - control-plane/config/manager/manager.yaml | 48 ------ .../rbac/auth_proxy_client_clusterrole.yaml | 7 - .../config/rbac/auth_proxy_role.yaml | 13 -- .../config/rbac/auth_proxy_role_binding.yaml | 12 -- .../config/rbac/auth_proxy_service.yaml | 14 -- .../rbac/ingressgateway_editor_role.yaml | 24 --- .../rbac/ingressgateway_viewer_role.yaml | 20 --- control-plane/config/rbac/kustomization.yaml | 12 -- .../config/rbac/leader_election_role.yaml | 33 ---- .../rbac/leader_election_role_binding.yaml | 12 -- .../rbac/partitionexport_editor_role.yaml | 24 --- .../rbac/partitionexport_viewer_role.yaml | 20 --- .../rbac/proxydefaults_editor_role.yaml | 24 --- .../rbac/proxydefaults_viewer_role.yaml | 20 --- control-plane/config/rbac/role.yaml | 12 +- control-plane/config/rbac/role_binding.yaml | 12 -- .../rbac/servicedefaults_editor_role.yaml | 24 --- .../rbac/servicedefaults_viewer_role.yaml | 20 --- .../rbac/serviceintentions_editor_role.yaml | 24 --- .../rbac/serviceintentions_viewer_role.yaml | 20 --- .../rbac/serviceresolver_editor_role.yaml | 24 --- .../rbac/serviceresolver_viewer_role.yaml | 20 --- .../rbac/servicerouter_editor_role.yaml | 24 --- .../rbac/servicerouter_viewer_role.yaml | 20 --- .../rbac/servicesplitter_editor_role.yaml | 24 --- .../rbac/servicesplitter_viewer_role.yaml | 20 --- .../rbac/terminatinggateway_editor_role.yaml | 24 --- .../rbac/terminatinggateway_viewer_role.yaml | 20 --- .../consul_v1alpha1_ingressgateway.yaml | 12 -- .../consul_v1alpha1_partitionexport.yaml | 7 - .../consul_v1alpha1_proxydefaults.yaml | 7 - .../consul_v1alpha1_servicedefaults.yaml | 6 - .../consul_v1alpha1_serviceintentions.yaml | 7 - .../consul_v1alpha1_serviceresolver.yaml | 7 - .../consul_v1alpha1_servicerouter.yaml | 11 -- .../consul_v1alpha1_servicesplitter.yaml | 7 - .../consul_v1alpha1_terminatinggateway.yaml | 11 -- .../config/samples/kustomization.yaml | 3 - .../config/webhook/kustomization.yaml | 6 - .../config/webhook/kustomizeconfig.yaml | 25 --- control-plane/config/webhook/manifests.yaml | 18 +- control-plane/config/webhook/service.yaml | 12 -- ...ller.go => exportedservices_controller.go} | 20 +-- ...> exportedservices_controller_ent_test.go} | 79 +++++---- control-plane/go.mod | 2 +- control-plane/go.sum | 4 +- .../subcommand/controller/command.go | 12 +- .../subcommand/partition-init/command.go | 2 +- .../partition-init/command_ent_test.go | 2 +- .../subcommand/server-acl-init/command.go | 6 + 109 files changed, 379 insertions(+), 1487 deletions(-) delete mode 100644 acceptance/tests/fixtures/bases/admin-partitions/kustomization.yaml rename acceptance/tests/fixtures/bases/{admin-partitions/partitionexports-default.yaml => exportedservices-default/exportedservices-default.yaml} (79%) create mode 100644 acceptance/tests/fixtures/bases/exportedservices-default/kustomization.yaml rename acceptance/tests/fixtures/bases/{admin-partitions/partitionexports-secondary.yaml => exportedservices-secondary/exportedservices-secondary.yaml} (79%) create mode 100644 acceptance/tests/fixtures/bases/exportedservices-secondary/kustomization.yaml rename acceptance/tests/fixtures/cases/crds-ent/{partitionexports.yaml => exportedservices.yaml} (87%) rename charts/consul/templates/{crd-partitionexports.yaml => crd-exportedservices.yaml} (93%) rename charts/consul/test/unit/{crd-partitionexports.bats => crd-exportedservices.bats} (73%) rename control-plane/api/v1alpha1/{partitionexports_types.go => exportedservices_types.go} (72%) rename control-plane/api/v1alpha1/{partitionexports_types_test.go => exportedservices_types_test.go} (61%) rename control-plane/api/v1alpha1/{partitionexports_webhook.go => exportedservices_webhook.go} (75%) rename control-plane/api/v1alpha1/{partitionexports_webhook_test.go => exportedservices_webhook_test.go} (79%) delete mode 100644 control-plane/config/certmanager/certificate.yaml delete mode 100644 control-plane/config/certmanager/kustomization.yaml delete mode 100644 control-plane/config/certmanager/kustomizeconfig.yaml rename control-plane/config/crd/bases/{consul.hashicorp.com_partitionexports.yaml => consul.hashicorp.com_exportedservices.yaml} (93%) 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_ingressgateways.yaml delete mode 100644 control-plane/config/crd/patches/cainjection_in_proxydefaults.yaml delete mode 100644 control-plane/config/crd/patches/cainjection_in_servicedefaults.yaml delete mode 100644 control-plane/config/crd/patches/cainjection_in_serviceintentions.yaml delete mode 100644 control-plane/config/crd/patches/cainjection_in_serviceresolvers.yaml delete mode 100644 control-plane/config/crd/patches/cainjection_in_servicerouters.yaml delete mode 100644 control-plane/config/crd/patches/cainjection_in_servicesplitters.yaml delete mode 100644 control-plane/config/crd/patches/cainjection_in_terminatinggateways.yaml delete mode 100644 control-plane/config/crd/patches/webhook_in_ingressgateways.yaml delete mode 100644 control-plane/config/crd/patches/webhook_in_partitionexports.yaml delete mode 100644 control-plane/config/crd/patches/webhook_in_proxydefaults.yaml delete mode 100644 control-plane/config/crd/patches/webhook_in_servicedefaults.yaml delete mode 100644 control-plane/config/crd/patches/webhook_in_serviceintentions.yaml delete mode 100644 control-plane/config/crd/patches/webhook_in_serviceresolvers.yaml delete mode 100644 control-plane/config/crd/patches/webhook_in_servicerouters.yaml delete mode 100644 control-plane/config/crd/patches/webhook_in_servicesplitters.yaml delete mode 100644 control-plane/config/crd/patches/webhook_in_terminatinggateways.yaml delete mode 100644 control-plane/config/default/kustomization.yaml delete mode 100644 control-plane/config/default/manager_auth_proxy_patch.yaml delete mode 100644 control-plane/config/default/manager_webhook_patch.yaml delete mode 100644 control-plane/config/default/webhookcainjection_patch.yaml delete mode 100644 control-plane/config/manager/kustomization.yaml delete mode 100644 control-plane/config/manager/manager.yaml delete mode 100644 control-plane/config/rbac/auth_proxy_client_clusterrole.yaml delete mode 100644 control-plane/config/rbac/auth_proxy_role.yaml delete mode 100644 control-plane/config/rbac/auth_proxy_role_binding.yaml delete mode 100644 control-plane/config/rbac/auth_proxy_service.yaml delete mode 100644 control-plane/config/rbac/ingressgateway_editor_role.yaml delete mode 100644 control-plane/config/rbac/ingressgateway_viewer_role.yaml delete mode 100644 control-plane/config/rbac/kustomization.yaml delete mode 100644 control-plane/config/rbac/leader_election_role.yaml delete mode 100644 control-plane/config/rbac/leader_election_role_binding.yaml delete mode 100644 control-plane/config/rbac/partitionexport_editor_role.yaml delete mode 100644 control-plane/config/rbac/partitionexport_viewer_role.yaml delete mode 100644 control-plane/config/rbac/proxydefaults_editor_role.yaml delete mode 100644 control-plane/config/rbac/proxydefaults_viewer_role.yaml delete mode 100644 control-plane/config/rbac/role_binding.yaml delete mode 100644 control-plane/config/rbac/servicedefaults_editor_role.yaml delete mode 100644 control-plane/config/rbac/servicedefaults_viewer_role.yaml delete mode 100644 control-plane/config/rbac/serviceintentions_editor_role.yaml delete mode 100644 control-plane/config/rbac/serviceintentions_viewer_role.yaml delete mode 100644 control-plane/config/rbac/serviceresolver_editor_role.yaml delete mode 100644 control-plane/config/rbac/serviceresolver_viewer_role.yaml delete mode 100644 control-plane/config/rbac/servicerouter_editor_role.yaml delete mode 100644 control-plane/config/rbac/servicerouter_viewer_role.yaml delete mode 100644 control-plane/config/rbac/servicesplitter_editor_role.yaml delete mode 100644 control-plane/config/rbac/servicesplitter_viewer_role.yaml delete mode 100644 control-plane/config/rbac/terminatinggateway_editor_role.yaml delete mode 100644 control-plane/config/rbac/terminatinggateway_viewer_role.yaml delete mode 100644 control-plane/config/samples/consul_v1alpha1_ingressgateway.yaml delete mode 100644 control-plane/config/samples/consul_v1alpha1_partitionexport.yaml delete mode 100644 control-plane/config/samples/consul_v1alpha1_proxydefaults.yaml delete mode 100644 control-plane/config/samples/consul_v1alpha1_servicedefaults.yaml delete mode 100644 control-plane/config/samples/consul_v1alpha1_serviceintentions.yaml delete mode 100644 control-plane/config/samples/consul_v1alpha1_serviceresolver.yaml delete mode 100644 control-plane/config/samples/consul_v1alpha1_servicerouter.yaml delete mode 100644 control-plane/config/samples/consul_v1alpha1_servicesplitter.yaml delete mode 100644 control-plane/config/samples/consul_v1alpha1_terminatinggateway.yaml delete mode 100644 control-plane/config/samples/kustomization.yaml delete mode 100644 control-plane/config/webhook/kustomization.yaml delete mode 100644 control-plane/config/webhook/kustomizeconfig.yaml delete mode 100644 control-plane/config/webhook/service.yaml rename control-plane/controller/{partitionexports_controller.go => exportedservices_controller.go} (52%) rename control-plane/controller/{partitionexports_controller_ent_test.go => exportedservices_controller_ent_test.go} (80%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 151a3c5cfe..77a02d9b43 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,8 +20,13 @@ FEATURES: * `global.tls.enableAutoEncryption=true` is required for TLS support. * If TLS is enabled in Vault, `global.secretsBackend.vault.ca` must be provided and should reference a Kube secret which holds a copy of the Vault CA cert. + * Add boolean metric to merged metrics response `consul_merged_service_metrics_success` to indicate if service metrics were + scraped successfully. [[GH-551](https://github.com/hashicorp/consul-k8s/pull/551)] +* Helm + * Rename `PartitionExports` CRD to `ExportedServices`. [[GH-902](https://github.com/hashicorp/consul-k8s/pull/902)] IMPROVEMENTS: +* CLI * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] * Control Plane * Add a label "managed-by" to every secret the control-plane creates. Only delete said secrets on an uninstall. [[GH-835](https://github.com/hashicorp/consul-k8s/pull/835)] diff --git a/acceptance/go.mod b/acceptance/go.mod index c43c0816aa..62efc96a62 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -5,7 +5,7 @@ go 1.17 require ( github.com/gruntwork-io/terratest v0.31.2 github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51 - github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f + github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/vault/api v1.2.0 github.com/stretchr/testify v1.7.0 diff --git a/acceptance/go.sum b/acceptance/go.sum index de7c95fae2..3340d47075 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -386,10 +386,10 @@ github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51 h1:Km6RYuAsJVVu3gipkTWF1SVYuvSJrksBtT89rO4hcdA= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51/go.mod h1:+Ay3RL0eZdI0wgT193r+EJTOk9cSn1WUlvBvk6Lfnmo= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f h1:fBBh4412td7nBzqyLkpGTH5dWycPs8p7Yg/Dy8VQjVU= -github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f h1:fBBh4412td7nBzqyLkpGTH5dWycPs8p7Yg/Dy8VQjVU= github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= diff --git a/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go index d68b2c5414..e303246bfe 100644 --- a/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -74,7 +74,7 @@ func TestControllerNamespaces(t *testing.T) { ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta3", + "global.image": "ashwinvenkatesh/consul@sha256:4be07b9c90fc590827ad72328da332c2003a14d237df317a0c977817f6fdaf0b", "global.enableConsulNamespaces": "true", "global.adminPartitions.enabled": "true", @@ -156,12 +156,12 @@ func TestControllerNamespaces(t *testing.T) { require.True(r, ok, "could not cast to ProxyConfigEntry") require.Equal(r, api.MeshGatewayModeLocal, proxyDefaultEntry.MeshGateway.Mode) - // partition-exports - entry, _, err = consulClient.ConfigEntries().Get(api.PartitionExports, "default", defaultOpts) + // exported-services + entry, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", defaultOpts) require.NoError(r, err) - partitionExportsEntry, ok := entry.(*api.PartitionExportsConfigEntry) - require.True(r, ok, "could not cast to PartitionExportsConfigEntry") - require.Equal(r, "frontend", partitionExportsEntry.Services[0].Name) + exportedServicesEntry, ok := entry.(*api.ExportedServicesConfigEntry) + require.True(r, ok, "could not cast to ExportedServicesConfigEntry") + require.Equal(r, "frontend", exportedServicesEntry.Services[0].Name) // mesh entry, _, err = consulClient.ConfigEntries().Get(api.MeshConfig, "mesh", defaultOpts) @@ -232,7 +232,7 @@ func TestControllerNamespaces(t *testing.T) { logger.Log(t, "patching partition-exports custom resource") patchServiceName := "backend" - k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "partitionexports", "default", "-p", fmt.Sprintf(`{"spec":{"services":[{"name": "%s", "namespace": "front", "consumers":[{"partition": "foo"}]}]}}`, patchServiceName), "--type=merge") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "exportedservices", "default", "-p", fmt.Sprintf(`{"spec":{"services":[{"name": "%s", "namespace": "front", "consumers":[{"partition": "foo"}]}]}}`, patchServiceName), "--type=merge") logger.Log(t, "patching mesh custom resource") k8s.RunKubectl(t, ctx.KubectlOptions(t), "patch", "-n", KubeNS, "mesh", "mesh", "-p", fmt.Sprintf(`{"spec":{"transparentProxy":{"meshDestinationsOnly": %t}}}`, false), "--type=merge") @@ -279,11 +279,11 @@ func TestControllerNamespaces(t *testing.T) { require.Equal(r, api.MeshGatewayModeRemote, proxyDefaultsEntry.MeshGateway.Mode) // partition-exports - entry, _, err = consulClient.ConfigEntries().Get(api.PartitionExports, "default", defaultOpts) + entry, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", defaultOpts) require.NoError(r, err) - partitionExportsEntry, ok := entry.(*api.PartitionExportsConfigEntry) - require.True(r, ok, "could not cast to PartitionExportsConfigEntry") - require.Equal(r, "backend", partitionExportsEntry.Services[0].Name) + exportedServicesEntry, ok := entry.(*api.ExportedServicesConfigEntry) + require.True(r, ok, "could not cast to ExportedServicesConfigEntry") + require.Equal(r, "backend", exportedServicesEntry.Services[0].Name) // mesh entry, _, err = consulClient.ConfigEntries().Get(api.MeshConfig, "mesh", defaultOpts) @@ -343,7 +343,7 @@ func TestControllerNamespaces(t *testing.T) { k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "proxydefaults", "global") logger.Log(t, "deleting partition-exports custom resource") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "partitionexports", "default") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "exportedservices", "default") logger.Log(t, "deleting mesh custom resource") k8s.RunKubectl(t, ctx.KubectlOptions(t), "delete", "-n", KubeNS, "mesh", "mesh") @@ -381,7 +381,7 @@ func TestControllerNamespaces(t *testing.T) { require.Contains(r, err.Error(), "404 (Config entry not found") // partition-exports - _, _, err = consulClient.ConfigEntries().Get(api.PartitionExports, "default", defaultOpts) + _, _, err = consulClient.ConfigEntries().Get(api.ExportedServices, "default", defaultOpts) require.Error(r, err) require.Contains(r, err.Error(), "404 (Config entry not found") diff --git a/acceptance/tests/fixtures/bases/admin-partitions/kustomization.yaml b/acceptance/tests/fixtures/bases/admin-partitions/kustomization.yaml deleted file mode 100644 index 04a88496e8..0000000000 --- a/acceptance/tests/fixtures/bases/admin-partitions/kustomization.yaml +++ /dev/null @@ -1,3 +0,0 @@ -resources: - - partitionexports-default.yaml - - partitionexports-secondary.yaml diff --git a/acceptance/tests/fixtures/bases/admin-partitions/partitionexports-default.yaml b/acceptance/tests/fixtures/bases/exportedservices-default/exportedservices-default.yaml similarity index 79% rename from acceptance/tests/fixtures/bases/admin-partitions/partitionexports-default.yaml rename to acceptance/tests/fixtures/bases/exportedservices-default/exportedservices-default.yaml index 718b5eae5e..a260602109 100644 --- a/acceptance/tests/fixtures/bases/admin-partitions/partitionexports-default.yaml +++ b/acceptance/tests/fixtures/bases/exportedservices-default/exportedservices-default.yaml @@ -1,5 +1,5 @@ apiVersion: consul.hashicorp.com/v1alpha1 -kind: PartitionExports +kind: ExportedServices metadata: name: default spec: diff --git a/acceptance/tests/fixtures/bases/exportedservices-default/kustomization.yaml b/acceptance/tests/fixtures/bases/exportedservices-default/kustomization.yaml new file mode 100644 index 0000000000..e540a4def1 --- /dev/null +++ b/acceptance/tests/fixtures/bases/exportedservices-default/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - exportedservices-default.yaml diff --git a/acceptance/tests/fixtures/bases/admin-partitions/partitionexports-secondary.yaml b/acceptance/tests/fixtures/bases/exportedservices-secondary/exportedservices-secondary.yaml similarity index 79% rename from acceptance/tests/fixtures/bases/admin-partitions/partitionexports-secondary.yaml rename to acceptance/tests/fixtures/bases/exportedservices-secondary/exportedservices-secondary.yaml index 2f09fe87be..a514ed50d9 100644 --- a/acceptance/tests/fixtures/bases/admin-partitions/partitionexports-secondary.yaml +++ b/acceptance/tests/fixtures/bases/exportedservices-secondary/exportedservices-secondary.yaml @@ -1,5 +1,5 @@ apiVersion: consul.hashicorp.com/v1alpha1 -kind: PartitionExports +kind: ExportedServices metadata: name: secondary spec: diff --git a/acceptance/tests/fixtures/bases/exportedservices-secondary/kustomization.yaml b/acceptance/tests/fixtures/bases/exportedservices-secondary/kustomization.yaml new file mode 100644 index 0000000000..10af8e20c5 --- /dev/null +++ b/acceptance/tests/fixtures/bases/exportedservices-secondary/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - exportedservices-secondary.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml index ccb255ba30..499fdc5bc1 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/kustomization.yaml @@ -1,5 +1,5 @@ resources: - - ../../../bases/admin-partitions + - ../../../bases/exportedservices-default patchesStrategicMerge: - patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml index 5e836da962..c98ecb6f48 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-default/patch.yaml @@ -1,5 +1,5 @@ apiVersion: consul.hashicorp.com/v1alpha1 -kind: PartitionExports +kind: ExportedServices metadata: name: default spec: diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml index ccb255ba30..499fdc5bc1 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/kustomization.yaml @@ -1,5 +1,5 @@ resources: - - ../../../bases/admin-partitions + - ../../../bases/exportedservices-default patchesStrategicMerge: - patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml index dda2d4bfde..f826174aec 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/default-partition-ns1/patch.yaml @@ -1,5 +1,5 @@ apiVersion: consul.hashicorp.com/v1alpha1 -kind: PartitionExports +kind: ExportedServices metadata: name: default spec: diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml index ccb255ba30..5a9c8412aa 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/kustomization.yaml @@ -1,5 +1,5 @@ resources: - - ../../../bases/admin-partitions + - ../../../bases/exportedservices-secondary patchesStrategicMerge: - patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml index 73ac31c6a8..d2fc1ab914 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-default/patch.yaml @@ -1,5 +1,5 @@ apiVersion: consul.hashicorp.com/v1alpha1 -kind: PartitionExports +kind: ExportedServices metadata: name: secondary spec: diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml index ccb255ba30..5a9c8412aa 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/kustomization.yaml @@ -1,5 +1,5 @@ resources: - - ../../../bases/admin-partitions + - ../../../bases/exportedservices-secondary patchesStrategicMerge: - patch.yaml diff --git a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml index 2e1b399797..4165f2d21a 100644 --- a/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml +++ b/acceptance/tests/fixtures/cases/crd-partitions/secondary-partition-ns1/patch.yaml @@ -1,5 +1,5 @@ apiVersion: consul.hashicorp.com/v1alpha1 -kind: PartitionExports +kind: ExportedServices metadata: name: secondary spec: diff --git a/acceptance/tests/fixtures/cases/crds-ent/partitionexports.yaml b/acceptance/tests/fixtures/cases/crds-ent/exportedservices.yaml similarity index 87% rename from acceptance/tests/fixtures/cases/crds-ent/partitionexports.yaml rename to acceptance/tests/fixtures/cases/crds-ent/exportedservices.yaml index cbcf65c389..4703d23493 100644 --- a/acceptance/tests/fixtures/cases/crds-ent/partitionexports.yaml +++ b/acceptance/tests/fixtures/cases/crds-ent/exportedservices.yaml @@ -1,5 +1,5 @@ apiVersion: consul.hashicorp.com/v1alpha1 -kind: PartitionExports +kind: ExportedServices metadata: name: default spec: diff --git a/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml b/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml index 75ca5cd845..cdc3e60cb1 100644 --- a/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml +++ b/acceptance/tests/fixtures/cases/crds-ent/kustomization.yaml @@ -1,3 +1,3 @@ resources: - ../../bases/crds-oss - - partitionexports.yaml + - exportedservices.yaml diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index a9c04a3c5e..7f2d21581b 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -96,7 +96,7 @@ func TestPartitions(t *testing.T) { serverHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta3", + "global.image": "ashwinvenkatesh/consul@sha256:dce7a25b9e15271d8102a0f14fae71af0b9c789bafd8cbe4a7d0f8c34abe0296", "global.adminPartitions.enabled": "true", "global.enableConsulNamespaces": "true", @@ -192,7 +192,7 @@ func TestPartitions(t *testing.T) { // Create client cluster. clientHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-beta3", + "global.image": "ashwinvenkatesh/consul@sha256:dce7a25b9e15271d8102a0f14fae71af0b9c789bafd8cbe4a7d0f8c34abe0296", "global.enabled": "false", "global.tls.enabled": "true", @@ -535,7 +535,7 @@ func TestPartitions(t *testing.T) { require.NoError(t, err) require.Len(t, services, 1) - logger.Log(t, "creating partition exports") + logger.Log(t, "creating exported services") if c.destinationNamespace == defaultNamespace { k8s.KubectlApplyK(t, serverClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/default-partition-default") k8s.KubectlApplyK(t, clientClusterContext.KubectlOptions(t), "../fixtures/cases/crd-partitions/secondary-partition-default") diff --git a/charts/consul/templates/controller-clusterrole.yaml b/charts/consul/templates/controller-clusterrole.yaml index 993768811c..45fa8d8458 100644 --- a/charts/consul/templates/controller-clusterrole.yaml +++ b/charts/consul/templates/controller-clusterrole.yaml @@ -17,7 +17,7 @@ rules: - serviceresolvers - proxydefaults - meshes - - partitionexports + - exportedservices - servicerouters - servicesplitters - serviceintentions @@ -38,7 +38,7 @@ rules: - serviceresolvers/status - proxydefaults/status - meshes/status - - partitionexports/status + - exportedservices/status - servicerouters/status - servicesplitters/status - serviceintentions/status diff --git a/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml b/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml index 7bef2e6c27..03f4ce15c4 100644 --- a/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml +++ b/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml @@ -200,4 +200,25 @@ webhooks: resources: - terminatinggateways sideEffects: None +- clientConfig: + service: + name: {{ template "consul.fullname" . }}-controller-webhook + namespace: {{ .Release.Namespace }} + path: /mutate-v1alpha1-exportedservices + failurePolicy: Fail + admissionReviewVersions: + - "v1beta1" + - "v1" + name: mutate-exportedservices.consul.hashicorp.com + rules: + - apiGroups: + - consul.hashicorp.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - exportedservices + sideEffects: None {{- end }} diff --git a/charts/consul/templates/crd-partitionexports.yaml b/charts/consul/templates/crd-exportedservices.yaml similarity index 93% rename from charts/consul/templates/crd-partitionexports.yaml rename to charts/consul/templates/crd-exportedservices.yaml index a39dcaad0a..67f67e5704 100644 --- a/charts/consul/templates/crd-partitionexports.yaml +++ b/charts/consul/templates/crd-exportedservices.yaml @@ -6,7 +6,7 @@ metadata: annotations: controller-gen.kubebuilder.io/version: v0.6.0 creationTimestamp: null - name: partitionexports.consul.hashicorp.com + name: exportedservices.consul.hashicorp.com labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} @@ -16,10 +16,10 @@ metadata: spec: group: consul.hashicorp.com names: - kind: PartitionExports - listKind: PartitionExportsList - plural: partitionexports - singular: partitionexports + kind: ExportedServices + listKind: ExportedServicesList + plural: exportedservices + singular: exportedservices scope: Namespaced versions: - additionalPrinterColumns: @@ -38,7 +38,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: PartitionExports is the Schema for the partitionexports API + description: ExportedServices is the Schema for the exportedservices API properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation @@ -53,7 +53,7 @@ spec: metadata: type: object spec: - description: PartitionExportsSpec defines the desired state of PartitionExports + description: ExportedServicesSpec defines the desired state of ExportedServices properties: services: description: Services is a list of services to be exported and the diff --git a/charts/consul/test/unit/crd-partitionexports.bats b/charts/consul/test/unit/crd-exportedservices.bats similarity index 73% rename from charts/consul/test/unit/crd-partitionexports.bats rename to charts/consul/test/unit/crd-exportedservices.bats index 35463eea29..cf1a35a587 100644 --- a/charts/consul/test/unit/crd-partitionexports.bats +++ b/charts/consul/test/unit/crd-exportedservices.bats @@ -2,17 +2,17 @@ load _helpers -@test "partitionExports/CustomerResourceDefinition: disabled by default" { +@test "exportedServices/CustomerResourceDefinition: disabled by default" { cd `chart_dir` assert_empty helm template \ - -s templates/crd-partitionexports.yaml \ + -s templates/crd-exportedservices.yaml \ . } -@test "partitionExports/CustomerResourceDefinition: enabled with controller.enabled=true" { +@test "exportedServices/CustomerResourceDefinition: enabled with controller.enabled=true" { cd `chart_dir` local actual=$(helm template \ - -s templates/crd-partitionexports.yaml \ + -s templates/crd-exportedservices.yaml \ --set 'controller.enabled=true' \ . | tee /dev/stderr | # The generated CRDs have "---" at the top which results in two objects diff --git a/control-plane/PROJECT b/control-plane/PROJECT index 9e26de1f52..16d303458c 100644 --- a/control-plane/PROJECT +++ b/control-plane/PROJECT @@ -56,7 +56,7 @@ resources: - controller: true domain: hashicorp.com group: consul - kind: PartitionExport + kind: ExportedServices path: github.com/hashicorp/consul-k8s/api/v1alpha1 version: v1alpha1 version: "3" diff --git a/control-plane/api/common/common.go b/control-plane/api/common/common.go index a44f527472..7c761b6477 100644 --- a/control-plane/api/common/common.go +++ b/control-plane/api/common/common.go @@ -8,7 +8,7 @@ const ( ServiceRouter string = "servicerouter" ServiceSplitter string = "servicesplitter" ServiceIntentions string = "serviceintentions" - PartitionExports string = "partitionexports" + ExportedServices string = "exportedservices" IngressGateway string = "ingressgateway" TerminatingGateway string = "terminatinggateway" diff --git a/control-plane/api/v1alpha1/partitionexports_types.go b/control-plane/api/v1alpha1/exportedservices_types.go similarity index 72% rename from control-plane/api/v1alpha1/partitionexports_types.go rename to control-plane/api/v1alpha1/exportedservices_types.go index 9fa01fa333..5c1e337c2d 100644 --- a/control-plane/api/v1alpha1/partitionexports_types.go +++ b/control-plane/api/v1alpha1/exportedservices_types.go @@ -16,38 +16,38 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" ) -const PartitionExportsKubeKind = "partitionexports" +const ExportedServicesKubeKind = "exportedservices" func init() { - SchemeBuilder.Register(&PartitionExports{}, &PartitionExportsList{}) + SchemeBuilder.Register(&ExportedServices{}, &ExportedServicesList{}) } //+kubebuilder:object:root=true //+kubebuilder:subresource:status -// PartitionExports is the Schema for the partitionexports API +// ExportedServices is the Schema for the exportedservices 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" -type PartitionExports struct { +type ExportedServices struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` - Spec PartitionExportsSpec `json:"spec,omitempty"` + Spec ExportedServicesSpec `json:"spec,omitempty"` Status `json:"status,omitempty"` } //+kubebuilder:object:root=true -// PartitionExportsList contains a list of PartitionExports -type PartitionExportsList struct { +// ExportedServicesList contains a list of ExportedServices +type ExportedServicesList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` - Items []PartitionExports `json:"items"` + Items []ExportedServices `json:"items"` } -// PartitionExportsSpec defines the desired state of PartitionExports -type PartitionExportsSpec struct { +// ExportedServicesSpec defines the desired state of ExportedServices +type ExportedServicesSpec struct { // Services is a list of services to be exported and the list of partitions // to expose them to. Services []ExportedService `json:"services,omitempty"` @@ -72,15 +72,15 @@ type ServiceConsumer struct { Partition string `json:"partition,omitempty"` } -func (in *PartitionExports) GetObjectMeta() metav1.ObjectMeta { +func (in *ExportedServices) GetObjectMeta() metav1.ObjectMeta { return in.ObjectMeta } -func (in *PartitionExports) AddFinalizer(name string) { +func (in *ExportedServices) AddFinalizer(name string) { in.ObjectMeta.Finalizers = append(in.Finalizers(), name) } -func (in *PartitionExports) RemoveFinalizer(name string) { +func (in *ExportedServices) RemoveFinalizer(name string) { var newFinalizers []string for _, oldF := range in.Finalizers() { if oldF != name { @@ -90,35 +90,35 @@ func (in *PartitionExports) RemoveFinalizer(name string) { in.ObjectMeta.Finalizers = newFinalizers } -func (in *PartitionExports) Finalizers() []string { +func (in *ExportedServices) Finalizers() []string { return in.ObjectMeta.Finalizers } -func (in *PartitionExports) ConsulKind() string { - return capi.PartitionExports +func (in *ExportedServices) ConsulKind() string { + return capi.ExportedServices } -func (in *PartitionExports) ConsulGlobalResource() bool { +func (in *ExportedServices) ConsulGlobalResource() bool { return true } -func (in *PartitionExports) ConsulMirroringNS() string { +func (in *ExportedServices) ConsulMirroringNS() string { return common.DefaultConsulNamespace } -func (in *PartitionExports) KubeKind() string { - return PartitionExportsKubeKind +func (in *ExportedServices) KubeKind() string { + return ExportedServicesKubeKind } -func (in *PartitionExports) ConsulName() string { +func (in *ExportedServices) ConsulName() string { return in.ObjectMeta.Name } -func (in *PartitionExports) KubernetesName() string { +func (in *ExportedServices) KubernetesName() string { return in.ObjectMeta.Name } -func (in *PartitionExports) SetSyncedCondition(status corev1.ConditionStatus, reason, message string) { +func (in *ExportedServices) SetSyncedCondition(status corev1.ConditionStatus, reason, message string) { in.Status.Conditions = Conditions{ { Type: ConditionSynced, @@ -130,11 +130,11 @@ func (in *PartitionExports) SetSyncedCondition(status corev1.ConditionStatus, re } } -func (in *PartitionExports) SetLastSyncedTime(time *metav1.Time) { +func (in *ExportedServices) SetLastSyncedTime(time *metav1.Time) { in.Status.LastSyncedTime = time } -func (in *PartitionExports) SyncedCondition() (status corev1.ConditionStatus, reason, message string) { +func (in *ExportedServices) SyncedCondition() (status corev1.ConditionStatus, reason, message string) { cond := in.Status.GetCondition(ConditionSynced) if cond == nil { return corev1.ConditionUnknown, "", "" @@ -142,7 +142,7 @@ func (in *PartitionExports) SyncedCondition() (status corev1.ConditionStatus, re return cond.Status, cond.Reason, cond.Message } -func (in *PartitionExports) SyncedConditionStatus() corev1.ConditionStatus { +func (in *ExportedServices) SyncedConditionStatus() corev1.ConditionStatus { cond := in.Status.GetCondition(ConditionSynced) if cond == nil { return corev1.ConditionUnknown @@ -150,12 +150,12 @@ func (in *PartitionExports) SyncedConditionStatus() corev1.ConditionStatus { return cond.Status } -func (in *PartitionExports) ToConsul(datacenter string) api.ConfigEntry { +func (in *ExportedServices) ToConsul(datacenter string) api.ConfigEntry { var services []capi.ExportedService for _, service := range in.Spec.Services { services = append(services, service.toConsul()) } - return &capi.PartitionExportsConfigEntry{ + return &capi.ExportedServicesConfigEntry{ Name: in.Name, Services: services, Meta: meta(datacenter), @@ -174,23 +174,23 @@ func (in *ExportedService) toConsul() capi.ExportedService { } } -func (in *PartitionExports) MatchesConsul(candidate api.ConfigEntry) bool { - configEntry, ok := candidate.(*capi.PartitionExportsConfigEntry) +func (in *ExportedServices) MatchesConsul(candidate api.ConfigEntry) bool { + configEntry, ok := candidate.(*capi.ExportedServicesConfigEntry) if !ok { return false } // No datacenter is passed to ToConsul as we ignore the Meta field when checking for equality. - return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.PartitionExportsConfigEntry{}, "Partition", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) + return cmp.Equal(in.ToConsul(""), configEntry, cmpopts.IgnoreFields(capi.ExportedServicesConfigEntry{}, "Partition", "Meta", "ModifyIndex", "CreateIndex"), cmpopts.IgnoreUnexported(), cmpopts.EquateEmpty()) } -func (in *PartitionExports) Validate(consulMeta common.ConsulMeta) error { +func (in *ExportedServices) Validate(consulMeta common.ConsulMeta) error { var errs field.ErrorList if !consulMeta.PartitionsEnabled { return apierrors.NewForbidden( - schema.GroupResource{Group: ConsulHashicorpGroup, Resource: common.PartitionExports}, + schema.GroupResource{Group: ConsulHashicorpGroup, Resource: common.ExportedServices}, in.KubernetesName(), - errors.New("Consul Enterprise Admin Partitions must be enabled to create PartitionExports")) + errors.New("Consul Enterprise Admin Partitions must be enabled to create ExportedServices")) } if in.Name != consulMeta.Partition { errs = append(errs, field.Invalid(field.NewPath("name"), in.Name, fmt.Sprintf(`%s resource name must be the same name as the partition, "%s"`, in.KubeKind(), consulMeta.Partition))) @@ -205,7 +205,7 @@ func (in *PartitionExports) Validate(consulMeta common.ConsulMeta) error { } if len(errs) > 0 { return apierrors.NewInvalid( - schema.GroupKind{Group: ConsulHashicorpGroup, Kind: PartitionExportsKubeKind}, + schema.GroupKind{Group: ConsulHashicorpGroup, Kind: ExportedServicesKubeKind}, in.KubernetesName(), errs) } return nil @@ -218,5 +218,5 @@ func (in *ExportedService) validate(path *field.Path) *field.Error { return nil } -func (in *PartitionExports) DefaultNamespaceFields(_ common.ConsulMeta) { +func (in *ExportedServices) DefaultNamespaceFields(_ common.ConsulMeta) { } diff --git a/control-plane/api/v1alpha1/partitionexports_types_test.go b/control-plane/api/v1alpha1/exportedservices_types_test.go similarity index 61% rename from control-plane/api/v1alpha1/partitionexports_types_test.go rename to control-plane/api/v1alpha1/exportedservices_types_test.go index dc0898da66..b35f27cca2 100644 --- a/control-plane/api/v1alpha1/partitionexports_types_test.go +++ b/control-plane/api/v1alpha1/exportedservices_types_test.go @@ -12,20 +12,20 @@ import ( ) // Test MatchesConsul for cases that should return true. -func TestPartitionExports_MatchesConsul(t *testing.T) { +func TestExportedServices_MatchesConsul(t *testing.T) { cases := map[string]struct { - Ours PartitionExports + Ours ExportedServices Theirs capi.ConfigEntry Matches bool }{ "empty fields matches": { - Ours: PartitionExports{ + Ours: ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: common.DefaultConsulPartition, }, - Spec: PartitionExportsSpec{}, + Spec: ExportedServicesSpec{}, }, - Theirs: &capi.PartitionExportsConfigEntry{ + Theirs: &capi.ExportedServicesConfigEntry{ Name: common.DefaultConsulPartition, CreateIndex: 1, ModifyIndex: 2, @@ -37,11 +37,11 @@ func TestPartitionExports_MatchesConsul(t *testing.T) { Matches: true, }, "all fields set matches": { - Ours: PartitionExports{ + Ours: ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: common.DefaultConsulPartition, }, - Spec: PartitionExportsSpec{ + Spec: ExportedServicesSpec{ Services: []ExportedService{ { Name: "service-frontend", @@ -70,7 +70,7 @@ func TestPartitionExports_MatchesConsul(t *testing.T) { }, }, }, - Theirs: &capi.PartitionExportsConfigEntry{ + Theirs: &capi.ExportedServicesConfigEntry{ Name: common.DefaultConsulPartition, Services: []capi.ExportedService{ { @@ -108,15 +108,15 @@ func TestPartitionExports_MatchesConsul(t *testing.T) { Matches: true, }, "mismatched types does not match": { - Ours: PartitionExports{ + Ours: ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: common.DefaultConsulPartition, }, - Spec: PartitionExportsSpec{}, + Spec: ExportedServicesSpec{}, }, Theirs: &capi.ServiceConfigEntry{ Name: common.DefaultConsulPartition, - Kind: capi.PartitionExports, + Kind: capi.ExportedServices, }, Matches: false, }, @@ -128,19 +128,19 @@ func TestPartitionExports_MatchesConsul(t *testing.T) { } } -func TestPartitionExports_ToConsul(t *testing.T) { +func TestExportedServices_ToConsul(t *testing.T) { cases := map[string]struct { - Ours PartitionExports - Exp *capi.PartitionExportsConfigEntry + Ours ExportedServices + Exp *capi.ExportedServicesConfigEntry }{ "empty fields": { - Ours: PartitionExports{ + Ours: ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: common.DefaultConsulPartition, }, - Spec: PartitionExportsSpec{}, + Spec: ExportedServicesSpec{}, }, - Exp: &capi.PartitionExportsConfigEntry{ + Exp: &capi.ExportedServicesConfigEntry{ Name: common.DefaultConsulPartition, Meta: map[string]string{ common.SourceKey: common.SourceValue, @@ -149,11 +149,11 @@ func TestPartitionExports_ToConsul(t *testing.T) { }, }, "every field set": { - Ours: PartitionExports{ + Ours: ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: common.DefaultConsulPartition, }, - Spec: PartitionExportsSpec{ + Spec: ExportedServicesSpec{ Services: []ExportedService{ { Name: "service-frontend", @@ -182,7 +182,7 @@ func TestPartitionExports_ToConsul(t *testing.T) { }, }, }, - Exp: &capi.PartitionExportsConfigEntry{ + Exp: &capi.ExportedServicesConfigEntry{ Name: common.DefaultConsulPartition, Services: []capi.ExportedService{ { @@ -220,49 +220,49 @@ func TestPartitionExports_ToConsul(t *testing.T) { for name, c := range cases { t.Run(name, func(t *testing.T) { act := c.Ours.ToConsul("datacenter") - partitionExports, ok := act.(*capi.PartitionExportsConfigEntry) + exportedServices, ok := act.(*capi.ExportedServicesConfigEntry) require.True(t, ok, "could not cast") - require.Equal(t, c.Exp, partitionExports) + require.Equal(t, c.Exp, exportedServices) }) } } -func TestPartitionExports_AddFinalizer(t *testing.T) { - partitionExports := &PartitionExports{} - partitionExports.AddFinalizer("finalizer") - require.Equal(t, []string{"finalizer"}, partitionExports.ObjectMeta.Finalizers) +func TestExportedServices_AddFinalizer(t *testing.T) { + exportedServices := &ExportedServices{} + exportedServices.AddFinalizer("finalizer") + require.Equal(t, []string{"finalizer"}, exportedServices.ObjectMeta.Finalizers) } -func TestPartitionExports_RemoveFinalizer(t *testing.T) { - partitionExports := &PartitionExports{ +func TestExportedServices_RemoveFinalizer(t *testing.T) { + exportedServices := &ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Finalizers: []string{"f1", "f2"}, }, } - partitionExports.RemoveFinalizer("f1") - require.Equal(t, []string{"f2"}, partitionExports.ObjectMeta.Finalizers) + exportedServices.RemoveFinalizer("f1") + require.Equal(t, []string{"f2"}, exportedServices.ObjectMeta.Finalizers) } -func TestPartitionExports_SetSyncedCondition(t *testing.T) { - partitionExports := &PartitionExports{} - partitionExports.SetSyncedCondition(corev1.ConditionTrue, "reason", "message") +func TestExportedServices_SetSyncedCondition(t *testing.T) { + exportedServices := &ExportedServices{} + exportedServices.SetSyncedCondition(corev1.ConditionTrue, "reason", "message") - require.Equal(t, corev1.ConditionTrue, partitionExports.Status.Conditions[0].Status) - require.Equal(t, "reason", partitionExports.Status.Conditions[0].Reason) - require.Equal(t, "message", partitionExports.Status.Conditions[0].Message) + require.Equal(t, corev1.ConditionTrue, exportedServices.Status.Conditions[0].Status) + require.Equal(t, "reason", exportedServices.Status.Conditions[0].Reason) + require.Equal(t, "message", exportedServices.Status.Conditions[0].Message) now := metav1.Now() - require.True(t, partitionExports.Status.Conditions[0].LastTransitionTime.Before(&now)) + require.True(t, exportedServices.Status.Conditions[0].LastTransitionTime.Before(&now)) } -func TestPartitionExports_SetLastSyncedTime(t *testing.T) { - partitionExports := &PartitionExports{} +func TestExportedServices_SetLastSyncedTime(t *testing.T) { + exportedServices := &ExportedServices{} syncedTime := metav1.NewTime(time.Now()) - partitionExports.SetLastSyncedTime(&syncedTime) + exportedServices.SetLastSyncedTime(&syncedTime) - require.Equal(t, &syncedTime, partitionExports.Status.LastSyncedTime) + require.Equal(t, &syncedTime, exportedServices.Status.LastSyncedTime) } -func TestPartitionExports_GetSyncedConditionStatus(t *testing.T) { +func TestExportedServices_GetSyncedConditionStatus(t *testing.T) { cases := []corev1.ConditionStatus{ corev1.ConditionUnknown, corev1.ConditionFalse, @@ -270,7 +270,7 @@ func TestPartitionExports_GetSyncedConditionStatus(t *testing.T) { } for _, status := range cases { t.Run(string(status), func(t *testing.T) { - partitionExports := &PartitionExports{ + exportedServices := &ExportedServices{ Status: Status{ Conditions: []Condition{{ Type: ConditionSynced, @@ -279,57 +279,57 @@ func TestPartitionExports_GetSyncedConditionStatus(t *testing.T) { }, } - require.Equal(t, status, partitionExports.SyncedConditionStatus()) + require.Equal(t, status, exportedServices.SyncedConditionStatus()) }) } } -func TestPartitionExports_GetConditionWhenStatusNil(t *testing.T) { - require.Nil(t, (&PartitionExports{}).GetCondition(ConditionSynced)) +func TestExportedServices_GetConditionWhenStatusNil(t *testing.T) { + require.Nil(t, (&ExportedServices{}).GetCondition(ConditionSynced)) } -func TestPartitionExports_SyncedConditionStatusWhenStatusNil(t *testing.T) { - require.Equal(t, corev1.ConditionUnknown, (&PartitionExports{}).SyncedConditionStatus()) +func TestExportedServices_SyncedConditionStatusWhenStatusNil(t *testing.T) { + require.Equal(t, corev1.ConditionUnknown, (&ExportedServices{}).SyncedConditionStatus()) } -func TestPartitionExports_SyncedConditionWhenStatusNil(t *testing.T) { - status, reason, message := (&PartitionExports{}).SyncedCondition() +func TestExportedServices_SyncedConditionWhenStatusNil(t *testing.T) { + status, reason, message := (&ExportedServices{}).SyncedCondition() require.Equal(t, corev1.ConditionUnknown, status) require.Equal(t, "", reason) require.Equal(t, "", message) } -func TestPartitionExports_ConsulKind(t *testing.T) { - require.Equal(t, capi.PartitionExports, (&PartitionExports{}).ConsulKind()) +func TestExportedServices_ConsulKind(t *testing.T) { + require.Equal(t, capi.ExportedServices, (&ExportedServices{}).ConsulKind()) } -func TestPartitionExports_KubeKind(t *testing.T) { - require.Equal(t, "partitionexports", (&PartitionExports{}).KubeKind()) +func TestExportedServices_KubeKind(t *testing.T) { + require.Equal(t, "exportedservices", (&ExportedServices{}).KubeKind()) } -func TestPartitionExports_ConsulName(t *testing.T) { - require.Equal(t, "foo", (&PartitionExports{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) +func TestExportedServices_ConsulName(t *testing.T) { + require.Equal(t, "foo", (&ExportedServices{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).ConsulName()) } -func TestPartitionExports_KubernetesName(t *testing.T) { - require.Equal(t, "foo", (&PartitionExports{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) +func TestExportedServices_KubernetesName(t *testing.T) { + require.Equal(t, "foo", (&ExportedServices{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}).KubernetesName()) } -func TestPartitionExports_ConsulNamespace(t *testing.T) { - require.Equal(t, common.DefaultConsulNamespace, (&PartitionExports{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"}}).ConsulMirroringNS()) +func TestExportedServices_ConsulNamespace(t *testing.T) { + require.Equal(t, common.DefaultConsulNamespace, (&ExportedServices{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "bar"}}).ConsulMirroringNS()) } -func TestPartitionExports_ConsulGlobalResource(t *testing.T) { - require.True(t, (&PartitionExports{}).ConsulGlobalResource()) +func TestExportedServices_ConsulGlobalResource(t *testing.T) { + require.True(t, (&ExportedServices{}).ConsulGlobalResource()) } -func TestPartitionExports_ObjectMeta(t *testing.T) { +func TestExportedServices_ObjectMeta(t *testing.T) { meta := metav1.ObjectMeta{ Name: "name", Namespace: "namespace", } - partitionExports := &PartitionExports{ + exportedServices := &ExportedServices{ ObjectMeta: meta, } - require.Equal(t, meta, partitionExports.GetObjectMeta()) + require.Equal(t, meta, exportedServices.GetObjectMeta()) } diff --git a/control-plane/api/v1alpha1/partitionexports_webhook.go b/control-plane/api/v1alpha1/exportedservices_webhook.go similarity index 75% rename from control-plane/api/v1alpha1/partitionexports_webhook.go rename to control-plane/api/v1alpha1/exportedservices_webhook.go index 4311055289..d80062e958 100644 --- a/control-plane/api/v1alpha1/partitionexports_webhook.go +++ b/control-plane/api/v1alpha1/exportedservices_webhook.go @@ -15,7 +15,7 @@ import ( // +kubebuilder:object:generate=false -type PartitionExportsWebhook struct { +type ExportedServicesWebhook struct { client.Client ConsulClient *capi.Client Logger logr.Logger @@ -30,11 +30,11 @@ type PartitionExportsWebhook 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-partitionexports,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=partitionexports,versions=v1alpha1,name=mutate-partitionexports.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 +// +kubebuilder:webhook:verbs=create;update,path=/mutate-v1alpha1-exportedservices,mutating=true,failurePolicy=fail,groups=consul.hashicorp.com,resources=exportedservices,versions=v1alpha1,name=mutate-exportedservices.consul.hashicorp.com,sideEffects=None,admissionReviewVersions=v1beta1;v1 -func (v *PartitionExportsWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { - var exports PartitionExports - var exportsList PartitionExportsList +func (v *ExportedServicesWebhook) Handle(ctx context.Context, req admission.Request) admission.Response { + var exports ExportedServices + var exportsList ExportedServicesList err := v.decoder.Decode(req, &exports) if err != nil { return admission.Errored(http.StatusBadRequest, err) @@ -49,7 +49,7 @@ func (v *PartitionExportsWebhook) Handle(ctx context.Context, req admission.Requ if len(exportsList.Items) > 0 { return admission.Errored(http.StatusBadRequest, - fmt.Errorf("%s resource already defined - only one partitionexports entry is supported per Kubernetes cluster", + fmt.Errorf("%s resource already defined - only one exportedservices entry is supported per Kubernetes cluster", exports.KubeKind())) } } @@ -61,7 +61,7 @@ func (v *PartitionExportsWebhook) Handle(ctx context.Context, req admission.Requ return admission.Allowed(fmt.Sprintf("valid %s request", exports.KubeKind())) } -func (v *PartitionExportsWebhook) InjectDecoder(d *admission.Decoder) error { +func (v *ExportedServicesWebhook) InjectDecoder(d *admission.Decoder) error { v.decoder = d return nil } diff --git a/control-plane/api/v1alpha1/partitionexports_webhook_test.go b/control-plane/api/v1alpha1/exportedservices_webhook_test.go similarity index 79% rename from control-plane/api/v1alpha1/partitionexports_webhook_test.go rename to control-plane/api/v1alpha1/exportedservices_webhook_test.go index caacf3dfbc..9c4b79b13d 100644 --- a/control-plane/api/v1alpha1/partitionexports_webhook_test.go +++ b/control-plane/api/v1alpha1/exportedservices_webhook_test.go @@ -15,24 +15,24 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook/admission" ) -func TestValidatePartitionExports(t *testing.T) { +func TestValidateExportedServices(t *testing.T) { otherNS := "other" otherPartition := "other" cases := map[string]struct { existingResources []runtime.Object - newResource *PartitionExports + newResource *ExportedServices consulMeta common.ConsulMeta expAllow bool expErrMessage string }{ "no duplicates, valid": { existingResources: nil, - newResource: &PartitionExports{ + newResource: &ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: otherPartition, }, - Spec: PartitionExportsSpec{ + Spec: ExportedServicesSpec{ Services: []ExportedService{ { Name: "service", @@ -48,17 +48,17 @@ func TestValidatePartitionExports(t *testing.T) { }, expAllow: true, }, - "partitionexports exists": { - existingResources: []runtime.Object{&PartitionExports{ + "exportedservices exists": { + existingResources: []runtime.Object{&ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: otherPartition, }, }}, - newResource: &PartitionExports{ + newResource: &ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: otherPartition, }, - Spec: PartitionExportsSpec{ + Spec: ExportedServicesSpec{ Services: []ExportedService{ { Name: "service", @@ -73,15 +73,15 @@ func TestValidatePartitionExports(t *testing.T) { Partition: otherPartition, }, expAllow: false, - expErrMessage: "partitionexports resource already defined - only one partitionexports entry is supported per Kubernetes cluster", + expErrMessage: "exportedservices resource already defined - only one exportedservices entry is supported per Kubernetes cluster", }, "name not partition name": { existingResources: []runtime.Object{}, - newResource: &PartitionExports{ + newResource: &ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: "local", }, - Spec: PartitionExportsSpec{ + Spec: ExportedServicesSpec{ Services: []ExportedService{ { Name: "service", @@ -96,15 +96,15 @@ func TestValidatePartitionExports(t *testing.T) { Partition: otherPartition, }, expAllow: false, - expErrMessage: "partitionexports.consul.hashicorp.com \"local\" is invalid: name: Invalid value: \"local\": partitionexports resource name must be the same name as the partition, \"other\"", + expErrMessage: "exportedservices.consul.hashicorp.com \"local\" is invalid: name: Invalid value: \"local\": exportedservices resource name must be the same name as the partition, \"other\"", }, "partitions disabled": { existingResources: []runtime.Object{}, - newResource: &PartitionExports{ + newResource: &ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: otherPartition, }, - Spec: PartitionExportsSpec{ + Spec: ExportedServicesSpec{ Services: []ExportedService{ { Name: "service", @@ -119,15 +119,15 @@ func TestValidatePartitionExports(t *testing.T) { Partition: "", }, expAllow: false, - expErrMessage: "partitionexports.consul.hashicorp.com \"other\" is forbidden: Consul Enterprise Admin Partitions must be enabled to create PartitionExports", + expErrMessage: "exportedservices.consul.hashicorp.com \"other\" is forbidden: Consul Enterprise Admin Partitions must be enabled to create ExportedServices", }, "no services": { existingResources: []runtime.Object{}, - newResource: &PartitionExports{ + newResource: &ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: otherPartition, }, - Spec: PartitionExportsSpec{ + Spec: ExportedServicesSpec{ Services: []ExportedService{}, }, }, @@ -136,15 +136,15 @@ func TestValidatePartitionExports(t *testing.T) { Partition: otherPartition, }, expAllow: false, - expErrMessage: "partitionexports.consul.hashicorp.com \"other\" is invalid: spec.services: Invalid value: []v1alpha1.ExportedService(nil): at least one service must be exported", + expErrMessage: "exportedservices.consul.hashicorp.com \"other\" is invalid: spec.services: Invalid value: []v1alpha1.ExportedService(nil): at least one service must be exported", }, "service with no consumers": { existingResources: []runtime.Object{}, - newResource: &PartitionExports{ + newResource: &ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: otherPartition, }, - Spec: PartitionExportsSpec{ + Spec: ExportedServicesSpec{ Services: []ExportedService{ { Name: "service", @@ -159,7 +159,7 @@ func TestValidatePartitionExports(t *testing.T) { Partition: otherPartition, }, expAllow: false, - expErrMessage: "partitionexports.consul.hashicorp.com \"other\" is invalid: spec.services[0]: Invalid value: []v1alpha1.ServiceConsumer(nil): service must have at least 1 consumer.", + expErrMessage: "exportedservices.consul.hashicorp.com \"other\" is invalid: spec.services[0]: Invalid value: []v1alpha1.ServiceConsumer(nil): service must have at least 1 consumer.", }, } for name, c := range cases { @@ -168,12 +168,12 @@ func TestValidatePartitionExports(t *testing.T) { marshalledRequestObject, err := json.Marshal(c.newResource) require.NoError(t, err) s := runtime.NewScheme() - s.AddKnownTypes(GroupVersion, &PartitionExports{}, &PartitionExportsList{}) + s.AddKnownTypes(GroupVersion, &ExportedServices{}, &ExportedServicesList{}) client := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(c.existingResources...).Build() decoder, err := admission.NewDecoder(s) require.NoError(t, err) - validator := &PartitionExportsWebhook{ + validator := &ExportedServicesWebhook{ Client: client, ConsulClient: nil, Logger: logrtest.TestLogger{T: t}, diff --git a/control-plane/api/v1alpha1/zz_generated.deepcopy.go b/control-plane/api/v1alpha1/zz_generated.deepcopy.go index eb7b167895..2fc836ebe8 100644 --- a/control-plane/api/v1alpha1/zz_generated.deepcopy.go +++ b/control-plane/api/v1alpha1/zz_generated.deepcopy.go @@ -1,4 +1,5 @@ //go:build !ignore_autogenerated +// +build !ignore_autogenerated // Code generated by controller-gen. DO NOT EDIT. @@ -97,6 +98,87 @@ func (in *ExportedService) DeepCopy() *ExportedService { 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) + in.Spec.DeepCopyInto(&out.Spec) + 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 { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// 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 *ExportedServicesSpec) DeepCopyInto(out *ExportedServicesSpec) { + *out = *in + if in.Services != nil { + in, out := &in.Services, &out.Services + *out = make([]ExportedService, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExportedServicesSpec. +func (in *ExportedServicesSpec) DeepCopy() *ExportedServicesSpec { + if in == nil { + return nil + } + out := new(ExportedServicesSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Expose) DeepCopyInto(out *Expose) { *out = *in @@ -641,87 +723,6 @@ func (in *MeshSpec) DeepCopy() *MeshSpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PartitionExports) DeepCopyInto(out *PartitionExports) { - *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 PartitionExports. -func (in *PartitionExports) DeepCopy() *PartitionExports { - if in == nil { - return nil - } - out := new(PartitionExports) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PartitionExports) 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 *PartitionExportsList) DeepCopyInto(out *PartitionExportsList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]PartitionExports, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PartitionExportsList. -func (in *PartitionExportsList) DeepCopy() *PartitionExportsList { - if in == nil { - return nil - } - out := new(PartitionExportsList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *PartitionExportsList) 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 *PartitionExportsSpec) DeepCopyInto(out *PartitionExportsSpec) { - *out = *in - if in.Services != nil { - in, out := &in.Services, &out.Services - *out = make([]ExportedService, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PartitionExportsSpec. -func (in *PartitionExportsSpec) DeepCopy() *PartitionExportsSpec { - if in == nil { - return nil - } - out := new(PartitionExportsSpec) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PassiveHealthCheck) DeepCopyInto(out *PassiveHealthCheck) { *out = *in diff --git a/control-plane/config/certmanager/certificate.yaml b/control-plane/config/certmanager/certificate.yaml deleted file mode 100644 index 58db114fa0..0000000000 --- a/control-plane/config/certmanager/certificate.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# The following manifests contain a self-signed issuer CR and a certificate CR. -# More document can be found at https://docs.cert-manager.io -# WARNING: Targets CertManager 0.11 check https://docs.cert-manager.io/en/latest/tasks/upgrading/index.html for -# breaking changes -apiVersion: cert-manager.io/v1alpha2 -kind: Issuer -metadata: - name: selfsigned-issuer - namespace: system -spec: - selfSigned: {} ---- -apiVersion: cert-manager.io/v1alpha2 -kind: Certificate -metadata: - name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml - namespace: system -spec: - # $(SERVICE_NAME) and $(SERVICE_NAMESPACE) will be substituted by kustomize - dnsNames: - - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc - - $(SERVICE_NAME).$(SERVICE_NAMESPACE).svc.cluster.local - issuerRef: - kind: Issuer - name: selfsigned-issuer - secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize diff --git a/control-plane/config/certmanager/kustomization.yaml b/control-plane/config/certmanager/kustomization.yaml deleted file mode 100644 index bebea5a595..0000000000 --- a/control-plane/config/certmanager/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -resources: -- certificate.yaml - -configurations: -- kustomizeconfig.yaml diff --git a/control-plane/config/certmanager/kustomizeconfig.yaml b/control-plane/config/certmanager/kustomizeconfig.yaml deleted file mode 100644 index 90d7c313ca..0000000000 --- a/control-plane/config/certmanager/kustomizeconfig.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# This configuration is for teaching kustomize how to update name ref and var substitution -nameReference: -- kind: Issuer - group: cert-manager.io - fieldSpecs: - - kind: Certificate - group: cert-manager.io - path: spec/issuerRef/name - -varReference: -- kind: Certificate - group: cert-manager.io - path: spec/commonName -- kind: Certificate - group: cert-manager.io - path: spec/dnsNames diff --git a/control-plane/config/crd/bases/consul.hashicorp.com_partitionexports.yaml b/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml similarity index 93% rename from control-plane/config/crd/bases/consul.hashicorp.com_partitionexports.yaml rename to control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml index 8e31c6ade8..7c9b46192b 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_partitionexports.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml @@ -6,14 +6,14 @@ metadata: annotations: controller-gen.kubebuilder.io/version: v0.6.0 creationTimestamp: null - name: partitionexports.consul.hashicorp.com + name: exportedservices.consul.hashicorp.com spec: group: consul.hashicorp.com names: - kind: PartitionExports - listKind: PartitionExportsList - plural: partitionexports - singular: partitionexports + kind: ExportedServices + listKind: ExportedServicesList + plural: exportedservices + singular: exportedservices scope: Namespaced versions: - additionalPrinterColumns: @@ -32,7 +32,7 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: PartitionExports is the Schema for the partitionexports API + description: ExportedServices is the Schema for the exportedservices API properties: apiVersion: description: 'APIVersion defines the versioned schema of this representation @@ -47,7 +47,7 @@ spec: metadata: type: object spec: - description: PartitionExportsSpec defines the desired state of PartitionExports + description: ExportedServicesSpec defines the desired state of ExportedServices properties: services: description: Services is a list of services to be exported and the diff --git a/control-plane/config/crd/kustomization.yaml b/control-plane/config/crd/kustomization.yaml deleted file mode 100644 index 1c9666aac6..0000000000 --- a/control-plane/config/crd/kustomization.yaml +++ /dev/null @@ -1,45 +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_servicedefaults.yaml -- bases/consul.hashicorp.com_serviceresolvers.yaml -- bases/consul.hashicorp.com_proxydefaults.yaml -- bases/consul.hashicorp.com_servicerouters.yaml -- bases/consul.hashicorp.com_serviceintentions.yaml -- bases/consul.hashicorp.com_ingressgateways.yaml -- bases/consul.hashicorp.com_terminatinggateways.yaml -- bases/consul.hashicorp.com_meshes.yaml -- bases/consul.hashicorp.com_partitionexports.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_servicedefaults.yaml -- patches/webhook_in_serviceresolvers.yaml -- patches/webhook_in_proxydefaults.yaml -- patches/webhook_in_servicerouters.yaml -- patches/webhook_in_serviceintentions.yaml -- patches/webhook_in_ingressgateways.yaml -- patches/webhook_in_terminatinggateways.yaml -#- patches/webhook_in_meshes.yaml -#- patches/webhook_in_partitionexports.yaml -# +kubebuilder:scaffold:crdkustomizewebhookpatch - -# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. -# patches here are for enabling the CA injection for each CRD -#- patches/cainjection_in_servicedefaults.yaml -#- patches/cainjection_in_serviceresolvers.yaml -#- patches/cainjection_in_proxydefaults.yaml -#- patches/cainjection_in_servicerouters.yaml -#- patches/cainjection_in_serviceintentions.yaml -#- patches/cainjection_in_ingressgateways.yaml -#- patches/cainjection_in_terminatinggateways.yaml -#- patches/cainjection_in_meshes.yaml -#- patches/cainjection_in_partitionexports.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_ingressgateways.yaml b/control-plane/config/crd/patches/cainjection_in_ingressgateways.yaml deleted file mode 100644 index aa1074fa2b..0000000000 --- a/control-plane/config/crd/patches/cainjection_in_ingressgateways.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: ingressgateways.consul.hashicorp.com diff --git a/control-plane/config/crd/patches/cainjection_in_proxydefaults.yaml b/control-plane/config/crd/patches/cainjection_in_proxydefaults.yaml deleted file mode 100644 index df0460c54c..0000000000 --- a/control-plane/config/crd/patches/cainjection_in_proxydefaults.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: proxydefaults.consul.hashicorp.com diff --git a/control-plane/config/crd/patches/cainjection_in_servicedefaults.yaml b/control-plane/config/crd/patches/cainjection_in_servicedefaults.yaml deleted file mode 100644 index 3ae80de8ce..0000000000 --- a/control-plane/config/crd/patches/cainjection_in_servicedefaults.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: servicedefaults.consul.hashicorp.com diff --git a/control-plane/config/crd/patches/cainjection_in_serviceintentions.yaml b/control-plane/config/crd/patches/cainjection_in_serviceintentions.yaml deleted file mode 100644 index e53864ab64..0000000000 --- a/control-plane/config/crd/patches/cainjection_in_serviceintentions.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: serviceintentions.consul.hashicorp.com diff --git a/control-plane/config/crd/patches/cainjection_in_serviceresolvers.yaml b/control-plane/config/crd/patches/cainjection_in_serviceresolvers.yaml deleted file mode 100644 index 39a09eb8e1..0000000000 --- a/control-plane/config/crd/patches/cainjection_in_serviceresolvers.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: serviceresolvers.consul.hashicorp.com diff --git a/control-plane/config/crd/patches/cainjection_in_servicerouters.yaml b/control-plane/config/crd/patches/cainjection_in_servicerouters.yaml deleted file mode 100644 index 798e76fd2a..0000000000 --- a/control-plane/config/crd/patches/cainjection_in_servicerouters.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: servicerouters.consul.hashicorp.com diff --git a/control-plane/config/crd/patches/cainjection_in_servicesplitters.yaml b/control-plane/config/crd/patches/cainjection_in_servicesplitters.yaml deleted file mode 100644 index 288ca2cf23..0000000000 --- a/control-plane/config/crd/patches/cainjection_in_servicesplitters.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: servicesplitters.consul.hashicorp.com diff --git a/control-plane/config/crd/patches/cainjection_in_terminatinggateways.yaml b/control-plane/config/crd/patches/cainjection_in_terminatinggateways.yaml deleted file mode 100644 index 9423b79fbf..0000000000 --- a/control-plane/config/crd/patches/cainjection_in_terminatinggateways.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: terminatinggateways.consul.hashicorp.com diff --git a/control-plane/config/crd/patches/webhook_in_ingressgateways.yaml b/control-plane/config/crd/patches/webhook_in_ingressgateways.yaml deleted file mode 100644 index fcc6f69fa5..0000000000 --- a/control-plane/config/crd/patches/webhook_in_ingressgateways.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: ingressgateways.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/crd/patches/webhook_in_partitionexports.yaml b/control-plane/config/crd/patches/webhook_in_partitionexports.yaml deleted file mode 100644 index 3084d0409c..0000000000 --- a/control-plane/config/crd/patches/webhook_in_partitionexports.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: partitionexports.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/crd/patches/webhook_in_proxydefaults.yaml b/control-plane/config/crd/patches/webhook_in_proxydefaults.yaml deleted file mode 100644 index 4d2d4bfff1..0000000000 --- a/control-plane/config/crd/patches/webhook_in_proxydefaults.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: proxydefaults.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/crd/patches/webhook_in_servicedefaults.yaml b/control-plane/config/crd/patches/webhook_in_servicedefaults.yaml deleted file mode 100644 index 774953f50f..0000000000 --- a/control-plane/config/crd/patches/webhook_in_servicedefaults.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: servicedefaults.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/crd/patches/webhook_in_serviceintentions.yaml b/control-plane/config/crd/patches/webhook_in_serviceintentions.yaml deleted file mode 100644 index 77fcdb48ff..0000000000 --- a/control-plane/config/crd/patches/webhook_in_serviceintentions.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: serviceintentions.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/crd/patches/webhook_in_serviceresolvers.yaml b/control-plane/config/crd/patches/webhook_in_serviceresolvers.yaml deleted file mode 100644 index b9f9b42a21..0000000000 --- a/control-plane/config/crd/patches/webhook_in_serviceresolvers.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: serviceresolvers.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/crd/patches/webhook_in_servicerouters.yaml b/control-plane/config/crd/patches/webhook_in_servicerouters.yaml deleted file mode 100644 index e4856434c8..0000000000 --- a/control-plane/config/crd/patches/webhook_in_servicerouters.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: servicerouters.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/crd/patches/webhook_in_servicesplitters.yaml b/control-plane/config/crd/patches/webhook_in_servicesplitters.yaml deleted file mode 100644 index e8f7c1371f..0000000000 --- a/control-plane/config/crd/patches/webhook_in_servicesplitters.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: servicesplitters.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/crd/patches/webhook_in_terminatinggateways.yaml b/control-plane/config/crd/patches/webhook_in_terminatinggateways.yaml deleted file mode 100644 index 05063cc954..0000000000 --- a/control-plane/config/crd/patches/webhook_in_terminatinggateways.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: terminatinggateways.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/default/kustomization.yaml b/control-plane/config/default/kustomization.yaml deleted file mode 100644 index df978482e5..0000000000 --- a/control-plane/config/default/kustomization.yaml +++ /dev/null @@ -1,74 +0,0 @@ -# Adds namespace to all resources. -namespace: default - -# Value of this field is prepended to the -# names of all resources, e.g. a deployment named -# "wordpress" becomes "alices-wordpress". -# Note that it should also match with the prefix (text before '-') of the namespace -# field above. -namePrefix: consul-controller- - -# Labels to add to all resources and selectors. -#commonLabels: -# someName: someValue - -# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in -# crd/kustomization.yaml -# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required. -# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'. -#- ../prometheus - - # Protect the /metrics endpoint by putting it behind auth. - # If you want your controller-manager to expose the /metrics - # endpoint w/o any authn/z, please comment the following line. - -# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in -# crd/kustomization.yaml - -# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. -# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks. -# 'CERTMANAGER' needs to be enabled to use ca injection -patchesStrategicMerge: -- manager_auth_proxy_patch.yaml -- manager_webhook_patch.yaml -- webhookcainjection_patch.yaml - -# the following config is for teaching kustomize how to do var substitution -# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. -vars: -- fieldref: - fieldPath: metadata.namespace - name: CERTIFICATE_NAMESPACE - objref: - group: cert-manager.io - kind: Certificate - name: serving-cert - version: v1alpha2 -- fieldref: {} - name: CERTIFICATE_NAME - objref: - group: cert-manager.io - kind: Certificate - name: serving-cert - version: v1alpha2 -- fieldref: - fieldPath: metadata.namespace - name: SERVICE_NAMESPACE - objref: - kind: Service - name: webhook-service - version: v1 -- fieldref: {} - name: SERVICE_NAME - objref: - kind: Service - name: webhook-service - version: v1 -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- ../crd -- ../rbac -- ../manager -- ../webhook -- ../certmanager diff --git a/control-plane/config/default/manager_auth_proxy_patch.yaml b/control-plane/config/default/manager_auth_proxy_patch.yaml deleted file mode 100644 index 77e743d1c1..0000000000 --- a/control-plane/config/default/manager_auth_proxy_patch.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# This patch inject a sidecar container which is a HTTP proxy for the -# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews. -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system -spec: - template: - spec: - containers: - - name: kube-rbac-proxy - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8080/" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - - name: manager - args: - - "--metrics-addr=127.0.0.1:8080" - - "--enable-leader-election" diff --git a/control-plane/config/default/manager_webhook_patch.yaml b/control-plane/config/default/manager_webhook_patch.yaml deleted file mode 100644 index 738de350b7..0000000000 --- a/control-plane/config/default/manager_webhook_patch.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system -spec: - template: - spec: - containers: - - name: manager - ports: - - containerPort: 9443 - name: webhook-server - protocol: TCP - volumeMounts: - - mountPath: /tmp/k8s-webhook-server/serving-certs - name: cert - readOnly: true - volumes: - - name: cert - secret: - defaultMode: 420 - secretName: webhook-server-cert diff --git a/control-plane/config/default/webhookcainjection_patch.yaml b/control-plane/config/default/webhookcainjection_patch.yaml deleted file mode 100644 index 79c5b20a63..0000000000 --- a/control-plane/config/default/webhookcainjection_patch.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# This patch add annotation to admission webhook config and -# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. -apiVersion: admissionregistration.k8s.io/v1beta1 -kind: MutatingWebhookConfiguration -metadata: - name: mutating-webhook-configuration - annotations: - cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) diff --git a/control-plane/config/manager/kustomization.yaml b/control-plane/config/manager/kustomization.yaml deleted file mode 100644 index 957b423a0a..0000000000 --- a/control-plane/config/manager/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -resources: -- manager.yaml -# todo: this was auto-generated -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -images: -- name: controller - newName: ashwinvenkatesh/consul-k8s - newTag: latest diff --git a/control-plane/config/manager/manager.yaml b/control-plane/config/manager/manager.yaml deleted file mode 100644 index b086533218..0000000000 --- a/control-plane/config/manager/manager.yaml +++ /dev/null @@ -1,48 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - labels: - control-plane: controller-manager - name: system ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system - labels: - control-plane: controller-manager -spec: - selector: - matchLabels: - control-plane: controller-manager - replicas: 1 - template: - metadata: - labels: - control-plane: controller-manager - spec: - containers: - - name: manager - env: - - name: HOST_IP - valueFrom: - fieldRef: - fieldPath: status.hostIP - - name: CONSUL_HTTP_ADDR - value: http://$(HOST_IP):8500 - command: - - consul-k8s - - controller - args: - - --enable-leader-election - image: controller:latest - resources: - limits: - cpu: 100m - memory: 30Mi - requests: - cpu: 100m - memory: 20Mi - - terminationGracePeriodSeconds: 10 diff --git a/control-plane/config/rbac/auth_proxy_client_clusterrole.yaml b/control-plane/config/rbac/auth_proxy_client_clusterrole.yaml deleted file mode 100644 index 7d62534c5f..0000000000 --- a/control-plane/config/rbac/auth_proxy_client_clusterrole.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRole -metadata: - name: metrics-reader -rules: -- nonResourceURLs: ["/metrics"] - verbs: ["get"] diff --git a/control-plane/config/rbac/auth_proxy_role.yaml b/control-plane/config/rbac/auth_proxy_role.yaml deleted file mode 100644 index 618f5e4177..0000000000 --- a/control-plane/config/rbac/auth_proxy_role.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: proxy-role -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] diff --git a/control-plane/config/rbac/auth_proxy_role_binding.yaml b/control-plane/config/rbac/auth_proxy_role_binding.yaml deleted file mode 100644 index 48ed1e4b85..0000000000 --- a/control-plane/config/rbac/auth_proxy_role_binding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: proxy-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: proxy-role -subjects: -- kind: ServiceAccount - name: default - namespace: system diff --git a/control-plane/config/rbac/auth_proxy_service.yaml b/control-plane/config/rbac/auth_proxy_service.yaml deleted file mode 100644 index 6cf656be14..0000000000 --- a/control-plane/config/rbac/auth_proxy_service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - control-plane: controller-manager - name: controller-manager-metrics-service - namespace: system -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - control-plane: controller-manager diff --git a/control-plane/config/rbac/ingressgateway_editor_role.yaml b/control-plane/config/rbac/ingressgateway_editor_role.yaml deleted file mode 100644 index 424e12e33c..0000000000 --- a/control-plane/config/rbac/ingressgateway_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit ingressgateways. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: ingressgateway-editor-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - ingressgateways - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - ingressgateways/status - verbs: - - get diff --git a/control-plane/config/rbac/ingressgateway_viewer_role.yaml b/control-plane/config/rbac/ingressgateway_viewer_role.yaml deleted file mode 100644 index 82ca5e79db..0000000000 --- a/control-plane/config/rbac/ingressgateway_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view ingressgateways. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: ingressgateway-viewer-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - ingressgateways - verbs: - - get - - list - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - ingressgateways/status - verbs: - - get diff --git a/control-plane/config/rbac/kustomization.yaml b/control-plane/config/rbac/kustomization.yaml deleted file mode 100644 index 66c28338fe..0000000000 --- a/control-plane/config/rbac/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -resources: -- role.yaml -- role_binding.yaml -- leader_election_role.yaml -- leader_election_role_binding.yaml -# Comment the following 4 lines if you want to disable -# the auth proxy (https://github.com/brancz/kube-rbac-proxy) -# which protects your /metrics endpoint. -- auth_proxy_service.yaml -- auth_proxy_role.yaml -- auth_proxy_role_binding.yaml -- auth_proxy_client_clusterrole.yaml diff --git a/control-plane/config/rbac/leader_election_role.yaml b/control-plane/config/rbac/leader_election_role.yaml deleted file mode 100644 index 7dc16c420e..0000000000 --- a/control-plane/config/rbac/leader_election_role.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# permissions to do leader election. -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: leader-election-role -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - "" - resources: - - configmaps/status - verbs: - - get - - update - - patch -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch diff --git a/control-plane/config/rbac/leader_election_role_binding.yaml b/control-plane/config/rbac/leader_election_role_binding.yaml deleted file mode 100644 index eed16906f4..0000000000 --- a/control-plane/config/rbac/leader_election_role_binding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: leader-election-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: leader-election-role -subjects: -- kind: ServiceAccount - name: default - namespace: system diff --git a/control-plane/config/rbac/partitionexport_editor_role.yaml b/control-plane/config/rbac/partitionexport_editor_role.yaml deleted file mode 100644 index 45b9d4c5c0..0000000000 --- a/control-plane/config/rbac/partitionexport_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit partitionexports. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: partitionexport-editor-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - partitionexports - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - partitionexports/status - verbs: - - get diff --git a/control-plane/config/rbac/partitionexport_viewer_role.yaml b/control-plane/config/rbac/partitionexport_viewer_role.yaml deleted file mode 100644 index ce62786b98..0000000000 --- a/control-plane/config/rbac/partitionexport_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view partitionexports. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: partitionexport-viewer-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - partitionexports - verbs: - - get - - list - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - partitionexports/status - verbs: - - get diff --git a/control-plane/config/rbac/proxydefaults_editor_role.yaml b/control-plane/config/rbac/proxydefaults_editor_role.yaml deleted file mode 100644 index 42afc1a916..0000000000 --- a/control-plane/config/rbac/proxydefaults_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit proxydefaults. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: proxydefaults-editor-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - proxydefaults - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - proxydefaults/status - verbs: - - get diff --git a/control-plane/config/rbac/proxydefaults_viewer_role.yaml b/control-plane/config/rbac/proxydefaults_viewer_role.yaml deleted file mode 100644 index b16fda3894..0000000000 --- a/control-plane/config/rbac/proxydefaults_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view proxydefaults. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: proxydefaults-viewer-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - proxydefaults - verbs: - - get - - list - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - proxydefaults/status - verbs: - - get diff --git a/control-plane/config/rbac/role.yaml b/control-plane/config/rbac/role.yaml index f1a46e72d3..6009210f4b 100644 --- a/control-plane/config/rbac/role.yaml +++ b/control-plane/config/rbac/role.yaml @@ -9,7 +9,7 @@ rules: - apiGroups: - consul.hashicorp.com resources: - - ingressgateways + - exportedservices verbs: - create - delete @@ -21,7 +21,7 @@ rules: - apiGroups: - consul.hashicorp.com resources: - - ingressgateways/status + - exportedservices/status verbs: - get - patch @@ -29,7 +29,7 @@ rules: - apiGroups: - consul.hashicorp.com resources: - - mesh + - ingressgateways verbs: - create - delete @@ -41,7 +41,7 @@ rules: - apiGroups: - consul.hashicorp.com resources: - - mesh/status + - ingressgateways/status verbs: - get - patch @@ -49,7 +49,7 @@ rules: - apiGroups: - consul.hashicorp.com resources: - - partitionexports + - mesh verbs: - create - delete @@ -61,7 +61,7 @@ rules: - apiGroups: - consul.hashicorp.com resources: - - partitionexports/status + - mesh/status verbs: - get - patch diff --git a/control-plane/config/rbac/role_binding.yaml b/control-plane/config/rbac/role_binding.yaml deleted file mode 100644 index 8f2658702c..0000000000 --- a/control-plane/config/rbac/role_binding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: manager-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: manager-role -subjects: -- kind: ServiceAccount - name: default - namespace: system diff --git a/control-plane/config/rbac/servicedefaults_editor_role.yaml b/control-plane/config/rbac/servicedefaults_editor_role.yaml deleted file mode 100644 index f5a7d27a26..0000000000 --- a/control-plane/config/rbac/servicedefaults_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit servicedefaults. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: servicedefaults-editor-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - servicedefaults - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - servicedefaults/status - verbs: - - get diff --git a/control-plane/config/rbac/servicedefaults_viewer_role.yaml b/control-plane/config/rbac/servicedefaults_viewer_role.yaml deleted file mode 100644 index ac9ccc9b3b..0000000000 --- a/control-plane/config/rbac/servicedefaults_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view servicedefaults. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: servicedefaults-viewer-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - servicedefaults - verbs: - - get - - list - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - servicedefaults/status - verbs: - - get diff --git a/control-plane/config/rbac/serviceintentions_editor_role.yaml b/control-plane/config/rbac/serviceintentions_editor_role.yaml deleted file mode 100644 index 83a0437d7d..0000000000 --- a/control-plane/config/rbac/serviceintentions_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit serviceintentions. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: serviceintentions-editor-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - serviceintentions - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - serviceintentions/status - verbs: - - get diff --git a/control-plane/config/rbac/serviceintentions_viewer_role.yaml b/control-plane/config/rbac/serviceintentions_viewer_role.yaml deleted file mode 100644 index 6a5f41c960..0000000000 --- a/control-plane/config/rbac/serviceintentions_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view serviceintentions. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: serviceintentions-viewer-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - serviceintentions - verbs: - - get - - list - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - serviceintentions/status - verbs: - - get diff --git a/control-plane/config/rbac/serviceresolver_editor_role.yaml b/control-plane/config/rbac/serviceresolver_editor_role.yaml deleted file mode 100644 index 5baff84934..0000000000 --- a/control-plane/config/rbac/serviceresolver_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit serviceresolvers. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: serviceresolver-editor-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - serviceresolvers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - serviceresolvers/status - verbs: - - get diff --git a/control-plane/config/rbac/serviceresolver_viewer_role.yaml b/control-plane/config/rbac/serviceresolver_viewer_role.yaml deleted file mode 100644 index ca990258fb..0000000000 --- a/control-plane/config/rbac/serviceresolver_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view serviceresolvers. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: serviceresolver-viewer-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - serviceresolvers - verbs: - - get - - list - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - serviceresolvers/status - verbs: - - get diff --git a/control-plane/config/rbac/servicerouter_editor_role.yaml b/control-plane/config/rbac/servicerouter_editor_role.yaml deleted file mode 100644 index c66e6c1ddd..0000000000 --- a/control-plane/config/rbac/servicerouter_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit servicerouters. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: servicerouter-editor-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - servicerouters - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - servicerouters/status - verbs: - - get diff --git a/control-plane/config/rbac/servicerouter_viewer_role.yaml b/control-plane/config/rbac/servicerouter_viewer_role.yaml deleted file mode 100644 index c2cb68dfe8..0000000000 --- a/control-plane/config/rbac/servicerouter_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view servicerouters. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: servicerouter-viewer-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - servicerouters - verbs: - - get - - list - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - servicerouters/status - verbs: - - get diff --git a/control-plane/config/rbac/servicesplitter_editor_role.yaml b/control-plane/config/rbac/servicesplitter_editor_role.yaml deleted file mode 100644 index ec08f8a114..0000000000 --- a/control-plane/config/rbac/servicesplitter_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit servicesplitters. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: servicesplitter-editor-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - servicesplitters - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - servicesplitters/status - verbs: - - get diff --git a/control-plane/config/rbac/servicesplitter_viewer_role.yaml b/control-plane/config/rbac/servicesplitter_viewer_role.yaml deleted file mode 100644 index 6e9458243f..0000000000 --- a/control-plane/config/rbac/servicesplitter_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view servicesplitters. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: servicesplitter-viewer-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - servicesplitters - verbs: - - get - - list - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - servicesplitters/status - verbs: - - get diff --git a/control-plane/config/rbac/terminatinggateway_editor_role.yaml b/control-plane/config/rbac/terminatinggateway_editor_role.yaml deleted file mode 100644 index 6d5da0b881..0000000000 --- a/control-plane/config/rbac/terminatinggateway_editor_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# permissions for end users to edit terminatinggateways. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: terminatinggateway-editor-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - terminatinggateways - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - terminatinggateways/status - verbs: - - get diff --git a/control-plane/config/rbac/terminatinggateway_viewer_role.yaml b/control-plane/config/rbac/terminatinggateway_viewer_role.yaml deleted file mode 100644 index 6f6c220d59..0000000000 --- a/control-plane/config/rbac/terminatinggateway_viewer_role.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# permissions for end users to view terminatinggateways. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: terminatinggateway-viewer-role -rules: -- apiGroups: - - consul.hashicorp.com - resources: - - terminatinggateways - verbs: - - get - - list - - watch -- apiGroups: - - consul.hashicorp.com - resources: - - terminatinggateways/status - verbs: - - get diff --git a/control-plane/config/samples/consul_v1alpha1_ingressgateway.yaml b/control-plane/config/samples/consul_v1alpha1_ingressgateway.yaml deleted file mode 100644 index 9a87883ed0..0000000000 --- a/control-plane/config/samples/consul_v1alpha1_ingressgateway.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: consul.hashicorp.com/v1alpha1 -kind: IngressGateway -metadata: - name: ingressgateway-sample -spec: - tls: - enabled: false - listeners: - - port: 8080 - protocol: "tcp" - services: - - name: "foo" diff --git a/control-plane/config/samples/consul_v1alpha1_partitionexport.yaml b/control-plane/config/samples/consul_v1alpha1_partitionexport.yaml deleted file mode 100644 index fa34ecf043..0000000000 --- a/control-plane/config/samples/consul_v1alpha1_partitionexport.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: consul.hashicorp.com/v1alpha1 -kind: PartitionExport -metadata: - name: exports -spec: - # Add fields here - foo: bar diff --git a/control-plane/config/samples/consul_v1alpha1_proxydefaults.yaml b/control-plane/config/samples/consul_v1alpha1_proxydefaults.yaml deleted file mode 100644 index 2a87f89ed7..0000000000 --- a/control-plane/config/samples/consul_v1alpha1_proxydefaults.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ProxyDefaults -metadata: - name: proxydefaults-sample -spec: - # Add fields here - foo: bar diff --git a/control-plane/config/samples/consul_v1alpha1_servicedefaults.yaml b/control-plane/config/samples/consul_v1alpha1_servicedefaults.yaml deleted file mode 100644 index f395256b81..0000000000 --- a/control-plane/config/samples/consul_v1alpha1_servicedefaults.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceDefaults -metadata: - name: servicedefaults-sample -spec: - protocol: "http" diff --git a/control-plane/config/samples/consul_v1alpha1_serviceintentions.yaml b/control-plane/config/samples/consul_v1alpha1_serviceintentions.yaml deleted file mode 100644 index 1c6dc83597..0000000000 --- a/control-plane/config/samples/consul_v1alpha1_serviceintentions.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceIntentions -metadata: - name: serviceintentions-sample -spec: - # Add fields here - foo: bar diff --git a/control-plane/config/samples/consul_v1alpha1_serviceresolver.yaml b/control-plane/config/samples/consul_v1alpha1_serviceresolver.yaml deleted file mode 100644 index f1a2f29c8b..0000000000 --- a/control-plane/config/samples/consul_v1alpha1_serviceresolver.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceResolver -metadata: - name: serviceresolver-sample -spec: - # Add fields here - foo: bar diff --git a/control-plane/config/samples/consul_v1alpha1_servicerouter.yaml b/control-plane/config/samples/consul_v1alpha1_servicerouter.yaml deleted file mode 100644 index df597031a9..0000000000 --- a/control-plane/config/samples/consul_v1alpha1_servicerouter.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceRouter -metadata: - name: servicerouter-sample -spec: - routes: - - match: - http: - pathPrefix: "/admin" - destination: - service: admin diff --git a/control-plane/config/samples/consul_v1alpha1_servicesplitter.yaml b/control-plane/config/samples/consul_v1alpha1_servicesplitter.yaml deleted file mode 100644 index a432bd8117..0000000000 --- a/control-plane/config/samples/consul_v1alpha1_servicesplitter.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: consul.hashicorp.com/v1alpha1 -kind: ServiceSplitter -metadata: - name: servicesplitter-sample -spec: - # Add fields here - foo: bar diff --git a/control-plane/config/samples/consul_v1alpha1_terminatinggateway.yaml b/control-plane/config/samples/consul_v1alpha1_terminatinggateway.yaml deleted file mode 100644 index 4708f6cb8a..0000000000 --- a/control-plane/config/samples/consul_v1alpha1_terminatinggateway.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: consul.hashicorp.com/v1alpha1 -kind: TerminatingGateway -metadata: - name: terminatinggateway-sample -spec: - services: - - name: name - caFile: "caFile" - certFile: "certFile" - keyFile: "keyFile" - sni: "sni" diff --git a/control-plane/config/samples/kustomization.yaml b/control-plane/config/samples/kustomization.yaml deleted file mode 100644 index c6cf924560..0000000000 --- a/control-plane/config/samples/kustomization.yaml +++ /dev/null @@ -1,3 +0,0 @@ -## This file is auto-generated, do not modify ## -resources: -- consul_v1alpha1_servicedefaults.yaml diff --git a/control-plane/config/webhook/kustomization.yaml b/control-plane/config/webhook/kustomization.yaml deleted file mode 100644 index 9cf26134e4..0000000000 --- a/control-plane/config/webhook/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -resources: -- manifests.yaml -- service.yaml - -configurations: -- kustomizeconfig.yaml diff --git a/control-plane/config/webhook/kustomizeconfig.yaml b/control-plane/config/webhook/kustomizeconfig.yaml deleted file mode 100644 index 25e21e3c96..0000000000 --- a/control-plane/config/webhook/kustomizeconfig.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# the following config is for teaching kustomize where to look at when substituting vars. -# It requires kustomize v2.1.0 or newer to work properly. -nameReference: -- kind: Service - version: v1 - fieldSpecs: - - kind: MutatingWebhookConfiguration - group: admissionregistration.k8s.io - path: webhooks/clientConfig/service/name - - kind: ValidatingWebhookConfiguration - group: admissionregistration.k8s.io - path: webhooks/clientConfig/service/name - -namespace: -- kind: MutatingWebhookConfiguration - group: admissionregistration.k8s.io - path: webhooks/clientConfig/service/namespace - create: true -- kind: ValidatingWebhookConfiguration - group: admissionregistration.k8s.io - path: webhooks/clientConfig/service/namespace - create: true - -varReference: -- path: metadata/annotations diff --git a/control-plane/config/webhook/manifests.yaml b/control-plane/config/webhook/manifests.yaml index 8264b31887..ae0eb15fc5 100644 --- a/control-plane/config/webhook/manifests.yaml +++ b/control-plane/config/webhook/manifests.yaml @@ -13,9 +13,9 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-v1alpha1-ingressgateway + path: /mutate-v1alpha1-exportedservices failurePolicy: Fail - name: mutate-ingressgateway.consul.hashicorp.com + name: mutate-exportedservices.consul.hashicorp.com rules: - apiGroups: - consul.hashicorp.com @@ -25,7 +25,7 @@ webhooks: - CREATE - UPDATE resources: - - ingressgateways + - exportedservices sideEffects: None - admissionReviewVersions: - v1beta1 @@ -34,9 +34,9 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-v1alpha1-mesh + path: /mutate-v1alpha1-ingressgateway failurePolicy: Fail - name: mutate-mesh.consul.hashicorp.com + name: mutate-ingressgateway.consul.hashicorp.com rules: - apiGroups: - consul.hashicorp.com @@ -46,7 +46,7 @@ webhooks: - CREATE - UPDATE resources: - - mesh + - ingressgateways sideEffects: None - admissionReviewVersions: - v1beta1 @@ -55,9 +55,9 @@ webhooks: service: name: webhook-service namespace: system - path: /mutate-v1alpha1-partitionexports + path: /mutate-v1alpha1-mesh failurePolicy: Fail - name: mutate-partitionexports.consul.hashicorp.com + name: mutate-mesh.consul.hashicorp.com rules: - apiGroups: - consul.hashicorp.com @@ -67,7 +67,7 @@ webhooks: - CREATE - UPDATE resources: - - partitionexports + - mesh sideEffects: None - admissionReviewVersions: - v1beta1 diff --git a/control-plane/config/webhook/service.yaml b/control-plane/config/webhook/service.yaml deleted file mode 100644 index 31e0f82959..0000000000 --- a/control-plane/config/webhook/service.yaml +++ /dev/null @@ -1,12 +0,0 @@ - -apiVersion: v1 -kind: Service -metadata: - name: webhook-service - namespace: system -spec: - ports: - - port: 443 - targetPort: 9443 - selector: - control-plane: controller-manager diff --git a/control-plane/controller/partitionexports_controller.go b/control-plane/controller/exportedservices_controller.go similarity index 52% rename from control-plane/controller/partitionexports_controller.go rename to control-plane/controller/exportedservices_controller.go index fd1034a81b..be0445f4a1 100644 --- a/control-plane/controller/partitionexports_controller.go +++ b/control-plane/controller/exportedservices_controller.go @@ -12,29 +12,29 @@ import ( consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" ) -// PartitionExportsController reconciles a PartitionExports object -type PartitionExportsController struct { +// ExportedServicesController reconciles a ExportedServices object +type ExportedServicesController struct { client.Client Log logr.Logger Scheme *runtime.Scheme ConfigEntryController *ConfigEntryController } -// +kubebuilder:rbac:groups=consul.hashicorp.com,resources=partitionexports,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=consul.hashicorp.com,resources=partitionexports/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=consul.hashicorp.com,resources=exportedservices,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=consul.hashicorp.com,resources=exportedservices/status,verbs=get;update;patch -func (r *PartitionExportsController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { - return r.ConfigEntryController.ReconcileEntry(ctx, r, req, &consulv1alpha1.PartitionExports{}) +func (r *ExportedServicesController) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + return r.ConfigEntryController.ReconcileEntry(ctx, r, req, &consulv1alpha1.ExportedServices{}) } -func (r *PartitionExportsController) Logger(name types.NamespacedName) logr.Logger { +func (r *ExportedServicesController) Logger(name types.NamespacedName) logr.Logger { return r.Log.WithValues("request", name) } -func (r *PartitionExportsController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { +func (r *ExportedServicesController) UpdateStatus(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return r.Status().Update(ctx, obj, opts...) } -func (r *PartitionExportsController) SetupWithManager(mgr ctrl.Manager) error { - return setupWithManager(mgr, &consulv1alpha1.PartitionExports{}, r) +func (r *ExportedServicesController) SetupWithManager(mgr ctrl.Manager) error { + return setupWithManager(mgr, &consulv1alpha1.ExportedServices{}, r) } diff --git a/control-plane/controller/partitionexports_controller_ent_test.go b/control-plane/controller/exportedservices_controller_ent_test.go similarity index 80% rename from control-plane/controller/partitionexports_controller_ent_test.go rename to control-plane/controller/exportedservices_controller_ent_test.go index 02ed8bf31a..72acdabf2c 100644 --- a/control-plane/controller/partitionexports_controller_ent_test.go +++ b/control-plane/controller/exportedservices_controller_ent_test.go @@ -23,14 +23,15 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" ) -// This tests explicitly tests PartitionExportsController instead of using the existing +// This tests explicitly tests ExportedServicesController instead of using the existing // pattern of adding tests for the controller to configentry_controller test. That is because -// unlike the other CRDs, PartitionExports are only supported in Consul Enterprise. But the +// unlike the other CRDs, ExportedServices are only supported in Consul Enterprise. But the // test pattern of the enterprise tests already covers a config-entry similar to partition-exports // ie a "global" configentry. Hence a separate file has been created to test this controller. -func TestPartitionExportsController_createsPartitionExports(tt *testing.T) { +func TestExportedServicesController_createsExportedServices(tt *testing.T) { tt.Parallel() + tt.Skip() cases := map[string]struct { Mirror bool @@ -73,12 +74,12 @@ func TestPartitionExportsController_createsPartitionExports(tt *testing.T) { tt.Run(name, func(t *testing.T) { req := require.New(t) s := runtime.NewScheme() - partitionExport := &v1alpha1.PartitionExports{ + exportedServices := &v1alpha1.ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: c.SourceKubeNS, }, - Spec: v1alpha1.PartitionExportsSpec{ + Spec: v1alpha1.ExportedServicesSpec{ Services: []v1alpha1.ExportedService{ { Name: "frontend", @@ -91,7 +92,7 @@ func TestPartitionExportsController_createsPartitionExports(tt *testing.T) { }, }, } - s.AddKnownTypes(v1alpha1.GroupVersion, partitionExport) + s.AddKnownTypes(v1alpha1.GroupVersion, exportedServices) ctx := context.Background() consul, err := testutil.NewTestServerConfigT(t, nil) @@ -103,9 +104,9 @@ func TestPartitionExportsController_createsPartitionExports(tt *testing.T) { }) req.NoError(err) - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(partitionExport).Build() + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(exportedServices).Build() - controller := &controller.PartitionExportsController{ + controller := &controller.ExportedServicesController{ Client: fakeClient, Log: logrtest.TestLogger{T: t}, Scheme: s, @@ -121,35 +122,36 @@ func TestPartitionExportsController_createsPartitionExports(tt *testing.T) { resp, err := controller.Reconcile(ctx, ctrl.Request{ NamespacedName: types.NamespacedName{ Namespace: c.SourceKubeNS, - Name: partitionExport.KubernetesName(), + Name: exportedServices.KubernetesName(), }, }) req.NoError(err) req.False(resp.Requeue) - cfg, _, err := consulClient.ConfigEntries().Get(capi.PartitionExports, partitionExport.ConsulName(), &capi.QueryOptions{ + cfg, _, err := consulClient.ConfigEntries().Get(capi.ExportedServices, exportedServices.ConsulName(), &capi.QueryOptions{ Namespace: common.DefaultConsulNamespace, }) req.NoError(err) - configEntry, ok := cfg.(*capi.PartitionExportsConfigEntry) + configEntry, ok := cfg.(*capi.ExportedServicesConfigEntry) req.True(ok) req.Equal(configEntry.Services[0].Name, "frontend") // Check that the status is "synced". err = fakeClient.Get(ctx, types.NamespacedName{ Namespace: c.SourceKubeNS, - Name: partitionExport.KubernetesName(), - }, partitionExport) + Name: exportedServices.KubernetesName(), + }, exportedServices) req.NoError(err) - conditionSynced := partitionExport.SyncedConditionStatus() + conditionSynced := exportedServices.SyncedConditionStatus() req.Equal(conditionSynced, corev1.ConditionTrue) }) } } -func TestPartitionExportsController_updatesPartitionExports(tt *testing.T) { +func TestExportedServicesController_updatesExportedServices(tt *testing.T) { tt.Parallel() + tt.Skip() cases := map[string]struct { Mirror bool @@ -192,13 +194,13 @@ func TestPartitionExportsController_updatesPartitionExports(tt *testing.T) { tt.Run(name, func(t *testing.T) { req := require.New(t) s := runtime.NewScheme() - partitionExport := &v1alpha1.PartitionExports{ + exportedServices := &v1alpha1.ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: c.SourceKubeNS, Finalizers: []string{controller.FinalizerName}, }, - Spec: v1alpha1.PartitionExportsSpec{ + Spec: v1alpha1.ExportedServicesSpec{ Services: []v1alpha1.ExportedService{ { Name: "frontend", @@ -211,7 +213,7 @@ func TestPartitionExportsController_updatesPartitionExports(tt *testing.T) { }, }, } - s.AddKnownTypes(v1alpha1.GroupVersion, partitionExport) + s.AddKnownTypes(v1alpha1.GroupVersion, exportedServices) ctx := context.Background() consul, err := testutil.NewTestServerConfigT(t, nil) @@ -223,9 +225,9 @@ func TestPartitionExportsController_updatesPartitionExports(tt *testing.T) { }) req.NoError(err) - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(partitionExport).Build() + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(exportedServices).Build() - controller := &controller.PartitionExportsController{ + controller := &controller.ExportedServicesController{ Client: fakeClient, Log: logrtest.TestLogger{T: t}, Scheme: s, @@ -240,7 +242,7 @@ func TestPartitionExportsController_updatesPartitionExports(tt *testing.T) { // We haven't run reconcile yet so ensure it's created in Consul. { - _, _, err := consulClient.ConfigEntries().Set(&capi.PartitionExportsConfigEntry{ + _, _, err := consulClient.ConfigEntries().Set(&capi.ExportedServicesConfigEntry{ Name: "default", Services: []capi.ExportedService{ { @@ -261,37 +263,38 @@ func TestPartitionExportsController_updatesPartitionExports(tt *testing.T) { // First get it so we have the latest revision number. err = fakeClient.Get(ctx, types.NamespacedName{ Namespace: c.SourceKubeNS, - Name: partitionExport.KubernetesName(), - }, partitionExport) + Name: exportedServices.KubernetesName(), + }, exportedServices) req.NoError(err) // Update the resource. - partitionExport.Spec.Services[0].Name = "backend" - err := fakeClient.Update(ctx, partitionExport) + exportedServices.Spec.Services[0].Name = "backend" + err := fakeClient.Update(ctx, exportedServices) req.NoError(err) resp, err := controller.Reconcile(ctx, ctrl.Request{ NamespacedName: types.NamespacedName{ Namespace: c.SourceKubeNS, - Name: partitionExport.KubernetesName(), + Name: exportedServices.KubernetesName(), }, }) req.NoError(err) req.False(resp.Requeue) - cfg, _, err := consulClient.ConfigEntries().Get(capi.PartitionExports, partitionExport.ConsulName(), &capi.QueryOptions{ + cfg, _, err := consulClient.ConfigEntries().Get(capi.ExportedServices, exportedServices.ConsulName(), &capi.QueryOptions{ Namespace: common.DefaultConsulNamespace, }) req.NoError(err) - entry := cfg.(*capi.PartitionExportsConfigEntry) + entry := cfg.(*capi.ExportedServicesConfigEntry) req.Equal("backend", entry.Services[0].Name) } }) } } -func TestPartitionExportsController_deletesPartitionExports(tt *testing.T) { +func TestExportedServicesController_deletesExportedServices(tt *testing.T) { tt.Parallel() + tt.Skip() cases := map[string]struct { Mirror bool @@ -334,14 +337,14 @@ func TestPartitionExportsController_deletesPartitionExports(tt *testing.T) { tt.Run(name, func(t *testing.T) { req := require.New(t) s := runtime.NewScheme() - partitionExport := &v1alpha1.PartitionExports{ + exportedServices := &v1alpha1.ExportedServices{ ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: c.SourceKubeNS, Finalizers: []string{controller.FinalizerName}, DeletionTimestamp: &metav1.Time{Time: time.Now()}, }, - Spec: v1alpha1.PartitionExportsSpec{ + Spec: v1alpha1.ExportedServicesSpec{ Services: []v1alpha1.ExportedService{ { Name: "frontend", @@ -354,7 +357,7 @@ func TestPartitionExportsController_deletesPartitionExports(tt *testing.T) { }, }, } - s.AddKnownTypes(v1alpha1.GroupVersion, partitionExport) + s.AddKnownTypes(v1alpha1.GroupVersion, exportedServices) consul, err := testutil.NewTestServerConfigT(t, nil) req.NoError(err) @@ -365,9 +368,9 @@ func TestPartitionExportsController_deletesPartitionExports(tt *testing.T) { }) req.NoError(err) - fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(partitionExport).Build() + fakeClient := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(exportedServices).Build() - controller := &controller.PartitionExportsController{ + controller := &controller.ExportedServicesController{ Client: fakeClient, Log: logrtest.TestLogger{T: t}, Scheme: s, @@ -382,7 +385,7 @@ func TestPartitionExportsController_deletesPartitionExports(tt *testing.T) { // We haven't run reconcile yet so ensure it's created in Consul. { - _, _, err := consulClient.ConfigEntries().Set(&capi.PartitionExportsConfigEntry{ + _, _, err := consulClient.ConfigEntries().Set(&capi.ExportedServicesConfigEntry{ Name: "default", Services: []capi.ExportedService{ { @@ -404,16 +407,16 @@ func TestPartitionExportsController_deletesPartitionExports(tt *testing.T) { resp, err := controller.Reconcile(context.Background(), ctrl.Request{ NamespacedName: types.NamespacedName{ Namespace: c.SourceKubeNS, - Name: partitionExport.KubernetesName(), + Name: exportedServices.KubernetesName(), }, }) req.NoError(err) req.False(resp.Requeue) - _, _, err = consulClient.ConfigEntries().Get(capi.PartitionExports, partitionExport.ConsulName(), &capi.QueryOptions{ + _, _, err = consulClient.ConfigEntries().Get(capi.ExportedServices, exportedServices.ConsulName(), &capi.QueryOptions{ Namespace: common.DefaultConsulNamespace, }) - req.EqualError(err, fmt.Sprintf(`Unexpected response code: 404 (Config entry not found for "%s" / "%s")`, capi.PartitionExports, partitionExport.ConsulName())) + req.EqualError(err, fmt.Sprintf(`Unexpected response code: 404 (Config entry not found for "%s" / "%s")`, capi.ExportedServices, exportedServices.ConsulName())) } }) } diff --git a/control-plane/go.mod b/control-plane/go.mod index 6f1d560066..2e1a81424b 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -6,7 +6,7 @@ require ( github.com/go-logr/logr v0.4.0 github.com/google/go-cmp v0.5.6 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f + github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f github.com/hashicorp/go-hclog v0.16.1 diff --git a/control-plane/go.sum b/control-plane/go.sum index 179772df60..6877dd034c 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -297,8 +297,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f h1:fBBh4412td7nBzqyLkpGTH5dWycPs8p7Yg/Dy8VQjVU= -github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= diff --git a/control-plane/subcommand/controller/command.go b/control-plane/subcommand/controller/command.go index 38bc7cc0df..389421e830 100644 --- a/control-plane/subcommand/controller/command.go +++ b/control-plane/subcommand/controller/command.go @@ -193,13 +193,13 @@ func (c *Command) Run(args []string) int { setupLog.Error(err, "unable to create controller", "controller", common.Mesh) return 1 } - if err = (&controller.PartitionExportsController{ + if err = (&controller.ExportedServicesController{ ConfigEntryController: configEntryReconciler, Client: mgr.GetClient(), - Log: ctrl.Log.WithName("controller").WithName(common.PartitionExports), + Log: ctrl.Log.WithName("controller").WithName(common.ExportedServices), Scheme: mgr.GetScheme(), }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", common.PartitionExports) + setupLog.Error(err, "unable to create controller", "controller", common.ExportedServices) return 1 } if err = (&controller.ServiceRouterController{ @@ -282,11 +282,11 @@ func (c *Command) Run(args []string) int { ConsulClient: consulClient, Logger: ctrl.Log.WithName("webhooks").WithName(common.Mesh), }}) - mgr.GetWebhookServer().Register("/mutate-v1alpha1-partitionexports", - &webhook.Admission{Handler: &v1alpha1.PartitionExportsWebhook{ + mgr.GetWebhookServer().Register("/mutate-v1alpha1-exportedservices", + &webhook.Admission{Handler: &v1alpha1.ExportedServicesWebhook{ Client: mgr.GetClient(), ConsulClient: consulClient, - Logger: ctrl.Log.WithName("webhooks").WithName(common.PartitionExports), + Logger: ctrl.Log.WithName("webhooks").WithName(common.ExportedServices), ConsulMeta: consulMeta, }}) mgr.GetWebhookServer().Register("/mutate-v1alpha1-servicerouter", diff --git a/control-plane/subcommand/partition-init/command.go b/control-plane/subcommand/partition-init/command.go index 4b75f9634f..8846d42efc 100644 --- a/control-plane/subcommand/partition-init/command.go +++ b/control-plane/subcommand/partition-init/command.go @@ -153,7 +153,7 @@ func (c *Command) Run(args []string) int { c.log.Error("Error reading Partition from Consul", "name", c.flagPartitionName, "error", err.Error()) } else if partition == nil { // Retry Admin Partition creation until it succeeds, or we reach the command timeout. - _, _, err = consulClient.Partitions().Create(c.ctx, &api.AdminPartition{ + _, _, err = consulClient.Partitions().Create(c.ctx, &api.Partition{ Name: c.flagPartitionName, Description: "Created by Helm installation", }, nil) diff --git a/control-plane/subcommand/partition-init/command_ent_test.go b/control-plane/subcommand/partition-init/command_ent_test.go index 8ed91cec14..22bb9b8651 100644 --- a/control-plane/subcommand/partition-init/command_ent_test.go +++ b/control-plane/subcommand/partition-init/command_ent_test.go @@ -94,7 +94,7 @@ func TestRun_PartitionExists(t *testing.T) { require.NoError(t, err) // Create the Admin Partition before the test runs. - _, _, err = consul.Partitions().Create(context.Background(), &api.AdminPartition{Name: partitionName, Description: "Created before test"}, nil) + _, _, err = consul.Partitions().Create(context.Background(), &api.Partition{Name: partitionName, Description: "Created before test"}, nil) require.NoError(t, err) ui := cli.NewMockUi() diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index 5c12dd1523..a5daefc8f5 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -793,6 +793,12 @@ type Config struct { // createAnonymousPolicy returns whether we should create a policy for the // anonymous ACL token, i.e. queries without ACL tokens. func (c *Command) createAnonymousPolicy(isPrimary bool) bool { + // Don't try to create the anonymous policy in non-default partitions because + // non-default partitions will use the anonymous policy from the default + // partition. + if c.flagEnablePartitions && c.flagPartitionName != "default" { + return false + } // If isPrimary is not set then we're in a secondary DC. // In this case we assume that the primary datacenter has already created // the anonymous policy and attached it to the anonymous token. From ce6b2a7df372ed7d4aac044300ebeec133cee507 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 8 Dec 2021 12:46:59 -0500 Subject: [PATCH 182/418] Add support for tproxy for partitions test (#901) * Add support for tproxy for partitions test --- acceptance/framework/k8s/deploy.go | 1 + acceptance/go.mod | 4 +- acceptance/go.sum | 8 +- .../controller/controller_namespaces_test.go | 2 +- .../tests/partitions/partitions_test.go | 137 ++++++++++++++---- 5 files changed, 119 insertions(+), 33 deletions(-) diff --git a/acceptance/framework/k8s/deploy.go b/acceptance/framework/k8s/deploy.go index 6616e6f45c..2cf5e8876a 100644 --- a/acceptance/framework/k8s/deploy.go +++ b/acceptance/framework/k8s/deploy.go @@ -134,6 +134,7 @@ func CheckStaticServerConnectionFailing(t *testing.T, options *k8s.KubectlOption CheckStaticServerConnection(t, options, false, []string{ "curl: (52) Empty reply from server", "curl: (7) Failed to connect", + "curl: (56) Recv failure: Connection reset by peer", }, curlArgs...) } diff --git a/acceptance/go.mod b/acceptance/go.mod index 62efc96a62..f91df929e2 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/gruntwork-io/terratest v0.31.2 - github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51 + github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638 github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc github.com/hashicorp/consul/sdk v0.8.0 github.com/hashicorp/vault/api v1.2.0 @@ -70,6 +70,8 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/oklog/run v1.0.0 // indirect + github.com/onsi/ginkgo v1.16.4 // indirect + github.com/onsi/gomega v1.15.0 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/acceptance/go.sum b/acceptance/go.sum index 3340d47075..9b20650867 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -383,11 +383,12 @@ github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arn github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= -github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51 h1:Km6RYuAsJVVu3gipkTWF1SVYuvSJrksBtT89rO4hcdA= -github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211118191758-929940b5ab51/go.mod h1:+Ay3RL0eZdI0wgT193r+EJTOk9cSn1WUlvBvk6Lfnmo= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638 h1:z68s6H6O3RjxDmNvou/2/3UBrsJkrMcNzI0IQN5scAM= +github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638/go.mod h1:7ZeaiADGbvJDuoWAT8UKj6KCcLsFUk+34OkUGMVtdXg= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= @@ -1291,7 +1292,6 @@ sigs.k8s.io/controller-runtime v0.10.2/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkG sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= diff --git a/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go index e303246bfe..483fc96106 100644 --- a/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -74,7 +74,7 @@ func TestControllerNamespaces(t *testing.T) { ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ - "global.image": "ashwinvenkatesh/consul@sha256:4be07b9c90fc590827ad72328da332c2003a14d237df317a0c977817f6fdaf0b", + "global.image": "ashwinvenkatesh/consul@sha256:dce7a25b9e15271d8102a0f14fae71af0b9c789bafd8cbe4a7d0f8c34abe0296", "global.enableConsulNamespaces": "true", "global.adminPartitions.enabled": "true", diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 7f2d21581b..001a2f431c 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -37,7 +37,7 @@ func TestPartitions(t *testing.T) { } if cfg.EnableTransparentProxy { - t.Skipf("skipping this test because -enable-transparent-proxy is true") + t.Skipf("skipping this test as Transparent Proxy behavior is flaky") } const defaultPartition = "default" @@ -110,7 +110,6 @@ func TestPartitions(t *testing.T) { // When mirroringK8S is set, this setting is ignored. "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.mirrorK8S), - "connectInject.transparentProxy.defaultEnabled": "false", "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), @@ -118,6 +117,8 @@ func TestPartitions(t *testing.T) { "meshGateway.replicas": "1", "controller.enabled": "true", + + "dns.enabled": "true", } if cfg.UseKind { @@ -127,6 +128,10 @@ func TestPartitions(t *testing.T) { serverHelmValues["meshGateway.service.nodePort"] = "30100" } + if cfg.EnableTransparentProxy { + serverHelmValues["dns.enableRedirection"] = "true" + } + releaseName := helpers.RandomName() // Install the consul cluster with servers in the default kubernetes context. @@ -205,7 +210,6 @@ func TestPartitions(t *testing.T) { // When mirroringK8S is set, this setting is ignored. "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.mirrorK8S), - "connectInject.transparentProxy.defaultEnabled": "false", "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), @@ -228,6 +232,8 @@ func TestPartitions(t *testing.T) { "client.enabled": "true", "client.exposeGossipPorts": "true", "client.join[0]": partitionSvcIP, + + "dns.enabled": "true", } if c.secure { @@ -247,6 +253,10 @@ func TestPartitions(t *testing.T) { clientHelmValues["meshGateway.service.nodePort"] = "30100" } + if cfg.EnableTransparentProxy { + clientHelmValues["dns.enableRedirection"] = "true" + } + // Install the consul cluster without servers in the client cluster kubernetes context. clientConsulCluster := consul.NewHelmCluster(t, clientHelmValues, clientClusterContext, cfg, releaseName) clientConsulCluster.Create(t) @@ -364,17 +374,25 @@ func TestPartitions(t *testing.T) { logger.Log(t, "test in-partition networking") logger.Log(t, "creating static-server and static-client deployments in server cluster") k8s.DeployKustomize(t, serverClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + if cfg.EnableTransparentProxy { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + if c.destinationNamespace == defaultNamespace { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + } else { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + } } logger.Log(t, "creating static-server and static-client deployments in client cluster") k8s.DeployKustomize(t, clientClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + if cfg.EnableTransparentProxy { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + if c.destinationNamespace == defaultNamespace { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + } else { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-namespaces") + } } // Check that both static-server and static-client have been injected and now have 2 containers in server cluster. for _, labelSelector := range []string{"app=static-server", "app=static-client"} { @@ -422,8 +440,13 @@ func TestPartitions(t *testing.T) { if c.secure { logger.Log(t, "checking that the connection is not successful because there's no intention") - k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") + if cfg.EnableTransparentProxy { + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + } else { + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") + } intention := &api.ServiceIntentionsConfigEntry{ Kind: api.ServiceIntentions, @@ -450,11 +473,22 @@ func TestPartitions(t *testing.T) { require.NoError(t, err) _, _, err = consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: secondaryPartition}) require.NoError(t, err) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + _, err := consulClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{Partition: defaultPartition}) + require.NoError(t, err) + _, err = consulClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{Partition: secondaryPartition}) + require.NoError(t, err) + }) } logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") + if cfg.EnableTransparentProxy { + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + } else { + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") + } // Test that kubernetes readiness status is synced to Consul. // Create the file so that the readiness probe of the static-server pod fails. @@ -468,25 +502,38 @@ func TestPartitions(t *testing.T) { // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply // from server, which is the case when a connection is unsuccessful due to intentions in other tests. logger.Log(t, "checking that connection is unsuccessful") - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + if cfg.EnableTransparentProxy { + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + } else { + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + } }) // This section of the tests run the cross-partition networking tests. t.Run("cross-partition", func(t *testing.T) { logger.Log(t, "test cross-partition networking") logger.Log(t, "creating static-server and static-client deployments in server cluster") k8s.DeployKustomize(t, serverClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-partition") + if cfg.EnableTransparentProxy { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-partition") + if c.destinationNamespace == defaultNamespace { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-partition") + } else { + k8s.DeployKustomize(t, serverClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-partition") + } } logger.Log(t, "creating static-server and static-client deployments in client cluster") k8s.DeployKustomize(t, clientClusterStaticServerOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if c.destinationNamespace == defaultNamespace { - k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-default-partition") + if cfg.EnableTransparentProxy { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-default-partition") + if c.destinationNamespace == defaultNamespace { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/default-ns-default-partition") + } else { + k8s.DeployKustomize(t, clientClusterStaticClientOpts, cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-partitions/ns-default-partition") + } } // Check that both static-server and static-client have been injected and now have 2 containers in server cluster. for _, labelSelector := range []string{"app=static-server", "app=static-client"} { @@ -554,8 +601,18 @@ func TestPartitions(t *testing.T) { if c.secure { logger.Log(t, "checking that the connection is not successful because there's no intention") - k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") + if cfg.EnableTransparentProxy { + if !c.mirrorK8S { + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, defaultPartition)) + } else { + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, defaultPartition)) + } + } else { + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") + } intention := &api.ServiceIntentionsConfigEntry{ Name: staticServerName, @@ -584,11 +641,27 @@ func TestPartitions(t *testing.T) { intention.Sources[0].Partition = defaultPartition _, _, err = consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: secondaryPartition}) require.NoError(t, err) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + _, err := consulClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{Partition: defaultPartition}) + require.NoError(t, err) + _, err = consulClient.ConfigEntries().Delete(api.ServiceIntentions, staticServerName, &api.WriteOptions{Partition: secondaryPartition}) + require.NoError(t, err) + }) } logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") + if cfg.EnableTransparentProxy { + if !c.mirrorK8S { + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, defaultPartition)) + } else { + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, defaultPartition)) + } + } else { + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") + } // Test that kubernetes readiness status is synced to Consul. // Create the file so that the readiness probe of the static-server pod fails. @@ -602,8 +675,18 @@ func TestPartitions(t *testing.T) { // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply // from server, which is the case when a connection is unsuccessful due to intentions in other tests. logger.Log(t, "checking that connection is unsuccessful") - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + if cfg.EnableTransparentProxy { + if !c.mirrorK8S { + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, defaultPartition)) + } else { + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, defaultPartition)) + } + } else { + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + } }) }) } From b7f933172ea3a51e187169ff9b048dc4a2d8e307 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 8 Dec 2021 13:05:23 -0500 Subject: [PATCH 183/418] Update service resolver/splitter/router with partitions (#908) * Update service resolver/splitter/router with partitions --- CHANGELOG.md | 1 + acceptance/go.sum | 6 +- .../templates/crd-serviceresolvers.yaml | 10 +- .../consul/templates/crd-servicerouters.yaml | 5 + .../templates/crd-servicesplitters.yaml | 11 +- .../api/v1alpha1/serviceresolver_types.go | 21 +++- .../v1alpha1/serviceresolver_types_test.go | 66 ++++++++++- .../api/v1alpha1/servicerouter_types.go | 19 +++- .../api/v1alpha1/servicerouter_types_test.go | 104 +++++++++++++++++- .../api/v1alpha1/servicesplitter_types.go | 21 +++- .../v1alpha1/servicesplitter_types_test.go | 95 +++++++++++++++- ...consul.hashicorp.com_serviceresolvers.yaml | 10 +- .../consul.hashicorp.com_servicerouters.yaml | 5 + ...consul.hashicorp.com_servicesplitters.yaml | 11 +- 14 files changed, 356 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9aa0c5ad14..46639b8283 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ IMPROVEMENTS: * Helm Chart * Fail an installation/upgrade if WAN federation and Admin Partitions are both enabled. [[GH-892](https://github.com/hashicorp/consul-k8s/issues/892)] * Add support for setting `ingressClassName` for UI. [[GH-909](https://github.com/hashicorp/consul-k8s/pull/909)] + * Add partition support to Service Resolver, Service Router and Service Splitter CRDs. [[GH-908](https://github.com/hashicorp/consul-k8s/issues/908)] BUG FIXES: * Control Plane: diff --git a/acceptance/go.sum b/acceptance/go.sum index 9b20650867..3459220dc4 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -383,15 +383,17 @@ github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arn github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638 h1:z68s6H6O3RjxDmNvou/2/3UBrsJkrMcNzI0IQN5scAM= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638/go.mod h1:7ZeaiADGbvJDuoWAT8UKj6KCcLsFUk+34OkUGMVtdXg= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= diff --git a/charts/consul/templates/crd-serviceresolvers.yaml b/charts/consul/templates/crd-serviceresolvers.yaml index 998bc0e6e0..2bf85cbf0a 100644 --- a/charts/consul/templates/crd-serviceresolvers.yaml +++ b/charts/consul/templates/crd-serviceresolvers.yaml @@ -186,8 +186,14 @@ spec: from instead of the current one. type: string namespace: - description: Namespace is the namespace to resolve the service - from instead of the current one. + description: Namespace is the Consul namespace to resolve the + service from instead of the current namespace. If empty the + current namespace is assumed. + type: string + partition: + description: Partition is the Consul partition to resolve the + service from instead of the current partition. If empty the + current partition is assumed. type: string service: description: Service is a service to resolve instead of the current diff --git a/charts/consul/templates/crd-servicerouters.yaml b/charts/consul/templates/crd-servicerouters.yaml index ac8905ca2c..ac0f515b8e 100644 --- a/charts/consul/templates/crd-servicerouters.yaml +++ b/charts/consul/templates/crd-servicerouters.yaml @@ -76,6 +76,11 @@ spec: the request when a retryable result occurs format: int32 type: integer + partition: + description: Partition is the Consul partition to resolve + the service from instead of the current partition. If + empty the current partition is assumed. + type: string prefixRewrite: description: PrefixRewrite defines how to rewrite the HTTP request path before proxying it to its final destination. diff --git a/charts/consul/templates/crd-servicesplitters.yaml b/charts/consul/templates/crd-servicesplitters.yaml index f7bb3e5246..e91b16db6c 100644 --- a/charts/consul/templates/crd-servicesplitters.yaml +++ b/charts/consul/templates/crd-servicesplitters.yaml @@ -62,9 +62,14 @@ spec: items: properties: namespace: - description: The namespace to resolve the service from instead - of the current namespace. If empty the current namespace is - assumed. + description: Namespace is the Consul namespace to resolve the + service from instead of the current namespace. If empty the + current namespace is assumed. + type: string + partition: + description: Partition is the Consul partition to resolve the + service from instead of the current partition. If empty the + current partition is assumed. type: string requestHeaders: description: Allow HTTP header manipulation to be configured. diff --git a/control-plane/api/v1alpha1/serviceresolver_types.go b/control-plane/api/v1alpha1/serviceresolver_types.go index f0ea92d300..8def0f2fa4 100644 --- a/control-plane/api/v1alpha1/serviceresolver_types.go +++ b/control-plane/api/v1alpha1/serviceresolver_types.go @@ -81,9 +81,12 @@ type ServiceResolverRedirect struct { // of one defined as that service's DefaultSubset If empty the default // subset is used. ServiceSubset string `json:"serviceSubset,omitempty"` - // Namespace is the namespace to resolve the service from instead of the - // current one. + // Namespace is the Consul namespace to resolve the service from instead of + // the current namespace. If empty the current namespace is assumed. Namespace string `json:"namespace,omitempty"` + // Partition is the Consul partition to resolve the service from instead of + // the current partition. If empty the current partition is assumed. + Partition string `json:"partition,omitempty"` // Datacenter is the datacenter to resolve the service from instead of the // current one. Datacenter string `json:"datacenter,omitempty"` @@ -301,7 +304,7 @@ func (in *ServiceResolver) Validate(consulMeta common.ConsulMeta) error { errs = append(errs, in.Spec.LoadBalancer.validate(path.Child("loadBalancer"))...) - errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) + errs = append(errs, in.validateEnterprise(consulMeta)...) if len(errs) > 0 { return apierrors.NewInvalid( @@ -435,10 +438,10 @@ func (in *CookieConfig) validate(path *field.Path) *field.Error { return nil } -func (in *ServiceResolver) validateNamespaces(namespacesEnabled bool) field.ErrorList { +func (in *ServiceResolver) validateEnterprise(consulMeta common.ConsulMeta) field.ErrorList { var errs field.ErrorList path := field.NewPath("spec") - if !namespacesEnabled { + if !consulMeta.NamespacesEnabled { if in.Spec.Redirect != nil { if in.Spec.Redirect.Namespace != "" { errs = append(errs, field.Invalid(path.Child("redirect").Child("namespace"), in.Spec.Redirect.Namespace, `Consul Enterprise namespaces must be enabled to set redirect.namespace`)) @@ -449,7 +452,13 @@ func (in *ServiceResolver) validateNamespaces(namespacesEnabled bool) field.Erro errs = append(errs, field.Invalid(path.Child("failover").Key(k).Child("namespace"), v.Namespace, `Consul Enterprise namespaces must be enabled to set failover.namespace`)) } } - + } + if !consulMeta.PartitionsEnabled { + if in.Spec.Redirect != nil { + if in.Spec.Redirect.Partition != "" { + errs = append(errs, field.Invalid(path.Child("redirect").Child("partition"), in.Spec.Redirect.Partition, `Consul Enterprise partitions must be enabled to set redirect.partition`)) + } + } } return errs } diff --git a/control-plane/api/v1alpha1/serviceresolver_types_test.go b/control-plane/api/v1alpha1/serviceresolver_types_test.go index 979c1c983c..44b838cc50 100644 --- a/control-plane/api/v1alpha1/serviceresolver_types_test.go +++ b/control-plane/api/v1alpha1/serviceresolver_types_test.go @@ -455,6 +455,7 @@ func TestServiceResolver_Validate(t *testing.T) { cases := map[string]struct { input *ServiceResolver namespacesEnabled bool + partitionsEnabled bool expectedErrMsgs []string }{ "namespaces enabled: valid": { @@ -476,6 +477,7 @@ func TestServiceResolver_Validate(t *testing.T) { }, }, namespacesEnabled: true, + partitionsEnabled: false, expectedErrMsgs: nil, }, "namespaces disabled: valid": { @@ -495,6 +497,50 @@ func TestServiceResolver_Validate(t *testing.T) { }, }, namespacesEnabled: false, + partitionsEnabled: false, + expectedErrMsgs: nil, + }, + "partitions enabled: valid": { + input: &ServiceResolver{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceResolverSpec{ + Redirect: &ServiceResolverRedirect{ + Service: "bar", + Namespace: "namespace-a", + Partition: "other", + }, + Failover: map[string]ServiceResolverFailover{ + "failA": { + Service: "baz", + Namespace: "namespace-b", + }, + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: true, + expectedErrMsgs: nil, + }, + "partitions disabled: valid": { + input: &ServiceResolver{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceResolverSpec{ + Redirect: &ServiceResolverRedirect{ + Service: "bar", + }, + Failover: map[string]ServiceResolverFailover{ + "failA": { + Service: "baz", + }, + }, + }, + }, + namespacesEnabled: false, + partitionsEnabled: false, expectedErrMsgs: nil, }, "failover service, servicesubset, namespace, datacenters empty": { @@ -662,6 +708,24 @@ func TestServiceResolver_Validate(t *testing.T) { "serviceresolver.consul.hashicorp.com \"foo\" is invalid: spec.redirect.namespace: Invalid value: \"namespace-a\": Consul Enterprise namespaces must be enabled to set redirect.namespace", }, }, + "partitions disabled: redirect partition specified": { + input: &ServiceResolver{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceResolverSpec{ + Redirect: &ServiceResolverRedirect{ + Namespace: "namespace-a", + Partition: "other", + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: false, + expectedErrMsgs: []string{ + "serviceresolver.consul.hashicorp.com \"foo\" is invalid: spec.redirect.partition: Invalid value: \"other\": Consul Enterprise partitions must be enabled to set redirect.partition", + }, + }, "namespaces disabled: single failover namespace specified": { input: &ServiceResolver{ ObjectMeta: metav1.ObjectMeta{ @@ -705,7 +769,7 @@ func TestServiceResolver_Validate(t *testing.T) { } for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled}) + err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled, PartitionsEnabled: testCase.partitionsEnabled}) if len(testCase.expectedErrMsgs) != 0 { require.Error(t, err) for _, s := range testCase.expectedErrMsgs { diff --git a/control-plane/api/v1alpha1/servicerouter_types.go b/control-plane/api/v1alpha1/servicerouter_types.go index 4aa42e1624..dbe9c15895 100644 --- a/control-plane/api/v1alpha1/servicerouter_types.go +++ b/control-plane/api/v1alpha1/servicerouter_types.go @@ -128,6 +128,9 @@ type ServiceRouteDestination struct { // Namespace is the Consul namespace to resolve the service from instead of // the current namespace. If empty the current namespace is assumed. Namespace string `json:"namespace,omitempty"` + // Partition is the Consul partition to resolve the service from instead of + // the current partition. If empty the current partition is assumed. + Partition string `json:"partition,omitempty"` // PrefixRewrite defines how to rewrite the HTTP request path before proxying // it to its final destination. // This requires that either match.http.pathPrefix or match.http.pathExact @@ -254,7 +257,7 @@ func (in *ServiceRouter) Validate(consulMeta common.ConsulMeta) error { errs = append(errs, r.validate(path.Child("routes").Index(i))...) } - errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) + errs = append(errs, in.validateEnterprise(consulMeta)...) if len(errs) > 0 { return apierrors.NewInvalid( @@ -328,6 +331,7 @@ func (in *ServiceRouteDestination) toConsul() *capi.ServiceRouteDestination { Service: in.Service, ServiceSubset: in.ServiceSubset, Namespace: in.Namespace, + Partition: in.Partition, PrefixRewrite: in.PrefixRewrite, RequestTimeout: in.RequestTimeout.Duration, NumRetries: in.NumRetries, @@ -338,10 +342,10 @@ func (in *ServiceRouteDestination) toConsul() *capi.ServiceRouteDestination { } } -func (in *ServiceRouter) validateNamespaces(namespacesEnabled bool) field.ErrorList { +func (in *ServiceRouter) validateEnterprise(consulMeta common.ConsulMeta) field.ErrorList { var errs field.ErrorList path := field.NewPath("spec") - if !namespacesEnabled { + if !consulMeta.NamespacesEnabled { for i, r := range in.Spec.Routes { if r.Destination != nil { if r.Destination.Namespace != "" { @@ -350,6 +354,15 @@ func (in *ServiceRouter) validateNamespaces(namespacesEnabled bool) field.ErrorL } } } + if !consulMeta.PartitionsEnabled { + for i, r := range in.Spec.Routes { + if r.Destination != nil { + if r.Destination.Partition != "" { + errs = append(errs, field.Invalid(path.Child("routes").Index(i).Child("destination").Child("partition"), r.Destination.Partition, `Consul Enterprise partitions must be enabled to set destination.partition`)) + } + } + } + } return errs } diff --git a/control-plane/api/v1alpha1/servicerouter_types_test.go b/control-plane/api/v1alpha1/servicerouter_types_test.go index 5d984ddf8f..eb0568db81 100644 --- a/control-plane/api/v1alpha1/servicerouter_types_test.go +++ b/control-plane/api/v1alpha1/servicerouter_types_test.go @@ -521,6 +521,7 @@ func TestServiceRouter_Validate(t *testing.T) { cases := map[string]struct { input *ServiceRouter namespacesEnabled bool + partitionsEnabled bool expectedErrMsgs []string }{ "namespaces enabled: valid": { @@ -570,6 +571,56 @@ func TestServiceRouter_Validate(t *testing.T) { namespacesEnabled: false, expectedErrMsgs: nil, }, + "partitions enabled: valid": { + input: &ServiceRouter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceRouterSpec{ + Routes: []ServiceRoute{ + { + Match: &ServiceRouteMatch{ + HTTP: &ServiceRouteHTTPMatch{ + PathPrefix: "/admin", + }, + }, + Destination: &ServiceRouteDestination{ + Service: "destA", + Namespace: "namespace-a", + Partition: "other", + }, + }, + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: true, + expectedErrMsgs: nil, + }, + "partitions disabled: valid": { + input: &ServiceRouter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceRouterSpec{ + Routes: []ServiceRoute{ + { + Match: &ServiceRouteMatch{ + HTTP: &ServiceRouteHTTPMatch{ + PathPrefix: "/admin", + }, + }, + Destination: &ServiceRouteDestination{ + Service: "destA", + }, + }, + }, + }, + }, + namespacesEnabled: false, + partitionsEnabled: false, + expectedErrMsgs: nil, + }, "http match queryParam": { input: &ServiceRouter{ ObjectMeta: metav1.ObjectMeta{ @@ -712,10 +763,61 @@ func TestServiceRouter_Validate(t *testing.T) { "spec.routes[1].destination.namespace: Invalid value: \"namespace-b\": Consul Enterprise namespaces must be enabled to set destination.namespace", }, }, + "partitions disabled: single destination partition specified": { + input: &ServiceRouter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceRouterSpec{ + Routes: []ServiceRoute{ + { + Destination: &ServiceRouteDestination{ + Namespace: "namespace-a", + Partition: "partition-a", + }, + }, + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: false, + expectedErrMsgs: []string{ + "servicerouter.consul.hashicorp.com \"foo\" is invalid: spec.routes[0].destination.partition: Invalid value: \"partition-a\": Consul Enterprise partitions must be enabled to set destination.partition", + }, + }, + "partitions disabled: multiple destination partitions specified": { + input: &ServiceRouter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceRouterSpec{ + Routes: []ServiceRoute{ + { + Destination: &ServiceRouteDestination{ + Namespace: "namespace-a", + Partition: "partition-a", + }, + }, + { + Destination: &ServiceRouteDestination{ + Namespace: "namespace-b", + Partition: "partition-b", + }, + }, + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: false, + expectedErrMsgs: []string{ + "spec.routes[0].destination.partition: Invalid value: \"partition-a\": Consul Enterprise partitions must be enabled to set destination.partition", + "spec.routes[1].destination.partition: Invalid value: \"partition-b\": Consul Enterprise partitions must be enabled to set destination.partition", + }, + }, } for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled}) + err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled, PartitionsEnabled: testCase.partitionsEnabled}) if len(testCase.expectedErrMsgs) != 0 { require.Error(t, err) for _, s := range testCase.expectedErrMsgs { diff --git a/control-plane/api/v1alpha1/servicesplitter_types.go b/control-plane/api/v1alpha1/servicesplitter_types.go index ea41ed6b1a..900cc1c545 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types.go +++ b/control-plane/api/v1alpha1/servicesplitter_types.go @@ -61,9 +61,12 @@ type ServiceSplit struct { // ServiceSubset is a named subset of the given service to resolve instead of one defined // as that service's DefaultSubset. If empty the default subset is used. ServiceSubset string `json:"serviceSubset,omitempty"` - // The namespace to resolve the service from instead of the current namespace. - // If empty the current namespace is assumed. + // Namespace is the Consul namespace to resolve the service from instead of + // the current namespace. If empty the current namespace is assumed. Namespace string `json:"namespace,omitempty"` + // Partition is the Consul partition to resolve the service from instead of + // the current partition. If empty the current partition is assumed. + Partition string `json:"partition,omitempty"` // Allow HTTP header manipulation to be configured. RequestHeaders *HTTPHeaderModifiers `json:"requestHeaders,omitempty"` ResponseHeaders *HTTPHeaderModifiers `json:"responseHeaders,omitempty"` @@ -168,7 +171,7 @@ func (in *ServiceSplitter) MatchesConsul(candidate capi.ConfigEntry) bool { func (in *ServiceSplitter) Validate(consulMeta common.ConsulMeta) error { errs := in.Spec.Splits.validate(field.NewPath("spec").Child("splits")) - errs = append(errs, in.validateNamespaces(consulMeta.NamespacesEnabled)...) + errs = append(errs, in.validateEnterprise(consulMeta)...) if len(errs) > 0 { return apierrors.NewInvalid( @@ -198,21 +201,29 @@ func (in ServiceSplit) toConsul() capi.ServiceSplit { Service: in.Service, ServiceSubset: in.ServiceSubset, Namespace: in.Namespace, + Partition: in.Partition, RequestHeaders: in.RequestHeaders.toConsul(), ResponseHeaders: in.ResponseHeaders.toConsul(), } } -func (in *ServiceSplitter) validateNamespaces(namespacesEnabled bool) field.ErrorList { +func (in *ServiceSplitter) validateEnterprise(consulMeta common.ConsulMeta) field.ErrorList { var errs field.ErrorList path := field.NewPath("spec") - if !namespacesEnabled { + if !consulMeta.NamespacesEnabled { for i, s := range in.Spec.Splits { if s.Namespace != "" { errs = append(errs, field.Invalid(path.Child("splits").Index(i).Child("namespace"), s.Namespace, `Consul Enterprise namespaces must be enabled to set split.namespace`)) } } } + if !consulMeta.PartitionsEnabled { + for i, s := range in.Spec.Splits { + if s.Partition != "" { + errs = append(errs, field.Invalid(path.Child("splits").Index(i).Child("partition"), s.Partition, `Consul Enterprise partitions must be enabled to set split.partition`)) + } + } + } return errs } diff --git a/control-plane/api/v1alpha1/servicesplitter_types_test.go b/control-plane/api/v1alpha1/servicesplitter_types_test.go index e37d29e9db..48e9eeac54 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types_test.go +++ b/control-plane/api/v1alpha1/servicesplitter_types_test.go @@ -387,6 +387,7 @@ func TestServiceSplitter_Validate(t *testing.T) { cases := map[string]struct { input *ServiceSplitter namespacesEnabled bool + partitionsEnabled bool expectedErrMsgs []string }{ "namespaces enabled: valid": { @@ -429,6 +430,50 @@ func TestServiceSplitter_Validate(t *testing.T) { namespacesEnabled: false, expectedErrMsgs: nil, }, + "partitions enabled: valid": { + input: &ServiceSplitter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceSplitterSpec{ + Splits: []ServiceSplit{ + { + Weight: 99.99, + Namespace: "namespace-a", + Partition: "partition-a", + }, + { + Weight: 0.01, + Namespace: "namespace-b", + Partition: "partition-b", + }, + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: true, + expectedErrMsgs: nil, + }, + "partitions disabled: valid": { + input: &ServiceSplitter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceSplitterSpec{ + Splits: []ServiceSplit{ + { + Weight: 99.99, + }, + { + Weight: 0.01, + }, + }, + }, + }, + namespacesEnabled: false, + partitionsEnabled: false, + expectedErrMsgs: nil, + }, "splits with 0 weight: valid": { input: &ServiceSplitter{ ObjectMeta: metav1.ObjectMeta{ @@ -541,10 +586,58 @@ func TestServiceSplitter_Validate(t *testing.T) { "spec.splits[1].namespace: Invalid value: \"namespace-b\": Consul Enterprise namespaces must be enabled to set split.namespace", }, }, + "partitions disabled: single split partition specified": { + input: &ServiceSplitter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceSplitterSpec{ + Splits: []ServiceSplit{ + { + Namespace: "namespace-a", + Partition: "partition-a", + Weight: 100, + }, + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: false, + expectedErrMsgs: []string{ + "servicesplitter.consul.hashicorp.com \"foo\" is invalid: spec.splits[0].partition: Invalid value: \"partition-a\": Consul Enterprise partitions must be enabled to set split.partition", + }, + }, + "partitions disabled: multiple split partitions specified": { + input: &ServiceSplitter{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + }, + Spec: ServiceSplitterSpec{ + Splits: []ServiceSplit{ + { + Namespace: "namespace-a", + Partition: "partition-a", + Weight: 50, + }, + { + Namespace: "namespace-b", + Partition: "partition-b", + Weight: 50, + }, + }, + }, + }, + namespacesEnabled: true, + partitionsEnabled: false, + expectedErrMsgs: []string{ + "spec.splits[0].partition: Invalid value: \"partition-a\": Consul Enterprise partitions must be enabled to set split.partition", + "spec.splits[1].partition: Invalid value: \"partition-b\": Consul Enterprise partitions must be enabled to set split.partition", + }, + }, } for name, testCase := range cases { t.Run(name, func(t *testing.T) { - err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled}) + err := testCase.input.Validate(common.ConsulMeta{NamespacesEnabled: testCase.namespacesEnabled, PartitionsEnabled: testCase.partitionsEnabled}) if len(testCase.expectedErrMsgs) != 0 { require.Error(t, err) for _, s := range testCase.expectedErrMsgs { 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 0be581e8b1..87285e8563 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml @@ -180,8 +180,14 @@ spec: from instead of the current one. type: string namespace: - description: Namespace is the namespace to resolve the service - from instead of the current one. + description: Namespace is the Consul namespace to resolve the + service from instead of the current namespace. If empty the + current namespace is assumed. + type: string + partition: + description: Partition is the Consul partition to resolve the + service from instead of the current partition. If empty the + current partition is assumed. type: string service: description: Service is a service to resolve instead of the current 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 17c7c75790..ec74f9b63d 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml @@ -70,6 +70,11 @@ spec: the request when a retryable result occurs format: int32 type: integer + partition: + description: Partition is the Consul partition to resolve + the service from instead of the current partition. If + empty the current partition is assumed. + type: string prefixRewrite: description: PrefixRewrite defines how to rewrite the HTTP request path before proxying it to its final destination. 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 de3d2d43fd..fbbac1010e 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml @@ -56,9 +56,14 @@ spec: items: properties: namespace: - description: The namespace to resolve the service from instead - of the current namespace. If empty the current namespace is - assumed. + description: Namespace is the Consul namespace to resolve the + service from instead of the current namespace. If empty the + current namespace is assumed. + type: string + partition: + description: Partition is the Consul partition to resolve the + service from instead of the current partition. If empty the + current partition is assumed. type: string requestHeaders: description: Allow HTTP header manipulation to be configured. From 71a6bb62604ca860116627c34bf135c605dac10a Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Wed, 8 Dec 2021 10:42:31 -0800 Subject: [PATCH 184/418] Retry testing the merged metrics (#914) --- acceptance/tests/metrics/metrics_test.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/acceptance/tests/metrics/metrics_test.go b/acceptance/tests/metrics/metrics_test.go index 25e480c8d3..0ad3ce22c4 100644 --- a/acceptance/tests/metrics/metrics_test.go +++ b/acceptance/tests/metrics/metrics_test.go @@ -3,7 +3,9 @@ package metrics import ( "context" "fmt" + "github.com/hashicorp/consul/sdk/testutil/retry" "testing" + "time" "github.com/hashicorp/consul-k8s/acceptance/framework/consul" "github.com/hashicorp/consul-k8s/acceptance/framework/environment" @@ -121,12 +123,17 @@ func TestAppMetrics(t *testing.T) { require.NoError(t, err) require.Len(t, podList.Items, 1) podIP := podList.Items[0].Status.PodIP - metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+staticClientName, "--", "curl", "--silent", "--show-error", fmt.Sprintf("http://%s:20200/metrics", podIP)) - require.NoError(t, err) - // This assertion represents the metrics from the envoy sidecar. - require.Contains(t, metricsOutput, `envoy_cluster_assignment_stale{local_cluster="server",consul_source_service="server"`) - // This assertion represents the metrics from the application. - require.Contains(t, metricsOutput, `service_started_total 1`) + + // Retry because sometimes the merged metrics server takes a couple hundred milliseconds + // to start. + retry.RunWith(&retry.Counter{Count: 3, Wait: 1 * time.Second}, t, func(r *retry.R) { + metricsOutput, err := k8s.RunKubectlAndGetOutputE(t, ctx.KubectlOptions(t), "exec", "deploy/"+staticClientName, "--", "curl", "--silent", "--show-error", fmt.Sprintf("http://%s:20200/metrics", podIP)) + require.NoError(r, err) + // This assertion represents the metrics from the envoy sidecar. + require.Contains(r, metricsOutput, `envoy_cluster_assignment_stale{local_cluster="server",consul_source_service="server"`) + // This assertion represents the metrics from the application. + require.Contains(r, metricsOutput, `service_started_total 1`) + }) } func assertGatewayMetricsEnabled(t *testing.T, ctx environment.TestContext, ns, label, metricsAssertion string) { From 4143aff573163b110972a245e0dafdb20fb8e797 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 8 Dec 2021 13:57:41 -0500 Subject: [PATCH 185/418] 1.11.0 rc (#913) * support 1.11.0-rc --- .circleci/config.yml | 4 ++-- acceptance/tests/controller/controller_namespaces_test.go | 2 +- acceptance/tests/partitions/partitions_test.go | 4 ++-- .../controller/exportedservices_controller_ent_test.go | 3 --- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f84aed3235..925adf6b24 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,8 +9,8 @@ executors: - image: docker.mirror.hashicorp.services/circleci/golang:1.17 environment: TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.11.0-beta3 # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.11.0+ent-beta3 # Consul's enterprise version to use in tests + CONSUL_VERSION: 1.11.0-rc # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.0+ent-rc # Consul's enterprise version to use in tests control-plane-path : &control-plane-path control-plane cli-path : &cli-path cli diff --git a/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go index 483fc96106..b272247db4 100644 --- a/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -74,7 +74,7 @@ func TestControllerNamespaces(t *testing.T) { ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ - "global.image": "ashwinvenkatesh/consul@sha256:dce7a25b9e15271d8102a0f14fae71af0b9c789bafd8cbe4a7d0f8c34abe0296", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-rc", "global.enableConsulNamespaces": "true", "global.adminPartitions.enabled": "true", diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 001a2f431c..357e2f6d85 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -96,7 +96,7 @@ func TestPartitions(t *testing.T) { serverHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "ashwinvenkatesh/consul@sha256:dce7a25b9e15271d8102a0f14fae71af0b9c789bafd8cbe4a7d0f8c34abe0296", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-rc", "global.adminPartitions.enabled": "true", "global.enableConsulNamespaces": "true", @@ -197,7 +197,7 @@ func TestPartitions(t *testing.T) { // Create client cluster. clientHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "ashwinvenkatesh/consul@sha256:dce7a25b9e15271d8102a0f14fae71af0b9c789bafd8cbe4a7d0f8c34abe0296", + "global.image": "hashicorp/consul-enterprise:1.11.0-ent-rc", "global.enabled": "false", "global.tls.enabled": "true", diff --git a/control-plane/controller/exportedservices_controller_ent_test.go b/control-plane/controller/exportedservices_controller_ent_test.go index 72acdabf2c..ec8f771586 100644 --- a/control-plane/controller/exportedservices_controller_ent_test.go +++ b/control-plane/controller/exportedservices_controller_ent_test.go @@ -31,7 +31,6 @@ import ( func TestExportedServicesController_createsExportedServices(tt *testing.T) { tt.Parallel() - tt.Skip() cases := map[string]struct { Mirror bool @@ -151,7 +150,6 @@ func TestExportedServicesController_createsExportedServices(tt *testing.T) { func TestExportedServicesController_updatesExportedServices(tt *testing.T) { tt.Parallel() - tt.Skip() cases := map[string]struct { Mirror bool @@ -294,7 +292,6 @@ func TestExportedServicesController_updatesExportedServices(tt *testing.T) { func TestExportedServicesController_deletesExportedServices(tt *testing.T) { tt.Parallel() - tt.Skip() cases := map[string]struct { Mirror bool From f84fef0a71ca1d6d50c0553922ce9b512ef5b0f5 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 8 Dec 2021 14:51:53 -0500 Subject: [PATCH 186/418] Update version to 0.38.0 (#915) --- charts/consul/Chart.yaml | 4 ++-- charts/consul/values.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index 740f90d1fd..0057b0780b 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: consul -version: 0.37.0 +version: 0.38.0 appVersion: 1.10.4 kubeVersion: ">=1.17.0-0" description: Official HashiCorp Consul Chart @@ -15,7 +15,7 @@ annotations: - name: consul image: hashicorp/consul:1.10.4 - name: consul-k8s-control-plane - image: hashicorp/consul-k8s-control-plane:0.37.0 + image: hashicorp/consul-k8s-control-plane:0.38.0 - name: envoy image: envoyproxy/envoy-alpine:v1.18.4 artifacthub.io/license: MPL-2.0 diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index e95e7043ee..7cf9156fbf 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -105,7 +105,7 @@ global: # image that is used for functionality such as catalog sync. # This can be overridden per component. # @default: hashicorp/consul-k8s-control-plane: - imageK8S: "hashicorp/consul-k8s-control-plane:0.37.0" + imageK8S: "hashicorp/consul-k8s-control-plane:0.38.0" # The name of the datacenter that the agents should # register as. This can't be changed once the Consul cluster is up and running From dd1e1b0abdcb96372b5dd428fbcf426016f57c12 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Wed, 8 Dec 2021 19:55:43 +0000 Subject: [PATCH 187/418] Release v0.38.0 --- CHANGELOG.md | 2 +- cli/version/version.go | 4 ++-- control-plane/version/version.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46639b8283..cbf669cb96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.38.0 (December 08, 2021) BREAKING CHANGES: * Control Plane diff --git a/cli/version/version.go b/cli/version/version.go index 52fb3c2b9c..c5b55dddda 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.37.0" + Version = "0.38.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 52fb3c2b9c..c5b55dddda 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.37.0" + Version = "0.38.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From aee48f05524f5ec1695a3913959ae33945c93023 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Wed, 8 Dec 2021 20:19:00 +0000 Subject: [PATCH 188/418] Putting source back into Dev Mode --- CHANGELOG.md | 2 ++ cli/version/version.go | 2 +- control-plane/version/version.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbf669cb96..473ce5ed73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## UNRELEASED + ## 0.38.0 (December 08, 2021) BREAKING CHANGES: diff --git a/cli/version/version.go b/cli/version/version.go index c5b55dddda..44f7aca672 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index c5b55dddda..44f7aca672 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 45d065b9e81becadfc0f2337e1c4e13f8e07a380 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Wed, 8 Dec 2021 22:04:06 -0600 Subject: [PATCH 189/418] add psp support when its configured --- acceptance/framework/vault/vault_cluster.go | 3 + acceptance/go.mod | 88 --------------------- 2 files changed, 3 insertions(+), 88 deletions(-) diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index b0f444f85e..bab5fbb753 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -56,6 +56,9 @@ func NewVaultCluster(t *testing.T, ctx environment.TestContext, cfg *config.Test KubectlOptions: kopts, Logger: logger, } + if cfg.EnablePodSecurityPolicies { + vaultHelmOpts.SetValues["global.psp.enable"] = "true" + } helm.AddRepo(t, vaultHelmOpts, "hashicorp", "https://helm.releases.hashicorp.com") // Ignoring the error from `helm repo update` as it could fail due to stale cache or unreachable servers and we're // asserting a chart version on Install which would fail in an obvious way should this not succeed. diff --git a/acceptance/go.mod b/acceptance/go.mod index f91df929e2..a6b5a6b25b 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -14,91 +14,3 @@ require ( k8s.io/apimachinery v0.22.2 k8s.io/client-go v0.22.2 ) - -require ( - cloud.google.com/go v0.54.0 // indirect - github.com/armon/go-metrics v0.3.9 // indirect - github.com/armon/go-radix v1.0.0 // indirect - github.com/aws/aws-sdk-go v1.30.27 // indirect - github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect - github.com/cenkalti/backoff/v3 v3.0.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/evanphx/json-patch v4.11.0+incompatible // indirect - github.com/fatih/color v1.12.0 // indirect - github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect - github.com/go-logr/logr v0.4.0 // indirect - github.com/go-sql-driver/mysql v1.5.0 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/golang/snappy v0.0.1 // indirect - github.com/google/go-cmp v0.5.6 // indirect - github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.1.2 // indirect - github.com/googleapis/gnostic v0.5.5 // indirect - github.com/gruntwork-io/gruntwork-cli v0.7.0 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-hclog v0.16.2 // indirect - github.com/hashicorp/go-immutable-radix v1.3.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-plugin v1.0.1 // indirect - github.com/hashicorp/go-retryablehttp v0.6.6 // indirect - github.com/hashicorp/go-rootcerts v1.0.2 // indirect - github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 // indirect - github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 // indirect - github.com/hashicorp/go-sockaddr v1.0.2 // indirect - github.com/hashicorp/go-uuid v1.0.2 // indirect - github.com/hashicorp/go-version v1.2.0 // indirect - github.com/hashicorp/golang-lru v0.5.3 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hashicorp/serf v0.9.6 // indirect - github.com/hashicorp/vault/sdk v0.2.1 // indirect - github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect - github.com/imdario/mergo v0.3.12 // indirect - github.com/jmespath/go-jmespath v0.3.0 // indirect - github.com/json-iterator/go v1.1.11 // indirect - github.com/mattn/go-colorable v0.1.8 // indirect - github.com/mattn/go-isatty v0.0.13 // indirect - github.com/mitchellh/copystructure v1.0.0 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/go-testing-interface v1.14.0 // indirect - github.com/mitchellh/mapstructure v1.4.2 // indirect - github.com/mitchellh/reflectwalk v1.0.0 // indirect - github.com/moby/spdystream v0.2.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/oklog/run v1.0.0 // indirect - github.com/onsi/ginkgo v1.16.4 // indirect - github.com/onsi/gomega v1.15.0 // indirect - github.com/pierrec/lz4 v2.5.2+incompatible // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/pquerna/otp v1.2.0 // indirect - github.com/russross/blackfriday/v2 v2.0.1 // indirect - github.com/ryanuber/go-glob v1.0.0 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/urfave/cli v1.22.2 // indirect - go.uber.org/atomic v1.7.0 // indirect - golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect - golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect - golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect - golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.6 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect - google.golang.org/grpc v1.38.0 // indirect - google.golang.org/protobuf v1.26.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/square/go-jose.v2 v2.5.1 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/klog/v2 v2.9.0 // indirect - k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect - k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect -) From 363186b9e87199bb48e404775f263da0ff4128ee Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Wed, 8 Dec 2021 22:09:32 -0600 Subject: [PATCH 190/418] go mod tidy vs 1.17 --- acceptance/go.mod | 86 +++++++++++++++++ acceptance/go.sum | 233 +--------------------------------------------- 2 files changed, 90 insertions(+), 229 deletions(-) diff --git a/acceptance/go.mod b/acceptance/go.mod index a6b5a6b25b..db655d76b3 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -14,3 +14,89 @@ require ( k8s.io/apimachinery v0.22.2 k8s.io/client-go v0.22.2 ) + +require ( + cloud.google.com/go v0.54.0 // indirect + github.com/armon/go-metrics v0.3.9 // indirect + github.com/armon/go-radix v1.0.0 // indirect + github.com/aws/aws-sdk-go v1.30.27 // indirect + github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect + github.com/cenkalti/backoff/v3 v3.0.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/evanphx/json-patch v4.11.0+incompatible // indirect + github.com/fatih/color v1.12.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 // indirect + github.com/go-logr/logr v0.4.0 // indirect + github.com/go-sql-driver/mysql v1.5.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.1 // indirect + github.com/google/go-cmp v0.5.6 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect + github.com/gruntwork-io/gruntwork-cli v0.7.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-hclog v0.16.2 // indirect + github.com/hashicorp/go-immutable-radix v1.3.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.0.1 // indirect + github.com/hashicorp/go-retryablehttp v0.6.6 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.1 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/hashicorp/go-version v1.2.0 // indirect + github.com/hashicorp/golang-lru v0.5.3 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hashicorp/serf v0.9.6 // indirect + github.com/hashicorp/vault/sdk v0.2.1 // indirect + github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jmespath/go-jmespath v0.3.0 // indirect + github.com/json-iterator/go v1.1.11 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.13 // indirect + github.com/mitchellh/copystructure v1.0.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.0 // indirect + github.com/mitchellh/mapstructure v1.4.2 // indirect + github.com/mitchellh/reflectwalk v1.0.0 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/oklog/run v1.0.0 // indirect + github.com/pierrec/lz4 v2.5.2+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pquerna/otp v1.2.0 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/urfave/cli v1.22.2 // indirect + go.uber.org/atomic v1.7.0 // indirect + golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect + golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect + golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect + golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + golang.org/x/text v0.3.6 // indirect + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect + google.golang.org/grpc v1.38.0 // indirect + google.golang.org/protobuf v1.26.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/square/go-jose.v2 v2.5.1 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/klog/v2 v2.9.0 // indirect + k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect + k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect + sigs.k8s.io/yaml v1.2.0 // indirect +) diff --git a/acceptance/go.sum b/acceptance/go.sum index 3459220dc4..c082349208 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -17,7 +17,6 @@ cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNF cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -27,11 +26,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go v44.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= @@ -46,7 +42,6 @@ github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMl github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= -github.com/Azure/go-autorest/autorest/azure/auth v0.5.0/go.mod h1:QRTvSZQpxqm8mSErhnbI+tANIBAKP7B+UIE2z4ypUO0= github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= @@ -59,7 +54,6 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935 github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= -github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= @@ -75,19 +69,14 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -102,29 +91,19 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.30.27 h1:9gPjZWVDSoQrBO2AvqrWObS6KAZByfEJxQoCYo4ZfK0= github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= -github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= 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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -134,11 +113,7 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= -github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -150,37 +125,26 @@ github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/digitalocean/godo v1.7.5/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= -github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= @@ -207,10 +171,8 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= @@ -221,7 +183,6 @@ github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= @@ -232,7 +193,6 @@ github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -245,41 +205,33 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8= github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -288,7 +240,6 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -311,10 +262,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -330,14 +279,11 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= -github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= @@ -349,7 +295,6 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= @@ -357,42 +302,32 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arnQQLM4RH+CYs= github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638 h1:z68s6H6O3RjxDmNvou/2/3UBrsJkrMcNzI0IQN5scAM= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638/go.mod h1:7ZeaiADGbvJDuoWAT8UKj6KCcLsFUk+34OkUGMVtdXg= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= @@ -403,12 +338,10 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f/go.mod h1:D4eo8/CN92vm9/9UDG+ldX1/fMFa4kpl8qzyTolus8o= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -418,7 +351,6 @@ github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= -github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 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= @@ -429,7 +361,6 @@ github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= 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= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= @@ -448,7 +379,6 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= @@ -456,16 +386,12 @@ github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= @@ -476,32 +402,21 @@ github.com/hashicorp/vault/api v1.2.0/go.mod h1:dAjw0T5shMnrfH7Q/Mst+LrcTKvStZBV github.com/hashicorp/vault/sdk v0.1.14-0.20200519221530-14615acda45f/go.mod h1:WX57W2PwkrOPQ6rVQk+dy5/htHIaB4aBM70EwKThu10= github.com/hashicorp/vault/sdk v0.2.1 h1:S4O6Iv/dyKlE9AUTXGa7VOvZmsCvg36toPKgV4f2P4M= github.com/hashicorp/vault/sdk v0.2.1/go.mod h1:WfUiO1vYzfBkz1TmoE4ZGU7HD0T0Cl/rZwaxjBkgN4U= -github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= -github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -512,16 +427,13 @@ github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMW github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -532,15 +444,11 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -555,13 +463,10 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= @@ -570,7 +475,6 @@ github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceT github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -578,8 +482,6 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/go-testing-interface v1.14.0 h1:/x0XQ6h+3U3nAyk1yx+bHPURrKa9sVVvYbuqZ7pIAtI= github.com/mitchellh/go-testing-interface v1.14.0/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -592,7 +494,6 @@ github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8 github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -604,40 +505,33 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.0-20180130162743-b8a9be070da4/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= -github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -645,9 +539,7 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= -github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -671,40 +563,25 @@ github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= -github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/zerolog v1.4.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -714,35 +591,21 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= -github.com/sean-/conswriter v0.0.0-20180208195008-f5ae3917a627/go.mod h1:7zjs06qF79/FKAJpBvFx3P8Ww4UTIMAe+lpNXDHziac= -github.com/sean-/pager v0.0.0-20180208200047-666be9bf53b5/go.mod h1:BeybITEsBEg6qbIiqJ6/Bqeq25bCLbL7YFmpaFfJDuM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -751,8 +614,6 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -763,18 +624,12 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -782,54 +637,26 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= -github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= -go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= -go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= -go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= -go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -841,7 +668,6 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -885,7 +711,6 @@ golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -895,7 +720,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -914,19 +738,15 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -942,14 +762,12 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -964,7 +782,6 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -979,12 +796,10 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -996,27 +811,19 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo= @@ -1039,7 +846,6 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1052,7 +858,6 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -1068,8 +873,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1088,10 +891,8 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -1100,7 +901,6 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= @@ -1140,8 +940,6 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4 google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1151,7 +949,6 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -1162,9 +959,6 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -1197,7 +991,6 @@ gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -1210,7 +1003,6 @@ gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1223,7 +1015,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1231,53 +1022,42 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= -k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= -k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= -k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= -k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= -k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= -k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= @@ -1289,15 +1069,10 @@ modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/controller-runtime v0.10.2/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= From 65a91a9c44e9f4d0e199729342114dee9b9db98f Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 9 Dec 2021 13:36:52 -0500 Subject: [PATCH 191/418] anony token --- .circleci/config.yml | 2 +- charts/consul/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 925adf6b24..1304e1f1cb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,7 +70,7 @@ commands: type: string consul-k8s-image: type: string - default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" + default: "ashwinvenkatesh/consul-k8s@sha256:5724b0bc0b28ac7b2dbea3d2b03c5360425be1d4dcb9cec31c99465e2fac70e4" go-path: type: string default: "/home/circleci/.go_workspace" diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 7cf9156fbf..57ec69261f 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -85,7 +85,7 @@ global: # image: "hashicorp/consul-enterprise:1.10.0-ent" # ``` # @default: hashicorp/consul: - image: "hashicorp/consul:1.10.4" + image: "ashwinvenkatesh/consul@sha256:a2638301c2386131f186c3ec30afc2073c8c74aeaadff63dae0089f5402bd0f0" # Array of objects containing image pull secret names that will be applied to each service account. # This can be used to reference image pull secrets if using a custom consul or consul-k8s-control-plane Docker image. From 9c4bee4aa21aaf6f4004df6ebab6a802cb4faf5c Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 9 Dec 2021 13:43:38 -0500 Subject: [PATCH 192/418] Revert erronous commit This reverts commit 65a91a9c44e9f4d0e199729342114dee9b9db98f. --- .circleci/config.yml | 2 +- charts/consul/values.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1304e1f1cb..925adf6b24 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,7 +70,7 @@ commands: type: string consul-k8s-image: type: string - default: "ashwinvenkatesh/consul-k8s@sha256:5724b0bc0b28ac7b2dbea3d2b03c5360425be1d4dcb9cec31c99465e2fac70e4" + default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" go-path: type: string default: "/home/circleci/.go_workspace" diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 57ec69261f..7cf9156fbf 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -85,7 +85,7 @@ global: # image: "hashicorp/consul-enterprise:1.10.0-ent" # ``` # @default: hashicorp/consul: - image: "ashwinvenkatesh/consul@sha256:a2638301c2386131f186c3ec30afc2073c8c74aeaadff63dae0089f5402bd0f0" + image: "hashicorp/consul:1.10.4" # Array of objects containing image pull secret names that will be applied to each service account. # This can be used to reference image pull secrets if using a custom consul or consul-k8s-control-plane Docker image. From 913f0c355dc9745ca7c0dc0f56eb56c71620b30e Mon Sep 17 00:00:00 2001 From: David Yu Date: Mon, 13 Dec 2021 11:14:31 -0800 Subject: [PATCH 193/418] Release.ubi.dockerfile: update to ubi-minimal:8.5 (#922) Update to the latest ubi-minimal base image --- control-plane/build-support/docker/Release.ubi.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control-plane/build-support/docker/Release.ubi.dockerfile b/control-plane/build-support/docker/Release.ubi.dockerfile index b57832398b..f5db390532 100644 --- a/control-plane/build-support/docker/Release.ubi.dockerfile +++ b/control-plane/build-support/docker/Release.ubi.dockerfile @@ -8,7 +8,7 @@ # We don't rebuild the software because we want the exact checksums and # binary signatures to match the software and our builds aren't fully # reproducible currently. -FROM registry.access.redhat.com/ubi8/ubi-minimal:8.4 +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.5 # NAME and VERSION are the name of the software in releases.hashicorp.com # and the version to download. Example: NAME=consul VERSION=1.2.3. From 3951adad7db2e3c4b24e00dcd2d361069b9dd7d3 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Mon, 13 Dec 2021 11:20:00 -0800 Subject: [PATCH 194/418] Go 1.17.5 (#926) * bump to go 1.17.5 for building binaries and testing * update path where modules are saved in new image * bump cache version because restoring from the old cache cannot do so in the new path on this new golang image --- .circleci/config.yml | 52 ++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 925adf6b24..da32949865 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ orbs: executors: go: docker: - - image: docker.mirror.hashicorp.services/circleci/golang:1.17 + - image: docker.mirror.hashicorp.services/cimg/go:1.17.5 environment: TEST_RESULTS: /tmp/test-results # path to where test results are saved CONSUL_VERSION: 1.11.0-rc # Consul's OSS version to use in tests @@ -30,9 +30,9 @@ commands: - run: name: Install gotestsum, kind, kubectl, and helm command: | - wget https://golang.org/dl/go1.17.3.linux-amd64.tar.gz - sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.3.linux-amd64.tar.gz - rm go1.17.3.linux-amd64.tar.gz + wget https://golang.org/dl/go1.17.5.linux-amd64.tar.gz + sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.5.linux-amd64.tar.gz + rm go1.17.5.linux-amd64.tar.gz echo 'export PATH=$PATH:/usr/local/go/bin' >> $BASH_ENV wget https://github.com/gotestyourself/gotestsum/releases/download/v1.6.4/gotestsum_1.6.4_linux_amd64.tar.gz @@ -145,7 +145,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-k8s-modcache-v1-{{ checksum "control-plane/go.mod" }} + - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} - run: name: go mod download @@ -154,9 +154,9 @@ jobs: # Save go module cache if the go.mod file has changed - save_cache: - key: consul-k8s-modcache-v1-{{ checksum "control-plane/go.mod" }} + key: consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} paths: - - "/go/pkg/mod" + - "/home/circleci/go/pkg/mod" # check go fmt output because it does not report non-zero when there are fmt changes - run: @@ -193,7 +193,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-k8s-modcache-v1-{{ checksum "control-plane/go.mod" }} + - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} # run go tests with gotestsum - run: @@ -224,7 +224,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-k8s-modcache-v1-{{ checksum "control-plane/go.mod" }} + - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} # run go tests with gotestsum - run: @@ -263,7 +263,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-k8s-modcache-v1-{{ checksum "control-plane/go.mod" }} + - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} - run: name: build local working_directory: *control-plane-path @@ -299,7 +299,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-k8s-cli-modcache-v1-{{ checksum "cli/go.mod" }} + - consul-k8s-cli-modcache-v2-{{ checksum "cli/go.mod" }} - run: name: go mod download @@ -308,9 +308,9 @@ jobs: # Save go module cache if the go.mod file has changed - save_cache: - key: consul-k8s-cli-modcache-v1-{{ checksum "cli/go.mod" }} + key: consul-k8s-cli-modcache-v2-{{ checksum "cli/go.mod" }} paths: - - "/go/pkg/mod" + - "/home/circleci/go/pkg/mod" - run: mkdir -p $TEST_RESULTS @@ -333,7 +333,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - run: name: go mod download @@ -342,9 +342,9 @@ jobs: # Save go module cache if the go.mod file has changed - save_cache: - key: consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} + key: consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} paths: - - "/go/pkg/mod" + - "/home/circleci/go/pkg/mod" # check go fmt output because it does not report non-zero when there are fmt changes - run: @@ -371,7 +371,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-helm-gen-modcache-v1-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} - run: name: go mod download @@ -380,9 +380,9 @@ jobs: # Save go module cache if the go.mod file has changed - save_cache: - key: consul-helm-helm-gen-modcache-v1-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + key: consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} paths: - - "/go/pkg/mod" + - "/home/circleci/go/pkg/mod" # check go fmt output because it does not report non-zero when there are fmt changes - run: @@ -409,7 +409,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -432,7 +432,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-helm-gen-modcache-v1-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -455,7 +455,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-helm-gen-modcache-v1-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -643,7 +643,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -698,7 +698,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -759,7 +759,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - run: mkdir -p $TEST_RESULTS @@ -812,7 +812,7 @@ jobs: # Restore go module cache if there is one - restore_cache: keys: - - consul-helm-acceptance-modcache-v1-{{ checksum "acceptance/go.mod" }} + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - run: mkdir -p $TEST_RESULTS From 1bc83fe95f20f4e821154f8792ddf936fdf30f5e Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Mon, 13 Dec 2021 16:40:10 -0500 Subject: [PATCH 195/418] CLI Upgrade Command (fixed PR) (#929) * Made an initial try at the consul-k8s upgrade command. Running into issues with the connect-injector webhook not starting on an install? * Upgrade commit * First pass at upgrade was successful. * notes from sync with Saad on what's left * Made an initial try at the consul-k8s upgrade command. Running into issues with the connect-injector webhook not starting on an install? * Upgrade commit * First pass at upgrade was successful. * notes from sync with Saad on what's left * Some basic cleanup * Remove TestDebugger * Remove validateLabels (unused) * Add the namespace and install flags * Add flag test and remove install option * Move presets into a config package * Add Changelog * Mark CHANGELOG update as BETA * Remove namespace from upgrade * Address @ndhanushkodi's comments * Enable the better demo * Remove unneeded test * Fixup import styling * Change install references to upgrade Co-authored-by: Saad Co-authored-by: Nitya Dhanushkodi --- CHANGELOG.md | 4 + cli/cmd/install/install.go | 20 +- cli/cmd/upgrade/upgrade.go | 420 +++++++++++++++++++++++++ cli/cmd/upgrade/upgrade_test.go | 68 ++++ cli/commands.go | 6 + cli/{cmd/install => config}/presets.go | 25 +- 6 files changed, 522 insertions(+), 21 deletions(-) create mode 100644 cli/cmd/upgrade/upgrade.go create mode 100644 cli/cmd/upgrade/upgrade_test.go rename cli/{cmd/install => config}/presets.go (62%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 473ce5ed73..02bd5de687 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,10 @@ FEATURES: * Helm * Rename `PartitionExports` CRD to `ExportedServices`. [[GH-902](https://github.com/hashicorp/consul-k8s/pull/902)] +FEATURES: +* CLI + * **BETA** Add `upgrade` command to modify Consul installation on Kubernetes. [[GH-898](https://github.com/hashicorp/consul-k8s/pull/898)] + IMPROVEMENTS: * CLI * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index 44b1bca41f..edc9308481 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -8,17 +8,17 @@ import ( "sync" "time" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - consulChart "github.com/hashicorp/consul-k8s/charts" "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + "github.com/hashicorp/consul-k8s/cli/config" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart/loader" helmCLI "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/cli/values" "helm.sh/helm/v3/pkg/getter" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" _ "k8s.io/client-go/plugin/pkg/client/auth" @@ -82,7 +82,7 @@ type Command struct { func (c *Command) init() { // Store all the possible preset values in 'presetList'. Printed in the help message. var presetList []string - for name := range presets { + for name := range config.Presets { presetList = append(presetList, name) } @@ -313,7 +313,7 @@ func (c *Command) Run(args []string) int { // Without informing the user, default global.name to consul if it hasn't been set already. We don't allow setting // the release name, and since that is hardcoded to "consul", setting global.name to "consul" makes it so resources // aren't double prefixed with "consul-consul-...". - vals = mergeMaps(convert(globalNameConsul), vals) + vals = MergeMaps(config.Convert(config.GlobalNameConsul), vals) // Dry Run should exit here, no need to actual locate/download the charts. if c.flagDryRun { @@ -454,15 +454,15 @@ func (c *Command) mergeValuesFlagsWithPrecedence(settings *helmCLI.EnvSettings) } if c.flagPreset != defaultPreset { // Note the ordering of the function call, presets have lower precedence than set vals. - presetMap := presets[c.flagPreset].(map[string]interface{}) - vals = mergeMaps(presetMap, vals) + presetMap := config.Presets[c.flagPreset].(map[string]interface{}) + vals = MergeMaps(presetMap, vals) } return vals, err } -// mergeMaps is a helper function used in Run. Merges two maps giving b precedent. +// MergeMaps is a helper function used in Run. Merges two maps giving b precedent. // @source: https://github.com/helm/helm/blob/main/pkg/cli/values/options.go -func mergeMaps(a, b map[string]interface{}) map[string]interface{} { +func MergeMaps(a, b map[string]interface{}) map[string]interface{} { out := make(map[string]interface{}, len(a)) for k, v := range a { out[k] = v @@ -471,7 +471,7 @@ func mergeMaps(a, b map[string]interface{}) map[string]interface{} { if v, ok := v.(map[string]interface{}); ok { if bv, ok := out[k]; ok { if bv, ok := bv.(map[string]interface{}); ok { - out[k] = mergeMaps(bv, v) + out[k] = MergeMaps(bv, v) continue } } @@ -492,7 +492,7 @@ func (c *Command) validateFlags(args []string) error { if len(c.flagValueFiles) != 0 && c.flagPreset != defaultPreset { return fmt.Errorf("Cannot set both -%s and -%s", flagNameConfigFile, flagNamePreset) } - if _, ok := presets[c.flagPreset]; c.flagPreset != defaultPreset && !ok { + if _, ok := config.Presets[c.flagPreset]; c.flagPreset != defaultPreset && !ok { return fmt.Errorf("'%s' is not a valid preset", c.flagPreset) } if !validLabel(c.flagNamespace) { diff --git a/cli/cmd/upgrade/upgrade.go b/cli/cmd/upgrade/upgrade.go new file mode 100644 index 0000000000..27771a8ab6 --- /dev/null +++ b/cli/cmd/upgrade/upgrade.go @@ -0,0 +1,420 @@ +package upgrade + +import ( + "errors" + "fmt" + "os" + "strings" + "sync" + "time" + + consulChart "github.com/hashicorp/consul-k8s/charts" + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" + "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + "github.com/hashicorp/consul-k8s/cli/cmd/install" + "github.com/hashicorp/consul-k8s/cli/config" + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart/loader" + helmCLI "helm.sh/helm/v3/pkg/cli" + "helm.sh/helm/v3/pkg/cli/values" + "helm.sh/helm/v3/pkg/getter" + "k8s.io/client-go/kubernetes" + "sigs.k8s.io/yaml" +) + +const ( + flagNamePreset = "preset" + defaultPreset = "" + + flagNameConfigFile = "config-file" + flagNameSetStringValues = "set-string" + flagNameSetValues = "set" + flagNameFileValues = "set-file" + + flagNameDryRun = "dry-run" + defaultDryRun = false + + flagNameAutoApprove = "auto-approve" + defaultAutoApprove = false + + flagNameTimeout = "timeout" + defaultTimeout = "10m" + + flagNameVerbose = "verbose" + defaultVerbose = false + + flagNameWait = "wait" + defaultWait = true +) + +type Command struct { + *common.BaseCommand + + kubernetes kubernetes.Interface + + set *flag.Sets + + flagPreset string + flagDryRun bool + flagAutoApprove bool + flagValueFiles []string + flagSetStringValues []string + flagSetValues []string + flagFileValues []string + flagTimeout string + timeoutDuration time.Duration + flagVerbose bool + flagWait bool + + flagKubeConfig string + flagKubeContext string + + once sync.Once + help string +} + +func (c *Command) init() { + // Store all the possible preset values in 'presetList'. Printed in the help message. + var presetList []string + for name := range config.Presets { + presetList = append(presetList, name) + } + + c.set = flag.NewSets() + f := c.set.NewSet("Command Options") + f.BoolVar(&flag.BoolVar{ + Name: flagNameAutoApprove, + Target: &c.flagAutoApprove, + Default: defaultAutoApprove, + Usage: "Skip confirmation prompt.", + }) + f.BoolVar(&flag.BoolVar{ + Name: flagNameDryRun, + Target: &c.flagDryRun, + Default: defaultDryRun, + Usage: "Run pre-upgrade checks and display summary of upgrade.", + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameConfigFile, + Aliases: []string{"f"}, + Target: &c.flagValueFiles, + Usage: "Path to a file to customize the upgrade, such as Consul Helm chart values file. Can be specified multiple times.", + }) + f.StringVar(&flag.StringVar{ + Name: flagNamePreset, + Target: &c.flagPreset, + Default: defaultPreset, + Usage: fmt.Sprintf("Use an upgrade preset, one of %s. Defaults to none", strings.Join(presetList, ", ")), + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameSetValues, + Target: &c.flagSetValues, + Usage: "Set a value to customize. Can be specified multiple times. Supports Consul Helm chart values.", + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameFileValues, + Target: &c.flagFileValues, + Usage: "Set a value to customize via a file. The contents of the file will be set as the value. Can be " + + "specified multiple times. Supports Consul Helm chart values.", + }) + f.StringSliceVar(&flag.StringSliceVar{ + Name: flagNameSetStringValues, + Target: &c.flagSetStringValues, + Usage: "Set a string value to customize. Can be specified multiple times. Supports Consul Helm chart values.", + }) + f.StringVar(&flag.StringVar{ + Name: flagNameTimeout, + Target: &c.flagTimeout, + Default: defaultTimeout, + Usage: "Timeout to wait for upgrade to be ready.", + }) + f.BoolVar(&flag.BoolVar{ + Name: flagNameVerbose, + Aliases: []string{"v"}, + Target: &c.flagVerbose, + Default: defaultVerbose, + Usage: "Output verbose logs from the upgrade command with the status of resources being upgraded.", + }) + f.BoolVar(&flag.BoolVar{ + Name: flagNameWait, + Target: &c.flagWait, + Default: defaultWait, + Usage: "Determines whether to wait for resources in upgrade to be ready before exiting command.", + }) + + f = c.set.NewSet("Global Options") + f.StringVar(&flag.StringVar{ + Name: "kubeconfig", + Aliases: []string{"c"}, + Target: &c.flagKubeConfig, + Default: "", + Usage: "Path to kubeconfig file.", + }) + f.StringVar(&flag.StringVar{ + Name: "context", + Target: &c.flagKubeContext, + Default: "", + Usage: "Kubernetes context to use.", + }) + + c.help = c.set.Help() + + // c.Init() calls the embedded BaseCommand's initialization function. + c.Init() +} + +func (c *Command) Run(args []string) int { + c.once.Do(c.init) + c.Log.ResetNamed("upgrade") + + defer common.CloseWithError(c.BaseCommand) + + if err := c.validateFlags(args); err != nil { + c.UI.Output(err.Error()) + return 1 + } + + // helmCLI.New() will create a settings object which is used by the Helm Go SDK calls. + settings := helmCLI.New() + + // Any overrides by our kubeconfig and kubecontext flags is done here. The Kube client that + // is created will use this command's flags first, then the HELM_KUBECONTEXT environment variable, + // then call out to genericclioptions.ConfigFlag + if c.flagKubeConfig != "" { + settings.KubeConfig = c.flagKubeConfig + } + if c.flagKubeContext != "" { + settings.KubeContext = c.flagKubeContext + } + + // Setup logger to stream Helm library logs + var uiLogger = func(s string, args ...interface{}) { + logMsg := fmt.Sprintf(s, args...) + + if c.flagVerbose { + // Only output all logs when verbose is enabled + c.UI.Output(logMsg, terminal.WithLibraryStyle()) + } else { + // When verbose is not enabled, output all logs except not ready messages for resources + if !strings.Contains(logMsg, "not ready") { + c.UI.Output(logMsg, terminal.WithLibraryStyle()) + } + } + } + + // Set up the kubernetes client to use for non Helm SDK calls to the Kubernetes API + // The Helm SDK will use settings.RESTClientGetter for its calls as well, so this will + // use a consistent method to target the right cluster for both Helm SDK and non Helm SDK calls. + if c.kubernetes == nil { + restConfig, err := settings.RESTClientGetter().ToRESTConfig() + if err != nil { + c.UI.Output("Retrieving Kubernetes auth: %v", err, terminal.WithErrorStyle()) + return 1 + } + c.kubernetes, err = kubernetes.NewForConfig(restConfig) + if err != nil { + c.UI.Output("Initializing Kubernetes client: %v", err, terminal.WithErrorStyle()) + return 1 + } + } + + c.UI.Output("Pre-Upgrade Checks", terminal.WithHeaderStyle()) + + // Note the logic here, common's CheckForInstallations function returns an error if + // the release is not found. In `upgrade` we should indeed error if a user doesn't currently have a release. + var foundNamespace string + if name, ns, err := common.CheckForInstallations(settings, uiLogger); err != nil { + c.UI.Output("could not find existing Consul installation - run `consul-k8s install`") + return 1 + } else { + c.UI.Output("Existing installation found to be upgraded.", terminal.WithSuccessStyle()) + c.UI.Output("Name: %s", name, terminal.WithInfoStyle()) + c.UI.Output("Namespace: %s", ns, terminal.WithInfoStyle()) + + foundNamespace = ns + } + + // Handle preset, value files, and set values logic. + vals, err := c.mergeValuesFlagsWithPrecedence(settings) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + valuesYaml, err := yaml.Marshal(vals) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // Print out the upgrade summary. + if !c.flagAutoApprove { + c.UI.Output("Consul Upgrade Summary", terminal.WithHeaderStyle()) + c.UI.Output("Installation name: %s", common.DefaultReleaseName, terminal.WithInfoStyle()) + c.UI.Output("Namespace: %s", foundNamespace, terminal.WithInfoStyle()) + + if len(vals) == 0 { + c.UI.Output("Overrides: "+string(valuesYaml), terminal.WithInfoStyle()) + } else { + c.UI.Output("Overrides:"+"\n"+string(valuesYaml), terminal.WithInfoStyle()) + } + } + + // Without informing the user, default global.name to consul if it hasn't been set already. We don't allow setting + // the release name, and since that is hardcoded to "consul", setting global.name to "consul" makes it so resources + // aren't double prefixed with "consul-consul-...". + vals = install.MergeMaps(config.Convert(config.GlobalNameConsul), vals) + + if !c.flagAutoApprove && !c.flagDryRun { + confirmation, err := c.UI.Input(&terminal.Input{ + Prompt: "Proceed with upgrade? (y/N)", + Style: terminal.InfoStyle, + Secret: false, + }) + + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + if common.Abort(confirmation) { + c.UI.Output("Upgrade aborted. To learn how to customize your upgrade, run:\nconsul-k8s upgrade --help", terminal.WithInfoStyle()) + return 1 + } + } + + if !c.flagDryRun { + c.UI.Output("Running Upgrade", terminal.WithHeaderStyle()) + } else { + c.UI.Output("Performing Dry Run Upgrade", terminal.WithHeaderStyle()) + } + + // Setup action configuration for Helm Go SDK function calls. + actionConfig := new(action.Configuration) + actionConfig, err = common.InitActionConfig(actionConfig, foundNamespace, settings, uiLogger) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // Setup the upgrade action. + upgrade := action.NewUpgrade(actionConfig) + upgrade.Namespace = foundNamespace + upgrade.DryRun = c.flagDryRun + upgrade.Wait = c.flagWait + upgrade.Timeout = c.timeoutDuration + + // Read the embedded chart files into []*loader.BufferedFile. + chartFiles, err := common.ReadChartFiles(consulChart.ConsulHelmChart, common.TopLevelChartDirName) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // Create a *chart.Chart object from the files to run the upgrade from. + chart, err := loader.LoadFiles(chartFiles) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + c.UI.Output("Loaded charts", terminal.WithSuccessStyle()) + + // Run the upgrade. Note that the dry run config is passed into the upgrade action, so upgrade.Run is called even during a dry run. + re, err := upgrade.Run(common.DefaultReleaseName, chart, vals) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + // Dry Run should exit here, printing the release's config. + if c.flagDryRun { + configYaml, err := yaml.Marshal(re.Config) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 + } + + if len(re.Config) == 0 { + c.UI.Output("Config: "+string(configYaml), terminal.WithInfoStyle()) + } else { + c.UI.Output("Config:"+"\n"+string(configYaml), terminal.WithInfoStyle()) + } + c.UI.Output("Dry run complete - upgrade can proceed.", terminal.WithSuccessStyle()) + return 0 + } + + c.UI.Output("Upgraded Consul into namespace %q", foundNamespace, terminal.WithSuccessStyle()) + + return 0 +} + +// validateFlags checks that the user's provided flags are valid. +func (c *Command) validateFlags(args []string) error { + if err := c.set.Parse(args); err != nil { + return err + } + if len(c.set.Args()) > 0 { + return errors.New("should have no non-flag arguments") + } + if len(c.flagValueFiles) != 0 && c.flagPreset != defaultPreset { + return fmt.Errorf("cannot set both -%s and -%s", flagNameConfigFile, flagNamePreset) + } + if _, ok := config.Presets[c.flagPreset]; c.flagPreset != defaultPreset && !ok { + return fmt.Errorf("'%s' is not a valid preset", c.flagPreset) + } + duration, err := time.ParseDuration(c.flagTimeout) + if err != nil { + return fmt.Errorf("unable to parse -%s: %s", flagNameTimeout, err) + } + c.timeoutDuration = duration + if len(c.flagValueFiles) != 0 { + for _, filename := range c.flagValueFiles { + if _, err := os.Stat(filename); err != nil && os.IsNotExist(err) { + return fmt.Errorf("file '%s' does not exist", filename) + } + } + } + + if c.flagDryRun { + c.UI.Output("Performing dry run upgrade.", terminal.WithInfoStyle()) + } + return nil +} + +// mergeValuesFlagsWithPrecedence is responsible for merging all the values to determine the values file for the +// upgrade based on the following precedence order from lowest to highest: +// 1. -preset +// 2. -f values-file +// 3. -set +// 4. -set-string +// 5. -set-file +// For example, -set-file will override a value provided via -set. +// Within each of these groups the rightmost flag value has the highest precedence. +func (c *Command) mergeValuesFlagsWithPrecedence(settings *helmCLI.EnvSettings) (map[string]interface{}, error) { + p := getter.All(settings) + v := &values.Options{ + ValueFiles: c.flagValueFiles, + StringValues: c.flagSetStringValues, + Values: c.flagSetValues, + FileValues: c.flagFileValues, + } + vals, err := v.MergeValues(p) + if err != nil { + return nil, fmt.Errorf("error merging values: %s", err) + } + if c.flagPreset != defaultPreset { + // Note the ordering of the function call, presets have lower precedence than set vals. + presetMap := config.Presets[c.flagPreset].(map[string]interface{}) + vals = install.MergeMaps(presetMap, vals) + } + return vals, err +} + +func (c *Command) Help() string { + c.once.Do(c.init) + s := "Usage: consul-k8s upgrade [flags]" + "\n" + "Upgrade Consul from an existing installation." + "\n" + return s + "\n" + c.help +} + +func (c *Command) Synopsis() string { + return "Upgrade Consul on Kubernetes." +} diff --git a/cli/cmd/upgrade/upgrade_test.go b/cli/cmd/upgrade/upgrade_test.go new file mode 100644 index 0000000000..ab6e830259 --- /dev/null +++ b/cli/cmd/upgrade/upgrade_test.go @@ -0,0 +1,68 @@ +package upgrade + +import ( + "os" + "testing" + + "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/go-hclog" +) + +// TestValidateFlags tests the validate flags function. +func TestValidateFlags(t *testing.T) { + // The following cases should all error, if they fail to this test fails. + testCases := []struct { + description string + input []string + }{ + { + "Should disallow non-flag arguments.", + []string{"foo", "-auto-approve"}, + }, + { + "Should disallow specifying both values file AND presets.", + []string{"-f='f.txt'", "-preset=demo"}, + }, + { + "Should error on invalid presets.", + []string{"-preset=foo"}, + }, + { + "Should error on invalid timeout.", + []string{"-timeout=invalid-timeout"}, + }, + { + "Should have errored on a non-existant file.", + []string{"-f=\"does_not_exist.txt\""}, + }, + } + + for _, testCase := range testCases { + c := getInitializedCommand(t) + t.Run(testCase.description, func(t *testing.T) { + if err := c.validateFlags(testCase.input); err == nil { + t.Errorf("Test case should have failed.") + } + }) + } +} + +// getInitializedCommand sets up a command struct for tests. +func getInitializedCommand(t *testing.T) *Command { + t.Helper() + log := hclog.New(&hclog.LoggerOptions{ + Name: "cli", + Level: hclog.Info, + Output: os.Stdout, + }) + + baseCommand := &common.BaseCommand{ + Log: log, + } + + c := &Command{ + BaseCommand: baseCommand, + } + c.init() + return c +} diff --git a/cli/commands.go b/cli/commands.go index 50da5806d4..17726ac5aa 100644 --- a/cli/commands.go +++ b/cli/commands.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/consul-k8s/cli/cmd/install" "github.com/hashicorp/consul-k8s/cli/cmd/status" "github.com/hashicorp/consul-k8s/cli/cmd/uninstall" + "github.com/hashicorp/consul-k8s/cli/cmd/upgrade" cmdversion "github.com/hashicorp/consul-k8s/cli/cmd/version" "github.com/hashicorp/consul-k8s/cli/version" "github.com/hashicorp/go-hclog" @@ -36,6 +37,11 @@ func initializeCommands(ctx context.Context, log hclog.Logger) (*common.BaseComm BaseCommand: baseCommand, }, nil }, + "upgrade": func() (cli.Command, error) { + return &upgrade.Command{ + BaseCommand: baseCommand, + }, nil + }, "version": func() (cli.Command, error) { return &cmdversion.Command{ BaseCommand: baseCommand, diff --git a/cli/cmd/install/presets.go b/cli/config/presets.go similarity index 62% rename from cli/cmd/install/presets.go rename to cli/config/presets.go index f901d1e930..06b91ce8ce 100644 --- a/cli/cmd/install/presets.go +++ b/cli/config/presets.go @@ -1,4 +1,4 @@ -package install +package config import "sigs.k8s.io/yaml" @@ -7,13 +7,14 @@ const ( PresetSecure = "secure" ) -// presets is a map of pre-configured helm values. -var presets = map[string]interface{}{ - PresetDemo: convert(demo), - PresetSecure: convert(secure), +// Presets is a map of pre-configured helm values. +var Presets = map[string]interface{}{ + PresetDemo: Convert(demo), + PresetSecure: Convert(secure), } -var demo = ` +// demo is a preset of common values for setting up Consul. +const demo = ` global: name: consul metrics: @@ -21,7 +22,7 @@ global: enableAgentMetrics: true connectInject: enabled: true - metrics: + metrics: defaultEnabled: true defaultEnableMerging: true enableGatewayMetrics: true @@ -29,7 +30,7 @@ server: replicas: 1 controller: enabled: true -ui: +ui: enabled: true service: enabled: true @@ -37,7 +38,8 @@ prometheus: enabled: true ` -var secure = ` +// secure is a preset of common values for setting up Consul in a secure manner. +const secure = ` global: name: consul gossipEncryption: @@ -55,13 +57,14 @@ controller: enabled: true ` -var globalNameConsul = ` +// GlobalNameConsul is used to set the global name of an install to consul. +const GlobalNameConsul = ` global: name: consul ` // convert is a helper function that converts a YAML string to a map. -func convert(s string) map[string]interface{} { +func Convert(s string) map[string]interface{} { var m map[string]interface{} _ = yaml.Unmarshal([]byte(s), &m) return m From 7c14eeabc0296a3671ae9e185e9b0cdcc2706646 Mon Sep 17 00:00:00 2001 From: David Yu Date: Mon, 13 Dec 2021 13:47:50 -0800 Subject: [PATCH 196/418] CHANGELOG: add CLI upgrade command to UNRELEASED and note UBI Image bump to ubi-minimal:8.5 (#930) --- CHANGELOG.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02bd5de687..bbade74d26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ ## UNRELEASED +FEATURES: +* CLI + * **BETA** Add `upgrade` command to modify Consul installation on Kubernetes. [[GH-898](https://github.com/hashicorp/consul-k8s/pull/898)] + +IMPROVEMENTS: +* Control Plane + * Bump `consul-k8s-control-plane` UBI images for OpenShift to use base image `ubi-minimal:8.5`: [[GH-922](https://github.com/hashicorp/consul-k8s/pull/922)] + + ## 0.38.0 (December 08, 2021) BREAKING CHANGES: @@ -27,10 +36,6 @@ FEATURES: * Helm * Rename `PartitionExports` CRD to `ExportedServices`. [[GH-902](https://github.com/hashicorp/consul-k8s/pull/902)] -FEATURES: -* CLI - * **BETA** Add `upgrade` command to modify Consul installation on Kubernetes. [[GH-898](https://github.com/hashicorp/consul-k8s/pull/898)] - IMPROVEMENTS: * CLI * Pre-check in the `install` command to verify the correct license secret exists when using an enterprise Consul image. [[GH-875](https://github.com/hashicorp/consul-k8s/pull/875)] From ff83358ee49ac7e880dce2533e626b4c00f3c7f2 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Mon, 13 Dec 2021 16:26:38 -0800 Subject: [PATCH 197/418] Revert go mod changes from #917 (#928) * And skip vault test if PSPs are enabled. Support for that will be added later. --- acceptance/go.mod | 2 + acceptance/go.sum | 233 ++++++++++++++++++++++++++- acceptance/tests/vault/vault_test.go | 3 + 3 files changed, 234 insertions(+), 4 deletions(-) diff --git a/acceptance/go.mod b/acceptance/go.mod index db655d76b3..f91df929e2 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -70,6 +70,8 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/oklog/run v1.0.0 // indirect + github.com/onsi/ginkgo v1.16.4 // indirect + github.com/onsi/gomega v1.15.0 // indirect github.com/pierrec/lz4 v2.5.2+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/acceptance/go.sum b/acceptance/go.sum index c082349208..3459220dc4 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -17,6 +17,7 @@ cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNF cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -26,8 +27,11 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v44.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= @@ -42,6 +46,7 @@ github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMl github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= +github.com/Azure/go-autorest/autorest/azure/auth v0.5.0/go.mod h1:QRTvSZQpxqm8mSErhnbI+tANIBAKP7B+UIE2z4ypUO0= github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4= github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= @@ -54,6 +59,7 @@ github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935 github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= +github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= @@ -69,14 +75,19 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= @@ -91,19 +102,29 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.30.27 h1:9gPjZWVDSoQrBO2AvqrWObS6KAZByfEJxQoCYo4ZfK0= github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= +github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= 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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -113,7 +134,11 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -125,26 +150,37 @@ github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/denverdino/aliyungo v0.0.0-20170926055100-d3308649c661/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/digitalocean/godo v1.7.5/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= +github.com/digitalocean/godo v1.10.0/go.mod h1:h6faOIcZ8lWIwNQ+DN7b3CgX4Kwby5T+nbpNqkUIozU= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= @@ -171,8 +207,10 @@ github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= @@ -183,6 +221,7 @@ github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc= github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= @@ -193,6 +232,7 @@ github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -205,33 +245,41 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-ldap/ldap/v3 v3.1.3/go.mod h1:3rbOH3jRS2u6jg2rJnKAMLE/xQyCKIveG2Sa/Cohzb8= github.com/go-ldap/ldap/v3 v3.1.10/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= @@ -240,6 +288,7 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -262,8 +311,10 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -279,11 +330,14 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk= +github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= @@ -295,6 +349,7 @@ github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= @@ -302,32 +357,42 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gruntwork-io/gruntwork-cli v0.7.0 h1:YgSAmfCj9c61H+zuvHwKfYUwlMhu5arnQQLM4RH+CYs= github.com/gruntwork-io/gruntwork-cli v0.7.0/go.mod h1:jp6Z7NcLF2avpY8v71fBx6hds9eOFPELSuD/VPv7w00= github.com/gruntwork-io/terratest v0.31.2 h1:xvYHA80MUq5kx670dM18HInewOrrQrAN+XbVVtytUHg= github.com/gruntwork-io/terratest v0.31.2/go.mod h1:EEgJie28gX/4AD71IFqgMj6e99KP5mi81hEtzmDjxTo= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638 h1:z68s6H6O3RjxDmNvou/2/3UBrsJkrMcNzI0IQN5scAM= github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638/go.mod h1:7ZeaiADGbvJDuoWAT8UKj6KCcLsFUk+34OkUGMVtdXg= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= @@ -338,10 +403,12 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f/go.mod h1:D4eo8/CN92vm9/9UDG+ldX1/fMFa4kpl8qzyTolus8o= github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -351,6 +418,7 @@ github.com/hashicorp/go-immutable-radix v1.3.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjh github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI= +github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 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= @@ -361,6 +429,7 @@ github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY= 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= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= @@ -379,6 +448,7 @@ github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= @@ -386,12 +456,16 @@ github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= github.com/hashicorp/serf v0.9.6 h1:uuEX1kLR6aoda1TBttmJQKDLZE1Ob7KN0NPdE7EtCDc= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= @@ -402,21 +476,32 @@ github.com/hashicorp/vault/api v1.2.0/go.mod h1:dAjw0T5shMnrfH7Q/Mst+LrcTKvStZBV github.com/hashicorp/vault/sdk v0.1.14-0.20200519221530-14615acda45f/go.mod h1:WX57W2PwkrOPQ6rVQk+dy5/htHIaB4aBM70EwKThu10= github.com/hashicorp/vault/sdk v0.2.1 h1:S4O6Iv/dyKlE9AUTXGa7VOvZmsCvg36toPKgV4f2P4M= github.com/hashicorp/vault/sdk v0.2.1/go.mod h1:WfUiO1vYzfBkz1TmoE4ZGU7HD0T0Cl/rZwaxjBkgN4U= +github.com/hashicorp/vic v1.5.1-0.20190403131502-bbfe86ec9443/go.mod h1:bEpDU35nTu0ey1EXjwNwPjI9xErAsoOCmcMb9GKvyxo= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M= github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= +github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= +github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/joyent/triton-go v0.0.0-20180628001255-830d2b111e62/go.mod h1:U+RSyWxWd04xTqnuOQxnai7XGS2PrPY2cfGoDKtMHjA= +github.com/joyent/triton-go v1.7.1-0.20200416154420-6801d15b779f/go.mod h1:KDSfL7qe5ZfQqvlDMkVjCztbmcpp/c8M77vhQP8ZPvk= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -427,13 +512,16 @@ github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMW github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -444,11 +532,15 @@ github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/linode/linodego v0.7.1/go.mod h1:ga11n3ivecUrPCHN0rANxKmfWBJVkOXfLMZinAbj2sY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -463,10 +555,13 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY= @@ -475,6 +570,7 @@ github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceT github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -482,6 +578,8 @@ github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eI github.com/mitchellh/go-testing-interface v1.14.0 h1:/x0XQ6h+3U3nAyk1yx+bHPURrKa9sVVvYbuqZ7pIAtI= github.com/mitchellh/go-testing-interface v1.14.0/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= @@ -494,6 +592,7 @@ github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8 github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -505,33 +604,40 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2/go.mod h1:TLb2Sg7HQcgGdloNxkrmtgDNR9uVYF3lfdFIN4Ro6Sk= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.0-20180130162743-b8a9be070da4/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= +github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -539,7 +645,9 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= +github.com/packethost/packngo v0.1.1-0.20180711074735-b9cb5096f54c/go.mod h1:otzZQXgoO96RTzDB/Hycg0qZcXZsWJGJRSXbmEIJ+4M= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -563,25 +671,40 @@ github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03/go.mod h1:gRAiPF5C5Nd0eyyRdqIu9qTiFSoZzpTq727b5B8fkkU= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rs/zerolog v1.4.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -591,21 +714,35 @@ github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkB github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sean-/conswriter v0.0.0-20180208195008-f5ae3917a627/go.mod h1:7zjs06qF79/FKAJpBvFx3P8Ww4UTIMAe+lpNXDHziac= +github.com/sean-/pager v0.0.0-20180208200047-666be9bf53b5/go.mod h1:BeybITEsBEg6qbIiqJ6/Bqeq25bCLbL7YFmpaFfJDuM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -614,6 +751,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -624,12 +763,18 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible/go.mod h1:0PfYow01SHPMhKY31xa+EFz2RStxIqj6JFAJS+IkCi4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -637,26 +782,54 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= +github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= +go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= +go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= +go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= +go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= +go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= +go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= +go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= +go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -668,6 +841,7 @@ golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -711,6 +885,7 @@ golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -720,6 +895,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -738,15 +914,19 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -762,12 +942,14 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -782,6 +964,7 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -796,10 +979,12 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -811,19 +996,27 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 h1:c8PlLMqBbOHoqtjteWm5/kbe6rNY2pbRfbIMVnepueo= @@ -846,6 +1039,7 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -858,6 +1052,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= @@ -873,6 +1068,8 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -891,8 +1088,10 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= @@ -901,6 +1100,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= @@ -940,6 +1140,8 @@ google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4 google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -949,6 +1151,7 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= @@ -959,6 +1162,9 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -991,6 +1197,7 @@ gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -1003,6 +1210,7 @@ gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1015,6 +1223,7 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1022,42 +1231,53 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs= k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= +k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= +k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= +k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM= k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= +k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= +k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= @@ -1069,10 +1289,15 @@ modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/controller-runtime v0.10.2/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index e19e196c84..459ffb53f8 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -57,6 +57,9 @@ path "pki/cert/ca" { // It then configures Consul to use vault as the backend and checks that it works. func TestVault(t *testing.T) { cfg := suite.Config() + if cfg.EnablePodSecurityPolicies { + t.Skipf("skipping this test because PSPs don't yet work with the acceptance test Vault installation") + } ctx := suite.Environment().DefaultContext(t) ns := ctx.KubectlOptions(t).Namespace From e3ad99e66ff23ab9192245d548b33a325ced2cce Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 14 Dec 2021 09:33:35 -0800 Subject: [PATCH 198/418] Support annotation service-tags: $POD_NAME (#931) Support the annotation ``` consul.hashicorp.com/service-tags: $POD_NAME ``` Where $POD_NAME will be replaced with the Pod's name. This mimics support we had before the endpoints controller where environment variable were interpolated for tags. This PR only supports $POD_NAME for now because it's the only environment variable we've been asked to support. --- CHANGELOG.md | 3 +- .../connect-inject/endpoints_controller.go | 44 ++++++++++++------- .../endpoints_controller_test.go | 8 ++-- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bbade74d26..4a287c4bf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ FEATURES: IMPROVEMENTS: * Control Plane - * Bump `consul-k8s-control-plane` UBI images for OpenShift to use base image `ubi-minimal:8.5`: [[GH-922](https://github.com/hashicorp/consul-k8s/pull/922)] + * Bump `consul-k8s-control-plane` UBI images for OpenShift to use base image `ubi-minimal:8.5`. [[GH-922](https://github.com/hashicorp/consul-k8s/pull/922)] + * Support the value `$POD_NAME` for the annotation `consul.hashicorp.com/service-tags` that will now be interpolated and set to the pod name. [[GH-931](https://github.com/hashicorp/consul-k8s/pull/931)] ## 0.38.0 (December 08, 2021) diff --git a/control-plane/connect-inject/endpoints_controller.go b/control-plane/connect-inject/endpoints_controller.go index 78b1748d4b..1712967308 100644 --- a/control-plane/connect-inject/endpoints_controller.go +++ b/control-plane/connect-inject/endpoints_controller.go @@ -416,15 +416,7 @@ func (r *EndpointsController) createServiceRegistrations(pod corev1.Pod, service meta[strings.TrimPrefix(k, annotationMeta)] = v } } - - var tags []string - if raw, ok := pod.Annotations[annotationTags]; ok && raw != "" { - tags = strings.Split(raw, ",") - } - // Get the tags from the deprecated tags annotation and combine. - if raw, ok := pod.Annotations[annotationConnectTags]; ok && raw != "" { - tags = append(tags, strings.Split(raw, ",")...) - } + tags := consulTags(pod) service := &api.AgentServiceRegistration{ ID: serviceID, @@ -433,9 +425,7 @@ func (r *EndpointsController) createServiceRegistrations(pod corev1.Pod, service Address: pod.Status.PodIP, Meta: meta, Namespace: r.consulNamespace(pod.Namespace), - } - if len(tags) > 0 { - service.Tags = tags + Tags: tags, } proxyServiceName := getProxyServiceName(pod, serviceEndpoints) @@ -496,9 +486,7 @@ func (r *EndpointsController) createServiceRegistrations(pod corev1.Pod, service AliasService: serviceID, }, }, - } - if len(tags) > 0 { - proxyService.Tags = tags + Tags: tags, } // A user can enable/disable tproxy for an entire namespace. @@ -1034,3 +1022,29 @@ func isLabeledIgnore(labels map[string]string) bool { return shouldIgnore && labelExists && err == nil } + +// consulTags returns tags that should be added to the Consul service and proxy registrations. +func consulTags(pod corev1.Pod) []string { + var tags []string + if raw, ok := pod.Annotations[annotationTags]; ok && raw != "" { + tags = strings.Split(raw, ",") + } + // Get the tags from the deprecated tags annotation and combine. + if raw, ok := pod.Annotations[annotationConnectTags]; ok && raw != "" { + tags = append(tags, strings.Split(raw, ",")...) + } + + var interpolatedTags []string + for _, t := range tags { + // Support light interpolation to preserve backwards compatibility where tags could + // be environment variables. + // Right now the only string we interpolate is $POD_NAME since that's all + // users have asked for as of now. More can be added here in the future. + if t == "$POD_NAME" { + t = pod.Name + } + interpolatedTags = append(interpolatedTags, t) + } + + return interpolatedTags +} diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index de021ec198..846c1c434e 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -886,8 +886,8 @@ func TestReconcileCreateEndpoint(t *testing.T) { pod1.Annotations[annotationService] = "different-consul-svc-name" pod1.Annotations[fmt.Sprintf("%sname", annotationMeta)] = "abc" pod1.Annotations[fmt.Sprintf("%sversion", annotationMeta)] = "2" - pod1.Annotations[annotationTags] = "abc,123" - pod1.Annotations[annotationConnectTags] = "def,456" + pod1.Annotations[annotationTags] = "abc,123,$POD_NAME" + pod1.Annotations[annotationConnectTags] = "def,456,$POD_NAME" pod1.Annotations[annotationUpstreams] = "upstream1:1234" pod1.Annotations[annotationEnableMetrics] = "true" pod1.Annotations[annotationPrometheusScrapePort] = "12345" @@ -930,7 +930,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { MetaKeyKubeNS: "default", MetaKeyManagedBy: managedByValue, }, - ServiceTags: []string{"abc", "123", "def", "456"}, + ServiceTags: []string{"abc", "123", "pod1", "def", "456", "pod1"}, }, }, expectedProxySvcInstances: []*api.CatalogService{ @@ -963,7 +963,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { MetaKeyKubeNS: "default", MetaKeyManagedBy: managedByValue, }, - ServiceTags: []string{"abc", "123", "def", "456"}, + ServiceTags: []string{"abc", "123", "pod1", "def", "456", "pod1"}, }, }, expectedAgentHealthChecks: []*api.AgentCheck{ From 1c07e5b83b1851756aa362c2713f58af4295dd29 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 15 Dec 2021 17:12:43 -0500 Subject: [PATCH 199/418] support Consul 1.11.1 (#935) --- .circleci/config.yml | 4 ++-- CHANGELOG.md | 6 +++++- acceptance/go.mod | 6 +++--- acceptance/go.sum | 14 ++++++-------- .../tests/controller/controller_namespaces_test.go | 2 -- acceptance/tests/partitions/partitions_test.go | 6 ------ charts/consul/Chart.yaml | 12 ++++++------ charts/consul/templates/server-statefulset.yaml | 4 ---- .../test/unit/ingress-gateways-deployment.bats | 2 +- .../consul/test/unit/mesh-gateway-deployment.bats | 2 +- charts/consul/test/unit/server-statefulset.bats | 9 --------- .../test/unit/terminating-gateways-deployment.bats | 2 +- charts/consul/test/unit/ui-ingress.bats | 13 ------------- charts/consul/values.yaml | 6 +++--- cli/go.mod | 6 +++--- cli/go.sum | 10 ++++++---- control-plane/go.mod | 7 +++---- control-plane/go.sum | 12 ++++++------ .../subcommand/consul-sidecar/command_test.go | 8 ++++---- .../create-federation-secret/command_test.go | 2 +- .../get-consul-client-ca/command_test.go | 2 +- .../subcommand/server-acl-init/command_test.go | 2 +- docs/admin-partitions-with-acls.md | 4 ++-- 23 files changed, 55 insertions(+), 86 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index da32949865..8a9d7d8fb5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,8 +9,8 @@ executors: - image: docker.mirror.hashicorp.services/cimg/go:1.17.5 environment: TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.11.0-rc # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.11.0+ent-rc # Consul's enterprise version to use in tests + CONSUL_VERSION: 1.11.1 # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.1+ent # Consul's enterprise version to use in tests control-plane-path : &control-plane-path control-plane cli-path : &cli-path cli diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a287c4bf1..7e9a68a6ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ ## UNRELEASED FEATURES: +* Helm + * Support Consul 1.11.1. [[GH-935](https://github.com/hashicorp/consul-k8s/pull/935)] + * Support Envoy 1.20.0. [[GH-935](https://github.com/hashicorp/consul-k8s/pull/935)] + * Minimum Kubernetes versions supported is 1.18+. [[GH-935](https://github.com/hashicorp/consul-k8s/pull/935)] * CLI * **BETA** Add `upgrade` command to modify Consul installation on Kubernetes. [[GH-898](https://github.com/hashicorp/consul-k8s/pull/898)] @@ -27,7 +31,7 @@ FEATURES: Requirements: * Consul 1.11+ - * Vault 1.19+ and Vault-K8s 0.14+ must be installed with the Vault Agent Injector enabled (`injector.enabled=true`) + * Vault 1.9+ and Vault-K8s 0.14+ must be installed with the Vault Agent Injector enabled (`injector.enabled=true`) into the Kubernetes cluster that Consul is installed into. * `global.tls.enableAutoEncryption=true` is required for TLS support. * If TLS is enabled in Vault, `global.secretsBackend.vault.ca` must be provided and should reference a Kube secret diff --git a/acceptance/go.mod b/acceptance/go.mod index f91df929e2..3c31530573 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -5,8 +5,8 @@ go 1.17 require ( github.com/gruntwork-io/terratest v0.31.2 github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638 - github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc - github.com/hashicorp/consul/sdk v0.8.0 + github.com/hashicorp/consul/api v1.12.0 + github.com/hashicorp/consul/sdk v0.9.0 github.com/hashicorp/vault/api v1.2.0 github.com/stretchr/testify v1.7.0 gopkg.in/yaml.v2 v2.4.0 @@ -83,7 +83,7 @@ require ( github.com/urfave/cli v1.22.2 // indirect go.uber.org/atomic v1.7.0 // indirect golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect - golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect + golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect diff --git a/acceptance/go.sum b/acceptance/go.sum index 3459220dc4..1953df0322 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -387,15 +387,12 @@ github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638 github.com/hashicorp/consul-k8s/control-plane v0.0.0-20211207212234-aea9efea5638/go.mod h1:7ZeaiADGbvJDuoWAT8UKj6KCcLsFUk+34OkUGMVtdXg= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.10.1-0.20211116182834-e6956893fb6f/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/api v1.12.0 h1:k3y1FYv6nuKyNTqj6w9gXOx5r5CfLj/k/euUeBXj1OY= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= -github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/consul/sdk v0.9.0 h1:NGSHAU7X3yDCjo8WBUbNOtD3BSqv8u0vu3+zNxgmxQI= +github.com/hashicorp/consul/sdk v0.9.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -927,8 +924,9 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/acceptance/tests/controller/controller_namespaces_test.go b/acceptance/tests/controller/controller_namespaces_test.go index b272247db4..b590d05b9e 100644 --- a/acceptance/tests/controller/controller_namespaces_test.go +++ b/acceptance/tests/controller/controller_namespaces_test.go @@ -74,8 +74,6 @@ func TestControllerNamespaces(t *testing.T) { ctx := suite.Environment().DefaultContext(t) helmValues := map[string]string{ - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-rc", - "global.enableConsulNamespaces": "true", "global.adminPartitions.enabled": "true", "controller.enabled": "true", diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 357e2f6d85..9fb8d8b97b 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -36,10 +36,6 @@ func TestPartitions(t *testing.T) { t.Skipf("skipping this test because Admin Partition tests are only supported in Kind for now") } - if cfg.EnableTransparentProxy { - t.Skipf("skipping this test as Transparent Proxy behavior is flaky") - } - const defaultPartition = "default" const secondaryPartition = "secondary" const defaultNamespace = "default" @@ -96,7 +92,6 @@ func TestPartitions(t *testing.T) { serverHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-rc", "global.adminPartitions.enabled": "true", "global.enableConsulNamespaces": "true", @@ -197,7 +192,6 @@ func TestPartitions(t *testing.T) { // Create client cluster. clientHelmValues := map[string]string{ "global.datacenter": "dc1", - "global.image": "hashicorp/consul-enterprise:1.11.0-ent-rc", "global.enabled": "false", "global.tls.enabled": "true", diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index 0057b0780b..45b05331dc 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 name: consul -version: 0.38.0 -appVersion: 1.10.4 -kubeVersion: ">=1.17.0-0" +version: 0.39.0 +appVersion: 1.11.1 +kubeVersion: ">=1.18.0-0" description: Official HashiCorp Consul Chart home: https://www.consul.io icon: https://raw.githubusercontent.com/hashicorp/consul-k8s/main/assets/icon.png @@ -13,11 +13,11 @@ annotations: artifacthub.io/prerelease: false artifacthub.io/images: | - name: consul - image: hashicorp/consul:1.10.4 + image: hashicorp/consul:1.11.1 - name: consul-k8s-control-plane - image: hashicorp/consul-k8s-control-plane:0.38.0 + image: hashicorp/consul-k8s-control-plane:0.39.0 - name: envoy - image: envoyproxy/envoy-alpine:v1.18.4 + image: envoyproxy/envoy-alpine:v1.20.0 artifacthub.io/license: MPL-2.0 artifacthub.io/links: | - name: Documentation diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 6803d2e760..16fae492ef 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -96,12 +96,8 @@ spec: {{ tpl .Values.server.tolerations . | nindent 8 | trim }} {{- end }} {{- if .Values.server.topologySpreadConstraints }} - {{- if and (ge .Capabilities.KubeVersion.Major "1") (ge .Capabilities.KubeVersion.Minor "18") }} topologySpreadConstraints: {{ tpl .Values.server.topologySpreadConstraints . | nindent 8 | trim }} - {{- else }} - {{- fail "`topologySpreadConstraints` requires Kubernetes 1.18 and above." }} - {{- end }} {{- end }} terminationGracePeriodSeconds: 30 serviceAccountName: {{ template "consul.fullname" . }}-server diff --git a/charts/consul/test/unit/ingress-gateways-deployment.bats b/charts/consul/test/unit/ingress-gateways-deployment.bats index ee1ac5f303..c22e325771 100644 --- a/charts/consul/test/unit/ingress-gateways-deployment.bats +++ b/charts/consul/test/unit/ingress-gateways-deployment.bats @@ -83,7 +83,7 @@ load _helpers --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -s -r '.[0].spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "envoyproxy/envoy-alpine:v1.18.4" ] + [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.0" ] } @test "ingressGateways/Deployment: envoy image can be set using the global value" { diff --git a/charts/consul/test/unit/mesh-gateway-deployment.bats b/charts/consul/test/unit/mesh-gateway-deployment.bats index f1af2fc2b2..37464b9676 100755 --- a/charts/consul/test/unit/mesh-gateway-deployment.bats +++ b/charts/consul/test/unit/mesh-gateway-deployment.bats @@ -335,7 +335,7 @@ key2: value2' \ --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "envoyproxy/envoy-alpine:v1.18.4" ] + [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.0" ] } @test "meshGateway/Deployment: setting meshGateway.imageEnvoy fails" { diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 15c03711db..c1d260e296 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -788,15 +788,6 @@ load _helpers . | tee /dev/stderr | yq '.spec.template.spec.topologySpreadConstraints == "foobar"' | tee /dev/stderr) [ "${actual}" = "true" ] - - # todo: test for Kube versions < 1.18 when helm supports --kube-version flag (https://github.com/helm/helm/pull/9040) - # not supported before 1.18 - # run helm template \ - # -s templates/server-statefulset.yaml \ - # --kube-version "1.17" \ - # . - # [ "$status" -eq 1 ] - # [[ "$output" =~ "`topologySpreadConstraints` requires Kubernetes 1.18 and above." ]] } #-------------------------------------------------------------------- diff --git a/charts/consul/test/unit/terminating-gateways-deployment.bats b/charts/consul/test/unit/terminating-gateways-deployment.bats index e0bbdcd0a4..39f2649270 100644 --- a/charts/consul/test/unit/terminating-gateways-deployment.bats +++ b/charts/consul/test/unit/terminating-gateways-deployment.bats @@ -83,7 +83,7 @@ load _helpers --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -s -r '.[0].spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "envoyproxy/envoy-alpine:v1.18.4" ] + [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.0" ] } @test "terminatingGateways/Deployment: envoy image can be set using the global value" { diff --git a/charts/consul/test/unit/ui-ingress.bats b/charts/consul/test/unit/ui-ingress.bats index aaa4e56653..005236be57 100755 --- a/charts/consul/test/unit/ui-ingress.bats +++ b/charts/consul/test/unit/ui-ingress.bats @@ -278,16 +278,3 @@ load _helpers yq -r '.spec.ingressClassName' | tee /dev/stderr) [ "${actual}" = "nginx" ] } - -@test "ui/Ingress: cannot set ingressClassName for Kube version < 1.18" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/ui-ingress.yaml \ - --set 'ui.ingress.enabled=true' \ - --set 'ui.ingress.ingressClassName=nginx' \ - --kube-version "1.17" \ - . | tee /dev/stderr | - yq -r '.spec.ingressClassName' | tee /dev/stderr) - [ "${actual}" = "null" ] -} - diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 7cf9156fbf..800c640528 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -85,7 +85,7 @@ global: # image: "hashicorp/consul-enterprise:1.10.0-ent" # ``` # @default: hashicorp/consul: - image: "hashicorp/consul:1.10.4" + image: "hashicorp/consul:1.11.1" # Array of objects containing image pull secret names that will be applied to each service account. # This can be used to reference image pull secrets if using a custom consul or consul-k8s-control-plane Docker image. @@ -105,7 +105,7 @@ global: # image that is used for functionality such as catalog sync. # This can be overridden per component. # @default: hashicorp/consul-k8s-control-plane: - imageK8S: "hashicorp/consul-k8s-control-plane:0.38.0" + imageK8S: "hashicorp/consul-k8s-control-plane:0.39.0" # The name of the datacenter that the agents should # register as. This can't be changed once the Consul cluster is up and running @@ -444,7 +444,7 @@ global: # connect-injected sidecar proxies and mesh, terminating, and ingress gateways. # See https://www.consul.io/docs/connect/proxies/envoy for full compatibility matrix between Consul and Envoy. # @default: envoyproxy/envoy-alpine: - imageEnvoy: "envoyproxy/envoy-alpine:v1.18.4" + imageEnvoy: "envoyproxy/envoy-alpine:v1.20.0" # Configuration for running this Helm chart on the Red Hat OpenShift platform. # This Helm chart currently supports OpenShift v4.x+. diff --git a/cli/go.mod b/cli/go.mod index 3bb781f2e2..b4558e3de0 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -131,12 +131,12 @@ require ( go.opencensus.io v0.22.3 // indirect go.starlark.net v0.0.0-20200707032745-474f21a9602d // indirect golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect - golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 // indirect + golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect - golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect + golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.4 // indirect + golang.org/x/text v0.3.6 // indirect golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect google.golang.org/appengine v1.6.5 // indirect google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect diff --git a/cli/go.sum b/cli/go.sum index bd14d14daa..56e60df33e 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -887,8 +887,9 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -957,9 +958,9 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20211013075003-97ac67df715c h1:taxlMj0D/1sOAuv/CbSD+MMDof2vbyPTqz5FNYKpXt8= -golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= @@ -969,8 +970,9 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/control-plane/go.mod b/control-plane/go.mod index 2e1a81424b..93e5bc5c77 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -6,8 +6,8 @@ require ( github.com/go-logr/logr v0.4.0 github.com/google/go-cmp v0.5.6 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc - github.com/hashicorp/consul/sdk v0.8.0 + github.com/hashicorp/consul/api v1.12.0 + github.com/hashicorp/consul/sdk v0.9.0 github.com/hashicorp/go-discover v0.0.0-20200812215701-c4b85f6ed31f github.com/hashicorp/go-hclog v0.16.1 github.com/hashicorp/go-multierror v1.1.0 @@ -83,7 +83,6 @@ require ( github.com/mattn/go-isatty v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/miekg/dns v1.1.41 // indirect - github.com/mitchellh/go-testing-interface v1.14.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/nicolai86/scaleway-sdk v1.10.2-0.20180628010248-798f60e20bb2 // indirect @@ -106,7 +105,7 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect - golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect + golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect diff --git a/control-plane/go.sum b/control-plane/go.sum index 6877dd034c..879cb915bf 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -297,11 +297,12 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc h1:tUgL1cinAFDtidyKqgsJzlxLkEi9atLmN6j8kgCr17Q= -github.com/hashicorp/consul/api v1.10.1-0.20211206193229-9b44861ce4bc/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= +github.com/hashicorp/consul/api v1.12.0 h1:k3y1FYv6nuKyNTqj6w9gXOx5r5CfLj/k/euUeBXj1OY= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.8.0 h1:OJtKBtEjboEZvG6AOUdh4Z1Zbyu0WcxQ0qatRrZHTVU= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= +github.com/hashicorp/consul/sdk v0.9.0 h1:NGSHAU7X3yDCjo8WBUbNOtD3BSqv8u0vu3+zNxgmxQI= +github.com/hashicorp/consul/sdk v0.9.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -433,8 +434,6 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.14.0 h1:/x0XQ6h+3U3nAyk1yx+bHPURrKa9sVVvYbuqZ7pIAtI= -github.com/mitchellh/go-testing-interface v1.14.0/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= @@ -718,8 +717,9 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= +golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= diff --git a/control-plane/subcommand/consul-sidecar/command_test.go b/control-plane/subcommand/consul-sidecar/command_test.go index 370b4afd8f..53008ffab9 100644 --- a/control-plane/subcommand/consul-sidecar/command_test.go +++ b/control-plane/subcommand/consul-sidecar/command_test.go @@ -91,7 +91,7 @@ func TestRunSignalHandlingMetricsOnly(t *testing.T) { UI: ui, } - randomPorts := freeport.MustTake(1) + randomPorts := freeport.GetN(t, 1) // Run async because we need to kill it when the test is over. exitChan := runCommandAsynchronously(&cmd, []string{ "-enable-service-registration=false", @@ -163,7 +163,7 @@ func TestRunSignalHandlingAllProcessesEnabled(t *testing.T) { require.NoError(t, err) - randomPorts := freeport.MustTake(1) + randomPorts := freeport.GetN(t, 1) // Run async because we need to kill it when the test is over. exitChan := runCommandAsynchronously(&cmd, []string{ "-service-config", configFile, @@ -301,7 +301,7 @@ func TestMergedMetricsServer(t *testing.T) { for _, c := range cases { t.Run(c.name, func(t *testing.T) { - randomPorts := freeport.MustTake(2) + randomPorts := freeport.GetN(t, 2) ui := cli.NewMockUi() cmd := Command{ UI: ui, @@ -485,7 +485,7 @@ func TestRun_ServicesRegistration_ConsulDown(t *testing.T) { // we need to reserve all 6 ports to avoid potential // port collisions with other tests - randomPorts := freeport.MustTake(6) + randomPorts := freeport.GetN(t, 6) // Run async because we need to kill it when the test is over. exitChan := runCommandAsynchronously(&cmd, []string{ diff --git a/control-plane/subcommand/create-federation-secret/command_test.go b/control-plane/subcommand/create-federation-secret/command_test.go index 607599a27e..3a28594f18 100644 --- a/control-plane/subcommand/create-federation-secret/command_test.go +++ b/control-plane/subcommand/create-federation-secret/command_test.go @@ -944,7 +944,7 @@ func TestRun_ConsulClientDelay(t *testing.T) { // We need to reserve all 6 ports to avoid potential // port collisions with other tests. - randomPorts := freeport.MustTake(6) + randomPorts := freeport.GetN(t, 6) caFile, certFile, keyFile := test.GenerateServerCerts(t) // Create fake k8s. diff --git a/control-plane/subcommand/get-consul-client-ca/command_test.go b/control-plane/subcommand/get-consul-client-ca/command_test.go index 2f9fb4de43..8655465771 100644 --- a/control-plane/subcommand/get-consul-client-ca/command_test.go +++ b/control-plane/subcommand/get-consul-client-ca/command_test.go @@ -139,7 +139,7 @@ func TestRun_ConsulServerAvailableLater(t *testing.T) { UI: ui, } - randomPorts := freeport.MustTake(6) + randomPorts := freeport.GetN(t, 6) // Start the consul agent asynchronously var a *testutil.TestServer diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index 0336ba366d..efcfaacac0 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -1169,7 +1169,7 @@ func TestRun_DelayedServers(t *testing.T) { require := require.New(t) k8s := fake.NewSimpleClientset() - randomPorts := freeport.MustTake(6) + randomPorts := freeport.GetN(t, 6) ui := cli.NewMockUi() cmd := Command{ diff --git a/docs/admin-partitions-with-acls.md b/docs/admin-partitions-with-acls.md index 8c9cf06c38..fb282fa38d 100644 --- a/docs/admin-partitions-with-acls.md +++ b/docs/admin-partitions-with-acls.md @@ -6,7 +6,7 @@ global: enableConsulNamespaces: true tls: enabled: true - image: hashicorp/consul-enterprise:1.11.0-ent-beta1 + image: hashicorp/consul-enterprise:1.11.1 adminPartitions: enabled: true acls: @@ -56,7 +56,7 @@ Configure the workload cluster using the following: global: enabled: false enableConsulNamespaces: true - image: hashicorp/consul-enterprise:1.11.0-ent-beta1 + image: hashicorp/consul-enterprise:1.11.1 adminPartitions: enabled: true name: "partition-name" From b072ad47bb833f1cf7ba95137201ba235a1fbd51 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Wed, 15 Dec 2021 22:44:04 +0000 Subject: [PATCH 200/418] Release v0.39.0 --- CHANGELOG.md | 2 +- cli/version/version.go | 4 ++-- control-plane/version/version.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e9a68a6ab..e24de4969a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.39.0 (December 15, 2021) FEATURES: * Helm diff --git a/cli/version/version.go b/cli/version/version.go index 44f7aca672..05e070223c 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.38.0" + Version = "0.39.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 44f7aca672..05e070223c 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.38.0" + Version = "0.39.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 0b37275c241056ac81b8f37eec131132df181f1c Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Wed, 15 Dec 2021 23:04:16 +0000 Subject: [PATCH 201/418] Putting source back into Dev Mode --- CHANGELOG.md | 2 ++ cli/version/version.go | 2 +- control-plane/version/version.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e24de4969a..66de91324f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## UNRELEASED + ## 0.39.0 (December 15, 2021) FEATURES: diff --git a/cli/version/version.go b/cli/version/version.go index 05e070223c..9f9594da46 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 05e070223c..9f9594da46 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 434f4bdc559cd5e0e2a461886337e215a99b1c6c Mon Sep 17 00:00:00 2001 From: David Yu Date: Mon, 3 Jan 2022 15:04:12 -0800 Subject: [PATCH 202/418] CONTRIBUTING: small typo for consul-k8s-control-plane binary (#946) * CONTRIBUTING: small typo for consul-k8s-control-plane binary * Update README.md with link to chart --- CONTRIBUTING.md | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f63ebdf5b4..2fe51207ae 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,7 +28,7 @@ ### Building and running `consul-k8s-control-plane` -To build and install the control plane binary `consul-k8s` locally, Go version 1.17.0+ is required. +To build and install the control plane binary `consul-k8s-control-plane` locally, Go version 1.17.0+ is required. You will also need to install the Docker engine: - [Docker for Mac](https://docs.docker.com/engine/installation/mac/) @@ -47,7 +47,7 @@ Change directories into the appropriate folder: $ cd control-plane ``` -To compile the `consul-k8s` binary for your local machine: +To compile the `consul-k8s-control-plane` binary for your local machine: ```shell $ make dev diff --git a/README.md b/README.md index f1be598922..b0767f1405 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ by contacting us at [security@hashicorp.com](mailto:security@hashicorp.com). ## Helm -Within the 'charts/consul' directory is the official HashiCorp Helm chart for installing +Within the ['charts/consul'](charts/consul) directory is the official HashiCorp Helm chart for installing and configuring Consul on Kubernetes. This chart supports multiple use cases of Consul on Kubernetes, depending on the values provided. From ac94f627c438b53594894c6adb4a82894bf12176 Mon Sep 17 00:00:00 2001 From: Lord-Y Date: Tue, 21 Dec 2021 15:16:16 +0100 Subject: [PATCH 203/418] [charts/consul] - Enable terminationGracePeriodSeconds customization Signed-off-by: Lord-Y --- .../ingress-gateways-deployment.yaml | 2 +- .../unit/ingress-gateways-deployment.bats | 28 ++++++++++++++++++- charts/consul/values.yaml | 3 ++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/charts/consul/templates/ingress-gateways-deployment.yaml b/charts/consul/templates/ingress-gateways-deployment.yaml index 5b8c8dc4b7..8d0ba09cdb 100644 --- a/charts/consul/templates/ingress-gateways-deployment.yaml +++ b/charts/consul/templates/ingress-gateways-deployment.yaml @@ -88,7 +88,7 @@ spec: tolerations: {{ tpl (default $defaults.tolerations .tolerations) $root | nindent 8 | trim }} {{- end }} - terminationGracePeriodSeconds: 10 + terminationGracePeriodSeconds: {{ default $defaults.terminationGracePeriodSeconds .terminationGracePeriodSeconds }} serviceAccountName: {{ template "consul.fullname" $root }}-{{ .name }} volumes: - name: consul-bin diff --git a/charts/consul/test/unit/ingress-gateways-deployment.bats b/charts/consul/test/unit/ingress-gateways-deployment.bats index c22e325771..1a4d184bfc 100644 --- a/charts/consul/test/unit/ingress-gateways-deployment.bats +++ b/charts/consul/test/unit/ingress-gateways-deployment.bats @@ -1609,4 +1609,30 @@ EOF [ "${actual}" = "ca" ] local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') [ "${actual}" = "/vault/custom/tls.crt" ] -} \ No newline at end of file +} + +#-------------------------------------------------------------------- +# terminationGracePeriodSeconds + +@test "ingressGateways/Deployment: terminationGracePeriodSeconds defaults to 10" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq -s -r '.[0].spec.template.spec.terminationGracePeriodSeconds' | tee /dev/stderr) + [ "${actual}" = "10" ] +} + +@test "ingressGateways/Deployment: terminationGracePeriodSeconds set defaults to 30" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'ingressGateways.defaults.terminationGracePeriodSeconds=30' \ + . | tee /dev/stderr | + yq -s -r '.[0].spec.template.spec.terminationGracePeriodSeconds' | tee /dev/stderr) + [ "${actual}" = "30" ] +} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 800c640528..ffb3e2247d 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2304,6 +2304,9 @@ ingressGateways: # Optional priorityClassName. priorityClassName: "" + # Amount of seconds to wait before killing the pod + terminationGracePeriodSeconds: 10 + # Annotations to apply to the ingress gateway deployment. Annotations defined # here will be applied to all ingress gateway deployments in addition to any # annotations defined for a specific gateway in `ingressGateways.gateways`. From fb466d42f240985f82dcee0aa37c018d87bdd6e7 Mon Sep 17 00:00:00 2001 From: Lord-Y Date: Wed, 22 Dec 2021 10:57:39 +0100 Subject: [PATCH 204/418] [charts/consul] - Update terminationGracePeriodSeconds test Signed-off-by: Lord-Y --- charts/consul/test/unit/ingress-gateways-deployment.bats | 7 +++++-- charts/consul/values.yaml | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/charts/consul/test/unit/ingress-gateways-deployment.bats b/charts/consul/test/unit/ingress-gateways-deployment.bats index 1a4d184bfc..2fd08a35f3 100644 --- a/charts/consul/test/unit/ingress-gateways-deployment.bats +++ b/charts/consul/test/unit/ingress-gateways-deployment.bats @@ -1614,7 +1614,7 @@ EOF #-------------------------------------------------------------------- # terminationGracePeriodSeconds -@test "ingressGateways/Deployment: terminationGracePeriodSeconds defaults to 10" { +@test "ingressGateways/Deployment: can set terminationGracePeriodSeconds through defaults" { cd `chart_dir` local actual=$(helm template \ -s templates/ingress-gateways-deployment.yaml \ @@ -1625,12 +1625,15 @@ EOF [ "${actual}" = "10" ] } -@test "ingressGateways/Deployment: terminationGracePeriodSeconds set defaults to 30" { +@test "ingressGateways/Deployment: can set terminationGracePeriodSeconds through specific gateway overriding defaults" { cd `chart_dir` local actual=$(helm template \ -s templates/ingress-gateways-deployment.yaml \ --set 'ingressGateways.enabled=true' \ --set 'connectInject.enabled=true' \ + --set 'ingressGateways.defaults.replicas=3' \ + --set 'ingressGateways.gateways[0].name=gateway1' \ + --set 'ingressGateways.gateways[0].replicas=12' \ --set 'ingressGateways.defaults.terminationGracePeriodSeconds=30' \ . | tee /dev/stderr | yq -s -r '.[0].spec.template.spec.terminationGracePeriodSeconds' | tee /dev/stderr) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index ffb3e2247d..c97aef15ce 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2304,7 +2304,7 @@ ingressGateways: # Optional priorityClassName. priorityClassName: "" - # Amount of seconds to wait before killing the pod + # Amount of seconds to wait for graceful termination before killing the pod. terminationGracePeriodSeconds: 10 # Annotations to apply to the ingress gateway deployment. Annotations defined From b6324266097834a700c85b6706b203f4be455274 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Tue, 4 Jan 2022 09:43:05 -0800 Subject: [PATCH 205/418] charts/consul: update tests and changelog for #938 by @Lord-Y --- CHANGELOG.md | 3 +++ .../unit/ingress-gateways-deployment.bats | 19 +++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66de91324f..17f3b4d878 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ ## UNRELEASED +IMPROVEMENTS: +* Helm + * Allow customization of `terminationGracePeriodSeconds` on the ingress gateways. [[GH-947](https://github.com/hashicorp/consul-k8s/pull/947)] ## 0.39.0 (December 15, 2021) diff --git a/charts/consul/test/unit/ingress-gateways-deployment.bats b/charts/consul/test/unit/ingress-gateways-deployment.bats index 2fd08a35f3..b72819c8ff 100644 --- a/charts/consul/test/unit/ingress-gateways-deployment.bats +++ b/charts/consul/test/unit/ingress-gateways-deployment.bats @@ -1614,7 +1614,7 @@ EOF #-------------------------------------------------------------------- # terminationGracePeriodSeconds -@test "ingressGateways/Deployment: can set terminationGracePeriodSeconds through defaults" { +@test "ingressGateways/Deployment: terminationGracePeriodSeconds defaults to 10" { cd `chart_dir` local actual=$(helm template \ -s templates/ingress-gateways-deployment.yaml \ @@ -1625,16 +1625,27 @@ EOF [ "${actual}" = "10" ] } +@test "ingressGateways/Deployment: terminationGracePeriodSeconds can be set through defaults" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'ingressGateways.defaults.terminationGracePeriodSeconds=5' \ + . | tee /dev/stderr | + yq -s -r '.[0].spec.template.spec.terminationGracePeriodSeconds' | tee /dev/stderr) + [ "${actual}" = "5" ] +} + @test "ingressGateways/Deployment: can set terminationGracePeriodSeconds through specific gateway overriding defaults" { cd `chart_dir` local actual=$(helm template \ -s templates/ingress-gateways-deployment.yaml \ --set 'ingressGateways.enabled=true' \ --set 'connectInject.enabled=true' \ - --set 'ingressGateways.defaults.replicas=3' \ + --set 'ingressGateways.defaults.terminationGracePeriodSeconds=5' \ --set 'ingressGateways.gateways[0].name=gateway1' \ - --set 'ingressGateways.gateways[0].replicas=12' \ - --set 'ingressGateways.defaults.terminationGracePeriodSeconds=30' \ + --set 'ingressGateways.gateways[0].terminationGracePeriodSeconds=30' \ . | tee /dev/stderr | yq -s -r '.[0].spec.template.spec.terminationGracePeriodSeconds' | tee /dev/stderr) [ "${actual}" = "30" ] From 90b61a700f46fee0fc6a65af3526d440c7660758 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Wed, 5 Jan 2022 17:13:01 -0700 Subject: [PATCH 206/418] Bump k8s versions (#950) --- .circleci/config.yml | 35 ++++++++---------------- README.md | 4 +-- charts/consul/test/terraform/aks/main.tf | 2 +- charts/consul/test/terraform/eks/main.tf | 2 +- charts/consul/test/terraform/gke/main.tf | 2 +- 5 files changed, 16 insertions(+), 29 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8a9d7d8fb5..48f27ca0cb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -488,7 +488,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.21.2" + version: "v1.22.4" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} @@ -520,7 +520,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.21.2" + version: "v1.22.4" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} @@ -600,7 +600,7 @@ jobs: ######################## # ACCEPTANCE TESTS ######################## - acceptance-gke-1-19: + acceptance-gke-1-20: environment: - TEST_RESULTS: /tmp/test-results docker: @@ -666,7 +666,7 @@ jobs: fail_only: true failure_message: "GKE acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - acceptance-aks-1-20: + acceptance-aks-1-21: environment: - TEST_RESULTS: /tmp/test-results docker: @@ -721,7 +721,7 @@ jobs: fail_only: true failure_message: "AKS acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - acceptance-eks-1-18: + acceptance-eks-1-19: environment: - TEST_RESULTS: /tmp/test-results docker: @@ -835,7 +835,7 @@ jobs: fail_only: true failure_message: "OpenShift acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - acceptance-kind-1-22: + acceptance-kind-1-23: environment: - TEST_RESULTS: /tmp/test-results machine: @@ -845,7 +845,7 @@ jobs: - checkout - install-prereqs - create-kind-clusters: - version: "v1.22.1" + version: "v1.23.0" - restore_cache: keys: - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} @@ -985,26 +985,13 @@ workflows: # - acceptance-openshift: # requires: # - cleanup-azure-resources - - acceptance-gke-1-19: + - acceptance-gke-1-20: requires: - cleanup-gcp-resources - - acceptance-eks-1-18: + - acceptance-eks-1-19: requires: - cleanup-eks-resources - - acceptance-aks-1-20: + - acceptance-aks-1-21: requires: - cleanup-azure-resources - - acceptance-kind-1-22 -# update-helm-charts-index: <-- Disable until we can figure out a release workflow. We currently don't want it to trigger on a tag because the tag is pushed by the eco-releases pipeline. -# jobs: -# - helm-chart-pipeline-approval: -# type: approval -# - update-helm-charts-index: -# requires: -# - helm-chart-pipeline-approval -# context: helm-charts-trigger-consul -# filters: -# tags: -# only: /^v.*/ -# branches: -# ignore: /.*/ + - acceptance-kind-1-23 diff --git a/README.md b/README.md index b0767f1405..86ec8f355d 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,8 @@ use Consul with Kubernetes, please see the ### Prerequisites * **Helm 3.2+** (Helm 2 is not supported) - * **Kubernetes 1.18+** - This is the earliest version of Kubernetes tested. - It is possible that this chart works with earlier versions but it is + * **Kubernetes 1.19+** - This is the earliest version of Kubernetes tested. + It is possible that this chart works with earlier versions, but it is untested. ### Usage diff --git a/charts/consul/test/terraform/aks/main.tf b/charts/consul/test/terraform/aks/main.tf index 774b94b68c..49ad4a0f6d 100644 --- a/charts/consul/test/terraform/aks/main.tf +++ b/charts/consul/test/terraform/aks/main.tf @@ -24,7 +24,7 @@ resource "azurerm_kubernetes_cluster" "default" { location = azurerm_resource_group.default[count.index].location resource_group_name = azurerm_resource_group.default[count.index].name dns_prefix = "consul-k8s-${random_id.suffix[count.index].dec}" - kubernetes_version = "1.20.9" + kubernetes_version = "1.21.7" default_node_pool { name = "default" diff --git a/charts/consul/test/terraform/eks/main.tf b/charts/consul/test/terraform/eks/main.tf index 3aa79db821..66ac50e2e4 100644 --- a/charts/consul/test/terraform/eks/main.tf +++ b/charts/consul/test/terraform/eks/main.tf @@ -54,7 +54,7 @@ module "eks" { version = "17.20.0" cluster_name = "consul-k8s-${random_id.suffix[count.index].dec}" - cluster_version = "1.18" + cluster_version = "1.19" subnets = module.vpc[count.index].private_subnets vpc_id = module.vpc[count.index].vpc_id diff --git a/charts/consul/test/terraform/gke/main.tf b/charts/consul/test/terraform/gke/main.tf index 8f86ad1290..5cf71b1138 100644 --- a/charts/consul/test/terraform/gke/main.tf +++ b/charts/consul/test/terraform/gke/main.tf @@ -10,7 +10,7 @@ resource "random_id" "suffix" { data "google_container_engine_versions" "main" { location = var.zone - version_prefix = "1.19." + version_prefix = "1.20." } resource "google_container_cluster" "cluster" { From 6e70d2df6fd5ece90a4c242a87118429e39ffaf1 Mon Sep 17 00:00:00 2001 From: Narsing Metpally Date: Mon, 10 Jan 2022 15:07:46 -0700 Subject: [PATCH 207/418] Add PodDisruptionBudget Kind when checking for existing versions (#923) Checking for existing version using just "policy/v1" doesn't work when running helm template, and as a result helm will generate a version of PodDisruptionBudget that is not supported by the cluster (see https://github.com/cortexproject/cortex-helm-chart/pull/277). The workaround is to add Kind to the '.Capabilities.APIVersions.Has' check so that 'helm template' will generate the right version of the PodDisruptionBudget resource. --- charts/consul/templates/server-disruptionbudget.yaml | 2 +- charts/consul/test/unit/server-disruptionbudget.bats | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/consul/templates/server-disruptionbudget.yaml b/charts/consul/templates/server-disruptionbudget.yaml index 866698aac8..edf9c1c57f 100644 --- a/charts/consul/templates/server-disruptionbudget.yaml +++ b/charts/consul/templates/server-disruptionbudget.yaml @@ -1,7 +1,7 @@ {{- if (and .Values.server.disruptionBudget.enabled (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled))) }} # PodDisruptionBudget to prevent degrading the server cluster through # voluntary cluster changes. -{{- if .Capabilities.APIVersions.Has "policy/v1" }} +{{- if .Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" }} apiVersion: policy/v1 {{- else }} apiVersion: policy/v1beta1 diff --git a/charts/consul/test/unit/server-disruptionbudget.bats b/charts/consul/test/unit/server-disruptionbudget.bats index db6ae1bca1..eb076ac775 100755 --- a/charts/consul/test/unit/server-disruptionbudget.bats +++ b/charts/consul/test/unit/server-disruptionbudget.bats @@ -127,7 +127,7 @@ load _helpers cd `chart_dir` local actual=$(helm template \ -s templates/server-disruptionbudget.yaml \ - --api-versions 'policy/v1' \ + --api-versions 'policy/v1/PodDisruptionBudget' \ . | tee /dev/stderr | yq -r '.apiVersion' | tee /dev/stderr) [ "${actual}" = "policy/v1" ] From 3b3719627ba79539481cc5e27948391e3c5936e3 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Wed, 12 Jan 2022 18:41:55 -0700 Subject: [PATCH 208/418] Update CHANGELOG.md for #923 (#957) --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 17f3b4d878..5186dcf40c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,11 @@ ## UNRELEASED IMPROVEMENTS: * Helm - * Allow customization of `terminationGracePeriodSeconds` on the ingress gateways. [[GH-947](https://github.com/hashicorp/consul-k8s/pull/947)] + * Allow customization of `terminationGracePeriodSeconds` on the ingress gateways. [[GH-947](https://github.com/hashicorp/consul-k8s/pull/947)] + +BUG FIXES: +* Helm + * Add `PodDisruptionBudget` Kind when checking for existing versions so that `helm template` can generate the right version. [[GH-923](https://github.com/hashicorp/consul-k8s/pull/923)] ## 0.39.0 (December 15, 2021) From f7c2071f81f3c0721a11f3262d77229601a7629f Mon Sep 17 00:00:00 2001 From: Michael Hofer Date: Fri, 14 Jan 2022 21:13:58 +0100 Subject: [PATCH 209/418] chore(charts): align helm template name for connect inject mutatingwebhookconfig (#952) --- ...> connect-inject-mutatingwebhookconfiguration.yaml} | 0 ...> connect-inject-mutatingwebhookconfiguration.bats} | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) rename charts/consul/templates/{connect-inject-mutatingwebhook.yaml => connect-inject-mutatingwebhookconfiguration.yaml} (100%) rename charts/consul/test/unit/{connect-inject-mutatingwebhook.bats => connect-inject-mutatingwebhookconfiguration.bats} (77%) diff --git a/charts/consul/templates/connect-inject-mutatingwebhook.yaml b/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml similarity index 100% rename from charts/consul/templates/connect-inject-mutatingwebhook.yaml rename to charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml diff --git a/charts/consul/test/unit/connect-inject-mutatingwebhook.bats b/charts/consul/test/unit/connect-inject-mutatingwebhookconfiguration.bats similarity index 77% rename from charts/consul/test/unit/connect-inject-mutatingwebhook.bats rename to charts/consul/test/unit/connect-inject-mutatingwebhookconfiguration.bats index 5e60732353..11c3a6b0a5 100755 --- a/charts/consul/test/unit/connect-inject-mutatingwebhook.bats +++ b/charts/consul/test/unit/connect-inject-mutatingwebhookconfiguration.bats @@ -5,14 +5,14 @@ load _helpers @test "connectInject/MutatingWebhookConfiguration: disabled by default" { cd `chart_dir` assert_empty helm template \ - -s templates/connect-inject-mutatingwebhook.yaml \ + -s templates/connect-inject-mutatingwebhookconfiguration.yaml \ . } @test "connectInject/MutatingWebhookConfiguration: enable with global.enabled false" { cd `chart_dir` local actual=$(helm template \ - -s templates/connect-inject-mutatingwebhook.yaml \ + -s templates/connect-inject-mutatingwebhookconfiguration.yaml \ --set 'global.enabled=false' \ --set 'client.enabled=true' \ --set 'connectInject.enabled=true' \ @@ -24,7 +24,7 @@ load _helpers @test "connectInject/MutatingWebhookConfiguration: disable with connectInject.enabled" { cd `chart_dir` assert_empty helm template \ - -s templates/connect-inject-mutatingwebhook.yaml \ + -s templates/connect-inject-mutatingwebhookconfiguration.yaml \ --set 'connectInject.enabled=false' \ . } @@ -32,7 +32,7 @@ load _helpers @test "connectInject/MutatingWebhookConfiguration: disable with global.enabled" { cd `chart_dir` assert_empty helm template \ - -s templates/connect-inject-mutatingwebhook.yaml \ + -s templates/connect-inject-mutatingwebhookconfiguration.yaml \ --set 'global.enabled=false' \ . } @@ -40,7 +40,7 @@ load _helpers @test "connectInject/MutatingWebhookConfiguration: namespace is set" { cd `chart_dir` local actual=$(helm template \ - -s templates/connect-inject-mutatingwebhook.yaml \ + -s templates/connect-inject-mutatingwebhookconfiguration.yaml \ --set 'connectInject.enabled=true' \ --namespace foo \ . | tee /dev/stderr | From 050993c3ea72f42e7ebe1614d725ccf5596b358e Mon Sep 17 00:00:00 2001 From: David Yu Date: Tue, 18 Jan 2022 14:38:40 -0800 Subject: [PATCH 210/418] chart: bump to envoy 1.20.1 (#958) * chart: bump to envoy 1.20.1 * Update Chart.yaml * Update CHANGELOG.md * Update CHANGELOG.md * bump envoy image * envoy bump ingress gw * bump mgw envoy --- CHANGELOG.md | 5 +++++ charts/consul/Chart.yaml | 2 +- charts/consul/test/unit/ingress-gateways-deployment.bats | 2 +- charts/consul/test/unit/mesh-gateway-deployment.bats | 4 ++-- charts/consul/test/unit/terminating-gateways-deployment.bats | 2 +- charts/consul/values.yaml | 2 +- 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5186dcf40c..812acbaa53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ ## UNRELEASED + +FEATURES: +* Helm + * Support Envoy 1.20.1. [[GH-935](https://github.com/hashicorp/consul-k8s/pull/958)] + IMPROVEMENTS: * Helm * Allow customization of `terminationGracePeriodSeconds` on the ingress gateways. [[GH-947](https://github.com/hashicorp/consul-k8s/pull/947)] diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index 45b05331dc..e7f331c4ae 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -17,7 +17,7 @@ annotations: - name: consul-k8s-control-plane image: hashicorp/consul-k8s-control-plane:0.39.0 - name: envoy - image: envoyproxy/envoy-alpine:v1.20.0 + image: envoyproxy/envoy-alpine:v1.20.1 artifacthub.io/license: MPL-2.0 artifacthub.io/links: | - name: Documentation diff --git a/charts/consul/test/unit/ingress-gateways-deployment.bats b/charts/consul/test/unit/ingress-gateways-deployment.bats index b72819c8ff..4ee307058d 100644 --- a/charts/consul/test/unit/ingress-gateways-deployment.bats +++ b/charts/consul/test/unit/ingress-gateways-deployment.bats @@ -83,7 +83,7 @@ load _helpers --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -s -r '.[0].spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.0" ] + [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.1" ] } @test "ingressGateways/Deployment: envoy image can be set using the global value" { diff --git a/charts/consul/test/unit/mesh-gateway-deployment.bats b/charts/consul/test/unit/mesh-gateway-deployment.bats index 37464b9676..f796f4bb46 100755 --- a/charts/consul/test/unit/mesh-gateway-deployment.bats +++ b/charts/consul/test/unit/mesh-gateway-deployment.bats @@ -335,7 +335,7 @@ key2: value2' \ --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.0" ] + [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.1" ] } @test "meshGateway/Deployment: setting meshGateway.imageEnvoy fails" { @@ -1530,4 +1530,4 @@ EOF --set 'meshGateway.enabled=true' . [ "$status" -eq 1 ] [[ "$output" =~ "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" ]] -} \ No newline at end of file +} diff --git a/charts/consul/test/unit/terminating-gateways-deployment.bats b/charts/consul/test/unit/terminating-gateways-deployment.bats index 39f2649270..76e5917a81 100644 --- a/charts/consul/test/unit/terminating-gateways-deployment.bats +++ b/charts/consul/test/unit/terminating-gateways-deployment.bats @@ -83,7 +83,7 @@ load _helpers --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -s -r '.[0].spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.0" ] + [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.1" ] } @test "terminatingGateways/Deployment: envoy image can be set using the global value" { diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index c97aef15ce..5c2b17f4ad 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -444,7 +444,7 @@ global: # connect-injected sidecar proxies and mesh, terminating, and ingress gateways. # See https://www.consul.io/docs/connect/proxies/envoy for full compatibility matrix between Consul and Envoy. # @default: envoyproxy/envoy-alpine: - imageEnvoy: "envoyproxy/envoy-alpine:v1.20.0" + imageEnvoy: "envoyproxy/envoy-alpine:v1.20.1" # Configuration for running this Helm chart on the Red Hat OpenShift platform. # This Helm chart currently supports OpenShift v4.x+. From b0df1aee891b5076f345e277028c5c6647c84e37 Mon Sep 17 00:00:00 2001 From: David Yu Date: Tue, 18 Jan 2022 15:19:28 -0800 Subject: [PATCH 211/418] CHANGELOG: typo (#977) typo in changelog link to PR --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 812acbaa53..3d68bbce50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ FEATURES: * Helm - * Support Envoy 1.20.1. [[GH-935](https://github.com/hashicorp/consul-k8s/pull/958)] + * Support Envoy 1.20.1. [[GH-958](https://github.com/hashicorp/consul-k8s/pull/958)] IMPROVEMENTS: * Helm From 89ae1d80f5b0af4fb7f7eea58325bb658a7a0947 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Tue, 18 Jan 2022 14:09:24 -0800 Subject: [PATCH 212/418] Setup and run partitions tests on EKS (#953) --- .circleci/config.yml | 2 +- .../tests/partitions/partitions_test.go | 22 ++---- charts/consul/test/terraform/eks/main.tf | 78 ++++++++++++++++++- charts/consul/test/terraform/eks/variables.tf | 7 ++ 4 files changed, 89 insertions(+), 20 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 48f27ca0cb..ef506e4ce5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -775,7 +775,7 @@ jobs: name: terraform destroy working_directory: *eks-terraform-path command: | - terraform destroy -auto-approve + terraform destroy -var cluster_count=2 -auto-approve when: always - slack/status: diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 9fb8d8b97b..4b7af3c0f3 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -32,10 +32,6 @@ func TestPartitions(t *testing.T) { t.Skipf("skipping this test because -enable-enterprise is not set") } - if !cfg.UseKind { - t.Skipf("skipping this test because Admin Partition tests are only supported in Kind for now") - } - const defaultPartition = "default" const secondaryPartition = "secondary" const defaultNamespace = "default" @@ -168,11 +164,11 @@ func TestPartitions(t *testing.T) { var partitionSvcIP string if !cfg.UseKind { // Get the IP of the partition service to configure the external server address in the values file for the workload cluster. - partitionSecretName := fmt.Sprintf("%s-partition-secret", releaseName) + partitionServiceName := fmt.Sprintf("%s-consul-partition-service", releaseName) logger.Logf(t, "retrieving partition service to determine external IP for servers") - partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionSecretName, metav1.GetOptions{}) + partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionServiceName, metav1.GetOptions{}) require.NoError(t, err) - partitionSvcIP = partitionsSvc.Status.LoadBalancer.Ingress[0].IP + partitionSvcIP = partitionsSvc.Status.LoadBalancer.Ingress[0].Hostname } else { nodeList, err := serverClusterContext.KubernetesClient(t).CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) require.NoError(t, err) @@ -181,13 +177,10 @@ func TestPartitions(t *testing.T) { } var k8sAuthMethodHost string - if cfg.UseKind { - // The Kubernetes AuthMethod IP for Kind is read from the endpoint for the Kubernetes service. On other clouds, - // this can be identified by reading the cluster config. - kubernetesEndpoint, err := clientClusterContext.KubernetesClient(t).CoreV1().Endpoints(defaultNamespace).Get(ctx, "kubernetes", metav1.GetOptions{}) - require.NoError(t, err) - k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) - } + // The Kubernetes AuthMethod IP for Kind is read from the endpoint for the Kubernetes service. + kubernetesEndpoint, err := clientClusterContext.KubernetesClient(t).CoreV1().Endpoints(defaultNamespace).Get(ctx, "kubernetes", metav1.GetOptions{}) + require.NoError(t, err) + k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) // Create client cluster. clientHelmValues := map[string]string{ @@ -258,7 +251,6 @@ func TestPartitions(t *testing.T) { // Ensure consul client are created. agentPodList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(clientClusterContext.KubectlOptions(t).Namespace).List(ctx, metav1.ListOptions{LabelSelector: "app=consul,component=client"}) require.NoError(t, err) - require.Len(t, agentPodList.Items, 1) output, err := k8s.RunKubectlAndGetOutputE(t, clientClusterContext.KubectlOptions(t), "logs", agentPodList.Items[0].Name, "-n", clientClusterContext.KubectlOptions(t).Namespace) require.NoError(t, err) diff --git a/charts/consul/test/terraform/eks/main.tf b/charts/consul/test/terraform/eks/main.tf index 66ac50e2e4..9b1a61bbb8 100644 --- a/charts/consul/test/terraform/eks/main.tf +++ b/charts/consul/test/terraform/eks/main.tf @@ -15,6 +15,8 @@ resource "random_id" "suffix" { data "aws_availability_zones" "available" {} +data "aws_caller_identity" "caller" {} + resource "random_string" "suffix" { length = 8 special = false @@ -23,13 +25,14 @@ resource "random_string" "suffix" { module "vpc" { count = var.cluster_count source = "terraform-aws-modules/vpc/aws" - version = "2.47.0" + version = "3.11.0" name = "consul-k8s-${random_id.suffix[count.index].dec}" - cidr = "10.0.0.0/16" + # The cidr range needs to be unique in each VPC to allow setting up a peering connection. + cidr = format("10.%s.0.0/16", count.index) azs = data.aws_availability_zones.available.names - private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] - public_subnets = ["10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"] + private_subnets = [format("10.%s.1.0/24", count.index), format("10.%s.2.0/24", count.index), format("10.%s.3.0/24", count.index)] + public_subnets = [format("10.%s.4.0/24", count.index), format("10.%s.5.0/24", count.index), format("10.%s.6.0/24", count.index)] enable_nat_gateway = true single_nat_gateway = true enable_dns_hostnames = true @@ -84,4 +87,71 @@ data "aws_eks_cluster" "cluster" { data "aws_eks_cluster_auth" "cluster" { count = var.cluster_count name = module.eks[count.index].cluster_id +} + +# The following resources are only applied when cluster_count=2 to set up vpc peering and the appropriate routes and +# security groups so traffic between VPCs is allowed. There is validation to ensure cluster_count can be 1 or 2. + +# Each EKS cluster needs to allow ingress traffic from the other VPC. +resource "aws_security_group_rule" "allowingressfrom1-0" { + count = var.cluster_count > 1 ? 1 : 0 + type = "ingress" + from_port = 0 + to_port = 65535 + protocol = "tcp" + cidr_blocks = [module.vpc[1].vpc_cidr_block] + security_group_id = module.eks[0].cluster_primary_security_group_id +} + +resource "aws_security_group_rule" "allowingressfrom0-1" { + count = var.cluster_count > 1 ? 1 : 0 + type = "ingress" + from_port = 0 + to_port = 65535 + protocol = "tcp" + cidr_blocks = [module.vpc[0].vpc_cidr_block] + security_group_id = module.eks[1].cluster_primary_security_group_id +} + +# Create a peering connection. This is the requester's side of the connection. +resource "aws_vpc_peering_connection" "peer" { + count = var.cluster_count > 1 ? 1 : 0 + vpc_id = module.vpc[0].vpc_id + peer_vpc_id = module.vpc[1].vpc_id + peer_owner_id = data.aws_caller_identity.caller.account_id + peer_region = var.region + auto_accept = false + + tags = { + Side = "Requester" + } +} + +# Accepter's side of the vpc peering connection. +resource "aws_vpc_peering_connection_accepter" "peer" { + count = var.cluster_count > 1 ? 1 : 0 + vpc_peering_connection_id = aws_vpc_peering_connection.peer[0].id + auto_accept = true + + tags = { + Side = "Accepter" + } +} + +# Add routes that so traffic going from VPC 0 to VPC 1 is routed through the peering connection. +resource "aws_route" "peering0" { + # We have 2 route tables to add a route to, the public and private route tables. + count = var.cluster_count > 1 ? 2 : 0 + route_table_id = [module.vpc[0].public_route_table_ids[0], module.vpc[0].private_route_table_ids[0]][count.index] + destination_cidr_block = module.vpc[1].vpc_cidr_block + vpc_peering_connection_id = aws_vpc_peering_connection.peer[0].id +} + +# Add routes that so traffic going from VPC 1 to VPC 0 is routed through the peering connection. +resource "aws_route" "peering1" { + # We have 2 route tables to add a route to, the public and private route tables. + count = var.cluster_count > 1 ? 2 : 0 + route_table_id = [module.vpc[1].public_route_table_ids[0], module.vpc[1].private_route_table_ids[0]][count.index] + destination_cidr_block = module.vpc[0].vpc_cidr_block + vpc_peering_connection_id = aws_vpc_peering_connection.peer[0].id } \ No newline at end of file diff --git a/charts/consul/test/terraform/eks/variables.tf b/charts/consul/test/terraform/eks/variables.tf index cab209fda0..a443d354b5 100644 --- a/charts/consul/test/terraform/eks/variables.tf +++ b/charts/consul/test/terraform/eks/variables.tf @@ -6,6 +6,13 @@ variable "region" { variable "cluster_count" { default = 1 description = "The number of Kubernetes clusters to create." + // We currently cannot support more than 2 cluster + // because setting up peering is more complicated if cluster count is + // more than two. + validation { + condition = var.cluster_count < 3 && var.cluster_count > 0 + error_message = "The cluster_count value must be 1 or 2." + } } variable "role_arn" { From 8db17c2b3540c0cd72b824835f80b053079bfeee Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 18 Jan 2022 16:39:40 -0700 Subject: [PATCH 213/418] Add partitions test for AKS (#955) --- acceptance/framework/consul/cli_cluster.go | 6 +- acceptance/framework/consul/consul_cluster.go | 10 +- acceptance/framework/helpers/helpers.go | 13 ++ .../tests/partitions/partitions_test.go | 206 +++++++++--------- charts/consul/test/terraform/aks/main.tf | 41 +++- charts/consul/test/terraform/aks/outputs.tf | 2 +- charts/consul/test/terraform/aks/variables.tf | 12 +- charts/consul/test/terraform/eks/main.tf | 2 +- charts/consul/test/terraform/eks/variables.tf | 2 +- charts/consul/test/terraform/gke/variables.tf | 4 +- 10 files changed, 175 insertions(+), 123 deletions(-) diff --git a/acceptance/framework/consul/cli_cluster.go b/acceptance/framework/consul/cli_cluster.go index e291805c44..bc5f7dde14 100644 --- a/acceptance/framework/consul/cli_cluster.go +++ b/acceptance/framework/consul/cli_cluster.go @@ -74,8 +74,8 @@ func NewCLICluster( require.NoError(t, err) // Merge all helm values - mergeMaps(values, valuesFromConfig) - mergeMaps(values, helmValues) + MergeMaps(values, valuesFromConfig) + MergeMaps(values, helmValues) logger := terratestLogger.New(logger.TestLogger{}) @@ -179,7 +179,7 @@ func (h *CLICluster) Destroy(t *testing.T) { func (h *CLICluster) Upgrade(t *testing.T, helmValues map[string]string) { t.Helper() - mergeMaps(h.helmOptions.SetValues, helmValues) + MergeMaps(h.helmOptions.SetValues, helmValues) helm.Upgrade(t, h.helmOptions, config.HelmChartPath, h.releaseName) helpers.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) } diff --git a/acceptance/framework/consul/consul_cluster.go b/acceptance/framework/consul/consul_cluster.go index 90b5dc392b..74c018093d 100644 --- a/acceptance/framework/consul/consul_cluster.go +++ b/acceptance/framework/consul/consul_cluster.go @@ -75,8 +75,8 @@ func NewHelmCluster( require.NoError(t, err) // Merge all helm values - mergeMaps(values, valuesFromConfig) - mergeMaps(values, helmValues) + MergeMaps(values, valuesFromConfig) + MergeMaps(values, helmValues) logger := terratestLogger.New(logger.TestLogger{}) @@ -213,7 +213,7 @@ func (h *HelmCluster) Destroy(t *testing.T) { func (h *HelmCluster) Upgrade(t *testing.T, helmValues map[string]string) { t.Helper() - mergeMaps(h.helmOptions.SetValues, helmValues) + MergeMaps(h.helmOptions.SetValues, helmValues) helm.Upgrade(t, h.helmOptions, config.HelmChartPath, h.releaseName) helpers.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) } @@ -473,9 +473,9 @@ func defaultValues() map[string]string { return values } -// mergeValues will merge the values in b with values in a and save in a. +// MergeMaps will merge the values in b with values in a and save in a. // If there are conflicts, the values in b will overwrite the values in a. -func mergeMaps(a, b map[string]string) { +func MergeMaps(a, b map[string]string) { for k, v := range b { a[k] = v } diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index bbf02bcbaf..b80e0ca383 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -173,6 +173,19 @@ func KubernetesContextFromOptions(t *testing.T, options *terratestk8s.KubectlOpt return rawConfig.CurrentContext } +// KubernetesAPIServerHostFromOptions returns the Kubernetes API server host from options. +func KubernetesAPIServerHostFromOptions(t *testing.T, options *terratestk8s.KubectlOptions) string { + t.Helper() + + configPath, err := options.GetConfigPath(t) + require.NoError(t, err) + + config, err := terratestk8s.LoadApiClientConfigE(configPath, options.ContextName) + require.NoError(t, err) + + return config.Host +} + // IsReady returns true if pod is ready. func IsReady(pod corev1.Pod) bool { if pod.Status.Phase == corev1.PodPending { diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 4b7af3c0f3..17da060163 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -23,7 +23,7 @@ const staticServerName = "static-server" const staticServerNamespace = "ns1" const staticClientNamespace = "ns2" -// Test that Connect works in a default installation for X-Partition and in-partition networking. +// Test that Connect works in a default and ACLsAndAutoEncryptEnabled installations for X-Partition and in-partition networking. func TestPartitions(t *testing.T) { env := suite.Environment() cfg := suite.Config() @@ -36,19 +36,19 @@ func TestPartitions(t *testing.T) { const secondaryPartition = "secondary" const defaultNamespace = "default" cases := []struct { - name string - destinationNamespace string - mirrorK8S bool - secure bool + name string + destinationNamespace string + mirrorK8S bool + ACLsAndAutoEncryptEnabled bool }{ { - "default namespace", + "default destination namespace", defaultNamespace, false, false, }, { - "default namespace; secure", + "default destination namespace; ACLs and auto-encrypt enabled", defaultNamespace, false, true, @@ -60,7 +60,7 @@ func TestPartitions(t *testing.T) { false, }, { - "single destination namespace; secure", + "single destination namespace; ACLs and auto-encrypt enabled", staticServerNamespace, false, true, @@ -72,7 +72,7 @@ func TestPartitions(t *testing.T) { false, }, { - "mirror k8s namespaces; secure", + "mirror k8s namespaces; ACLs and auto-encrypt enabled", staticServerNamespace, true, true, @@ -86,32 +86,38 @@ func TestPartitions(t *testing.T) { ctx := context.Background() - serverHelmValues := map[string]string{ - "global.datacenter": "dc1", - + commonHelmValues := map[string]string{ "global.adminPartitions.enabled": "true", - "global.enableConsulNamespaces": "true", - "global.tls.enabled": "true", - "global.tls.httpsOnly": strconv.FormatBool(c.secure), - "global.tls.enableAutoEncrypt": strconv.FormatBool(c.secure), - "server.exposeGossipAndRPCPorts": "true", + "global.enableConsulNamespaces": "true", + + "global.tls.enabled": "true", + "global.tls.httpsOnly": strconv.FormatBool(c.ACLsAndAutoEncryptEnabled), + "global.tls.enableAutoEncrypt": strconv.FormatBool(c.ACLsAndAutoEncryptEnabled), + + "global.acls.manageSystemACLs": strconv.FormatBool(c.ACLsAndAutoEncryptEnabled), "connectInject.enabled": "true", // When mirroringK8S is set, this setting is ignored. "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.mirrorK8S), - "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), - "meshGateway.enabled": "true", "meshGateway.replicas": "1", "controller.enabled": "true", - "dns.enabled": "true", + "dns.enabled": "true", + "dns.enableRedirection": strconv.FormatBool(cfg.EnableTransparentProxy), } + serverHelmValues := map[string]string{ + "server.exposeGossipAndRPCPorts": "true", + } + + // On Kind, there are no load balancers but since all clusters + // share the same node network (docker bridge), we can use + // a NodePort service so that we can access node(s) in a different Kind cluster. if cfg.UseKind { serverHelmValues["global.adminPartitions.service.type"] = "NodePort" serverHelmValues["global.adminPartitions.service.nodePort.https"] = "30000" @@ -119,118 +125,95 @@ func TestPartitions(t *testing.T) { serverHelmValues["meshGateway.service.nodePort"] = "30100" } - if cfg.EnableTransparentProxy { - serverHelmValues["dns.enableRedirection"] = "true" - } - releaseName := helpers.RandomName() + consul.MergeMaps(serverHelmValues, commonHelmValues) + // Install the consul cluster with servers in the default kubernetes context. serverConsulCluster := consul.NewHelmCluster(t, serverHelmValues, serverClusterContext, cfg, releaseName) serverConsulCluster.Create(t) - // Get the TLS CA certificate and key secret from the server cluster and apply it to client cluster. - tlsCert := fmt.Sprintf("%s-consul-ca-cert", releaseName) - tlsKey := fmt.Sprintf("%s-consul-ca-key", releaseName) + // Get the TLS CA certificate and key secret from the server cluster and apply it to the client cluster. + caCertSecretName := fmt.Sprintf("%s-consul-ca-cert", releaseName) + caKeySecretName := fmt.Sprintf("%s-consul-ca-key", releaseName) - logger.Logf(t, "retrieving ca cert secret %s from the server cluster and applying to the client cluster", tlsCert) - caCertSecret, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, tlsCert, metav1.GetOptions{}) - caCertSecret.ResourceVersion = "" - require.NoError(t, err) - _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, caCertSecret, metav1.CreateOptions{}) - require.NoError(t, err) + logger.Logf(t, "retrieving ca cert secret %s from the server cluster and applying to the client cluster", caCertSecretName) + moveSecret(t, serverClusterContext, clientClusterContext, caCertSecretName) - if !c.secure { - // When running in the insecure mode, auto-encrypt is disabled which requires both - // the CA cert and CA key to be available in the clients cluster. - logger.Logf(t, "retrieving ca key secret %s from the server cluster and applying to the client cluster", tlsKey) - caKeySecret, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, tlsKey, metav1.GetOptions{}) - caKeySecret.ResourceVersion = "" - require.NoError(t, err) - _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, caKeySecret, metav1.CreateOptions{}) - require.NoError(t, err) + if !c.ACLsAndAutoEncryptEnabled { + // When auto-encrypt is disabled, we need both + // the CA cert and CA key to be available in the clients cluster to generate client certificates and keys. + logger.Logf(t, "retrieving ca key secret %s from the server cluster and applying to the client cluster", caKeySecretName) + moveSecret(t, serverClusterContext, clientClusterContext, caKeySecretName) } partitionToken := fmt.Sprintf("%s-consul-partitions-acl-token", releaseName) - if c.secure { - logger.Logf(t, "retrieving partition token secret %s from the server cluster and applying to the client cluster", tlsKey) - token, err := serverClusterContext.KubernetesClient(t).CoreV1().Secrets(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionToken, metav1.GetOptions{}) - token.ResourceVersion = "" - require.NoError(t, err) - _, err = clientClusterContext.KubernetesClient(t).CoreV1().Secrets(clientClusterContext.KubectlOptions(t).Namespace).Create(ctx, token, metav1.CreateOptions{}) - require.NoError(t, err) + if c.ACLsAndAutoEncryptEnabled { + logger.Logf(t, "retrieving partition token secret %s from the server cluster and applying to the client cluster", partitionToken) + moveSecret(t, serverClusterContext, clientClusterContext, partitionToken) } - var partitionSvcIP string - if !cfg.UseKind { - // Get the IP of the partition service to configure the external server address in the values file for the workload cluster. - partitionServiceName := fmt.Sprintf("%s-consul-partition-service", releaseName) - logger.Logf(t, "retrieving partition service to determine external IP for servers") - partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionServiceName, metav1.GetOptions{}) - require.NoError(t, err) - partitionSvcIP = partitionsSvc.Status.LoadBalancer.Ingress[0].Hostname - } else { + var partitionSvcAddress string + if cfg.UseKind { nodeList, err := serverClusterContext.KubernetesClient(t).CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) require.NoError(t, err) // Get the address of the (only) node from the Kind cluster. - partitionSvcIP = nodeList.Items[0].Status.Addresses[0].Address + partitionSvcAddress = nodeList.Items[0].Status.Addresses[0].Address + } else { + // Get the IP of the partition service to configure the external server address in the values file for the clients cluster. + partitionServiceName := fmt.Sprintf("%s-consul-partition-service", releaseName) + logger.Logf(t, "retrieving partition service to determine external address for servers") + partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionServiceName, metav1.GetOptions{}) + require.NoError(t, err) + + // On AWS, load balancers have a hostname for ingress, while on Azure and GCP + // load balancers have IPs. + if partitionsSvc.Status.LoadBalancer.Ingress[0].Hostname != "" { + partitionSvcAddress = partitionsSvc.Status.LoadBalancer.Ingress[0].Hostname + } else { + partitionSvcAddress = partitionsSvc.Status.LoadBalancer.Ingress[0].IP + } } var k8sAuthMethodHost string - // The Kubernetes AuthMethod IP for Kind is read from the endpoint for the Kubernetes service. - kubernetesEndpoint, err := clientClusterContext.KubernetesClient(t).CoreV1().Endpoints(defaultNamespace).Get(ctx, "kubernetes", metav1.GetOptions{}) - require.NoError(t, err) - k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) + // When running on kind, the kube API address in kubeconfig will have a localhost address + // which will not work from inside the container. That's why we need to use the endpoints address instead + // which will point the node IP. + if cfg.UseKind { + // The Kubernetes AuthMethod host is read from the endpoints for the Kubernetes service. + kubernetesEndpoint, err := clientClusterContext.KubernetesClient(t).CoreV1().Endpoints(defaultNamespace).Get(ctx, "kubernetes", metav1.GetOptions{}) + require.NoError(t, err) + k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) + } else { + k8sAuthMethodHost = helpers.KubernetesAPIServerHostFromOptions(t, clientClusterContext.KubectlOptions(t)) + } // Create client cluster. clientHelmValues := map[string]string{ - "global.datacenter": "dc1", - "global.enabled": "false", + "global.enabled": "false", - "global.tls.enabled": "true", - "global.tls.httpsOnly": strconv.FormatBool(c.secure), - "global.tls.enableAutoEncrypt": strconv.FormatBool(c.secure), - - "server.exposeGossipAndRPCPorts": "true", - - "connectInject.enabled": "true", - // When mirroringK8S is set, this setting is ignored. - "connectInject.consulNamespaces.consulDestinationNamespace": c.destinationNamespace, - "connectInject.consulNamespaces.mirroringK8S": strconv.FormatBool(c.mirrorK8S), + "global.adminPartitions.name": secondaryPartition, - "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), - - "global.adminPartitions.enabled": "true", - "global.adminPartitions.name": secondaryPartition, - "global.enableConsulNamespaces": "true", - - "meshGateway.enabled": "true", - "meshGateway.replicas": "1", - - "controller.enabled": "true", - - "global.tls.caCert.secretName": tlsCert, + "global.tls.caCert.secretName": caCertSecretName, "global.tls.caCert.secretKey": "tls.crt", "externalServers.enabled": "true", - "externalServers.hosts[0]": partitionSvcIP, + "externalServers.hosts[0]": partitionSvcAddress, "externalServers.tlsServerName": "server.dc1.consul", "client.enabled": "true", "client.exposeGossipPorts": "true", - "client.join[0]": partitionSvcIP, - - "dns.enabled": "true", + "client.join[0]": partitionSvcAddress, } - if c.secure { - // setup partition token if ACLs enabled. + if c.ACLsAndAutoEncryptEnabled { + // Setup partition token and auth method host if ACLs enabled. clientHelmValues["global.acls.bootstrapToken.secretName"] = partitionToken clientHelmValues["global.acls.bootstrapToken.secretKey"] = "token" clientHelmValues["externalServers.k8sAuthMethodHost"] = k8sAuthMethodHost } else { - // provide CA key when auto-encrypt is disabled. - clientHelmValues["global.tls.caKey.secretName"] = tlsKey + // Provide CA key when auto-encrypt is disabled. + clientHelmValues["global.tls.caKey.secretName"] = caKeySecretName clientHelmValues["global.tls.caKey.secretKey"] = "tls.key" } @@ -240,17 +223,16 @@ func TestPartitions(t *testing.T) { clientHelmValues["meshGateway.service.nodePort"] = "30100" } - if cfg.EnableTransparentProxy { - clientHelmValues["dns.enableRedirection"] = "true" - } + consul.MergeMaps(clientHelmValues, commonHelmValues) // Install the consul cluster without servers in the client cluster kubernetes context. clientConsulCluster := consul.NewHelmCluster(t, clientHelmValues, clientClusterContext, cfg, releaseName) clientConsulCluster.Create(t) - // Ensure consul client are created. + // Ensure consul clients are created. agentPodList, err := clientClusterContext.KubernetesClient(t).CoreV1().Pods(clientClusterContext.KubectlOptions(t).Namespace).List(ctx, metav1.ListOptions{LabelSelector: "app=consul,component=client"}) require.NoError(t, err) + require.NotEmpty(t, agentPodList.Items) output, err := k8s.RunKubectlAndGetOutputE(t, clientClusterContext.KubectlOptions(t), "logs", agentPodList.Items[0].Name, "-n", clientClusterContext.KubectlOptions(t).Namespace) require.NoError(t, err) @@ -291,7 +273,7 @@ func TestPartitions(t *testing.T) { k8s.RunKubectl(t, clientClusterContext.KubectlOptions(t), "delete", "ns", staticServerNamespace, staticClientNamespace) }) - consulClient := serverConsulCluster.SetupConsulClient(t, c.secure) + consulClient := serverConsulCluster.SetupConsulClient(t, c.ACLsAndAutoEncryptEnabled) serverQueryServerOpts := &api.QueryOptions{Namespace: staticServerNamespace, Partition: defaultPartition} clientQueryServerOpts := &api.QueryOptions{Namespace: staticClientNamespace, Partition: defaultPartition} @@ -307,12 +289,12 @@ func TestPartitions(t *testing.T) { } // Check that the ACL token is deleted. - if c.secure { + if c.ACLsAndAutoEncryptEnabled { // We need to register the cleanup function before we create the deployments // because golang will execute them in reverse order i.e. the last registered // cleanup function will be executed first. t.Cleanup(func() { - if c.secure { + if c.ACLsAndAutoEncryptEnabled { retry.Run(t, func(r *retry.R) { tokens, _, err := consulClient.ACL().TokenList(serverQueryServerOpts) require.NoError(r, err) @@ -355,7 +337,7 @@ func TestPartitions(t *testing.T) { helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { k8s.KubectlDeleteK(t, clientClusterContext.KubectlOptions(t), kustomizeDir) }) - // This section of the tests run the in-partition networking tests. + // This section of the tests runs the in-partition networking tests. t.Run("in-partition", func(t *testing.T) { logger.Log(t, "test in-partition networking") logger.Log(t, "creating static-server and static-client deployments in server cluster") @@ -424,7 +406,7 @@ func TestPartitions(t *testing.T) { require.NoError(t, err) require.Len(t, services, 1) - if c.secure { + if c.ACLsAndAutoEncryptEnabled { logger.Log(t, "checking that the connection is not successful because there's no intention") if cfg.EnableTransparentProxy { k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) @@ -496,7 +478,7 @@ func TestPartitions(t *testing.T) { k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") } }) - // This section of the tests run the cross-partition networking tests. + // This section of the tests runs the cross-partition networking tests. t.Run("cross-partition", func(t *testing.T) { logger.Log(t, "test cross-partition networking") logger.Log(t, "creating static-server and static-client deployments in server cluster") @@ -585,7 +567,7 @@ func TestPartitions(t *testing.T) { }) } - if c.secure { + if c.ACLsAndAutoEncryptEnabled { logger.Log(t, "checking that the connection is not successful because there's no intention") if cfg.EnableTransparentProxy { if !c.mirrorK8S { @@ -620,7 +602,7 @@ func TestPartitions(t *testing.T) { intention.Sources[0].Namespace = c.destinationNamespace } - logger.Log(t, "creating intention") + logger.Log(t, "creating intentions in each partition") intention.Sources[0].Partition = secondaryPartition _, _, err := consulClient.ConfigEntries().Set(intention, &api.WriteOptions{Partition: defaultPartition}) require.NoError(t, err) @@ -677,3 +659,13 @@ func TestPartitions(t *testing.T) { }) } } + +func moveSecret(t *testing.T, sourceContext, destContext environment.TestContext, secretName string) { + t.Helper() + + secret, err := sourceContext.KubernetesClient(t).CoreV1().Secrets(sourceContext.KubectlOptions(t).Namespace).Get(context.Background(), secretName, metav1.GetOptions{}) + secret.ResourceVersion = "" + require.NoError(t, err) + _, err = destContext.KubernetesClient(t).CoreV1().Secrets(destContext.KubectlOptions(t).Namespace).Create(context.Background(), secret, metav1.CreateOptions{}) + require.NoError(t, err) +} diff --git a/charts/consul/test/terraform/aks/main.tf b/charts/consul/test/terraform/aks/main.tf index 49ad4a0f6d..e12ad64cf9 100644 --- a/charts/consul/test/terraform/aks/main.tf +++ b/charts/consul/test/terraform/aks/main.tf @@ -1,5 +1,5 @@ provider "azurerm" { - version = "2.78.0" + version = "2.90.0" features {} } @@ -18,6 +18,27 @@ resource "azurerm_resource_group" "default" { tags = var.tags } +resource "azurerm_virtual_network" "default" { + count = var.cluster_count + name = "consul-k8s-${random_id.suffix[count.index].dec}" + location = azurerm_resource_group.default[count.index].location + resource_group_name = azurerm_resource_group.default[count.index].name + address_space = ["192.${count.index + 168}.0.0/16"] + + subnet { + name = "consul-k8s-${random_id.suffix[count.index].dec}-subnet" + address_prefix = "192.${count.index + 168}.1.0/24" + } +} + +resource "azurerm_virtual_network_peering" "default" { + count = var.cluster_count > 1 ? var.cluster_count : 0 + name = "peering-${count.index}" + resource_group_name = azurerm_resource_group.default[count.index].name + virtual_network_name = azurerm_virtual_network.default[count.index].name + remote_virtual_network_id = azurerm_virtual_network.default[count.index == 0 ? 1 : 0].id +} + resource "azurerm_kubernetes_cluster" "default" { count = var.cluster_count name = "consul-k8s-${random_id.suffix[count.index].dec}" @@ -26,11 +47,29 @@ resource "azurerm_kubernetes_cluster" "default" { dns_prefix = "consul-k8s-${random_id.suffix[count.index].dec}" kubernetes_version = "1.21.7" + // We're setting the network plugin and other network properties explicitly + // here even though they are the same as defaults to ensure that none of these CIDRs + // overlap with our vnet and subnet. Please see + // https://docs.microsoft.com/en-us/azure/aks/configure-kubenet#create-an-aks-cluster-in-the-virtual-network. + // We want to use kubenet plugin rather than Azure CNI because pods + // using kubenet will not be routable when we peer VNets, + // and that gives us more confidence that in any tests where cross-cluster + // communication is tested, the connections goes through the appropriate gateway + // rather than directly from pod to pod. + network_profile { + network_plugin = "kubenet" + service_cidr = "10.0.0.0/16" + dns_service_ip = "10.0.0.10" + pod_cidr = "10.244.0.0/16" + docker_bridge_cidr = "172.17.0.1/16" + } + default_node_pool { name = "default" node_count = 3 vm_size = "Standard_D2_v2" os_disk_size_gb = 30 + vnet_subnet_id = azurerm_virtual_network.default[count.index].subnet.*.id[0] } service_principal { diff --git a/charts/consul/test/terraform/aks/outputs.tf b/charts/consul/test/terraform/aks/outputs.tf index 666fa81394..9ba75d10f8 100644 --- a/charts/consul/test/terraform/aks/outputs.tf +++ b/charts/consul/test/terraform/aks/outputs.tf @@ -1,3 +1,3 @@ output "kubeconfigs" { value = local_file.kubeconfigs.*.filename -} +} \ No newline at end of file diff --git a/charts/consul/test/terraform/aks/variables.tf b/charts/consul/test/terraform/aks/variables.tf index 6c06405bfe..1651ce7b09 100644 --- a/charts/consul/test/terraform/aks/variables.tf +++ b/charts/consul/test/terraform/aks/variables.tf @@ -16,10 +16,18 @@ variable "client_secret" { variable "cluster_count" { default = 1 description = "The number of Kubernetes clusters to create." + + // We currently cannot support more than 2 clusters + // because setting up peering is more complicated if cluster count is + // more than two. + validation { + condition = var.cluster_count < 3 && var.cluster_count > 0 + error_message = "The cluster_count value must be 1 or 2." + } } variable "tags" { - type = map - default = {} + type = map + default = {} description = "Tags to attach to the created resources." } diff --git a/charts/consul/test/terraform/eks/main.tf b/charts/consul/test/terraform/eks/main.tf index 9b1a61bbb8..7b8160ea7d 100644 --- a/charts/consul/test/terraform/eks/main.tf +++ b/charts/consul/test/terraform/eks/main.tf @@ -27,7 +27,7 @@ module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "3.11.0" - name = "consul-k8s-${random_id.suffix[count.index].dec}" + name = "consul-k8s-${random_id.suffix[count.index].dec}" # The cidr range needs to be unique in each VPC to allow setting up a peering connection. cidr = format("10.%s.0.0/16", count.index) azs = data.aws_availability_zones.available.names diff --git a/charts/consul/test/terraform/eks/variables.tf b/charts/consul/test/terraform/eks/variables.tf index a443d354b5..361a5f5c45 100644 --- a/charts/consul/test/terraform/eks/variables.tf +++ b/charts/consul/test/terraform/eks/variables.tf @@ -6,7 +6,7 @@ variable "region" { variable "cluster_count" { default = 1 description = "The number of Kubernetes clusters to create." - // We currently cannot support more than 2 cluster + // We currently cannot support more than 2 clusters // because setting up peering is more complicated if cluster count is // more than two. validation { diff --git a/charts/consul/test/terraform/gke/variables.tf b/charts/consul/test/terraform/gke/variables.tf index 28defc2526..95f5d043ff 100644 --- a/charts/consul/test/terraform/gke/variables.tf +++ b/charts/consul/test/terraform/gke/variables.tf @@ -22,7 +22,7 @@ variable "cluster_count" { } variable "labels" { - type = map - default = {} + type = map + default = {} description = "Labels to attach to the created resources." } From 5a5bc6a7a44e7b8a20d62e0e229400c7a71dd898 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Tue, 18 Jan 2022 19:01:51 -0500 Subject: [PATCH 214/418] Add partitions test to GKE (#963) --- .../tests/partitions/partitions_test.go | 24 ++++++++++------- .../templates/server-podsecuritypolicy.yaml | 9 +++++++ charts/consul/test/terraform/gke/main.tf | 21 ++++++++++++++- charts/consul/test/terraform/gke/variables.tf | 8 ++++++ .../test/unit/server-podsecuritypolicy.bats | 26 +++++++++++++++++++ 5 files changed, 78 insertions(+), 10 deletions(-) diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 17da060163..e7dc0934ff 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -5,6 +5,7 @@ import ( "fmt" "strconv" "testing" + "time" terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/consul" @@ -163,16 +164,21 @@ func TestPartitions(t *testing.T) { // Get the IP of the partition service to configure the external server address in the values file for the clients cluster. partitionServiceName := fmt.Sprintf("%s-consul-partition-service", releaseName) logger.Logf(t, "retrieving partition service to determine external address for servers") - partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionServiceName, metav1.GetOptions{}) - require.NoError(t, err) - // On AWS, load balancers have a hostname for ingress, while on Azure and GCP - // load balancers have IPs. - if partitionsSvc.Status.LoadBalancer.Ingress[0].Hostname != "" { - partitionSvcAddress = partitionsSvc.Status.LoadBalancer.Ingress[0].Hostname - } else { - partitionSvcAddress = partitionsSvc.Status.LoadBalancer.Ingress[0].IP - } + // It can take some time for the load balancers to be ready and have an IP/Hostname. + // Wait for 60 seconds before failing. + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { + partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionServiceName, metav1.GetOptions{}) + require.NoError(t, err) + require.NotEmpty(r, partitionsSvc.Status.LoadBalancer.Ingress) + // On AWS, load balancers have a hostname for ingress, while on Azure and GCP + // load balancers have IPs. + if partitionsSvc.Status.LoadBalancer.Ingress[0].Hostname != "" { + partitionSvcAddress = partitionsSvc.Status.LoadBalancer.Ingress[0].Hostname + } else { + partitionSvcAddress = partitionsSvc.Status.LoadBalancer.Ingress[0].IP + } + }) } var k8sAuthMethodHost string diff --git a/charts/consul/templates/server-podsecuritypolicy.yaml b/charts/consul/templates/server-podsecuritypolicy.yaml index b45f9521f5..c037ee9b8e 100644 --- a/charts/consul/templates/server-podsecuritypolicy.yaml +++ b/charts/consul/templates/server-podsecuritypolicy.yaml @@ -27,6 +27,15 @@ spec: - 'downwardAPI' - 'persistentVolumeClaim' hostNetwork: false + hostPorts: + {{- if .Values.server.exposeGossipAndRPCPorts }} + - min: 8300 + max: 8300 + - min: {{ .Values.server.ports.serflan.port }} + max: {{ .Values.server.ports.serflan.port }} + - min: 8302 + max: 8302 + {{- end }} hostIPC: false hostPID: false runAsUser: diff --git a/charts/consul/test/terraform/gke/main.tf b/charts/consul/test/terraform/gke/main.tf index 5cf71b1138..45850114fb 100644 --- a/charts/consul/test/terraform/gke/main.tf +++ b/charts/consul/test/terraform/gke/main.tf @@ -24,7 +24,9 @@ resource "google_container_cluster" "cluster" { location = var.zone min_master_version = data.google_container_engine_versions.main.latest_master_version node_version = data.google_container_engine_versions.main.latest_master_version - + node_config { + tags = ["consul-k8s-${random_id.suffix[count.index].dec}"] + } pod_security_policy_config { enabled = true } @@ -32,6 +34,23 @@ resource "google_container_cluster" "cluster" { resource_labels = var.labels } +resource "google_compute_firewall" "firewall-rules" { + project = var.project + name = "consul-k8s-acceptance-firewall-${random_id.suffix[count.index].dec}" + network = "default" + description = "Creates firewall rule allowing traffic from nodes and pods of the ${random_id.suffix[count.index == 0 ? 1 : 0].dec} Kubernetes cluster." + + count = var.cluster_count > 1 ? var.cluster_count : 0 + + allow { + protocol = "all" + } + + source_ranges = [google_container_cluster.cluster[count.index == 0 ? 1 : 0].cluster_ipv4_cidr] + source_tags = ["consul-k8s-${random_id.suffix[count.index == 0 ? 1 : 0].dec}"] + target_tags = ["consul-k8s-${random_id.suffix[count.index].dec}"] +} + resource "null_resource" "kubectl" { count = var.init_cli ? var.cluster_count : 0 diff --git a/charts/consul/test/terraform/gke/variables.tf b/charts/consul/test/terraform/gke/variables.tf index 95f5d043ff..04d214cedb 100644 --- a/charts/consul/test/terraform/gke/variables.tf +++ b/charts/consul/test/terraform/gke/variables.tf @@ -19,6 +19,14 @@ variable "init_cli" { variable "cluster_count" { default = 1 description = "The number of Kubernetes clusters to create." + + // We currently cannot support more than 2 cluster + // because setting up peering is more complicated if cluster count is + // more than two. + validation { + condition = var.cluster_count < 3 && var.cluster_count > 0 + error_message = "The cluster_count value must be 1 or 2." + } } variable "labels" { diff --git a/charts/consul/test/unit/server-podsecuritypolicy.bats b/charts/consul/test/unit/server-podsecuritypolicy.bats index c71c5e9a00..a87980ee80 100644 --- a/charts/consul/test/unit/server-podsecuritypolicy.bats +++ b/charts/consul/test/unit/server-podsecuritypolicy.bats @@ -27,3 +27,29 @@ load _helpers yq -s 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] } + +#-------------------------------------------------------------------- +# server.exposeGossipAndRPCPorts + +@test "server/PodSecurityPolicy: hostPort 8300, 8301 and 8302 allowed when exposeGossipAndRPCPorts=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-podsecuritypolicy.yaml \ + --set 'global.enablePodSecurityPolicies=true' \ + --set 'server.exposeGossipAndRPCPorts=true' \ + . | tee /dev/stderr | + yq -c '.spec.hostPorts' | tee /dev/stderr) + [ "${actual}" = '[{"min":8300,"max":8300},{"min":8301,"max":8301},{"min":8302,"max":8302}]' ] +} + +@test "server/PodSecurityPolicy: hostPort 8300, server.ports.serflan.port and 8302 allowed when exposeGossipAndRPCPorts=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-podsecuritypolicy.yaml \ + --set 'global.enablePodSecurityPolicies=true' \ + --set 'server.exposeGossipAndRPCPorts=true' \ + --set 'server.ports.serflan.port=8333' \ + . | tee /dev/stderr | + yq -c '.spec.hostPorts' | tee /dev/stderr) + [ "${actual}" = '[{"min":8300,"max":8300},{"min":8333,"max":8333},{"min":8302,"max":8302}]' ] +} From 0666932162e69c0544a43c9fafaecf2ab01833c4 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 18 Jan 2022 17:37:24 -0700 Subject: [PATCH 215/418] cli: fix panic with go 1.17.5 or greater (#975) --- cli/go.mod | 2 +- cli/go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/go.mod b/cli/go.mod index b4558e3de0..5bab90cae6 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -134,7 +134,7 @@ require ( golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect - golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 // indirect + golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect golang.org/x/text v0.3.6 // indirect golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect diff --git a/cli/go.sum b/cli/go.sum index 56e60df33e..e80ec5eba6 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -961,6 +961,8 @@ golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= From e7b21bbe8b1d833d9d95c6c50c35e879992f4f05 Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Fri, 10 Dec 2021 16:06:52 -0500 Subject: [PATCH 216/418] server-acl-init: add api-gateway-controller token generation --- .../consul/templates/server-acl-init-job.yaml | 4 +++ .../subcommand/server-acl-init/command.go | 12 ++++++++ .../subcommand/server-acl-init/rules.go | 28 +++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/charts/consul/templates/server-acl-init-job.yaml b/charts/consul/templates/server-acl-init-job.yaml index 95758c5c77..191338d41d 100644 --- a/charts/consul/templates/server-acl-init-job.yaml +++ b/charts/consul/templates/server-acl-init-job.yaml @@ -237,6 +237,10 @@ spec: -create-controller-token=true \ {{- end }} + {{- if .Values.apiGateway.enabled }} + -create-api-gateway-token=true \ + {{- end }} + {{- if .Values.global.enableConsulNamespaces }} -enable-namespaces=true \ diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index a5daefc8f5..6ef05ab7b7 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -57,6 +57,8 @@ type Command struct { flagIngressGatewayNames []string flagTerminatingGatewayNames []string + flagCreateAPIGatewayToken bool + // Flags to configure Consul connection. flagServerAddresses []string flagServerPort uint @@ -162,6 +164,8 @@ func (c *Command) init() { "Name of a terminating gateway that needs an acl token. May be specified multiple times. "+ "[Enterprise Only] If using Consul namespaces and registering the gateway outside of the "+ "default namespace, specify the value in the form ..") + c.flags.BoolVar(&c.flagCreateAPIGatewayToken, "create-api-gateway-token", false, + "Toggle for creating a token for the API Gateway controller integration.") c.flags.Var((*flags.AppendSliceValue)(&c.flagServerAddresses), "server-address", "The IP, DNS name or the cloud auto-join string of the Consul server(s). If providing IPs or DNS names, may be specified multiple times. "+ @@ -527,6 +531,14 @@ func (c *Command) Run(args []string) int { } } + if c.flagCreateAPIGatewayToken { + err := c.createLocalACL("api-gateway-controller", apiGatewayControllerRules, consulDC, isPrimary, consulClient) + if err != nil { + c.log.Error(err.Error()) + return 1 + } + } + if c.flagCreateMeshGatewayToken { meshGatewayRules, err := c.meshGatewayRules() if err != nil { diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index 1ab5076db3..0515715bc9 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -138,6 +138,34 @@ partition_prefix "" { return c.renderRules(anonTokenRulesTpl) } +func (c *Command) apiGatewayControllerRules() (string, error) { + apiGatewayRulesTpl := ` +{{- if .EnablePartitions }} +partition "{{ .PartitionName }}" { + mesh = "write" + acl = "write" +{{- else }} + operator = "write" + acl = "write" +{{- end }} +{{- if .EnableNamespaces }} + namespace_prefix "" { +{{- end }} + service_prefix "" { + policy = "write" + intentions = "write" + } +{{- if .EnableNamespaces }} + } +{{- end }} +{{- if .EnablePartitions }} +} +{{- end }} + ` + + c.renderRules(apiGatewayRulesTpl) +} + // This assumes users are using the default name for the service, i.e. // "mesh-gateway". func (c *Command) meshGatewayRules() (string, error) { From 5280b17133707a2961dbb985f6b20744e2d5bd67 Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Fri, 10 Dec 2021 16:07:37 -0500 Subject: [PATCH 217/418] templates: add initial api-gateway templates --- .../api-gateway-controller-clusterrole.yaml | 176 + ...gateway-controller-clusterrolebinding.yaml | 21 + .../api-gateway-controller-deployment.yaml | 147 + .../api-gateway-controller-service.yaml | 27 + ...api-gateway-controller-serviceaccount.yaml | 23 + .../api-gateway-crd-gatewayconfig.yaml | 3849 +++++++++++++++++ .../templates/api-gateway-gatewayclass.yaml | 20 + .../api-gateway-gatewayclassconfig.yaml | 50 + charts/consul/values.yaml | 94 + 9 files changed, 4407 insertions(+) create mode 100644 charts/consul/templates/api-gateway-controller-clusterrole.yaml create mode 100644 charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml create mode 100644 charts/consul/templates/api-gateway-controller-deployment.yaml create mode 100644 charts/consul/templates/api-gateway-controller-service.yaml create mode 100644 charts/consul/templates/api-gateway-controller-serviceaccount.yaml create mode 100644 charts/consul/templates/api-gateway-crd-gatewayconfig.yaml create mode 100644 charts/consul/templates/api-gateway-gatewayclass.yaml create mode 100644 charts/consul/templates/api-gateway-gatewayclassconfig.yaml diff --git a/charts/consul/templates/api-gateway-controller-clusterrole.yaml b/charts/consul/templates/api-gateway-controller-clusterrole.yaml new file mode 100644 index 0000000000..47544e6b56 --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-clusterrole.yaml @@ -0,0 +1,176 @@ +{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +# The ClusterRole to enable the API Gateway controller to access required api endpoints. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller +rules: +- apiGroups: + - api-gateway.consul.hashicorp.com + resources: + - gatewayclassconfigs + verbs: + - get + - list + - update + - watch +- apiGroups: + - api-gateway.consul.hashicorp.com + resources: + - gatewayclassconfigs/finalizers + verbs: + - update +- apiGroups: + - apps + resources: + - deployments + verbs: + - create + - get + - list + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - get + - list + - update +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - "" + resources: + - configmaps/status + verbs: + - get + - patch + - update +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +- apiGroups: + - "" + resources: + - pods + verbs: + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - services + verbs: + - create + - get + - list + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses/finalizers + verbs: + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - gatewayclasses/status + verbs: + - get + - patch + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - gateways + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - gateways/finalizers + verbs: + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - gateways/status + verbs: + - get + - patch + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes/finalizers + verbs: + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - httproutes/status + verbs: + - get + - patch + - update +{{- end }} diff --git a/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml b/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml new file mode 100644 index 0000000000..1c3cba8441 --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml @@ -0,0 +1,21 @@ +{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller-role-binding + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "consul.fullname" . }}-api-gateway-controller +subjects: +- kind: ServiceAccount + name: {{ template "consul.fullname" . }}-api-gateway-controller-svc-account + namespace: {{ .Release.Namespace }} +{{- end }} + diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml new file mode 100644 index 0000000000..c6a73d1f0e --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -0,0 +1,147 @@ +{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +{{- if not .Values.client.grpc }}{{ fail "client.grpc must be true for api gateway" }}{{ end }} +{{- if and .Values.global.adminPartitions.enabled (not .Values.global.enableConsulNamespaces) }}{{ fail "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" }}{{ end }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller +spec: + replicas: {{ .Values.apiGateway.controller.replicas }} + selector: + matchLabels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + release: {{ .Release.Name }} + component: api-gateway-controller + template: + metadata: + annotations: + consul.hashicorp.com/connect-inject: "false" + {{- if (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) }} + "vault.hashicorp.com/agent-init-first": "true" + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" + "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + {{- end }} + {{- end }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + release: {{ .Release.Name }} + component: api-gateway-controller + spec: + serviceAccountName: {{ template "consul.fullname" . }}-api-gateway-controller-svc-account + containers: + - name: api-gateway-controller + image: {{ .Values.apiGateway.image }} + ports: + - containerPort: 9090 + name: sds + protocol: TCP + env: + {{- if .Values.global.tls.enabled }} + - name: CONSUL_CACERT + value: /consul/tls/ca/tls.crt + {{- end }} + - name: HOST_IP + valueFrom: + fieldRef: + fieldPath: status.hostIP + - name: IP + valueFrom: + fieldRef: + fieldPath: status.podIP + {{- if .Values.global.acls.manageSystemACLs }} + - name: CONSUL_HTTP_TOKEN + valueFrom: + secretKeyRef: + name: "{{ template "consul.fullname" . }}-api-gateway-controller-acl-token" + key: "token" + {{- end }} + - name: CONSUL_HTTP_ADDR + {{- if .Values.global.tls.enabled }} + value: https://$(HOST_IP):8501 + {{- else }} + value: http://$(HOST_IP):8500 + {{- end }} + command: + - "/bin/sh" + - "-ec" + - | + consul-api-gateway server \ + -sds-server-host $(IP) \ + -k8s-namespace {{ .Release.Namespace }} \ + -log-level {{ default .Values.global.logLevel .Values.apiGateway.logLevel }} \ + volumeMounts: + {{- if .Values.global.tls.enabled }} + {{- if .Values.global.tls.enableAutoEncrypt }} + - name: consul-auto-encrypt-ca-cert + {{- else }} + - name: consul-ca-cert + {{- end }} + mountPath: /consul/tls/ca + readOnly: true + {{- end }} + volumes: + {{- if .Values.global.tls.enabled }} + {{- if not (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots) }} + - name: consul-ca-cert + secret: + {{- if .Values.global.tls.caCert.secretName }} + secretName: {{ .Values.global.tls.caCert.secretName }} + {{- else }} + secretName: {{ template "consul.fullname" . }}-ca-cert + {{- end }} + items: + - key: {{ default "tls.crt" .Values.global.tls.caCert.secretKey }} + path: tls.crt + {{- end }} + {{- if .Values.global.tls.enableAutoEncrypt }} + - name: consul-auto-encrypt-ca-cert + emptyDir: + medium: "Memory" + {{- end }} + {{- end }} + {{- if or (and .Values.global.acls.manageSystemACLs) (and .Values.global.tls.enabled .Values.global.tls.enableAutoEncrypt) }} + initContainers: + {{- if .Values.global.acls.manageSystemACLs }} + - name: injector-acl-init + image: {{ .Values.global.imageK8S }} + command: + - "/bin/sh" + - "-ec" + - | + consul-k8s-control-plane acl-init \ + -secret-name="{{ template "consul.fullname" . }}-api-gateway-controller-acl-token" \ + -k8s-namespace={{ .Release.Namespace }} + resources: + requests: + memory: "25Mi" + cpu: "50m" + limits: + memory: "25Mi" + cpu: "50m" + {{- end }} + {{- if (and .Values.global.tls.enabled .Values.global.tls.enableAutoEncrypt) }} + {{- include "consul.getAutoEncryptClientCA" . | nindent 6 }} + {{- end }} + {{- end }} + {{- if .Values.apiGateway.controller.priorityClassName }} + priorityClassName: {{ .Values.apiGateway.controller.priorityClassName | quote }} + {{- end }} + {{- if .Values.apiGateway.controller.nodeSelector }} + nodeSelector: + {{ tpl .Values.apiGateway.controller.nodeSelector . | indent 8 | trim }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/consul/templates/api-gateway-controller-service.yaml b/charts/consul/templates/api-gateway-controller-service.yaml new file mode 100644 index 0000000000..ffebbbd50f --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-service.yaml @@ -0,0 +1,27 @@ +{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller + annotations: + {{- if .Values.apiGateway.controller.service.annotations }} + {{ tpl .Values.apiGateway.controller.service.annotations . | nindent 4 | trim }} + {{- end }} +spec: + ports: + - name: sds + port: 9090 + protocol: TCP + targetPort: 9090 + selector: + app: {{ template "consul.name" . }} + release: "{{ .Release.Name }}" + component: api-gateway-controller +{{- end }} diff --git a/charts/consul/templates/api-gateway-controller-serviceaccount.yaml b/charts/consul/templates/api-gateway-controller-serviceaccount.yaml new file mode 100644 index 0000000000..f25a184ad5 --- /dev/null +++ b/charts/consul/templates/api-gateway-controller-serviceaccount.yaml @@ -0,0 +1,23 @@ +{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "consul.fullname" . }}-api-gateway-controller-svc-account + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway-controller + {{- if .Values.apiGateway.serviceAccount.annotations }} + annotations: + {{ tpl .Values.apiGateway.serviceAccount.annotations . | nindent 4 | trim }} + {{- end }} +{{- with .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range . }} + - name: {{ .name }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/consul/templates/api-gateway-crd-gatewayconfig.yaml b/charts/consul/templates/api-gateway-crd-gatewayconfig.yaml new file mode 100644 index 0000000000..d8631d606f --- /dev/null +++ b/charts/consul/templates/api-gateway-crd-gatewayconfig.yaml @@ -0,0 +1,3849 @@ +{{- if .Values.apiGateway.enabled }} +# Generated from: kubectl kustomize 'github.com/hashicorp/consul-api-gateway/config/crd?ref=v0.1.0-techpreview' +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.6.0 + creationTimestamp: null + name: gatewayclassconfigs.api-gateway.consul.hashicorp.com +spec: + group: api-gateway.consul.hashicorp.com + names: + kind: GatewayClassConfig + listKind: GatewayClassConfigList + plural: gatewayclassconfigs + singular: gatewayclassconfig + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: GatewayClassConfig describes the configuration of a consul-api-gateway + GatewayClass. + 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: Spec defines the desired state of GatewayClassConfig. + properties: + consul: + description: Configuration information about connecting to Consul. + properties: + address: + description: The address of the consul server to communicate with + in the gateway pod. If not specified, the pod will attempt to + use a local agent on the host on which it is running. + type: string + authentication: + description: Consul authentication information + properties: + account: + description: The Kubernetes service account to authenticate + as. + type: string + method: + description: The Consul auth method used for initial authentication + by consul-api-gateway. + type: string + namespace: + description: The Consul namespace to use for authentication. + type: string + type: object + caSecret: + description: The location of a secret to mount with the Consul + root CA. + type: string + ports: + description: The information about Consul's ports + properties: + grpc: + description: The grpc port for Consul's xDS server. + type: integer + http: + description: The port for Consul's HTTP server. + type: integer + type: object + scheme: + description: The scheme to use for connecting to Consul. + enum: + - http + - https + type: string + type: object + copyAnnotations: + description: Annotation Information to copy to services or deployments + properties: + service: + description: List of annotations to copy to the gateway service. + items: + type: string + type: array + type: object + image: + description: Configuration information about the images to use + properties: + consulAPIGateway: + description: The image to use for consul-api-gateway. + type: string + envoy: + description: The image to use for Envoy. + type: string + type: object + logLevel: + description: Logging levels + enum: + - trace + - debug + - info + - warning + - error + type: string + nodeSelector: + additionalProperties: + type: string + description: 'NodeSelector is a selector which must be true for the + pod to fit on a node. Selector which must match a node''s labels + for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + serviceType: + description: Service Type string describes ingress methods for a service + enum: + - ClusterIP + - NodePort + - LoadBalancer + type: string + useHostPorts: + description: If this is set, then the Envoy container ports are mapped + to host ports. + type: boolean + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 + creationTimestamp: null + name: gatewayclasses.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: GatewayClass + listKind: GatewayClassList + plural: gatewayclasses + shortNames: + - gc + singular: gatewayclass + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.controller + name: Controller + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .spec.description + name: Description + priority: 1 + type: string + name: v1alpha2 + schema: + openAPIV3Schema: + description: "GatewayClass describes a class of Gateways available to the + user for creating Gateway resources. \n It is recommended that this resource + be used as a template for Gateways. This means that a Gateway is based on + the state of the GatewayClass at the time it was created and changes to + the GatewayClass or associated parameters are not propagated down to existing + Gateways. This recommendation is intended to limit the blast radius of changes + to GatewayClass or associated parameters. If implementations choose to propagate + GatewayClass changes to existing Gateways, that MUST be clearly documented + by the implementation. \n Whenever one or more Gateways are using a GatewayClass, + implementations MUST add the `gateway-exists-finalizer.gateway.networking.k8s.io` + finalizer on the associated GatewayClass. This ensures that a GatewayClass + associated with a Gateway is not deleted while in use. \n GatewayClass is + a Cluster level resource." + 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: Spec defines the desired state of GatewayClass. + properties: + controllerName: + description: "ControllerName is the name of the controller that is + managing Gateways of this class. The value of this field MUST be + a domain prefixed path. \n Example: \"example.net/gateway-controller\". + \n This field is not mutable and cannot be empty. \n Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + description: + description: Description helps describe a GatewayClass with more details. + maxLength: 64 + type: string + parametersRef: + description: "ParametersRef is a reference to a resource that contains + the configuration parameters corresponding to the GatewayClass. + This is optional if the controller does not require any additional + configuration. \n ParametersRef can reference a standard Kubernetes + resource, i.e. ConfigMap, or an implementation-specific custom resource. + The resource can be cluster-scoped or namespace-scoped. \n If the + referent cannot be found, the GatewayClass's \"InvalidParameters\" + status condition will be true. \n Support: Custom" + properties: + group: + description: Group is the group of the referent. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: Namespace is the namespace of the referent. This + field is required when referring to a Namespace-scoped resource + and MUST be unset when referring to a Cluster-scoped resource. + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + required: + - controllerName + type: object + status: + default: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Waiting + status: Unknown + type: Accepted + description: Status defines the current state of GatewayClass. + properties: + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: Waiting + status: Unknown + type: Accepted + description: "Conditions is the current status from the controller + for this GatewayClass. \n Controllers should prefer to publish conditions + using values of GatewayClassConditionType for the type of each Condition." + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: + \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type + \ // +patchStrategy=merge // +listType=map // +listMapKey=type + \ Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 + creationTimestamp: null + name: gateways.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: Gateway + listKind: GatewayList + plural: gateways + shortNames: + - gtw + singular: gateway + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.gatewayClassName + name: Class + type: string + - jsonPath: .status.addresses[*].value + name: Address + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: Gateway represents an instance of a service-traffic handling + infrastructure by binding Listeners to a set of IP addresses. + 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: Spec defines the desired state of Gateway. + properties: + addresses: + description: "Addresses requested for this Gateway. This is optional + and behavior can depend on the implementation. If a value is set + in the spec and the requested address is invalid or unavailable, + the implementation MUST indicate this in the associated entry in + GatewayStatus.Addresses. \n The Addresses field represents a request + for the address(es) on the \"outside of the Gateway\", that traffic + bound for this Gateway will use. This could be the IP address or + hostname of an external load balancer or other networking infrastructure, + or some other address that traffic will be sent to. \n The .listener.hostname + field is used to route traffic that has already arrived at the Gateway + to the correct in-cluster destination. \n If no Addresses are specified, + the implementation MAY schedule the Gateway in an implementation-specific + manner, assigning an appropriate set of Addresses. \n The implementation + MUST bind all Listeners to every GatewayAddress that it assigns + to the Gateway and add a corresponding entry in GatewayStatus.Addresses. + \n Support: Core" + items: + description: GatewayAddress describes an address that can be bound + to a Gateway. + properties: + type: + default: IPAddress + description: Type of the address. + enum: + - IPAddress + - Hostname + - NamedAddress + type: string + value: + description: "Value of the address. The validity of the values + will depend on the type and support by the controller. \n + Examples: `1.2.3.4`, `128::1`, `my-ip-address`." + maxLength: 253 + minLength: 1 + type: string + required: + - value + type: object + maxItems: 16 + type: array + gatewayClassName: + description: GatewayClassName used for this Gateway. This is the name + of a GatewayClass resource. + maxLength: 253 + minLength: 1 + type: string + listeners: + description: "Listeners associated with this Gateway. Listeners define + logical endpoints that are bound on this Gateway's addresses. At + least one Listener MUST be specified. \n Each listener in a Gateway + must have a unique combination of Hostname, Port, and Protocol. + \n An implementation MAY group Listeners by Port and then collapse + each group of Listeners into a single Listener if the implementation + determines that the Listeners in the group are \"compatible\". An + implementation MAY also group together and collapse compatible Listeners + belonging to different Gateways. \n For example, an implementation + might consider Listeners to be compatible with each other if all + of the following conditions are met: \n 1. Either each Listener + within the group specifies the \"HTTP\" Protocol or each Listener + within the group specifies either the \"HTTPS\" or \"TLS\" Protocol. + \n 2. Each Listener within the group specifies a Hostname that is + unique within the group. \n 3. As a special case, one Listener + within a group may omit Hostname, in which case this Listener + matches when no other Listener matches. \n If the implementation + does collapse compatible Listeners, the hostname provided in the + incoming client request MUST be matched to a Listener to find the + correct set of Routes. The incoming hostname MUST be matched using + the Hostname field for each Listener in order of most to least specific. + That is, exact matches must be processed before wildcard matches. + \n If this field specifies multiple Listeners that have the same + Port value but are not compatible, the implementation must raise + a \"Conflicted\" condition in the Listener status. \n Support: Core" + items: + description: Listener embodies the concept of a logical endpoint + where a Gateway accepts network connections. + properties: + allowedRoutes: + default: + namespaces: + from: Same + description: "AllowedRoutes defines the types of routes that + MAY be attached to a Listener and the trusted namespaces where + those Route resources MAY be present. \n Although a client + request may match multiple route rules, only one rule may + ultimately receive the request. Matching precedence MUST be + determined in order of the following criteria: \n * The most + specific match as defined by the Route type. * The oldest + Route based on creation timestamp. For example, a Route with + \ a creation timestamp of \"2020-09-08 01:02:03\" is given + precedence over a Route with a creation timestamp of \"2020-09-08 + 01:02:04\". * If everything else is equivalent, the Route + appearing first in alphabetical order (namespace/name) should + be given precedence. For example, foo/bar is given precedence + over foo/baz. \n All valid rules within a Route attached to + this Listener should be implemented. Invalid Route rules can + be ignored (sometimes that will mean the full Route). If a + Route rule transitions from valid to invalid, support for + that Route rule should be dropped to ensure consistency. For + example, even if a filter specified by a Route rule is invalid, + the rest of the rules within that Route should still be supported. + \n Support: Core" + properties: + kinds: + description: "Kinds specifies the groups and kinds of Routes + that are allowed to bind to this Gateway Listener. When + unspecified or empty, the kinds of Routes selected are + determined using the Listener protocol. \n A RouteGroupKind + MUST correspond to kinds of Routes that are compatible + with the application protocol specified in the Listener's + Protocol field. If an implementation does not support + or recognize this resource type, it MUST set the \"ResolvedRefs\" + condition to False for this Listener with the \"InvalidRoutesRef\" + reason. \n Support: Core" + items: + description: RouteGroupKind indicates the group and kind + of a Route resource. + properties: + group: + default: gateway.networking.k8s.io + description: Group is the group of the Route. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is the kind of the Route. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + required: + - kind + type: object + maxItems: 8 + type: array + namespaces: + default: + from: Same + description: "Namespaces indicates namespaces from which + Routes may be attached to this Listener. This is restricted + to the namespace of this Gateway by default. \n Support: + Core" + properties: + from: + default: Same + description: "From indicates where Routes will be selected + for this Gateway. Possible values are: * All: Routes + in all namespaces may be used by this Gateway. * Selector: + Routes in namespaces selected by the selector may + be used by this Gateway. * Same: Only Routes in + the same namespace may be used by this Gateway. \n + Support: Core" + enum: + - All + - Selector + - Same + type: string + selector: + description: "Selector must be specified when From is + set to \"Selector\". In that case, only Routes in + Namespaces matching this Selector will be selected + by this Gateway. This field is ignored for other values + of \"From\". \n Support: Core" + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". The + requirements are ANDed. + type: object + type: object + type: object + type: object + hostname: + description: "Hostname specifies the virtual hostname to match + for protocol types that define this concept. When unspecified, + all hostnames are matched. This field is ignored for protocols + that don't require hostname based matching. \n Implementations + MUST apply Hostname matching appropriately for each of the + following protocols: \n * TLS: The Listener Hostname MUST + match the SNI. * HTTP: The Listener Hostname MUST match the + Host header of the request. * HTTPS: The Listener Hostname + SHOULD match at both the TLS and HTTP protocol layers as + described above. If an implementation does not ensure that + both the SNI and Host header match the Listener hostname, + \ it MUST clearly document that. \n For HTTPRoute and TLSRoute + resources, there is an interaction with the `spec.hostnames` + array. When both listener and route specify hostnames, there + MUST be an intersection between the values for a Route to + be accepted. For more information, refer to the Route specific + Hostnames documentation. \n Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + name: + description: "Name is the name of the Listener. \n Support: + Core" + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + port: + description: "Port is the network port. Multiple listeners may + use the same port, subject to the Listener compatibility rules. + \n Support: Core" + format: int32 + maximum: 65535 + minimum: 1 + type: integer + protocol: + description: "Protocol specifies the network protocol this listener + expects to receive. \n Support: Core" + maxLength: 255 + minLength: 1 + pattern: ^[a-zA-Z0-9]([-a-zSA-Z0-9]*[a-zA-Z0-9])?$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9]+$ + type: string + tls: + description: "TLS is the TLS configuration for the Listener. + This field is required if the Protocol field is \"HTTPS\" + or \"TLS\". It is invalid to set this field if the Protocol + field is \"HTTP\", \"TCP\", or \"UDP\". \n The association + of SNIs to Certificate defined in GatewayTLSConfig is defined + based on the Hostname field for this listener. \n The GatewayClass + MUST use the longest matching SNI out of all available certificates + for any TLS handshake. \n Support: Core" + properties: + certificateRefs: + description: "CertificateRefs contains a series of references + to Kubernetes objects that contains TLS certificates and + private keys. These certificates are used to establish + a TLS handshake for requests that match the hostname of + the associated listener. \n A single CertificateRef to + a Kubernetes Secret has \"Core\" support. Implementations + MAY choose to support attaching multiple certificates + to a Listener, but this behavior is implementation-specific. + \n References to a resource in different namespace are + invalid UNLESS there is a ReferencePolicy in the target + namespace that allows the certificate to be attached. + If a ReferencePolicy does not allow this reference, the + \"ResolvedRefs\" condition MUST be set to False for this + listener with the \"InvalidCertificateRef\" reason. \n + This field is required to have at least one element when + the mode is set to \"Terminate\" (default) and is optional + otherwise. \n CertificateRefs can reference to standard + Kubernetes resources, i.e. Secret, or implementation-specific + custom resources. \n Support: Core - A single reference + to a Kubernetes Secret \n Support: Implementation-specific + (More than one reference or other resource types)" + items: + description: "SecretObjectReference identifies an API + object including its namespace, defaulting to Secret. + \n The API object must be valid in the cluster; the + Group and Kind must be registered in the cluster for + this reference to be valid. \n References to objects + with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate + Conditions set on the containing object." + properties: + group: + default: "" + description: Group is the group of the referent. For + example, "networking.k8s.io". When unspecified (empty + string), core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the backend. + When unspecified, the local namespace is inferred. + \n Note that when a namespace is specified, a ReferencePolicy + object is required in the referent namespace to + allow that namespace's owner to accept the reference. + See the ReferencePolicy documentation for details. + \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + maxItems: 64 + type: array + mode: + default: Terminate + description: "Mode defines the TLS behavior for the TLS + session initiated by the client. There are two possible + modes: \n - Terminate: The TLS session between the downstream + client and the Gateway is terminated at the Gateway. + This mode requires certificateRefs to be set and contain + at least one element. - Passthrough: The TLS session is + NOT terminated by the Gateway. This implies that the + Gateway can't decipher the TLS stream except for the + ClientHello message of the TLS protocol. CertificateRefs + field is ignored in this mode. \n Support: Core" + enum: + - Terminate + - Passthrough + type: string + options: + additionalProperties: + description: AnnotationValue is the value of an annotation + in Gateway API. This is used for validation of maps + such as TLS options. This roughly matches Kubernetes + annotation validation, although the length validation + in that case is based on the entire size of the annotations + struct. + maxLength: 4096 + minLength: 0 + type: string + description: "Options are a list of key/value pairs to enable + extended TLS configuration for each implementation. For + example, configuring the minimum TLS version or supported + cipher suites. \n A set of common keys MAY be defined + by the API in the future. To avoid any ambiguity, implementation-specific + definitions MUST use domain-prefixed names, such as `example.com/my-custom-option`. + Un-prefixed names are reserved for key names defined by + Gateway API. \n Support: Implementation-specific" + maxProperties: 16 + type: object + type: object + required: + - name + - port + - protocol + type: object + maxItems: 64 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + required: + - gatewayClassName + - listeners + type: object + status: + default: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: NotReconciled + status: Unknown + type: Scheduled + description: Status defines the current state of Gateway. + properties: + addresses: + description: Addresses lists the IP addresses that have actually been + bound to the Gateway. These addresses may differ from the addresses + in the Spec, e.g. if the Gateway automatically assigns an address + from a reserved pool. + items: + description: GatewayAddress describes an address that can be bound + to a Gateway. + properties: + type: + default: IPAddress + description: Type of the address. + enum: + - IPAddress + - Hostname + - NamedAddress + type: string + value: + description: "Value of the address. The validity of the values + will depend on the type and support by the controller. \n + Examples: `1.2.3.4`, `128::1`, `my-ip-address`." + maxLength: 253 + minLength: 1 + type: string + required: + - value + type: object + maxItems: 16 + type: array + conditions: + default: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: Waiting for controller + reason: NotReconciled + status: Unknown + type: Scheduled + description: "Conditions describe the current conditions of the Gateway. + \n Implementations should prefer to express Gateway conditions using + the `GatewayConditionType` and `GatewayConditionReason` constants + so that operators and tools can converge on a common vocabulary + to describe Gateway state. \n Known condition types are: \n * \"Scheduled\" + * \"Ready\"" + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: + \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type + \ // +patchStrategy=merge // +listType=map // +listMapKey=type + \ Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + listeners: + description: Listeners provide status for each unique listener port + defined in the Spec. + items: + description: ListenerStatus is the status associated with a Listener. + properties: + attachedRoutes: + description: AttachedRoutes represents the total number of Routes + that have been successfully attached to this Listener. + format: int32 + type: integer + conditions: + description: Conditions describe the current condition of this + listener. + items: + description: "Condition contains details for one aspect of + the current state of this API Resource. --- This struct + is intended for direct use as an array at the field path + .status.conditions. For example, type FooStatus struct{ + \ // Represents the observations of a foo's current state. + \ // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type + \ // +patchStrategy=merge // +listType=map // + +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should + be when the underlying condition changed. If that is + not known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, + if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier + indicating the reason for the condition's last transition. + Producers of specific condition types may define expected + values and meanings for this field, and whether the + values are considered a guaranteed API. The value should + be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is + (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + name: + description: Name is the name of the Listener that this status + corresponds to. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + supportedKinds: + description: "SupportedKinds is the list indicating the Kinds + supported by this listener. This MUST represent the kinds + an implementation supports for that Listener configuration. + \n If kinds are specified in Spec that are not supported, + they MUST NOT appear in this list and an implementation MUST + set the \"ResolvedRefs\" condition to \"False\" with the \"InvalidRouteKinds\" + reason. If both valid and invalid Route kinds are specified, + the implementation MUST reference the valid Route kinds that + have been specified." + items: + description: RouteGroupKind indicates the group and kind of + a Route resource. + properties: + group: + default: gateway.networking.k8s.io + description: Group is the group of the Route. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is the kind of the Route. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + required: + - kind + type: object + maxItems: 8 + type: array + required: + - attachedRoutes + - conditions + - name + - supportedKinds + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 + creationTimestamp: null + name: httproutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: HTTPRoute + listKind: HTTPRouteList + plural: httproutes + singular: httproute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.hostnames + name: Hostnames + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: HTTPRoute provides a way to route HTTP requests. This includes + the capability to match requests by hostname, path, header, or query param. + Filters can be used to specify additional processing steps. Backends specify + where matching requests should be routed. + 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: Spec defines the desired state of HTTPRoute. + properties: + hostnames: + description: "Hostnames defines a set of hostname that should match + against the HTTP Host header to select a HTTPRoute to process the + request. This matches the RFC 1123 definition of a hostname with + 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may + be prefixed with a wildcard label (`*.`). The wildcard label + must appear by itself as the first label. \n If a hostname is specified + by both the Listener and HTTPRoute, there must be at least one intersecting + hostname for the HTTPRoute to be attached to the Listener. For example: + \n * A Listener with `test.example.com` as the hostname matches + HTTPRoutes that have either not specified any hostnames, or have + specified at least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches HTTPRoutes + \ that have either not specified any hostnames or have specified + at least one hostname that matches the Listener hostname. For + example, `test.example.com` and `*.example.com` would both match. + On the other hand, `example.com` and `test.example.net` would + not match. \n If both the Listener and HTTPRoute have specified + hostnames, any HTTPRoute hostnames that do not match the Listener + hostname MUST be ignored. For example, if a Listener specified `*.example.com`, + and the HTTPRoute specified `test.example.com` and `test.example.net`, + `test.example.net` must not be considered for a match. \n If both + the Listener and HTTPRoute have specified hostnames, and none match + with the criteria above, then the HTTPRoute is not accepted. The + implementation must raise an 'Accepted' Condition with a status + of `False` in the corresponding RouteParentStatus. \n Support: Core" + items: + description: "Hostname is the fully qualified domain name of a network + host. This matches the RFC 1123 definition of a hostname with + 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname + may be prefixed with a wildcard label (`*.`). The wildcard label + must appear by itself as the first label. \n Hostname can be \"precise\" + which is a domain name without the terminating dot of a network + host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain + name prefixed with a single wildcard label (e.g. `*.example.com`). + \n Note that as per RFC1035 and RFC1123, a *label* must consist + of lower case alphanumeric characters or '-', and must start and + end with an alphanumeric character. No other punctuation is allowed." + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: "ParentRefs references the resources (usually Gateways) + that a Route wants to be attached to. Note that the referenced parent + resource needs to allow this for the attachment to be complete. + For Gateways, that means the Gateway needs to allow attachment from + Routes of this kind and namespace. \n The only kind of parent resource + with \"Core\" support is Gateway. This API may be extended in the + future to support additional kinds of parent resources such as one + of the route kinds. \n It is invalid to reference an identical parent + more than once. It is valid to reference multiple distinct sections + within the same parent resource, such as 2 Listeners within a Gateway. + \n It is possible to separately reference multiple distinct objects + that may be collapsed by an implementation. For example, some implementations + may choose to merge compatible Gateway Listeners together. If that + is the case, the list of routes attached to those resources should + also be merged." + items: + description: "ParentRef identifies an API object (usually a Gateway) + that can be considered a parent of this resource (usually a route). + The only kind of parent resource with \"Core\" support is Gateway. + This API may be extended in the future to support additional kinds + of parent resources, such as HTTPRoute. \n The API object must + be valid in the cluster; the Group and Kind must be registered + in the cluster for this reference to be valid. \n References to + objects with invalid Group and Kind are not valid, and must be + rejected by the implementation, with appropriate Conditions set + on the containing object." + properties: + group: + default: gateway.networking.k8s.io + description: "Group is the group of the referent. \n Support: + Core" + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: "Kind is kind of the referent. \n Support: Core + (Gateway) Support: Custom (Other Resources)" + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: "Name is the name of the referent. \n Support: + Core" + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the referent. When + unspecified (or empty string), this refers to the local namespace + of the Route. \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within the + target resource. In the following resources, SectionName is + interpreted as the following: \n * Gateway: Listener Name + \n Implementations MAY choose to support attaching Routes + to other resources. If that is the case, they MUST clearly + document how SectionName is interpreted. \n When unspecified + (empty string), this will reference the entire resource. For + the purpose of status, an attachment is considered successful + if at least one section in the parent resource accepts it. + For example, Gateway listeners can restrict which Routes can + attach to them by Route kind, namespace, or hostname. If 1 + of 2 Gateway listeners accept attachment from the referencing + Route, the Route MUST be considered successfully attached. + If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. \n + Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + rules: + default: + - matches: + - path: + type: PathPrefix + value: / + description: Rules are a list of HTTP matchers, filters and actions. + items: + description: HTTPRouteRule defines semantics for matching an HTTP + request based on conditions (matches), processing it (filters), + and forwarding the request to an API object (backendRefs). + properties: + backendRefs: + description: "If unspecified or invalid (refers to a non-existent + resource or a Service with no endpoints), the rule performs + no forwarding. If there are also no filters specified that + would result in a response being sent, a HTTP 503 status code + is returned. 503 responses must be sent so that the overall + weight is respected; if an invalid backend is requested to + have 80% of requests, then 80% of requests must get a 503 + instead. \n Support: Core for Kubernetes Service Support: + Custom for any other resource \n Support for weight: Core" + items: + description: HTTPBackendRef defines how a HTTPRoute should + forward an HTTP request. + properties: + filters: + description: "Filters defined at this level should be + executed if and only if the request is being forwarded + to the backend defined here. \n Support: Custom (For + broader support of filters, use the Filters field in + HTTPRouteRule.)" + items: + description: HTTPRouteFilter defines processing steps + that must be completed during the request or response + lifecycle. HTTPRouteFilters are meant as an extension + point to express processing that may be done in Gateway + implementations. Some examples include request or + response modification, implementing authentication + strategies, rate-limiting, and traffic shaping. API + guarantee/conformance is defined based on the type + of the filter. + properties: + extensionRef: + description: "ExtensionRef is an optional, implementation-specific + extension to the \"filter\" behavior. For example, + resource \"myroutefilter\" in group \"networking.example.net\"). + ExtensionRef MUST NOT be used for core and extended + filters. \n Support: Implementation-specific" + properties: + group: + description: Group is the group of the referent. + For example, "networking.k8s.io". When unspecified + (empty string), core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: "RequestHeaderModifier defines a schema + for a filter that modifies request headers. \n + Support: Core" + properties: + add: + description: "Add adds the given header(s) (name, + value) to the request before the action. It + appends to any existing values associated + with the header name. \n Input: GET /foo + HTTP/1.1 my-header: foo \n Config: add: + \ - name: \"my-header\" value: \"bar\" + \n Output: GET /foo HTTP/1.1 my-header: + foo my-header: bar" + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: "Name is the name of the + HTTP Header to be matched. Name matching + MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + \n If multiple entries specify equivalent + header names, the first entry with an + equivalent name MUST be considered for + a match. Subsequent entries with an + equivalent header name MUST be ignored. + Due to the case-insensitivity of header + names, \"foo\" and \"Foo\" are considered + equivalent." + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: "Remove the given header(s) from + the HTTP request before the action. The value + of Remove is a list of HTTP header names. + Note that the header names are case-insensitive + (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + \n Input: GET /foo HTTP/1.1 my-header1: + foo my-header2: bar my-header3: baz \n + Config: remove: [\"my-header1\", \"my-header3\"] + \n Output: GET /foo HTTP/1.1 my-header2: + bar" + items: + type: string + maxItems: 16 + type: array + set: + description: "Set overwrites the request with + the given header (name, value) before the + action. \n Input: GET /foo HTTP/1.1 my-header: + foo \n Config: set: - name: \"my-header\" + \ value: \"bar\" \n Output: GET /foo + HTTP/1.1 my-header: bar" + items: + description: HTTPHeader represents an HTTP + Header name and value as defined by RFC + 7230. + properties: + name: + description: "Name is the name of the + HTTP Header to be matched. Name matching + MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + \n If multiple entries specify equivalent + header names, the first entry with an + equivalent name MUST be considered for + a match. Subsequent entries with an + equivalent header name MUST be ignored. + Due to the case-insensitivity of header + names, \"foo\" and \"Foo\" are considered + equivalent." + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP + Header to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: "RequestMirror defines a schema for + a filter that mirrors requests. Requests are sent + to the specified destination, but responses from + that destination are ignored. \n Support: Extended" + properties: + backendRef: + description: "BackendRef references a resource + where mirrored requests are sent. \n If the + referent cannot be found, this BackendRef + is invalid and must be dropped from the Gateway. + The controller must ensure the \"ResolvedRefs\" + condition on the Route status is set to `status: + False` and not configure this backend in the + underlying implementation. \n If there is + a cross-namespace reference to an *existing* + object that is not allowed by a ReferencePolicy, + the controller must ensure the \"ResolvedRefs\" + \ condition on the Route is set to `status: + False`, with the \"RefNotPermitted\" reason + and not configure this backend in the underlying + implementation. \n In either error case, the + Message of the `ResolvedRefs` Condition should + be used to provide more detail about the problem. + \n Support: Extended for Kubernetes Service + Support: Custom for any other resource" + properties: + group: + default: "" + description: Group is the group of the referent. + For example, "networking.k8s.io". When + unspecified (empty string), core API group + is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: Kind is kind of the referent. + For example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace + of the backend. When unspecified, the + local namespace is inferred. \n Note that + when a namespace is specified, a ReferencePolicy + object is required in the referent namespace + to allow that namespace's owner to accept + the reference. See the ReferencePolicy + documentation for details. \n Support: + Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: Port specifies the destination + port number to use for this resource. + Port is required when the referent is + a Kubernetes Service. For other resources, + destination port might be derived from + the referent resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + required: + - backendRef + type: object + requestRedirect: + description: "RequestRedirect defines a schema for + a filter that responds to the request with an + HTTP redirection. \n Support: Core" + properties: + hostname: + description: "Hostname is the hostname to be + used in the value of the `Location` header + in the response. When empty, the hostname + of the request is used. \n Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + port: + description: "Port is the port to be used in + the value of the `Location` header in the + response. When empty, port (if specified) + of the request is used. \n Support: Extended" + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: "Scheme is the scheme to be used + in the value of the `Location` header in the + response. When empty, the scheme of the request + is used. \n Support: Extended" + enum: + - http + - https + type: string + statusCode: + default: 302 + description: "StatusCode is the HTTP status + code to be used in response. \n Support: Core" + enum: + - 301 + - 302 + type: integer + type: object + type: + description: "Type identifies the type of filter + to apply. As with other API fields, types are + classified into three conformance levels: \n - + Core: Filter types and their corresponding configuration + defined by \"Support: Core\" in this package, + e.g. \"RequestHeaderModifier\". All implementations + must support core filters. \n - Extended: Filter + types and their corresponding configuration defined + by \"Support: Extended\" in this package, e.g. + \"RequestMirror\". Implementers are encouraged + to support extended filters. \n - Custom: Filters + that are defined and supported by specific vendors. + \ In the future, filters showing convergence + in behavior across multiple implementations + will be considered for inclusion in extended or + core conformance levels. Filter-specific configuration + for such filters is specified using the ExtensionRef + field. `Type` should be set to \"ExtensionRef\" + for custom filters. \n Implementers are encouraged + to define custom implementation types to extend + the core API with implementation-specific behavior. + \n If a reference to a custom filter type cannot + be resolved, the filter MUST NOT be skipped. Instead, + requests that would have been processed by that + filter MUST receive a HTTP error response." + enum: + - RequestHeaderModifier + - RequestMirror + - RequestRedirect + - ExtensionRef + type: string + required: + - type + type: object + maxItems: 16 + type: array + group: + default: "" + description: Group is the group of the referent. For example, + "networking.k8s.io". When unspecified (empty string), + core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the backend. + When unspecified, the local namespace is inferred. \n + Note that when a namespace is specified, a ReferencePolicy + object is required in the referent namespace to allow + that namespace's owner to accept the reference. See + the ReferencePolicy documentation for details. \n Support: + Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: Port specifies the destination port number + to use for this resource. Port is required when the + referent is a Kubernetes Service. For other resources, + destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: "Weight specifies the proportion of requests + forwarded to the referenced backend. This is computed + as weight/(sum of all weights in this BackendRefs list). + For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision + an implementation supports. Weight is not a percentage + and the sum of weights does not need to equal 100. \n + If only one backend is specified and it has a weight + greater than 0, 100% of the traffic is forwarded to + that backend. If weight is set to 0, no traffic should + be forwarded for this entry. If unspecified, weight + defaults to 1. \n Support for this field varies based + on the context where used." + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + maxItems: 16 + type: array + filters: + description: "Filters define the filters that are applied to + requests that match this rule. \n The effects of ordering + of multiple behaviors are currently unspecified. This can + change in the future based on feedback during the alpha stage. + \n Conformance-levels at this level are defined based on the + type of filter: \n - ALL core filters MUST be supported by + all implementations. - Implementers are encouraged to support + extended filters. - Implementation-specific custom filters + have no API guarantees across implementations. \n Specifying + a core filter multiple times has unspecified or custom conformance. + \n Support: Core" + items: + description: HTTPRouteFilter defines processing steps that + must be completed during the request or response lifecycle. + HTTPRouteFilters are meant as an extension point to express + processing that may be done in Gateway implementations. + Some examples include request or response modification, + implementing authentication strategies, rate-limiting, and + traffic shaping. API guarantee/conformance is defined based + on the type of the filter. + properties: + extensionRef: + description: "ExtensionRef is an optional, implementation-specific + extension to the \"filter\" behavior. For example, + resource \"myroutefilter\" in group \"networking.example.net\"). + ExtensionRef MUST NOT be used for core and extended + filters. \n Support: Implementation-specific" + properties: + group: + description: Group is the group of the referent. For + example, "networking.k8s.io". When unspecified (empty + string), core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + - name + type: object + requestHeaderModifier: + description: "RequestHeaderModifier defines a schema for + a filter that modifies request headers. \n Support: + Core" + properties: + add: + description: "Add adds the given header(s) (name, + value) to the request before the action. It appends + to any existing values associated with the header + name. \n Input: GET /foo HTTP/1.1 my-header: + foo \n Config: add: - name: \"my-header\" value: + \"bar\" \n Output: GET /foo HTTP/1.1 my-header: + foo my-header: bar" + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: "Name is the name of the HTTP Header + to be matched. Name matching MUST be case + insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + \n If multiple entries specify equivalent + header names, the first entry with an equivalent + name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST + be ignored. Due to the case-insensitivity + of header names, \"foo\" and \"Foo\" are considered + equivalent." + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + remove: + description: "Remove the given header(s) from the + HTTP request before the action. The value of Remove + is a list of HTTP header names. Note that the header + names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). + \n Input: GET /foo HTTP/1.1 my-header1: foo + \ my-header2: bar my-header3: baz \n Config: + \ remove: [\"my-header1\", \"my-header3\"] \n Output: + \ GET /foo HTTP/1.1 my-header2: bar" + items: + type: string + maxItems: 16 + type: array + set: + description: "Set overwrites the request with the + given header (name, value) before the action. \n + Input: GET /foo HTTP/1.1 my-header: foo \n Config: + \ set: - name: \"my-header\" value: \"bar\" + \n Output: GET /foo HTTP/1.1 my-header: bar" + items: + description: HTTPHeader represents an HTTP Header + name and value as defined by RFC 7230. + properties: + name: + description: "Name is the name of the HTTP Header + to be matched. Name matching MUST be case + insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). + \n If multiple entries specify equivalent + header names, the first entry with an equivalent + name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST + be ignored. Due to the case-insensitivity + of header names, \"foo\" and \"Foo\" are considered + equivalent." + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + value: + description: Value is the value of HTTP Header + to be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + requestMirror: + description: "RequestMirror defines a schema for a filter + that mirrors requests. Requests are sent to the specified + destination, but responses from that destination are + ignored. \n Support: Extended" + properties: + backendRef: + description: "BackendRef references a resource where + mirrored requests are sent. \n If the referent cannot + be found, this BackendRef is invalid and must be + dropped from the Gateway. The controller must ensure + the \"ResolvedRefs\" condition on the Route status + is set to `status: False` and not configure this + backend in the underlying implementation. \n If + there is a cross-namespace reference to an *existing* + object that is not allowed by a ReferencePolicy, + the controller must ensure the \"ResolvedRefs\" + \ condition on the Route is set to `status: False`, + with the \"RefNotPermitted\" reason and not configure + this backend in the underlying implementation. \n + In either error case, the Message of the `ResolvedRefs` + Condition should be used to provide more detail + about the problem. \n Support: Extended for Kubernetes + Service Support: Custom for any other resource" + properties: + group: + default: "" + description: Group is the group of the referent. + For example, "networking.k8s.io". When unspecified + (empty string), core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: Kind is kind of the referent. For + example "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the + backend. When unspecified, the local namespace + is inferred. \n Note that when a namespace is + specified, a ReferencePolicy object is required + in the referent namespace to allow that namespace's + owner to accept the reference. See the ReferencePolicy + documentation for details. \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: Port specifies the destination port + number to use for this resource. Port is required + when the referent is a Kubernetes Service. For + other resources, destination port might be derived + from the referent resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + required: + - backendRef + type: object + requestRedirect: + description: "RequestRedirect defines a schema for a filter + that responds to the request with an HTTP redirection. + \n Support: Core" + properties: + hostname: + description: "Hostname is the hostname to be used + in the value of the `Location` header in the response. + When empty, the hostname of the request is used. + \n Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + port: + description: "Port is the port to be used in the value + of the `Location` header in the response. When empty, + port (if specified) of the request is used. \n Support: + Extended" + format: int32 + maximum: 65535 + minimum: 1 + type: integer + scheme: + description: "Scheme is the scheme to be used in the + value of the `Location` header in the response. + When empty, the scheme of the request is used. \n + Support: Extended" + enum: + - http + - https + type: string + statusCode: + default: 302 + description: "StatusCode is the HTTP status code to + be used in response. \n Support: Core" + enum: + - 301 + - 302 + type: integer + type: object + type: + description: "Type identifies the type of filter to apply. + As with other API fields, types are classified into + three conformance levels: \n - Core: Filter types and + their corresponding configuration defined by \"Support: + Core\" in this package, e.g. \"RequestHeaderModifier\". + All implementations must support core filters. \n + - Extended: Filter types and their corresponding configuration + defined by \"Support: Extended\" in this package, + e.g. \"RequestMirror\". Implementers are encouraged + to support extended filters. \n - Custom: Filters that + are defined and supported by specific vendors. In + the future, filters showing convergence in behavior + across multiple implementations will be considered + for inclusion in extended or core conformance levels. + Filter-specific configuration for such filters is + specified using the ExtensionRef field. `Type` should + be set to \"ExtensionRef\" for custom filters. \n + Implementers are encouraged to define custom implementation + types to extend the core API with implementation-specific + behavior. \n If a reference to a custom filter type + cannot be resolved, the filter MUST NOT be skipped. + Instead, requests that would have been processed by + that filter MUST receive a HTTP error response." + enum: + - RequestHeaderModifier + - RequestMirror + - RequestRedirect + - ExtensionRef + type: string + required: + - type + type: object + maxItems: 16 + type: array + matches: + default: + - path: + type: PathPrefix + value: / + description: "Matches define conditions used for matching the + rule against incoming HTTP requests. Each match is independent, + i.e. this rule will be matched if **any** one of the matches + is satisfied. \n For example, take the following matches configuration: + \n ``` matches: - path: value: \"/foo\" headers: - + name: \"version\" value: \"v2\" - path: value: \"/v2/foo\" + ``` \n For a request to match against this rule, a request + must satisfy EITHER of the two conditions: \n - path prefixed + with `/foo` AND contains the header `version: v2` - path prefix + of `/v2/foo` \n See the documentation for HTTPRouteMatch on + how to specify multiple match conditions that should be ANDed + together. \n If no matches are specified, the default is a + prefix path match on \"/\", which has the effect of matching + every HTTP request. \n Proxy or Load Balancer routing configuration + generated from HTTPRoutes MUST prioritize rules based on the + following criteria, continuing on ties. Precedence must be + given to the the Rule with the largest number of: \n * Characters + in a matching non-wildcard hostname. * Characters in a matching + hostname. * Characters in a matching path. * Header matches. + * Query param matches. \n If ties still exist across multiple + Routes, matching precedence MUST be determined in order of + the following criteria, continuing on ties: \n * The oldest + Route based on creation timestamp. * The Route appearing first + in alphabetical order by \"/\". \n If ties + still exist within the Route that has been given precedence, + matching precedence MUST be granted to the first matching + rule meeting the above criteria." + items: + description: "HTTPRouteMatch defines the predicate used to + match requests to a given action. Multiple match types are + ANDed together, i.e. the match will evaluate to true only + if all conditions are satisfied. \n For example, the match + below will match a HTTP request only if its path starts + with `/foo` AND it contains the `version: v1` header: \n + ``` match: path: value: \"/foo\" headers: - name: + \"version\" value \"v1\" ```" + properties: + headers: + description: Headers specifies HTTP request header matchers. + Multiple match values are ANDed together, meaning, a + request must match all the specified headers to select + the route. + items: + description: HTTPHeaderMatch describes how to select + a HTTP route by matching HTTP request headers. + properties: + name: + description: "Name is the name of the HTTP Header + to be matched. Name matching MUST be case insensitive. + (See https://tools.ietf.org/html/rfc7230#section-3.2). + \n If multiple entries specify equivalent header + names, only the first entry with an equivalent + name MUST be considered for a match. Subsequent + entries with an equivalent header name MUST be + ignored. Due to the case-insensitivity of header + names, \"foo\" and \"Foo\" are considered equivalent. + \n When a header is repeated in an HTTP request, + it is implementation-specific behavior as to how + this is represented. Generally, proxies should + follow the guidance from the RFC: https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 + regarding processing a repeated header, with special + handling for \"Set-Cookie\"." + maxLength: 256 + minLength: 1 + pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ + type: string + type: + default: Exact + description: "Type specifies how to match against + the value of the header. \n Support: Core (Exact) + \n Support: Custom (RegularExpression) \n Since + RegularExpression HeaderMatchType has custom conformance, + implementations can support POSIX, PCRE or any + other dialects of regular expressions. Please + read the implementation's documentation to determine + the supported dialect." + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP Header to + be matched. + maxLength: 4096 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + method: + description: "Method specifies HTTP method matcher. When + specified, this route will be matched only if the request + has the specified method. \n Support: Extended" + enum: + - GET + - HEAD + - POST + - PUT + - DELETE + - CONNECT + - OPTIONS + - TRACE + - PATCH + type: string + path: + default: + type: PathPrefix + value: / + description: Path specifies a HTTP request path matcher. + If this field is not specified, a default prefix match + on the "/" path is provided. + properties: + type: + default: PathPrefix + description: "Type specifies how to match against + the path Value. \n Support: Core (Exact, PathPrefix) + \n Support: Custom (RegularExpression)" + enum: + - Exact + - PathPrefix + - RegularExpression + type: string + value: + default: / + description: Value of the HTTP path to match against. + maxLength: 1024 + type: string + type: object + queryParams: + description: QueryParams specifies HTTP query parameter + matchers. Multiple match values are ANDed together, + meaning, a request must match all the specified query + parameters to select the route. + items: + description: HTTPQueryParamMatch describes how to select + a HTTP route by matching HTTP query parameters. + properties: + name: + description: Name is the name of the HTTP query + param to be matched. This must be an exact string + match. (See https://tools.ietf.org/html/rfc7230#section-2.7.3). + maxLength: 256 + minLength: 1 + type: string + type: + default: Exact + description: "Type specifies how to match against + the value of the query parameter. \n Support: + Extended (Exact) \n Support: Custom (RegularExpression) + \n Since RegularExpression QueryParamMatchType + has custom conformance, implementations can support + POSIX, PCRE or any other dialects of regular expressions. + Please read the implementation's documentation + to determine the supported dialect." + enum: + - Exact + - RegularExpression + type: string + value: + description: Value is the value of HTTP query param + to be matched. + maxLength: 1024 + minLength: 1 + type: string + required: + - name + - value + type: object + maxItems: 16 + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + maxItems: 8 + type: array + type: object + maxItems: 16 + type: array + type: object + status: + description: Status defines the current state of HTTPRoute. + properties: + parents: + description: "Parents is a list of parent resources (usually Gateways) + that are associated with the route, and the status of the route + with respect to each parent. When this route attaches to a parent, + the controller that manages the parent must add an entry to this + list when the controller first sees the route and should update + the entry as appropriate when the route or gateway is modified. + \n Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this + API can only populate Route status for the Gateways/parent resources + they are responsible for. \n A maximum of 32 Gateways will be represented + in this list. An empty list means the route has not been attached + to any Gateway." + items: + description: RouteParentStatus describes the status of a route with + respect to an associated Parent. + properties: + conditions: + description: "Conditions describes the status of the route with + respect to the Gateway. Note that the route's availability + is also subject to the Gateway's own status conditions and + listener status. \n If the Route's ParentRef specifies an + existing Gateway that supports Routes of this kind AND that + Gateway's controller has sufficient access, then that Gateway's + controller MUST set the \"Accepted\" condition on the Route, + to indicate whether the route has been accepted or rejected + by the Gateway, and why. \n A Route MUST be considered \"Accepted\" + if at least one of the Route's rules is implemented by the + Gateway. \n There are a number of cases where the \"Accepted\" + condition may not be set due to lack of controller visibility, + that includes when: \n * The Route refers to a non-existent + parent. * The Route is of a type that the controller does + not support. * The Route is in a namespace the the controller + does not have access to." + items: + description: "Condition contains details for one aspect of + the current state of this API Resource. --- This struct + is intended for direct use as an array at the field path + .status.conditions. For example, type FooStatus struct{ + \ // Represents the observations of a foo's current state. + \ // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type + \ // +patchStrategy=merge // +listType=map // + +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should + be when the underlying condition changed. If that is + not known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, + if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier + indicating the reason for the condition's last transition. + Producers of specific condition types may define expected + values and meanings for this field, and whether the + values are considered a guaranteed API. The value should + be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is + (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: "ControllerName is a domain/path string that indicates + the name of the controller that wrote this status. This corresponds + with the controllerName field on GatewayClass. \n Example: + \"example.net/gateway-controller\". \n The format of this + field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid + Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: ParentRef corresponds with a ParentRef in the spec + that this RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: "Group is the group of the referent. \n Support: + Core" + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: "Kind is kind of the referent. \n Support: + Core (Gateway) Support: Custom (Other Resources)" + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: "Name is the name of the referent. \n Support: + Core" + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the referent. + When unspecified (or empty string), this refers to the + local namespace of the Route. \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within + the target resource. In the following resources, SectionName + is interpreted as the following: \n * Gateway: Listener + Name \n Implementations MAY choose to support attaching + Routes to other resources. If that is the case, they MUST + clearly document how SectionName is interpreted. \n When + unspecified (empty string), this will reference the entire + resource. For the purpose of status, an attachment is + considered successful if at least one section in the parent + resource accepts it. For example, Gateway listeners can + restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept + attachment from the referencing Route, the Route MUST + be considered successfully attached. If no Gateway listeners + accept attachment from this Route, the Route MUST be considered + detached from the Gateway. \n Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 + creationTimestamp: null + name: referencepolicies.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: ReferencePolicy + listKind: ReferencePolicyList + plural: referencepolicies + shortNames: + - refpol + singular: referencepolicy + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: "ReferencePolicy identifies kinds of resources in other namespaces + that are trusted to reference the specified kinds of resources in the same + namespace as the policy. \n Each ReferencePolicy can be used to represent + a unique trust relationship. Additional Reference Policies can be used to + add to the set of trusted sources of inbound references for the namespace + they are defined within. \n All cross-namespace references in Gateway API + (with the exception of cross-namespace Gateway-route attachment) require + a ReferencePolicy. \n Support: Core" + 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: Spec defines the desired state of ReferencePolicy. + properties: + from: + description: "From describes the trusted namespaces and kinds that + can reference the resources described in \"To\". Each entry in this + list must be considered to be an additional place that references + can be valid from, or to put this another way, entries must be combined + using OR. \n Support: Core" + items: + description: ReferencePolicyFrom describes trusted namespaces and + kinds. + properties: + group: + description: "Group is the group of the referent. When empty, + the Kubernetes core API group is inferred. \n Support: Core" + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: "Kind is the kind of the referent. Although implementations + may support additional resources, the following Route types + are part of the \"Core\" support level for this field: \n + * HTTPRoute * TCPRoute * TLSRoute * UDPRoute" + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + namespace: + description: "Namespace is the namespace of the referent. \n + Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + type: object + maxItems: 16 + minItems: 1 + type: array + to: + description: "To describes the resources that may be referenced by + the resources described in \"From\". Each entry in this list must + be considered to be an additional place that references can be valid + to, or to put this another way, entries must be combined using OR. + \n Support: Core" + items: + description: ReferencePolicyTo describes what Kinds are allowed + as targets of the references. + properties: + group: + description: "Group is the group of the referent. When empty, + the Kubernetes core API group is inferred. \n Support: Core" + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: "Kind is the kind of the referent. Although implementations + may support additional resources, the following types are + part of the \"Core\" support level for this field: \n * Service" + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. When unspecified + or empty, this policy refers to all resources of the specified + Group and Kind in the local namespace. + maxLength: 253 + minLength: 1 + type: string + required: + - group + - kind + type: object + maxItems: 16 + minItems: 1 + type: array + required: + - from + - to + type: object + type: object + served: true + storage: true + subresources: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 + creationTimestamp: null + name: tcproutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: TCPRoute + listKind: TCPRouteList + plural: tcproutes + singular: tcproute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: TCPRoute provides a way to route TCP requests. When combined + with a Gateway listener, it can be used to forward connections on the port + specified by the listener to a set of backends specified by the TCPRoute. + 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: Spec defines the desired state of TCPRoute. + properties: + parentRefs: + description: "ParentRefs references the resources (usually Gateways) + that a Route wants to be attached to. Note that the referenced parent + resource needs to allow this for the attachment to be complete. + For Gateways, that means the Gateway needs to allow attachment from + Routes of this kind and namespace. \n The only kind of parent resource + with \"Core\" support is Gateway. This API may be extended in the + future to support additional kinds of parent resources such as one + of the route kinds. \n It is invalid to reference an identical parent + more than once. It is valid to reference multiple distinct sections + within the same parent resource, such as 2 Listeners within a Gateway. + \n It is possible to separately reference multiple distinct objects + that may be collapsed by an implementation. For example, some implementations + may choose to merge compatible Gateway Listeners together. If that + is the case, the list of routes attached to those resources should + also be merged." + items: + description: "ParentRef identifies an API object (usually a Gateway) + that can be considered a parent of this resource (usually a route). + The only kind of parent resource with \"Core\" support is Gateway. + This API may be extended in the future to support additional kinds + of parent resources, such as HTTPRoute. \n The API object must + be valid in the cluster; the Group and Kind must be registered + in the cluster for this reference to be valid. \n References to + objects with invalid Group and Kind are not valid, and must be + rejected by the implementation, with appropriate Conditions set + on the containing object." + properties: + group: + default: gateway.networking.k8s.io + description: "Group is the group of the referent. \n Support: + Core" + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: "Kind is kind of the referent. \n Support: Core + (Gateway) Support: Custom (Other Resources)" + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: "Name is the name of the referent. \n Support: + Core" + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the referent. When + unspecified (or empty string), this refers to the local namespace + of the Route. \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within the + target resource. In the following resources, SectionName is + interpreted as the following: \n * Gateway: Listener Name + \n Implementations MAY choose to support attaching Routes + to other resources. If that is the case, they MUST clearly + document how SectionName is interpreted. \n When unspecified + (empty string), this will reference the entire resource. For + the purpose of status, an attachment is considered successful + if at least one section in the parent resource accepts it. + For example, Gateway listeners can restrict which Routes can + attach to them by Route kind, namespace, or hostname. If 1 + of 2 Gateway listeners accept attachment from the referencing + Route, the Route MUST be considered successfully attached. + If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. \n + Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + rules: + description: Rules are a list of TCP matchers and actions. + items: + description: TCPRouteRule is the configuration for a given rule. + properties: + backendRefs: + description: "BackendRefs defines the backend(s) where matching + requests should be sent. If unspecified or invalid (refers + to a non-existent resource or a Service with no endpoints), + the underlying implementation MUST actively reject connection + attempts to this backend. Connection rejections must respect + weight; if an invalid backend is requested to have 80% of + connections, then 80% of connections must be rejected instead. + \n Support: Core for Kubernetes Service Support: Custom for + any other resource \n Support for weight: Extended" + items: + description: "BackendRef defines how a Route should forward + a request to a Kubernetes resource. \n Note that when a + namespace is specified, a ReferencePolicy object is required + in the referent namespace to allow that namespace's owner + to accept the reference. See the ReferencePolicy documentation + for details." + properties: + group: + default: "" + description: Group is the group of the referent. For example, + "networking.k8s.io". When unspecified (empty string), + core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the backend. + When unspecified, the local namespace is inferred. \n + Note that when a namespace is specified, a ReferencePolicy + object is required in the referent namespace to allow + that namespace's owner to accept the reference. See + the ReferencePolicy documentation for details. \n Support: + Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: Port specifies the destination port number + to use for this resource. Port is required when the + referent is a Kubernetes Service. For other resources, + destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: "Weight specifies the proportion of requests + forwarded to the referenced backend. This is computed + as weight/(sum of all weights in this BackendRefs list). + For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision + an implementation supports. Weight is not a percentage + and the sum of weights does not need to equal 100. \n + If only one backend is specified and it has a weight + greater than 0, 100% of the traffic is forwarded to + that backend. If weight is set to 0, no traffic should + be forwarded for this entry. If unspecified, weight + defaults to 1. \n Support for this field varies based + on the context where used." + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + maxItems: 16 + minItems: 1 + type: array + type: object + maxItems: 16 + minItems: 1 + type: array + required: + - rules + type: object + status: + description: Status defines the current state of TCPRoute. + properties: + parents: + description: "Parents is a list of parent resources (usually Gateways) + that are associated with the route, and the status of the route + with respect to each parent. When this route attaches to a parent, + the controller that manages the parent must add an entry to this + list when the controller first sees the route and should update + the entry as appropriate when the route or gateway is modified. + \n Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this + API can only populate Route status for the Gateways/parent resources + they are responsible for. \n A maximum of 32 Gateways will be represented + in this list. An empty list means the route has not been attached + to any Gateway." + items: + description: RouteParentStatus describes the status of a route with + respect to an associated Parent. + properties: + conditions: + description: "Conditions describes the status of the route with + respect to the Gateway. Note that the route's availability + is also subject to the Gateway's own status conditions and + listener status. \n If the Route's ParentRef specifies an + existing Gateway that supports Routes of this kind AND that + Gateway's controller has sufficient access, then that Gateway's + controller MUST set the \"Accepted\" condition on the Route, + to indicate whether the route has been accepted or rejected + by the Gateway, and why. \n A Route MUST be considered \"Accepted\" + if at least one of the Route's rules is implemented by the + Gateway. \n There are a number of cases where the \"Accepted\" + condition may not be set due to lack of controller visibility, + that includes when: \n * The Route refers to a non-existent + parent. * The Route is of a type that the controller does + not support. * The Route is in a namespace the the controller + does not have access to." + items: + description: "Condition contains details for one aspect of + the current state of this API Resource. --- This struct + is intended for direct use as an array at the field path + .status.conditions. For example, type FooStatus struct{ + \ // Represents the observations of a foo's current state. + \ // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type + \ // +patchStrategy=merge // +listType=map // + +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should + be when the underlying condition changed. If that is + not known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, + if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier + indicating the reason for the condition's last transition. + Producers of specific condition types may define expected + values and meanings for this field, and whether the + values are considered a guaranteed API. The value should + be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is + (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: "ControllerName is a domain/path string that indicates + the name of the controller that wrote this status. This corresponds + with the controllerName field on GatewayClass. \n Example: + \"example.net/gateway-controller\". \n The format of this + field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid + Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: ParentRef corresponds with a ParentRef in the spec + that this RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: "Group is the group of the referent. \n Support: + Core" + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: "Kind is kind of the referent. \n Support: + Core (Gateway) Support: Custom (Other Resources)" + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: "Name is the name of the referent. \n Support: + Core" + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the referent. + When unspecified (or empty string), this refers to the + local namespace of the Route. \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within + the target resource. In the following resources, SectionName + is interpreted as the following: \n * Gateway: Listener + Name \n Implementations MAY choose to support attaching + Routes to other resources. If that is the case, they MUST + clearly document how SectionName is interpreted. \n When + unspecified (empty string), this will reference the entire + resource. For the purpose of status, an attachment is + considered successful if at least one section in the parent + resource accepts it. For example, Gateway listeners can + restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept + attachment from the referencing Route, the Route MUST + be considered successfully attached. If no Gateway listeners + accept attachment from this Route, the Route MUST be considered + detached from the Gateway. \n Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 + creationTimestamp: null + name: tlsroutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: TLSRoute + listKind: TLSRouteList + plural: tlsroutes + singular: tlsroute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: "The TLSRoute resource is similar to TCPRoute, but can be configured + to match against TLS-specific metadata. This allows more flexibility in + matching streams for a given TLS listener. \n If you need to forward traffic + to a single target for a TLS listener, you could choose to use a TCPRoute + with a TLS listener." + 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: Spec defines the desired state of TLSRoute. + properties: + hostnames: + description: "Hostnames defines a set of SNI names that should match + against the SNI attribute of TLS ClientHello message in TLS handshake. + This matches the RFC 1123 definition of a hostname with 2 notable + exceptions: \n 1. IPs are not allowed in SNI names per RFC 6066. + 2. A hostname may be prefixed with a wildcard label (`*.`). The + wildcard label must appear by itself as the first label. \n If + a hostname is specified by both the Listener and TLSRoute, there + must be at least one intersecting hostname for the TLSRoute to be + attached to the Listener. For example: \n * A Listener with `test.example.com` + as the hostname matches TLSRoutes that have either not specified + any hostnames, or have specified at least one of `test.example.com` + or `*.example.com`. * A Listener with `*.example.com` as the hostname + matches TLSRoutes that have either not specified any hostnames + or have specified at least one hostname that matches the Listener + hostname. For example, `test.example.com` and `*.example.com` + would both match. On the other hand, `example.com` and `test.example.net` + would not match. \n If both the Listener and TLSRoute have specified + hostnames, any TLSRoute hostnames that do not match the Listener + hostname MUST be ignored. For example, if a Listener specified `*.example.com`, + and the TLSRoute specified `test.example.com` and `test.example.net`, + `test.example.net` must not be considered for a match. \n If both + the Listener and TLSRoute have specified hostnames, and none match + with the criteria above, then the TLSRoute is not accepted. The + implementation must raise an 'Accepted' Condition with a status + of `False` in the corresponding RouteParentStatus. \n Support: Core" + items: + description: "Hostname is the fully qualified domain name of a network + host. This matches the RFC 1123 definition of a hostname with + 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname + may be prefixed with a wildcard label (`*.`). The wildcard label + must appear by itself as the first label. \n Hostname can be \"precise\" + which is a domain name without the terminating dot of a network + host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain + name prefixed with a single wildcard label (e.g. `*.example.com`). + \n Note that as per RFC1035 and RFC1123, a *label* must consist + of lower case alphanumeric characters or '-', and must start and + end with an alphanumeric character. No other punctuation is allowed." + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + type: array + parentRefs: + description: "ParentRefs references the resources (usually Gateways) + that a Route wants to be attached to. Note that the referenced parent + resource needs to allow this for the attachment to be complete. + For Gateways, that means the Gateway needs to allow attachment from + Routes of this kind and namespace. \n The only kind of parent resource + with \"Core\" support is Gateway. This API may be extended in the + future to support additional kinds of parent resources such as one + of the route kinds. \n It is invalid to reference an identical parent + more than once. It is valid to reference multiple distinct sections + within the same parent resource, such as 2 Listeners within a Gateway. + \n It is possible to separately reference multiple distinct objects + that may be collapsed by an implementation. For example, some implementations + may choose to merge compatible Gateway Listeners together. If that + is the case, the list of routes attached to those resources should + also be merged." + items: + description: "ParentRef identifies an API object (usually a Gateway) + that can be considered a parent of this resource (usually a route). + The only kind of parent resource with \"Core\" support is Gateway. + This API may be extended in the future to support additional kinds + of parent resources, such as HTTPRoute. \n The API object must + be valid in the cluster; the Group and Kind must be registered + in the cluster for this reference to be valid. \n References to + objects with invalid Group and Kind are not valid, and must be + rejected by the implementation, with appropriate Conditions set + on the containing object." + properties: + group: + default: gateway.networking.k8s.io + description: "Group is the group of the referent. \n Support: + Core" + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: "Kind is kind of the referent. \n Support: Core + (Gateway) Support: Custom (Other Resources)" + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: "Name is the name of the referent. \n Support: + Core" + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the referent. When + unspecified (or empty string), this refers to the local namespace + of the Route. \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within the + target resource. In the following resources, SectionName is + interpreted as the following: \n * Gateway: Listener Name + \n Implementations MAY choose to support attaching Routes + to other resources. If that is the case, they MUST clearly + document how SectionName is interpreted. \n When unspecified + (empty string), this will reference the entire resource. For + the purpose of status, an attachment is considered successful + if at least one section in the parent resource accepts it. + For example, Gateway listeners can restrict which Routes can + attach to them by Route kind, namespace, or hostname. If 1 + of 2 Gateway listeners accept attachment from the referencing + Route, the Route MUST be considered successfully attached. + If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. \n + Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + rules: + description: Rules are a list of TLS matchers and actions. + items: + description: TLSRouteRule is the configuration for a given rule. + properties: + backendRefs: + description: "BackendRefs defines the backend(s) where matching + requests should be sent. If unspecified or invalid (refers + to a non-existent resource or a Service with no endpoints), + the rule performs no forwarding; if no filters are specified + that would result in a response being sent, the underlying + implementation must actively reject request attempts to this + backend, by rejecting the connection or returning a 503 status + code. Request rejections must respect weight; if an invalid + backend is requested to have 80% of requests, then 80% of + requests must be rejected instead. \n Support: Core for Kubernetes + Service Support: Custom for any other resource \n Support + for weight: Extended" + items: + description: "BackendRef defines how a Route should forward + a request to a Kubernetes resource. \n Note that when a + namespace is specified, a ReferencePolicy object is required + in the referent namespace to allow that namespace's owner + to accept the reference. See the ReferencePolicy documentation + for details." + properties: + group: + default: "" + description: Group is the group of the referent. For example, + "networking.k8s.io". When unspecified (empty string), + core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the backend. + When unspecified, the local namespace is inferred. \n + Note that when a namespace is specified, a ReferencePolicy + object is required in the referent namespace to allow + that namespace's owner to accept the reference. See + the ReferencePolicy documentation for details. \n Support: + Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: Port specifies the destination port number + to use for this resource. Port is required when the + referent is a Kubernetes Service. For other resources, + destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: "Weight specifies the proportion of requests + forwarded to the referenced backend. This is computed + as weight/(sum of all weights in this BackendRefs list). + For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision + an implementation supports. Weight is not a percentage + and the sum of weights does not need to equal 100. \n + If only one backend is specified and it has a weight + greater than 0, 100% of the traffic is forwarded to + that backend. If weight is set to 0, no traffic should + be forwarded for this entry. If unspecified, weight + defaults to 1. \n Support for this field varies based + on the context where used." + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + maxItems: 16 + minItems: 1 + type: array + type: object + maxItems: 16 + minItems: 1 + type: array + required: + - rules + type: object + status: + description: Status defines the current state of TLSRoute. + properties: + parents: + description: "Parents is a list of parent resources (usually Gateways) + that are associated with the route, and the status of the route + with respect to each parent. When this route attaches to a parent, + the controller that manages the parent must add an entry to this + list when the controller first sees the route and should update + the entry as appropriate when the route or gateway is modified. + \n Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this + API can only populate Route status for the Gateways/parent resources + they are responsible for. \n A maximum of 32 Gateways will be represented + in this list. An empty list means the route has not been attached + to any Gateway." + items: + description: RouteParentStatus describes the status of a route with + respect to an associated Parent. + properties: + conditions: + description: "Conditions describes the status of the route with + respect to the Gateway. Note that the route's availability + is also subject to the Gateway's own status conditions and + listener status. \n If the Route's ParentRef specifies an + existing Gateway that supports Routes of this kind AND that + Gateway's controller has sufficient access, then that Gateway's + controller MUST set the \"Accepted\" condition on the Route, + to indicate whether the route has been accepted or rejected + by the Gateway, and why. \n A Route MUST be considered \"Accepted\" + if at least one of the Route's rules is implemented by the + Gateway. \n There are a number of cases where the \"Accepted\" + condition may not be set due to lack of controller visibility, + that includes when: \n * The Route refers to a non-existent + parent. * The Route is of a type that the controller does + not support. * The Route is in a namespace the the controller + does not have access to." + items: + description: "Condition contains details for one aspect of + the current state of this API Resource. --- This struct + is intended for direct use as an array at the field path + .status.conditions. For example, type FooStatus struct{ + \ // Represents the observations of a foo's current state. + \ // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type + \ // +patchStrategy=merge // +listType=map // + +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should + be when the underlying condition changed. If that is + not known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, + if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier + indicating the reason for the condition's last transition. + Producers of specific condition types may define expected + values and meanings for this field, and whether the + values are considered a guaranteed API. The value should + be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is + (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: "ControllerName is a domain/path string that indicates + the name of the controller that wrote this status. This corresponds + with the controllerName field on GatewayClass. \n Example: + \"example.net/gateway-controller\". \n The format of this + field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid + Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: ParentRef corresponds with a ParentRef in the spec + that this RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: "Group is the group of the referent. \n Support: + Core" + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: "Kind is kind of the referent. \n Support: + Core (Gateway) Support: Custom (Other Resources)" + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: "Name is the name of the referent. \n Support: + Core" + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the referent. + When unspecified (or empty string), this refers to the + local namespace of the Route. \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within + the target resource. In the following resources, SectionName + is interpreted as the following: \n * Gateway: Listener + Name \n Implementations MAY choose to support attaching + Routes to other resources. If that is the case, they MUST + clearly document how SectionName is interpreted. \n When + unspecified (empty string), this will reference the entire + resource. For the purpose of status, an attachment is + considered successful if at least one section in the parent + resource accepts it. For example, Gateway listeners can + restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept + attachment from the referencing Route, the Route MUST + be considered successfully attached. If no Gateway listeners + accept attachment from this Route, the Route MUST be considered + detached from the Gateway. \n Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 + creationTimestamp: null + name: udproutes.gateway.networking.k8s.io +spec: + group: gateway.networking.k8s.io + names: + categories: + - gateway-api + kind: UDPRoute + listKind: UDPRouteList + plural: udproutes + singular: udproute + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha2 + schema: + openAPIV3Schema: + description: UDPRoute provides a way to route UDP traffic. When combined with + a Gateway listener, it can be used to forward traffic on the port specified + by the listener to a set of backends specified by the UDPRoute. + 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: Spec defines the desired state of UDPRoute. + properties: + parentRefs: + description: "ParentRefs references the resources (usually Gateways) + that a Route wants to be attached to. Note that the referenced parent + resource needs to allow this for the attachment to be complete. + For Gateways, that means the Gateway needs to allow attachment from + Routes of this kind and namespace. \n The only kind of parent resource + with \"Core\" support is Gateway. This API may be extended in the + future to support additional kinds of parent resources such as one + of the route kinds. \n It is invalid to reference an identical parent + more than once. It is valid to reference multiple distinct sections + within the same parent resource, such as 2 Listeners within a Gateway. + \n It is possible to separately reference multiple distinct objects + that may be collapsed by an implementation. For example, some implementations + may choose to merge compatible Gateway Listeners together. If that + is the case, the list of routes attached to those resources should + also be merged." + items: + description: "ParentRef identifies an API object (usually a Gateway) + that can be considered a parent of this resource (usually a route). + The only kind of parent resource with \"Core\" support is Gateway. + This API may be extended in the future to support additional kinds + of parent resources, such as HTTPRoute. \n The API object must + be valid in the cluster; the Group and Kind must be registered + in the cluster for this reference to be valid. \n References to + objects with invalid Group and Kind are not valid, and must be + rejected by the implementation, with appropriate Conditions set + on the containing object." + properties: + group: + default: gateway.networking.k8s.io + description: "Group is the group of the referent. \n Support: + Core" + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: "Kind is kind of the referent. \n Support: Core + (Gateway) Support: Custom (Other Resources)" + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: "Name is the name of the referent. \n Support: + Core" + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the referent. When + unspecified (or empty string), this refers to the local namespace + of the Route. \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within the + target resource. In the following resources, SectionName is + interpreted as the following: \n * Gateway: Listener Name + \n Implementations MAY choose to support attaching Routes + to other resources. If that is the case, they MUST clearly + document how SectionName is interpreted. \n When unspecified + (empty string), this will reference the entire resource. For + the purpose of status, an attachment is considered successful + if at least one section in the parent resource accepts it. + For example, Gateway listeners can restrict which Routes can + attach to them by Route kind, namespace, or hostname. If 1 + of 2 Gateway listeners accept attachment from the referencing + Route, the Route MUST be considered successfully attached. + If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. \n + Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + rules: + description: Rules are a list of UDP matchers and actions. + items: + description: UDPRouteRule is the configuration for a given rule. + properties: + backendRefs: + description: "BackendRefs defines the backend(s) where matching + requests should be sent. If unspecified or invalid (refers + to a non-existent resource or a Service with no endpoints), + the underlying implementation MUST actively reject connection + attempts to this backend. Packet drops must respect weight; + if an invalid backend is requested to have 80% of the packets, + then 80% of packets must be dropped instead. \n Support: Core + for Kubernetes Service Support: Custom for any other resource + \n Support for weight: Extended" + items: + description: "BackendRef defines how a Route should forward + a request to a Kubernetes resource. \n Note that when a + namespace is specified, a ReferencePolicy object is required + in the referent namespace to allow that namespace's owner + to accept the reference. See the ReferencePolicy documentation + for details." + properties: + group: + default: "" + description: Group is the group of the referent. For example, + "networking.k8s.io". When unspecified (empty string), + core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: Kind is kind of the referent. For example + "HTTPRoute" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the backend. + When unspecified, the local namespace is inferred. \n + Note that when a namespace is specified, a ReferencePolicy + object is required in the referent namespace to allow + that namespace's owner to accept the reference. See + the ReferencePolicy documentation for details. \n Support: + Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: Port specifies the destination port number + to use for this resource. Port is required when the + referent is a Kubernetes Service. For other resources, + destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: "Weight specifies the proportion of requests + forwarded to the referenced backend. This is computed + as weight/(sum of all weights in this BackendRefs list). + For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision + an implementation supports. Weight is not a percentage + and the sum of weights does not need to equal 100. \n + If only one backend is specified and it has a weight + greater than 0, 100% of the traffic is forwarded to + that backend. If weight is set to 0, no traffic should + be forwarded for this entry. If unspecified, weight + defaults to 1. \n Support for this field varies based + on the context where used." + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + maxItems: 16 + minItems: 1 + type: array + type: object + maxItems: 16 + minItems: 1 + type: array + required: + - rules + type: object + status: + description: Status defines the current state of UDPRoute. + properties: + parents: + description: "Parents is a list of parent resources (usually Gateways) + that are associated with the route, and the status of the route + with respect to each parent. When this route attaches to a parent, + the controller that manages the parent must add an entry to this + list when the controller first sees the route and should update + the entry as appropriate when the route or gateway is modified. + \n Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this + API can only populate Route status for the Gateways/parent resources + they are responsible for. \n A maximum of 32 Gateways will be represented + in this list. An empty list means the route has not been attached + to any Gateway." + items: + description: RouteParentStatus describes the status of a route with + respect to an associated Parent. + properties: + conditions: + description: "Conditions describes the status of the route with + respect to the Gateway. Note that the route's availability + is also subject to the Gateway's own status conditions and + listener status. \n If the Route's ParentRef specifies an + existing Gateway that supports Routes of this kind AND that + Gateway's controller has sufficient access, then that Gateway's + controller MUST set the \"Accepted\" condition on the Route, + to indicate whether the route has been accepted or rejected + by the Gateway, and why. \n A Route MUST be considered \"Accepted\" + if at least one of the Route's rules is implemented by the + Gateway. \n There are a number of cases where the \"Accepted\" + condition may not be set due to lack of controller visibility, + that includes when: \n * The Route refers to a non-existent + parent. * The Route is of a type that the controller does + not support. * The Route is in a namespace the the controller + does not have access to." + items: + description: "Condition contains details for one aspect of + the current state of this API Resource. --- This struct + is intended for direct use as an array at the field path + .status.conditions. For example, type FooStatus struct{ + \ // Represents the observations of a foo's current state. + \ // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type + \ // +patchStrategy=merge // +listType=map // + +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` + \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should + be when the underlying condition changed. If that is + not known, then using the time when the API field changed + is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, + if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the + current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier + indicating the reason for the condition's last transition. + Producers of specific condition types may define expected + values and meanings for this field, and whether the + values are considered a guaranteed API. The value should + be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across + resources like Available, but because arbitrary conditions + can be useful (see .node.status.conditions), the ability + to deconflict is important. The regex it matches is + (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: "ControllerName is a domain/path string that indicates + the name of the controller that wrote this status. This corresponds + with the controllerName field on GatewayClass. \n Example: + \"example.net/gateway-controller\". \n The format of this + field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid + Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: ParentRef corresponds with a ParentRef in the spec + that this RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: "Group is the group of the referent. \n Support: + Core" + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: "Kind is kind of the referent. \n Support: + Core (Gateway) Support: Custom (Other Resources)" + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: "Name is the name of the referent. \n Support: + Core" + maxLength: 253 + minLength: 1 + type: string + namespace: + description: "Namespace is the namespace of the referent. + When unspecified (or empty string), this refers to the + local namespace of the Route. \n Support: Core" + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + sectionName: + description: "SectionName is the name of a section within + the target resource. In the following resources, SectionName + is interpreted as the following: \n * Gateway: Listener + Name \n Implementations MAY choose to support attaching + Routes to other resources. If that is the case, they MUST + clearly document how SectionName is interpreted. \n When + unspecified (empty string), this will reference the entire + resource. For the purpose of status, an attachment is + considered successful if at least one section in the parent + resource accepts it. For example, Gateway listeners can + restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept + attachment from the referencing Route, the Route MUST + be considered successfully attached. If no Gateway listeners + accept attachment from this Route, the Route MUST be considered + detached from the Gateway. \n Support: Core" + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] + +{{ end }} \ No newline at end of file diff --git a/charts/consul/templates/api-gateway-gatewayclass.yaml b/charts/consul/templates/api-gateway-gatewayclass.yaml new file mode 100644 index 0000000000..1673102c7c --- /dev/null +++ b/charts/consul/templates/api-gateway-gatewayclass.yaml @@ -0,0 +1,20 @@ +{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +{{- if .Values.apiGateway.managedGatewayClass.enabled }} +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: GatewayClass +metadata: + name: consul-api-gateway + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway +spec: + controllerName: hashicorp.com/consul-api-gateway-controller + parametersRef: + group: api-gateway.consul.hashicorp.com + kind: GatewayClassConfig + name: consul-api-gateway-class-config +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/consul/templates/api-gateway-gatewayclassconfig.yaml b/charts/consul/templates/api-gateway-gatewayclassconfig.yaml new file mode 100644 index 0000000000..c4ba0348d9 --- /dev/null +++ b/charts/consul/templates/api-gateway-gatewayclassconfig.yaml @@ -0,0 +1,50 @@ +{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +{{- if .Values.apiGateway.managedGatewayClass.enabled }} +apiVersion: api-gateway.consul.hashicorp.com/v1alpha1 +kind: GatewayClassConfig +metadata: + name: consul-api-gateway-class-config + labels: + app: {{ template "consul.name" . }} + chart: {{ template "consul.chart" . }} + heritage: {{ .Release.Service }} + release: {{ .Release.Name }} + component: api-gateway +spec: + consul: + authentication: + {{- if .Values.global.tls.enabled }} + scheme: https + {{- if not (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots) }} + {{- if .Values.global.tls.caCert.secretName }} + caSecret: {{ .Values.global.tls.caCert.secretName }} + {{- else }} + caSecret: {{ template "consul.fullname" . }}-ca-cert + {{- end }} + {{- end }} + {{- else }} + scheme: http + {{- end }} + ports: + grpc: 8502 + {{- if .Values.global.tls.enabled }} + http: 8501 + {{- else }} + http: 8500 + {{- end }} + image: + consulAPIGateway: {{ .Values.apiGateway.image }} + envoy: {{ .Values.global.imageEnvoy }} + {{- if .Values.apiGateway.nodeSelector }} + nodeSelector: + {{ tpl .Values.apiGateway.managedGatewayClass.nodeSelector . | indent 4 | trim }} + {{- end }} + {{- if .Values.apiGateway.managedGatewayClass.copyAnnotations.service }} + copyAnnotations: + service: + {{ tpl .Values.apiGateway.managedGatewayClass.copyAnnotations.service.annotations . | nindent 6 | trim }} + {{- end }} + serviceType: {{ .Values.apiGateway.managedGatewayClass.serviceType }} + logLevel: {{ default .Values.global.logLevel .Values.apiGateway.managedGatewayClass.logLevel }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 5c2b17f4ad..a34c6bae99 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2458,6 +2458,100 @@ terminatingGateways: gateways: - name: terminating-gateway +# Conffiguration setings for the Consul API Gateway integration +apiGateway: + # When true the helm chart will install the Consul API Gateway controller + enabled: false + + # Image to use for the api-gateway-controller pods and gateway instances + # @type: string + image: "hashicorp/consul-api-gateway:0.1.0-techpreview" + + + # Override global log verbosity level for api-gateway-controller pods. One of "debug", "info", "warn", or "error". + # @type: string + logLevel: info + managedGatewayClass: + enabled: true + # This value defines `nodeSelector` (https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) + # labels for gateway pod assignment, formatted as a multi-line string. + # + # Example: + # + # ```yaml + # nodeSelector: | + # beta.kubernetes.io/arch: amd64 + # ``` + # + # @type: string + nodeSelector: null + + # This value defines the type of service created for gateways (e.g. LoadBalancer, ClusterIP) + serviceType: LoadBalancer + + # This value toggles if the gateway ports should be mapped to host ports + useHostPorts: false + + copyAnnotations: + # This value defines a list of annotations to be copied from the Gateway to the Service created, formatted as a multi-line string. + # + # Example: + # + # ```yaml + # service: | + # - external-dns.alpha.kubernetes.io/hostname + # ``` + # + # @type: string + service: null + + # Override global log verbosity level for ateway pods. One of "debug", "info", "warn", or "error". + # @type: string + logLevel: info + + + + controller: + replicas: 1 + + # Annotations to apply to the api-gateway-controller pods. + # + # ```yaml + # annotations: | + # "annotation-key": "annotation-value" + # ``` + # + # @type: string + annotations: null + + # This value references an existing + # Kubernetes `priorityClassName` (https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#pod-priority) + # that can be assigned to api-gateway-controller pods. + priorityClassName: "" + + # This value defines `nodeSelector` (https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) + # labels for api-gateway-controller pod assignment, formatted as a multi-line string. + # + # Example: + # + # ```yaml + # nodeSelector: | + # beta.kubernetes.io/arch: amd64 + # ``` + # + # @type: string + nodeSelector: null + service: + # Annotations to apply to the api-gateway-controller service. + # + # ```yaml + # annotations: | + # "annotation-key": "annotation-value" + # ``` + # + # @type: string + annotations: null + # Configuration settings for the webhook-cert-manager # `webhook-cert-manager` ensures that cert bundles are up to date for the mutating webhook. webhookCertManager: From a85c5858ce83092188dbece91847bafd73f4281e Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Wed, 19 Jan 2022 12:03:00 -0500 Subject: [PATCH 218/418] plumb through auto encrypt and auth method --- .../api-gateway-controller-clusterrole.yaml | 35 + .../api-gateway-controller-deployment.yaml | 4 +- .../api-gateway-crd-gatewayconfig.yaml | 3849 ----------------- .../api-gateway-gatewayclassconfig.yaml | 11 +- charts/consul/values.yaml | 13 +- .../subcommand/server-acl-init/command.go | 7 +- .../subcommand/server-acl-init/rules.go | 2 +- 7 files changed, 60 insertions(+), 3861 deletions(-) delete mode 100644 charts/consul/templates/api-gateway-crd-gatewayconfig.yaml diff --git a/charts/consul/templates/api-gateway-controller-clusterrole.yaml b/charts/consul/templates/api-gateway-controller-clusterrole.yaml index 47544e6b56..491f336042 100644 --- a/charts/consul/templates/api-gateway-controller-clusterrole.yaml +++ b/charts/consul/templates/api-gateway-controller-clusterrole.yaml @@ -95,6 +95,15 @@ rules: - get - list - watch +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - create + - get + - list + - watch - apiGroups: - gateway.networking.k8s.io resources: @@ -173,4 +182,30 @@ rules: - get - patch - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - tcproutes + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - gateway.networking.k8s.io + resources: + - tcproutes/finalizers + verbs: + - update +- apiGroups: + - gateway.networking.k8s.io + resources: + - tcproutes/status + verbs: + - get + - patch + - update {{- end }} diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml index c6a73d1f0e..53ae2d7ac5 100644 --- a/charts/consul/templates/api-gateway-controller-deployment.yaml +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -60,8 +60,8 @@ spec: fieldPath: status.hostIP - name: IP valueFrom: - fieldRef: - fieldPath: status.podIP + fieldRef: + fieldPath: status.podIP {{- if .Values.global.acls.manageSystemACLs }} - name: CONSUL_HTTP_TOKEN valueFrom: diff --git a/charts/consul/templates/api-gateway-crd-gatewayconfig.yaml b/charts/consul/templates/api-gateway-crd-gatewayconfig.yaml deleted file mode 100644 index d8631d606f..0000000000 --- a/charts/consul/templates/api-gateway-crd-gatewayconfig.yaml +++ /dev/null @@ -1,3849 +0,0 @@ -{{- if .Values.apiGateway.enabled }} -# Generated from: kubectl kustomize 'github.com/hashicorp/consul-api-gateway/config/crd?ref=v0.1.0-techpreview' -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.6.0 - creationTimestamp: null - name: gatewayclassconfigs.api-gateway.consul.hashicorp.com -spec: - group: api-gateway.consul.hashicorp.com - names: - kind: GatewayClassConfig - listKind: GatewayClassConfigList - plural: gatewayclassconfigs - singular: gatewayclassconfig - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: GatewayClassConfig describes the configuration of a consul-api-gateway - GatewayClass. - 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: Spec defines the desired state of GatewayClassConfig. - properties: - consul: - description: Configuration information about connecting to Consul. - properties: - address: - description: The address of the consul server to communicate with - in the gateway pod. If not specified, the pod will attempt to - use a local agent on the host on which it is running. - type: string - authentication: - description: Consul authentication information - properties: - account: - description: The Kubernetes service account to authenticate - as. - type: string - method: - description: The Consul auth method used for initial authentication - by consul-api-gateway. - type: string - namespace: - description: The Consul namespace to use for authentication. - type: string - type: object - caSecret: - description: The location of a secret to mount with the Consul - root CA. - type: string - ports: - description: The information about Consul's ports - properties: - grpc: - description: The grpc port for Consul's xDS server. - type: integer - http: - description: The port for Consul's HTTP server. - type: integer - type: object - scheme: - description: The scheme to use for connecting to Consul. - enum: - - http - - https - type: string - type: object - copyAnnotations: - description: Annotation Information to copy to services or deployments - properties: - service: - description: List of annotations to copy to the gateway service. - items: - type: string - type: array - type: object - image: - description: Configuration information about the images to use - properties: - consulAPIGateway: - description: The image to use for consul-api-gateway. - type: string - envoy: - description: The image to use for Envoy. - type: string - type: object - logLevel: - description: Logging levels - enum: - - trace - - debug - - info - - warning - - error - type: string - nodeSelector: - additionalProperties: - type: string - description: 'NodeSelector is a selector which must be true for the - pod to fit on a node. Selector which must match a node''s labels - for the pod to be scheduled on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' - type: object - serviceType: - description: Service Type string describes ingress methods for a service - enum: - - ClusterIP - - NodePort - - LoadBalancer - type: string - useHostPorts: - description: If this is set, then the Envoy container ports are mapped - to host ports. - type: boolean - type: object - type: object - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 - creationTimestamp: null - name: gatewayclasses.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: GatewayClass - listKind: GatewayClassList - plural: gatewayclasses - shortNames: - - gc - singular: gatewayclass - scope: Cluster - versions: - - additionalPrinterColumns: - - jsonPath: .spec.controller - name: Controller - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - - jsonPath: .spec.description - name: Description - priority: 1 - type: string - name: v1alpha2 - schema: - openAPIV3Schema: - description: "GatewayClass describes a class of Gateways available to the - user for creating Gateway resources. \n It is recommended that this resource - be used as a template for Gateways. This means that a Gateway is based on - the state of the GatewayClass at the time it was created and changes to - the GatewayClass or associated parameters are not propagated down to existing - Gateways. This recommendation is intended to limit the blast radius of changes - to GatewayClass or associated parameters. If implementations choose to propagate - GatewayClass changes to existing Gateways, that MUST be clearly documented - by the implementation. \n Whenever one or more Gateways are using a GatewayClass, - implementations MUST add the `gateway-exists-finalizer.gateway.networking.k8s.io` - finalizer on the associated GatewayClass. This ensures that a GatewayClass - associated with a Gateway is not deleted while in use. \n GatewayClass is - a Cluster level resource." - 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: Spec defines the desired state of GatewayClass. - properties: - controllerName: - description: "ControllerName is the name of the controller that is - managing Gateways of this class. The value of this field MUST be - a domain prefixed path. \n Example: \"example.net/gateway-controller\". - \n This field is not mutable and cannot be empty. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - description: - description: Description helps describe a GatewayClass with more details. - maxLength: 64 - type: string - parametersRef: - description: "ParametersRef is a reference to a resource that contains - the configuration parameters corresponding to the GatewayClass. - This is optional if the controller does not require any additional - configuration. \n ParametersRef can reference a standard Kubernetes - resource, i.e. ConfigMap, or an implementation-specific custom resource. - The resource can be cluster-scoped or namespace-scoped. \n If the - referent cannot be found, the GatewayClass's \"InvalidParameters\" - status condition will be true. \n Support: Custom" - properties: - group: - description: Group is the group of the referent. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: Namespace is the namespace of the referent. This - field is required when referring to a Namespace-scoped resource - and MUST be unset when referring to a Cluster-scoped resource. - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - name - type: object - required: - - controllerName - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Waiting - status: Unknown - type: Accepted - description: Status defines the current state of GatewayClass. - properties: - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: Waiting - status: Unknown - type: Accepted - description: "Conditions is the current status from the controller - for this GatewayClass. \n Controllers should prefer to publish conditions - using values of GatewayClassConditionType for the type of each Condition." - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: - \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // +listMapKey=type - \ Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 - creationTimestamp: null - name: gateways.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: Gateway - listKind: GatewayList - plural: gateways - shortNames: - - gtw - singular: gateway - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.gatewayClassName - name: Class - type: string - - jsonPath: .status.addresses[*].value - name: Address - type: string - - jsonPath: .status.conditions[?(@.type=="Ready")].status - name: Ready - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: Gateway represents an instance of a service-traffic handling - infrastructure by binding Listeners to a set of IP addresses. - 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: Spec defines the desired state of Gateway. - properties: - addresses: - description: "Addresses requested for this Gateway. This is optional - and behavior can depend on the implementation. If a value is set - in the spec and the requested address is invalid or unavailable, - the implementation MUST indicate this in the associated entry in - GatewayStatus.Addresses. \n The Addresses field represents a request - for the address(es) on the \"outside of the Gateway\", that traffic - bound for this Gateway will use. This could be the IP address or - hostname of an external load balancer or other networking infrastructure, - or some other address that traffic will be sent to. \n The .listener.hostname - field is used to route traffic that has already arrived at the Gateway - to the correct in-cluster destination. \n If no Addresses are specified, - the implementation MAY schedule the Gateway in an implementation-specific - manner, assigning an appropriate set of Addresses. \n The implementation - MUST bind all Listeners to every GatewayAddress that it assigns - to the Gateway and add a corresponding entry in GatewayStatus.Addresses. - \n Support: Core" - items: - description: GatewayAddress describes an address that can be bound - to a Gateway. - properties: - type: - default: IPAddress - description: Type of the address. - enum: - - IPAddress - - Hostname - - NamedAddress - type: string - value: - description: "Value of the address. The validity of the values - will depend on the type and support by the controller. \n - Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - gatewayClassName: - description: GatewayClassName used for this Gateway. This is the name - of a GatewayClass resource. - maxLength: 253 - minLength: 1 - type: string - listeners: - description: "Listeners associated with this Gateway. Listeners define - logical endpoints that are bound on this Gateway's addresses. At - least one Listener MUST be specified. \n Each listener in a Gateway - must have a unique combination of Hostname, Port, and Protocol. - \n An implementation MAY group Listeners by Port and then collapse - each group of Listeners into a single Listener if the implementation - determines that the Listeners in the group are \"compatible\". An - implementation MAY also group together and collapse compatible Listeners - belonging to different Gateways. \n For example, an implementation - might consider Listeners to be compatible with each other if all - of the following conditions are met: \n 1. Either each Listener - within the group specifies the \"HTTP\" Protocol or each Listener - within the group specifies either the \"HTTPS\" or \"TLS\" Protocol. - \n 2. Each Listener within the group specifies a Hostname that is - unique within the group. \n 3. As a special case, one Listener - within a group may omit Hostname, in which case this Listener - matches when no other Listener matches. \n If the implementation - does collapse compatible Listeners, the hostname provided in the - incoming client request MUST be matched to a Listener to find the - correct set of Routes. The incoming hostname MUST be matched using - the Hostname field for each Listener in order of most to least specific. - That is, exact matches must be processed before wildcard matches. - \n If this field specifies multiple Listeners that have the same - Port value but are not compatible, the implementation must raise - a \"Conflicted\" condition in the Listener status. \n Support: Core" - items: - description: Listener embodies the concept of a logical endpoint - where a Gateway accepts network connections. - properties: - allowedRoutes: - default: - namespaces: - from: Same - description: "AllowedRoutes defines the types of routes that - MAY be attached to a Listener and the trusted namespaces where - those Route resources MAY be present. \n Although a client - request may match multiple route rules, only one rule may - ultimately receive the request. Matching precedence MUST be - determined in order of the following criteria: \n * The most - specific match as defined by the Route type. * The oldest - Route based on creation timestamp. For example, a Route with - \ a creation timestamp of \"2020-09-08 01:02:03\" is given - precedence over a Route with a creation timestamp of \"2020-09-08 - 01:02:04\". * If everything else is equivalent, the Route - appearing first in alphabetical order (namespace/name) should - be given precedence. For example, foo/bar is given precedence - over foo/baz. \n All valid rules within a Route attached to - this Listener should be implemented. Invalid Route rules can - be ignored (sometimes that will mean the full Route). If a - Route rule transitions from valid to invalid, support for - that Route rule should be dropped to ensure consistency. For - example, even if a filter specified by a Route rule is invalid, - the rest of the rules within that Route should still be supported. - \n Support: Core" - properties: - kinds: - description: "Kinds specifies the groups and kinds of Routes - that are allowed to bind to this Gateway Listener. When - unspecified or empty, the kinds of Routes selected are - determined using the Listener protocol. \n A RouteGroupKind - MUST correspond to kinds of Routes that are compatible - with the application protocol specified in the Listener's - Protocol field. If an implementation does not support - or recognize this resource type, it MUST set the \"ResolvedRefs\" - condition to False for this Listener with the \"InvalidRoutesRef\" - reason. \n Support: Core" - items: - description: RouteGroupKind indicates the group and kind - of a Route resource. - properties: - group: - default: gateway.networking.k8s.io - description: Group is the group of the Route. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is the kind of the Route. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - required: - - kind - type: object - maxItems: 8 - type: array - namespaces: - default: - from: Same - description: "Namespaces indicates namespaces from which - Routes may be attached to this Listener. This is restricted - to the namespace of this Gateway by default. \n Support: - Core" - properties: - from: - default: Same - description: "From indicates where Routes will be selected - for this Gateway. Possible values are: * All: Routes - in all namespaces may be used by this Gateway. * Selector: - Routes in namespaces selected by the selector may - be used by this Gateway. * Same: Only Routes in - the same namespace may be used by this Gateway. \n - Support: Core" - enum: - - All - - Selector - - Same - type: string - selector: - description: "Selector must be specified when From is - set to \"Selector\". In that case, only Routes in - Namespaces matching this Selector will be selected - by this Gateway. This field is ignored for other values - of \"From\". \n Support: Core" - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are ANDed. - items: - description: A label selector requirement is a - selector that contains values, a key, and an - operator that relates the key and values. - properties: - key: - description: key is the label key that the - selector applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are - In, NotIn, Exists and DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. If the - operator is Exists or DoesNotExist, the - values array must be empty. This array is - replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is "In", - and the values array contains only "value". The - requirements are ANDed. - type: object - type: object - type: object - type: object - hostname: - description: "Hostname specifies the virtual hostname to match - for protocol types that define this concept. When unspecified, - all hostnames are matched. This field is ignored for protocols - that don't require hostname based matching. \n Implementations - MUST apply Hostname matching appropriately for each of the - following protocols: \n * TLS: The Listener Hostname MUST - match the SNI. * HTTP: The Listener Hostname MUST match the - Host header of the request. * HTTPS: The Listener Hostname - SHOULD match at both the TLS and HTTP protocol layers as - described above. If an implementation does not ensure that - both the SNI and Host header match the Listener hostname, - \ it MUST clearly document that. \n For HTTPRoute and TLSRoute - resources, there is an interaction with the `spec.hostnames` - array. When both listener and route specify hostnames, there - MUST be an intersection between the values for a Route to - be accepted. For more information, refer to the Route specific - Hostnames documentation. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - name: - description: "Name is the name of the Listener. \n Support: - Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - port: - description: "Port is the network port. Multiple listeners may - use the same port, subject to the Listener compatibility rules. - \n Support: Core" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - protocol: - description: "Protocol specifies the network protocol this listener - expects to receive. \n Support: Core" - maxLength: 255 - minLength: 1 - pattern: ^[a-zA-Z0-9]([-a-zSA-Z0-9]*[a-zA-Z0-9])?$|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9]+$ - type: string - tls: - description: "TLS is the TLS configuration for the Listener. - This field is required if the Protocol field is \"HTTPS\" - or \"TLS\". It is invalid to set this field if the Protocol - field is \"HTTP\", \"TCP\", or \"UDP\". \n The association - of SNIs to Certificate defined in GatewayTLSConfig is defined - based on the Hostname field for this listener. \n The GatewayClass - MUST use the longest matching SNI out of all available certificates - for any TLS handshake. \n Support: Core" - properties: - certificateRefs: - description: "CertificateRefs contains a series of references - to Kubernetes objects that contains TLS certificates and - private keys. These certificates are used to establish - a TLS handshake for requests that match the hostname of - the associated listener. \n A single CertificateRef to - a Kubernetes Secret has \"Core\" support. Implementations - MAY choose to support attaching multiple certificates - to a Listener, but this behavior is implementation-specific. - \n References to a resource in different namespace are - invalid UNLESS there is a ReferencePolicy in the target - namespace that allows the certificate to be attached. - If a ReferencePolicy does not allow this reference, the - \"ResolvedRefs\" condition MUST be set to False for this - listener with the \"InvalidCertificateRef\" reason. \n - This field is required to have at least one element when - the mode is set to \"Terminate\" (default) and is optional - otherwise. \n CertificateRefs can reference to standard - Kubernetes resources, i.e. Secret, or implementation-specific - custom resources. \n Support: Core - A single reference - to a Kubernetes Secret \n Support: Implementation-specific - (More than one reference or other resource types)" - items: - description: "SecretObjectReference identifies an API - object including its namespace, defaulting to Secret. - \n The API object must be valid in the cluster; the - Group and Kind must be registered in the cluster for - this reference to be valid. \n References to objects - with invalid Group and Kind are not valid, and must - be rejected by the implementation, with appropriate - Conditions set on the containing object." - properties: - group: - default: "" - description: Group is the group of the referent. For - example, "networking.k8s.io". When unspecified (empty - string), core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Secret - description: Kind is kind of the referent. For example - "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. - When unspecified, the local namespace is inferred. - \n Note that when a namespace is specified, a ReferencePolicy - object is required in the referent namespace to - allow that namespace's owner to accept the reference. - See the ReferencePolicy documentation for details. - \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - name - type: object - maxItems: 64 - type: array - mode: - default: Terminate - description: "Mode defines the TLS behavior for the TLS - session initiated by the client. There are two possible - modes: \n - Terminate: The TLS session between the downstream - client and the Gateway is terminated at the Gateway. - This mode requires certificateRefs to be set and contain - at least one element. - Passthrough: The TLS session is - NOT terminated by the Gateway. This implies that the - Gateway can't decipher the TLS stream except for the - ClientHello message of the TLS protocol. CertificateRefs - field is ignored in this mode. \n Support: Core" - enum: - - Terminate - - Passthrough - type: string - options: - additionalProperties: - description: AnnotationValue is the value of an annotation - in Gateway API. This is used for validation of maps - such as TLS options. This roughly matches Kubernetes - annotation validation, although the length validation - in that case is based on the entire size of the annotations - struct. - maxLength: 4096 - minLength: 0 - type: string - description: "Options are a list of key/value pairs to enable - extended TLS configuration for each implementation. For - example, configuring the minimum TLS version or supported - cipher suites. \n A set of common keys MAY be defined - by the API in the future. To avoid any ambiguity, implementation-specific - definitions MUST use domain-prefixed names, such as `example.com/my-custom-option`. - Un-prefixed names are reserved for key names defined by - Gateway API. \n Support: Implementation-specific" - maxProperties: 16 - type: object - type: object - required: - - name - - port - - protocol - type: object - maxItems: 64 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - required: - - gatewayClassName - - listeners - type: object - status: - default: - conditions: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: NotReconciled - status: Unknown - type: Scheduled - description: Status defines the current state of Gateway. - properties: - addresses: - description: Addresses lists the IP addresses that have actually been - bound to the Gateway. These addresses may differ from the addresses - in the Spec, e.g. if the Gateway automatically assigns an address - from a reserved pool. - items: - description: GatewayAddress describes an address that can be bound - to a Gateway. - properties: - type: - default: IPAddress - description: Type of the address. - enum: - - IPAddress - - Hostname - - NamedAddress - type: string - value: - description: "Value of the address. The validity of the values - will depend on the type and support by the controller. \n - Examples: `1.2.3.4`, `128::1`, `my-ip-address`." - maxLength: 253 - minLength: 1 - type: string - required: - - value - type: object - maxItems: 16 - type: array - conditions: - default: - - lastTransitionTime: "1970-01-01T00:00:00Z" - message: Waiting for controller - reason: NotReconciled - status: Unknown - type: Scheduled - description: "Conditions describe the current conditions of the Gateway. - \n Implementations should prefer to express Gateway conditions using - the `GatewayConditionType` and `GatewayConditionReason` constants - so that operators and tools can converge on a common vocabulary - to describe Gateway state. \n Known condition types are: \n * \"Scheduled\" - * \"Ready\"" - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: - \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // +listMapKey=type - \ Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - listeners: - description: Listeners provide status for each unique listener port - defined in the Spec. - items: - description: ListenerStatus is the status associated with a Listener. - properties: - attachedRoutes: - description: AttachedRoutes represents the total number of Routes - that have been successfully attached to this Listener. - format: int32 - type: integer - conditions: - description: Conditions describe the current condition of this - listener. - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, type FooStatus struct{ - \ // Represents the observations of a foo's current state. - \ // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // - +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - name: - description: Name is the name of the Listener that this status - corresponds to. - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - supportedKinds: - description: "SupportedKinds is the list indicating the Kinds - supported by this listener. This MUST represent the kinds - an implementation supports for that Listener configuration. - \n If kinds are specified in Spec that are not supported, - they MUST NOT appear in this list and an implementation MUST - set the \"ResolvedRefs\" condition to \"False\" with the \"InvalidRouteKinds\" - reason. If both valid and invalid Route kinds are specified, - the implementation MUST reference the valid Route kinds that - have been specified." - items: - description: RouteGroupKind indicates the group and kind of - a Route resource. - properties: - group: - default: gateway.networking.k8s.io - description: Group is the group of the Route. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is the kind of the Route. - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - required: - - kind - type: object - maxItems: 8 - type: array - required: - - attachedRoutes - - conditions - - name - - supportedKinds - type: object - maxItems: 64 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 - creationTimestamp: null - name: httproutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: HTTPRoute - listKind: HTTPRouteList - plural: httproutes - singular: httproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .spec.hostnames - name: Hostnames - type: string - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: HTTPRoute provides a way to route HTTP requests. This includes - the capability to match requests by hostname, path, header, or query param. - Filters can be used to specify additional processing steps. Backends specify - where matching requests should be routed. - 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: Spec defines the desired state of HTTPRoute. - properties: - hostnames: - description: "Hostnames defines a set of hostname that should match - against the HTTP Host header to select a HTTPRoute to process the - request. This matches the RFC 1123 definition of a hostname with - 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname may - be prefixed with a wildcard label (`*.`). The wildcard label - must appear by itself as the first label. \n If a hostname is specified - by both the Listener and HTTPRoute, there must be at least one intersecting - hostname for the HTTPRoute to be attached to the Listener. For example: - \n * A Listener with `test.example.com` as the hostname matches - HTTPRoutes that have either not specified any hostnames, or have - specified at least one of `test.example.com` or `*.example.com`. - * A Listener with `*.example.com` as the hostname matches HTTPRoutes - \ that have either not specified any hostnames or have specified - at least one hostname that matches the Listener hostname. For - example, `test.example.com` and `*.example.com` would both match. - On the other hand, `example.com` and `test.example.net` would - not match. \n If both the Listener and HTTPRoute have specified - hostnames, any HTTPRoute hostnames that do not match the Listener - hostname MUST be ignored. For example, if a Listener specified `*.example.com`, - and the HTTPRoute specified `test.example.com` and `test.example.net`, - `test.example.net` must not be considered for a match. \n If both - the Listener and HTTPRoute have specified hostnames, and none match - with the criteria above, then the HTTPRoute is not accepted. The - implementation must raise an 'Accepted' Condition with a status - of `False` in the corresponding RouteParentStatus. \n Support: Core" - items: - description: "Hostname is the fully qualified domain name of a network - host. This matches the RFC 1123 definition of a hostname with - 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname - may be prefixed with a wildcard label (`*.`). The wildcard label - must appear by itself as the first label. \n Hostname can be \"precise\" - which is a domain name without the terminating dot of a network - host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain - name prefixed with a single wildcard label (e.g. `*.example.com`). - \n Note that as per RFC1035 and RFC1123, a *label* must consist - of lower case alphanumeric characters or '-', and must start and - end with an alphanumeric character. No other punctuation is allowed." - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - maxItems: 16 - type: array - parentRefs: - description: "ParentRefs references the resources (usually Gateways) - that a Route wants to be attached to. Note that the referenced parent - resource needs to allow this for the attachment to be complete. - For Gateways, that means the Gateway needs to allow attachment from - Routes of this kind and namespace. \n The only kind of parent resource - with \"Core\" support is Gateway. This API may be extended in the - future to support additional kinds of parent resources such as one - of the route kinds. \n It is invalid to reference an identical parent - more than once. It is valid to reference multiple distinct sections - within the same parent resource, such as 2 Listeners within a Gateway. - \n It is possible to separately reference multiple distinct objects - that may be collapsed by an implementation. For example, some implementations - may choose to merge compatible Gateway Listeners together. If that - is the case, the list of routes attached to those resources should - also be merged." - items: - description: "ParentRef identifies an API object (usually a Gateway) - that can be considered a parent of this resource (usually a route). - The only kind of parent resource with \"Core\" support is Gateway. - This API may be extended in the future to support additional kinds - of parent resources, such as HTTPRoute. \n The API object must - be valid in the cluster; the Group and Kind must be registered - in the cluster for this reference to be valid. \n References to - objects with invalid Group and Kind are not valid, and must be - rejected by the implementation, with appropriate Conditions set - on the containing object." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. \n Support: - Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core - (Gateway) Support: Custom (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: - Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When - unspecified (or empty string), this refers to the local namespace - of the Route. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - sectionName: - description: "SectionName is the name of a section within the - target resource. In the following resources, SectionName is - interpreted as the following: \n * Gateway: Listener Name - \n Implementations MAY choose to support attaching Routes - to other resources. If that is the case, they MUST clearly - document how SectionName is interpreted. \n When unspecified - (empty string), this will reference the entire resource. For - the purpose of status, an attachment is considered successful - if at least one section in the parent resource accepts it. - For example, Gateway listeners can restrict which Routes can - attach to them by Route kind, namespace, or hostname. If 1 - of 2 Gateway listeners accept attachment from the referencing - Route, the Route MUST be considered successfully attached. - If no Gateway listeners accept attachment from this Route, - the Route MUST be considered detached from the Gateway. \n - Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - default: - - matches: - - path: - type: PathPrefix - value: / - description: Rules are a list of HTTP matchers, filters and actions. - items: - description: HTTPRouteRule defines semantics for matching an HTTP - request based on conditions (matches), processing it (filters), - and forwarding the request to an API object (backendRefs). - properties: - backendRefs: - description: "If unspecified or invalid (refers to a non-existent - resource or a Service with no endpoints), the rule performs - no forwarding. If there are also no filters specified that - would result in a response being sent, a HTTP 503 status code - is returned. 503 responses must be sent so that the overall - weight is respected; if an invalid backend is requested to - have 80% of requests, then 80% of requests must get a 503 - instead. \n Support: Core for Kubernetes Service Support: - Custom for any other resource \n Support for weight: Core" - items: - description: HTTPBackendRef defines how a HTTPRoute should - forward an HTTP request. - properties: - filters: - description: "Filters defined at this level should be - executed if and only if the request is being forwarded - to the backend defined here. \n Support: Custom (For - broader support of filters, use the Filters field in - HTTPRouteRule.)" - items: - description: HTTPRouteFilter defines processing steps - that must be completed during the request or response - lifecycle. HTTPRouteFilters are meant as an extension - point to express processing that may be done in Gateway - implementations. Some examples include request or - response modification, implementing authentication - strategies, rate-limiting, and traffic shaping. API - guarantee/conformance is defined based on the type - of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific - extension to the \"filter\" behavior. For example, - resource \"myroutefilter\" in group \"networking.example.net\"). - ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. - For example, "networking.k8s.io". When unspecified - (empty string), core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For - example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema - for a filter that modifies request headers. \n - Support: Core" - properties: - add: - description: "Add adds the given header(s) (name, - value) to the request before the action. It - appends to any existing values associated - with the header name. \n Input: GET /foo - HTTP/1.1 my-header: foo \n Config: add: - \ - name: \"my-header\" value: \"bar\" - \n Output: GET /foo HTTP/1.1 my-header: - foo my-header: bar" - items: - description: HTTPHeader represents an HTTP - Header name and value as defined by RFC - 7230. - properties: - name: - description: "Name is the name of the - HTTP Header to be matched. Name matching - MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - \n If multiple entries specify equivalent - header names, the first entry with an - equivalent name MUST be considered for - a match. Subsequent entries with an - equivalent header name MUST be ignored. - Due to the case-insensitivity of header - names, \"foo\" and \"Foo\" are considered - equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP - Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from - the HTTP request before the action. The value - of Remove is a list of HTTP header names. - Note that the header names are case-insensitive - (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - \n Input: GET /foo HTTP/1.1 my-header1: - foo my-header2: bar my-header3: baz \n - Config: remove: [\"my-header1\", \"my-header3\"] - \n Output: GET /foo HTTP/1.1 my-header2: - bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with - the given header (name, value) before the - action. \n Input: GET /foo HTTP/1.1 my-header: - foo \n Config: set: - name: \"my-header\" - \ value: \"bar\" \n Output: GET /foo - HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP - Header name and value as defined by RFC - 7230. - properties: - name: - description: "Name is the name of the - HTTP Header to be matched. Name matching - MUST be case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - \n If multiple entries specify equivalent - header names, the first entry with an - equivalent name MUST be considered for - a match. Subsequent entries with an - equivalent header name MUST be ignored. - Due to the case-insensitivity of header - names, \"foo\" and \"Foo\" are considered - equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP - Header to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for - a filter that mirrors requests. Requests are sent - to the specified destination, but responses from - that destination are ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource - where mirrored requests are sent. \n If the - referent cannot be found, this BackendRef - is invalid and must be dropped from the Gateway. - The controller must ensure the \"ResolvedRefs\" - condition on the Route status is set to `status: - False` and not configure this backend in the - underlying implementation. \n If there is - a cross-namespace reference to an *existing* - object that is not allowed by a ReferencePolicy, - the controller must ensure the \"ResolvedRefs\" - \ condition on the Route is set to `status: - False`, with the \"RefNotPermitted\" reason - and not configure this backend in the underlying - implementation. \n In either error case, the - Message of the `ResolvedRefs` Condition should - be used to provide more detail about the problem. - \n Support: Extended for Kubernetes Service - Support: Custom for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. - For example, "networking.k8s.io". When - unspecified (empty string), core API group - is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. - For example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace - of the backend. When unspecified, the - local namespace is inferred. \n Note that - when a namespace is specified, a ReferencePolicy - object is required in the referent namespace - to allow that namespace's owner to accept - the reference. See the ReferencePolicy - documentation for details. \n Support: - Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination - port number to use for this resource. - Port is required when the referent is - a Kubernetes Service. For other resources, - destination port might be derived from - the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - requestRedirect: - description: "RequestRedirect defines a schema for - a filter that responds to the request with an - HTTP redirection. \n Support: Core" - properties: - hostname: - description: "Hostname is the hostname to be - used in the value of the `Location` header - in the response. When empty, the hostname - of the request is used. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - port: - description: "Port is the port to be used in - the value of the `Location` header in the - response. When empty, port (if specified) - of the request is used. \n Support: Extended" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: "Scheme is the scheme to be used - in the value of the `Location` header in the - response. When empty, the scheme of the request - is used. \n Support: Extended" - enum: - - http - - https - type: string - statusCode: - default: 302 - description: "StatusCode is the HTTP status - code to be used in response. \n Support: Core" - enum: - - 301 - - 302 - type: integer - type: object - type: - description: "Type identifies the type of filter - to apply. As with other API fields, types are - classified into three conformance levels: \n - - Core: Filter types and their corresponding configuration - defined by \"Support: Core\" in this package, - e.g. \"RequestHeaderModifier\". All implementations - must support core filters. \n - Extended: Filter - types and their corresponding configuration defined - by \"Support: Extended\" in this package, e.g. - \"RequestMirror\". Implementers are encouraged - to support extended filters. \n - Custom: Filters - that are defined and supported by specific vendors. - \ In the future, filters showing convergence - in behavior across multiple implementations - will be considered for inclusion in extended or - core conformance levels. Filter-specific configuration - for such filters is specified using the ExtensionRef - field. `Type` should be set to \"ExtensionRef\" - for custom filters. \n Implementers are encouraged - to define custom implementation types to extend - the core API with implementation-specific behavior. - \n If a reference to a custom filter type cannot - be resolved, the filter MUST NOT be skipped. Instead, - requests that would have been processed by that - filter MUST receive a HTTP error response." - enum: - - RequestHeaderModifier - - RequestMirror - - RequestRedirect - - ExtensionRef - type: string - required: - - type - type: object - maxItems: 16 - type: array - group: - default: "" - description: Group is the group of the referent. For example, - "networking.k8s.io". When unspecified (empty string), - core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example - "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. - When unspecified, the local namespace is inferred. \n - Note that when a namespace is specified, a ReferencePolicy - object is required in the referent namespace to allow - that namespace's owner to accept the reference. See - the ReferencePolicy documentation for details. \n Support: - Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number - to use for this resource. Port is required when the - referent is a Kubernetes Service. For other resources, - destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests - forwarded to the referenced backend. This is computed - as weight/(sum of all weights in this BackendRefs list). - For non-zero values, there may be some epsilon from - the exact proportion defined here depending on the precision - an implementation supports. Weight is not a percentage - and the sum of weights does not need to equal 100. \n - If only one backend is specified and it has a weight - greater than 0, 100% of the traffic is forwarded to - that backend. If weight is set to 0, no traffic should - be forwarded for this entry. If unspecified, weight - defaults to 1. \n Support for this field varies based - on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - type: array - filters: - description: "Filters define the filters that are applied to - requests that match this rule. \n The effects of ordering - of multiple behaviors are currently unspecified. This can - change in the future based on feedback during the alpha stage. - \n Conformance-levels at this level are defined based on the - type of filter: \n - ALL core filters MUST be supported by - all implementations. - Implementers are encouraged to support - extended filters. - Implementation-specific custom filters - have no API guarantees across implementations. \n Specifying - a core filter multiple times has unspecified or custom conformance. - \n Support: Core" - items: - description: HTTPRouteFilter defines processing steps that - must be completed during the request or response lifecycle. - HTTPRouteFilters are meant as an extension point to express - processing that may be done in Gateway implementations. - Some examples include request or response modification, - implementing authentication strategies, rate-limiting, and - traffic shaping. API guarantee/conformance is defined based - on the type of the filter. - properties: - extensionRef: - description: "ExtensionRef is an optional, implementation-specific - extension to the \"filter\" behavior. For example, - resource \"myroutefilter\" in group \"networking.example.net\"). - ExtensionRef MUST NOT be used for core and extended - filters. \n Support: Implementation-specific" - properties: - group: - description: Group is the group of the referent. For - example, "networking.k8s.io". When unspecified (empty - string), core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For example - "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - - name - type: object - requestHeaderModifier: - description: "RequestHeaderModifier defines a schema for - a filter that modifies request headers. \n Support: - Core" - properties: - add: - description: "Add adds the given header(s) (name, - value) to the request before the action. It appends - to any existing values associated with the header - name. \n Input: GET /foo HTTP/1.1 my-header: - foo \n Config: add: - name: \"my-header\" value: - \"bar\" \n Output: GET /foo HTTP/1.1 my-header: - foo my-header: bar" - items: - description: HTTPHeader represents an HTTP Header - name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header - to be matched. Name matching MUST be case - insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - \n If multiple entries specify equivalent - header names, the first entry with an equivalent - name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST - be ignored. Due to the case-insensitivity - of header names, \"foo\" and \"Foo\" are considered - equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header - to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - remove: - description: "Remove the given header(s) from the - HTTP request before the action. The value of Remove - is a list of HTTP header names. Note that the header - names are case-insensitive (see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2). - \n Input: GET /foo HTTP/1.1 my-header1: foo - \ my-header2: bar my-header3: baz \n Config: - \ remove: [\"my-header1\", \"my-header3\"] \n Output: - \ GET /foo HTTP/1.1 my-header2: bar" - items: - type: string - maxItems: 16 - type: array - set: - description: "Set overwrites the request with the - given header (name, value) before the action. \n - Input: GET /foo HTTP/1.1 my-header: foo \n Config: - \ set: - name: \"my-header\" value: \"bar\" - \n Output: GET /foo HTTP/1.1 my-header: bar" - items: - description: HTTPHeader represents an HTTP Header - name and value as defined by RFC 7230. - properties: - name: - description: "Name is the name of the HTTP Header - to be matched. Name matching MUST be case - insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2). - \n If multiple entries specify equivalent - header names, the first entry with an equivalent - name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST - be ignored. Due to the case-insensitivity - of header names, \"foo\" and \"Foo\" are considered - equivalent." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - value: - description: Value is the value of HTTP Header - to be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - requestMirror: - description: "RequestMirror defines a schema for a filter - that mirrors requests. Requests are sent to the specified - destination, but responses from that destination are - ignored. \n Support: Extended" - properties: - backendRef: - description: "BackendRef references a resource where - mirrored requests are sent. \n If the referent cannot - be found, this BackendRef is invalid and must be - dropped from the Gateway. The controller must ensure - the \"ResolvedRefs\" condition on the Route status - is set to `status: False` and not configure this - backend in the underlying implementation. \n If - there is a cross-namespace reference to an *existing* - object that is not allowed by a ReferencePolicy, - the controller must ensure the \"ResolvedRefs\" - \ condition on the Route is set to `status: False`, - with the \"RefNotPermitted\" reason and not configure - this backend in the underlying implementation. \n - In either error case, the Message of the `ResolvedRefs` - Condition should be used to provide more detail - about the problem. \n Support: Extended for Kubernetes - Service Support: Custom for any other resource" - properties: - group: - default: "" - description: Group is the group of the referent. - For example, "networking.k8s.io". When unspecified - (empty string), core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For - example "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the - backend. When unspecified, the local namespace - is inferred. \n Note that when a namespace is - specified, a ReferencePolicy object is required - in the referent namespace to allow that namespace's - owner to accept the reference. See the ReferencePolicy - documentation for details. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port - number to use for this resource. Port is required - when the referent is a Kubernetes Service. For - other resources, destination port might be derived - from the referent resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - required: - - name - type: object - required: - - backendRef - type: object - requestRedirect: - description: "RequestRedirect defines a schema for a filter - that responds to the request with an HTTP redirection. - \n Support: Core" - properties: - hostname: - description: "Hostname is the hostname to be used - in the value of the `Location` header in the response. - When empty, the hostname of the request is used. - \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - port: - description: "Port is the port to be used in the value - of the `Location` header in the response. When empty, - port (if specified) of the request is used. \n Support: - Extended" - format: int32 - maximum: 65535 - minimum: 1 - type: integer - scheme: - description: "Scheme is the scheme to be used in the - value of the `Location` header in the response. - When empty, the scheme of the request is used. \n - Support: Extended" - enum: - - http - - https - type: string - statusCode: - default: 302 - description: "StatusCode is the HTTP status code to - be used in response. \n Support: Core" - enum: - - 301 - - 302 - type: integer - type: object - type: - description: "Type identifies the type of filter to apply. - As with other API fields, types are classified into - three conformance levels: \n - Core: Filter types and - their corresponding configuration defined by \"Support: - Core\" in this package, e.g. \"RequestHeaderModifier\". - All implementations must support core filters. \n - - Extended: Filter types and their corresponding configuration - defined by \"Support: Extended\" in this package, - e.g. \"RequestMirror\". Implementers are encouraged - to support extended filters. \n - Custom: Filters that - are defined and supported by specific vendors. In - the future, filters showing convergence in behavior - across multiple implementations will be considered - for inclusion in extended or core conformance levels. - Filter-specific configuration for such filters is - specified using the ExtensionRef field. `Type` should - be set to \"ExtensionRef\" for custom filters. \n - Implementers are encouraged to define custom implementation - types to extend the core API with implementation-specific - behavior. \n If a reference to a custom filter type - cannot be resolved, the filter MUST NOT be skipped. - Instead, requests that would have been processed by - that filter MUST receive a HTTP error response." - enum: - - RequestHeaderModifier - - RequestMirror - - RequestRedirect - - ExtensionRef - type: string - required: - - type - type: object - maxItems: 16 - type: array - matches: - default: - - path: - type: PathPrefix - value: / - description: "Matches define conditions used for matching the - rule against incoming HTTP requests. Each match is independent, - i.e. this rule will be matched if **any** one of the matches - is satisfied. \n For example, take the following matches configuration: - \n ``` matches: - path: value: \"/foo\" headers: - - name: \"version\" value: \"v2\" - path: value: \"/v2/foo\" - ``` \n For a request to match against this rule, a request - must satisfy EITHER of the two conditions: \n - path prefixed - with `/foo` AND contains the header `version: v2` - path prefix - of `/v2/foo` \n See the documentation for HTTPRouteMatch on - how to specify multiple match conditions that should be ANDed - together. \n If no matches are specified, the default is a - prefix path match on \"/\", which has the effect of matching - every HTTP request. \n Proxy or Load Balancer routing configuration - generated from HTTPRoutes MUST prioritize rules based on the - following criteria, continuing on ties. Precedence must be - given to the the Rule with the largest number of: \n * Characters - in a matching non-wildcard hostname. * Characters in a matching - hostname. * Characters in a matching path. * Header matches. - * Query param matches. \n If ties still exist across multiple - Routes, matching precedence MUST be determined in order of - the following criteria, continuing on ties: \n * The oldest - Route based on creation timestamp. * The Route appearing first - in alphabetical order by \"/\". \n If ties - still exist within the Route that has been given precedence, - matching precedence MUST be granted to the first matching - rule meeting the above criteria." - items: - description: "HTTPRouteMatch defines the predicate used to - match requests to a given action. Multiple match types are - ANDed together, i.e. the match will evaluate to true only - if all conditions are satisfied. \n For example, the match - below will match a HTTP request only if its path starts - with `/foo` AND it contains the `version: v1` header: \n - ``` match: path: value: \"/foo\" headers: - name: - \"version\" value \"v1\" ```" - properties: - headers: - description: Headers specifies HTTP request header matchers. - Multiple match values are ANDed together, meaning, a - request must match all the specified headers to select - the route. - items: - description: HTTPHeaderMatch describes how to select - a HTTP route by matching HTTP request headers. - properties: - name: - description: "Name is the name of the HTTP Header - to be matched. Name matching MUST be case insensitive. - (See https://tools.ietf.org/html/rfc7230#section-3.2). - \n If multiple entries specify equivalent header - names, only the first entry with an equivalent - name MUST be considered for a match. Subsequent - entries with an equivalent header name MUST be - ignored. Due to the case-insensitivity of header - names, \"foo\" and \"Foo\" are considered equivalent. - \n When a header is repeated in an HTTP request, - it is implementation-specific behavior as to how - this is represented. Generally, proxies should - follow the guidance from the RFC: https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 - regarding processing a repeated header, with special - handling for \"Set-Cookie\"." - maxLength: 256 - minLength: 1 - pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$ - type: string - type: - default: Exact - description: "Type specifies how to match against - the value of the header. \n Support: Core (Exact) - \n Support: Custom (RegularExpression) \n Since - RegularExpression HeaderMatchType has custom conformance, - implementations can support POSIX, PCRE or any - other dialects of regular expressions. Please - read the implementation's documentation to determine - the supported dialect." - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP Header to - be matched. - maxLength: 4096 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - method: - description: "Method specifies HTTP method matcher. When - specified, this route will be matched only if the request - has the specified method. \n Support: Extended" - enum: - - GET - - HEAD - - POST - - PUT - - DELETE - - CONNECT - - OPTIONS - - TRACE - - PATCH - type: string - path: - default: - type: PathPrefix - value: / - description: Path specifies a HTTP request path matcher. - If this field is not specified, a default prefix match - on the "/" path is provided. - properties: - type: - default: PathPrefix - description: "Type specifies how to match against - the path Value. \n Support: Core (Exact, PathPrefix) - \n Support: Custom (RegularExpression)" - enum: - - Exact - - PathPrefix - - RegularExpression - type: string - value: - default: / - description: Value of the HTTP path to match against. - maxLength: 1024 - type: string - type: object - queryParams: - description: QueryParams specifies HTTP query parameter - matchers. Multiple match values are ANDed together, - meaning, a request must match all the specified query - parameters to select the route. - items: - description: HTTPQueryParamMatch describes how to select - a HTTP route by matching HTTP query parameters. - properties: - name: - description: Name is the name of the HTTP query - param to be matched. This must be an exact string - match. (See https://tools.ietf.org/html/rfc7230#section-2.7.3). - maxLength: 256 - minLength: 1 - type: string - type: - default: Exact - description: "Type specifies how to match against - the value of the query parameter. \n Support: - Extended (Exact) \n Support: Custom (RegularExpression) - \n Since RegularExpression QueryParamMatchType - has custom conformance, implementations can support - POSIX, PCRE or any other dialects of regular expressions. - Please read the implementation's documentation - to determine the supported dialect." - enum: - - Exact - - RegularExpression - type: string - value: - description: Value is the value of HTTP query param - to be matched. - maxLength: 1024 - minLength: 1 - type: string - required: - - name - - value - type: object - maxItems: 16 - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - type: object - maxItems: 8 - type: array - type: object - maxItems: 16 - type: array - type: object - status: - description: Status defines the current state of HTTPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) - that are associated with the route, and the status of the route - with respect to each parent. When this route attaches to a parent, - the controller that manages the parent must add an entry to this - list when the controller first sees the route and should update - the entry as appropriate when the route or gateway is modified. - \n Note that parent references that cannot be resolved by an implementation - of this API will not be added to this list. Implementations of this - API can only populate Route status for the Gateways/parent resources - they are responsible for. \n A maximum of 32 Gateways will be represented - in this list. An empty list means the route has not been attached - to any Gateway." - items: - description: RouteParentStatus describes the status of a route with - respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with - respect to the Gateway. Note that the route's availability - is also subject to the Gateway's own status conditions and - listener status. \n If the Route's ParentRef specifies an - existing Gateway that supports Routes of this kind AND that - Gateway's controller has sufficient access, then that Gateway's - controller MUST set the \"Accepted\" condition on the Route, - to indicate whether the route has been accepted or rejected - by the Gateway, and why. \n A Route MUST be considered \"Accepted\" - if at least one of the Route's rules is implemented by the - Gateway. \n There are a number of cases where the \"Accepted\" - condition may not be set due to lack of controller visibility, - that includes when: \n * The Route refers to a non-existent - parent. * The Route is of a type that the controller does - not support. * The Route is in a namespace the the controller - does not have access to." - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, type FooStatus struct{ - \ // Represents the observations of a foo's current state. - \ // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // - +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates - the name of the controller that wrote this status. This corresponds - with the controllerName field on GatewayClass. \n Example: - \"example.net/gateway-controller\". \n The format of this - field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid - Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec - that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. \n Support: - Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: - Core (Gateway) Support: Custom (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: - Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. - When unspecified (or empty string), this refers to the - local namespace of the Route. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - sectionName: - description: "SectionName is the name of a section within - the target resource. In the following resources, SectionName - is interpreted as the following: \n * Gateway: Listener - Name \n Implementations MAY choose to support attaching - Routes to other resources. If that is the case, they MUST - clearly document how SectionName is interpreted. \n When - unspecified (empty string), this will reference the entire - resource. For the purpose of status, an attachment is - considered successful if at least one section in the parent - resource accepts it. For example, Gateway listeners can - restrict which Routes can attach to them by Route kind, - namespace, or hostname. If 1 of 2 Gateway listeners accept - attachment from the referencing Route, the Route MUST - be considered successfully attached. If no Gateway listeners - accept attachment from this Route, the Route MUST be considered - detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 - creationTimestamp: null - name: referencepolicies.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: ReferencePolicy - listKind: ReferencePolicyList - plural: referencepolicies - shortNames: - - refpol - singular: referencepolicy - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: "ReferencePolicy identifies kinds of resources in other namespaces - that are trusted to reference the specified kinds of resources in the same - namespace as the policy. \n Each ReferencePolicy can be used to represent - a unique trust relationship. Additional Reference Policies can be used to - add to the set of trusted sources of inbound references for the namespace - they are defined within. \n All cross-namespace references in Gateway API - (with the exception of cross-namespace Gateway-route attachment) require - a ReferencePolicy. \n Support: Core" - 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: Spec defines the desired state of ReferencePolicy. - properties: - from: - description: "From describes the trusted namespaces and kinds that - can reference the resources described in \"To\". Each entry in this - list must be considered to be an additional place that references - can be valid from, or to put this another way, entries must be combined - using OR. \n Support: Core" - items: - description: ReferencePolicyFrom describes trusted namespaces and - kinds. - properties: - group: - description: "Group is the group of the referent. When empty, - the Kubernetes core API group is inferred. \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: "Kind is the kind of the referent. Although implementations - may support additional resources, the following Route types - are part of the \"Core\" support level for this field: \n - * HTTPRoute * TCPRoute * TLSRoute * UDPRoute" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - namespace: - description: "Namespace is the namespace of the referent. \n - Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - type: object - maxItems: 16 - minItems: 1 - type: array - to: - description: "To describes the resources that may be referenced by - the resources described in \"From\". Each entry in this list must - be considered to be an additional place that references can be valid - to, or to put this another way, entries must be combined using OR. - \n Support: Core" - items: - description: ReferencePolicyTo describes what Kinds are allowed - as targets of the references. - properties: - group: - description: "Group is the group of the referent. When empty, - the Kubernetes core API group is inferred. \n Support: Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: "Kind is the kind of the referent. Although implementations - may support additional resources, the following types are - part of the \"Core\" support level for this field: \n * Service" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. When unspecified - or empty, this policy refers to all resources of the specified - Group and Kind in the local namespace. - maxLength: 253 - minLength: 1 - type: string - required: - - group - - kind - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - from - - to - type: object - type: object - served: true - storage: true - subresources: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 - creationTimestamp: null - name: tcproutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: TCPRoute - listKind: TCPRouteList - plural: tcproutes - singular: tcproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: TCPRoute provides a way to route TCP requests. When combined - with a Gateway listener, it can be used to forward connections on the port - specified by the listener to a set of backends specified by the TCPRoute. - 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: Spec defines the desired state of TCPRoute. - properties: - parentRefs: - description: "ParentRefs references the resources (usually Gateways) - that a Route wants to be attached to. Note that the referenced parent - resource needs to allow this for the attachment to be complete. - For Gateways, that means the Gateway needs to allow attachment from - Routes of this kind and namespace. \n The only kind of parent resource - with \"Core\" support is Gateway. This API may be extended in the - future to support additional kinds of parent resources such as one - of the route kinds. \n It is invalid to reference an identical parent - more than once. It is valid to reference multiple distinct sections - within the same parent resource, such as 2 Listeners within a Gateway. - \n It is possible to separately reference multiple distinct objects - that may be collapsed by an implementation. For example, some implementations - may choose to merge compatible Gateway Listeners together. If that - is the case, the list of routes attached to those resources should - also be merged." - items: - description: "ParentRef identifies an API object (usually a Gateway) - that can be considered a parent of this resource (usually a route). - The only kind of parent resource with \"Core\" support is Gateway. - This API may be extended in the future to support additional kinds - of parent resources, such as HTTPRoute. \n The API object must - be valid in the cluster; the Group and Kind must be registered - in the cluster for this reference to be valid. \n References to - objects with invalid Group and Kind are not valid, and must be - rejected by the implementation, with appropriate Conditions set - on the containing object." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. \n Support: - Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core - (Gateway) Support: Custom (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: - Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When - unspecified (or empty string), this refers to the local namespace - of the Route. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - sectionName: - description: "SectionName is the name of a section within the - target resource. In the following resources, SectionName is - interpreted as the following: \n * Gateway: Listener Name - \n Implementations MAY choose to support attaching Routes - to other resources. If that is the case, they MUST clearly - document how SectionName is interpreted. \n When unspecified - (empty string), this will reference the entire resource. For - the purpose of status, an attachment is considered successful - if at least one section in the parent resource accepts it. - For example, Gateway listeners can restrict which Routes can - attach to them by Route kind, namespace, or hostname. If 1 - of 2 Gateway listeners accept attachment from the referencing - Route, the Route MUST be considered successfully attached. - If no Gateway listeners accept attachment from this Route, - the Route MUST be considered detached from the Gateway. \n - Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - description: Rules are a list of TCP matchers and actions. - items: - description: TCPRouteRule is the configuration for a given rule. - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching - requests should be sent. If unspecified or invalid (refers - to a non-existent resource or a Service with no endpoints), - the underlying implementation MUST actively reject connection - attempts to this backend. Connection rejections must respect - weight; if an invalid backend is requested to have 80% of - connections, then 80% of connections must be rejected instead. - \n Support: Core for Kubernetes Service Support: Custom for - any other resource \n Support for weight: Extended" - items: - description: "BackendRef defines how a Route should forward - a request to a Kubernetes resource. \n Note that when a - namespace is specified, a ReferencePolicy object is required - in the referent namespace to allow that namespace's owner - to accept the reference. See the ReferencePolicy documentation - for details." - properties: - group: - default: "" - description: Group is the group of the referent. For example, - "networking.k8s.io". When unspecified (empty string), - core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example - "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. - When unspecified, the local namespace is inferred. \n - Note that when a namespace is specified, a ReferencePolicy - object is required in the referent namespace to allow - that namespace's owner to accept the reference. See - the ReferencePolicy documentation for details. \n Support: - Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number - to use for this resource. Port is required when the - referent is a Kubernetes Service. For other resources, - destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests - forwarded to the referenced backend. This is computed - as weight/(sum of all weights in this BackendRefs list). - For non-zero values, there may be some epsilon from - the exact proportion defined here depending on the precision - an implementation supports. Weight is not a percentage - and the sum of weights does not need to equal 100. \n - If only one backend is specified and it has a weight - greater than 0, 100% of the traffic is forwarded to - that backend. If weight is set to 0, no traffic should - be forwarded for this entry. If unspecified, weight - defaults to 1. \n Support for this field varies based - on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - minItems: 1 - type: array - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of TCPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) - that are associated with the route, and the status of the route - with respect to each parent. When this route attaches to a parent, - the controller that manages the parent must add an entry to this - list when the controller first sees the route and should update - the entry as appropriate when the route or gateway is modified. - \n Note that parent references that cannot be resolved by an implementation - of this API will not be added to this list. Implementations of this - API can only populate Route status for the Gateways/parent resources - they are responsible for. \n A maximum of 32 Gateways will be represented - in this list. An empty list means the route has not been attached - to any Gateway." - items: - description: RouteParentStatus describes the status of a route with - respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with - respect to the Gateway. Note that the route's availability - is also subject to the Gateway's own status conditions and - listener status. \n If the Route's ParentRef specifies an - existing Gateway that supports Routes of this kind AND that - Gateway's controller has sufficient access, then that Gateway's - controller MUST set the \"Accepted\" condition on the Route, - to indicate whether the route has been accepted or rejected - by the Gateway, and why. \n A Route MUST be considered \"Accepted\" - if at least one of the Route's rules is implemented by the - Gateway. \n There are a number of cases where the \"Accepted\" - condition may not be set due to lack of controller visibility, - that includes when: \n * The Route refers to a non-existent - parent. * The Route is of a type that the controller does - not support. * The Route is in a namespace the the controller - does not have access to." - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, type FooStatus struct{ - \ // Represents the observations of a foo's current state. - \ // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // - +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates - the name of the controller that wrote this status. This corresponds - with the controllerName field on GatewayClass. \n Example: - \"example.net/gateway-controller\". \n The format of this - field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid - Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec - that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. \n Support: - Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: - Core (Gateway) Support: Custom (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: - Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. - When unspecified (or empty string), this refers to the - local namespace of the Route. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - sectionName: - description: "SectionName is the name of a section within - the target resource. In the following resources, SectionName - is interpreted as the following: \n * Gateway: Listener - Name \n Implementations MAY choose to support attaching - Routes to other resources. If that is the case, they MUST - clearly document how SectionName is interpreted. \n When - unspecified (empty string), this will reference the entire - resource. For the purpose of status, an attachment is - considered successful if at least one section in the parent - resource accepts it. For example, Gateway listeners can - restrict which Routes can attach to them by Route kind, - namespace, or hostname. If 1 of 2 Gateway listeners accept - attachment from the referencing Route, the Route MUST - be considered successfully attached. If no Gateway listeners - accept attachment from this Route, the Route MUST be considered - detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 - creationTimestamp: null - name: tlsroutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: TLSRoute - listKind: TLSRouteList - plural: tlsroutes - singular: tlsroute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: "The TLSRoute resource is similar to TCPRoute, but can be configured - to match against TLS-specific metadata. This allows more flexibility in - matching streams for a given TLS listener. \n If you need to forward traffic - to a single target for a TLS listener, you could choose to use a TCPRoute - with a TLS listener." - 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: Spec defines the desired state of TLSRoute. - properties: - hostnames: - description: "Hostnames defines a set of SNI names that should match - against the SNI attribute of TLS ClientHello message in TLS handshake. - This matches the RFC 1123 definition of a hostname with 2 notable - exceptions: \n 1. IPs are not allowed in SNI names per RFC 6066. - 2. A hostname may be prefixed with a wildcard label (`*.`). The - wildcard label must appear by itself as the first label. \n If - a hostname is specified by both the Listener and TLSRoute, there - must be at least one intersecting hostname for the TLSRoute to be - attached to the Listener. For example: \n * A Listener with `test.example.com` - as the hostname matches TLSRoutes that have either not specified - any hostnames, or have specified at least one of `test.example.com` - or `*.example.com`. * A Listener with `*.example.com` as the hostname - matches TLSRoutes that have either not specified any hostnames - or have specified at least one hostname that matches the Listener - hostname. For example, `test.example.com` and `*.example.com` - would both match. On the other hand, `example.com` and `test.example.net` - would not match. \n If both the Listener and TLSRoute have specified - hostnames, any TLSRoute hostnames that do not match the Listener - hostname MUST be ignored. For example, if a Listener specified `*.example.com`, - and the TLSRoute specified `test.example.com` and `test.example.net`, - `test.example.net` must not be considered for a match. \n If both - the Listener and TLSRoute have specified hostnames, and none match - with the criteria above, then the TLSRoute is not accepted. The - implementation must raise an 'Accepted' Condition with a status - of `False` in the corresponding RouteParentStatus. \n Support: Core" - items: - description: "Hostname is the fully qualified domain name of a network - host. This matches the RFC 1123 definition of a hostname with - 2 notable exceptions: \n 1. IPs are not allowed. 2. A hostname - may be prefixed with a wildcard label (`*.`). The wildcard label - must appear by itself as the first label. \n Hostname can be \"precise\" - which is a domain name without the terminating dot of a network - host (e.g. \"foo.example.com\") or \"wildcard\", which is a domain - name prefixed with a single wildcard label (e.g. `*.example.com`). - \n Note that as per RFC1035 and RFC1123, a *label* must consist - of lower case alphanumeric characters or '-', and must start and - end with an alphanumeric character. No other punctuation is allowed." - maxLength: 253 - minLength: 1 - pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - maxItems: 16 - type: array - parentRefs: - description: "ParentRefs references the resources (usually Gateways) - that a Route wants to be attached to. Note that the referenced parent - resource needs to allow this for the attachment to be complete. - For Gateways, that means the Gateway needs to allow attachment from - Routes of this kind and namespace. \n The only kind of parent resource - with \"Core\" support is Gateway. This API may be extended in the - future to support additional kinds of parent resources such as one - of the route kinds. \n It is invalid to reference an identical parent - more than once. It is valid to reference multiple distinct sections - within the same parent resource, such as 2 Listeners within a Gateway. - \n It is possible to separately reference multiple distinct objects - that may be collapsed by an implementation. For example, some implementations - may choose to merge compatible Gateway Listeners together. If that - is the case, the list of routes attached to those resources should - also be merged." - items: - description: "ParentRef identifies an API object (usually a Gateway) - that can be considered a parent of this resource (usually a route). - The only kind of parent resource with \"Core\" support is Gateway. - This API may be extended in the future to support additional kinds - of parent resources, such as HTTPRoute. \n The API object must - be valid in the cluster; the Group and Kind must be registered - in the cluster for this reference to be valid. \n References to - objects with invalid Group and Kind are not valid, and must be - rejected by the implementation, with appropriate Conditions set - on the containing object." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. \n Support: - Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core - (Gateway) Support: Custom (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: - Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When - unspecified (or empty string), this refers to the local namespace - of the Route. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - sectionName: - description: "SectionName is the name of a section within the - target resource. In the following resources, SectionName is - interpreted as the following: \n * Gateway: Listener Name - \n Implementations MAY choose to support attaching Routes - to other resources. If that is the case, they MUST clearly - document how SectionName is interpreted. \n When unspecified - (empty string), this will reference the entire resource. For - the purpose of status, an attachment is considered successful - if at least one section in the parent resource accepts it. - For example, Gateway listeners can restrict which Routes can - attach to them by Route kind, namespace, or hostname. If 1 - of 2 Gateway listeners accept attachment from the referencing - Route, the Route MUST be considered successfully attached. - If no Gateway listeners accept attachment from this Route, - the Route MUST be considered detached from the Gateway. \n - Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - description: Rules are a list of TLS matchers and actions. - items: - description: TLSRouteRule is the configuration for a given rule. - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching - requests should be sent. If unspecified or invalid (refers - to a non-existent resource or a Service with no endpoints), - the rule performs no forwarding; if no filters are specified - that would result in a response being sent, the underlying - implementation must actively reject request attempts to this - backend, by rejecting the connection or returning a 503 status - code. Request rejections must respect weight; if an invalid - backend is requested to have 80% of requests, then 80% of - requests must be rejected instead. \n Support: Core for Kubernetes - Service Support: Custom for any other resource \n Support - for weight: Extended" - items: - description: "BackendRef defines how a Route should forward - a request to a Kubernetes resource. \n Note that when a - namespace is specified, a ReferencePolicy object is required - in the referent namespace to allow that namespace's owner - to accept the reference. See the ReferencePolicy documentation - for details." - properties: - group: - default: "" - description: Group is the group of the referent. For example, - "networking.k8s.io". When unspecified (empty string), - core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example - "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. - When unspecified, the local namespace is inferred. \n - Note that when a namespace is specified, a ReferencePolicy - object is required in the referent namespace to allow - that namespace's owner to accept the reference. See - the ReferencePolicy documentation for details. \n Support: - Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number - to use for this resource. Port is required when the - referent is a Kubernetes Service. For other resources, - destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests - forwarded to the referenced backend. This is computed - as weight/(sum of all weights in this BackendRefs list). - For non-zero values, there may be some epsilon from - the exact proportion defined here depending on the precision - an implementation supports. Weight is not a percentage - and the sum of weights does not need to equal 100. \n - If only one backend is specified and it has a weight - greater than 0, 100% of the traffic is forwarded to - that backend. If weight is set to 0, no traffic should - be forwarded for this entry. If unspecified, weight - defaults to 1. \n Support for this field varies based - on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - minItems: 1 - type: array - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of TLSRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) - that are associated with the route, and the status of the route - with respect to each parent. When this route attaches to a parent, - the controller that manages the parent must add an entry to this - list when the controller first sees the route and should update - the entry as appropriate when the route or gateway is modified. - \n Note that parent references that cannot be resolved by an implementation - of this API will not be added to this list. Implementations of this - API can only populate Route status for the Gateways/parent resources - they are responsible for. \n A maximum of 32 Gateways will be represented - in this list. An empty list means the route has not been attached - to any Gateway." - items: - description: RouteParentStatus describes the status of a route with - respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with - respect to the Gateway. Note that the route's availability - is also subject to the Gateway's own status conditions and - listener status. \n If the Route's ParentRef specifies an - existing Gateway that supports Routes of this kind AND that - Gateway's controller has sufficient access, then that Gateway's - controller MUST set the \"Accepted\" condition on the Route, - to indicate whether the route has been accepted or rejected - by the Gateway, and why. \n A Route MUST be considered \"Accepted\" - if at least one of the Route's rules is implemented by the - Gateway. \n There are a number of cases where the \"Accepted\" - condition may not be set due to lack of controller visibility, - that includes when: \n * The Route refers to a non-existent - parent. * The Route is of a type that the controller does - not support. * The Route is in a namespace the the controller - does not have access to." - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, type FooStatus struct{ - \ // Represents the observations of a foo's current state. - \ // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // - +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates - the name of the controller that wrote this status. This corresponds - with the controllerName field on GatewayClass. \n Example: - \"example.net/gateway-controller\". \n The format of this - field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid - Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec - that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. \n Support: - Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: - Core (Gateway) Support: Custom (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: - Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. - When unspecified (or empty string), this refers to the - local namespace of the Route. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - sectionName: - description: "SectionName is the name of a section within - the target resource. In the following resources, SectionName - is interpreted as the following: \n * Gateway: Listener - Name \n Implementations MAY choose to support attaching - Routes to other resources. If that is the case, they MUST - clearly document how SectionName is interpreted. \n When - unspecified (empty string), this will reference the entire - resource. For the purpose of status, an attachment is - considered successful if at least one section in the parent - resource accepts it. For example, Gateway listeners can - restrict which Routes can attach to them by Route kind, - namespace, or hostname. If 1 of 2 Gateway listeners accept - attachment from the referencing Route, the Route MUST - be considered successfully attached. If no Gateway listeners - accept attachment from this Route, the Route MUST be considered - detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - api-approved.kubernetes.io: https://github.com/kubernetes-sigs/gateway-api/pull/891 - creationTimestamp: null - name: udproutes.gateway.networking.k8s.io -spec: - group: gateway.networking.k8s.io - names: - categories: - - gateway-api - kind: UDPRoute - listKind: UDPRouteList - plural: udproutes - singular: udproute - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha2 - schema: - openAPIV3Schema: - description: UDPRoute provides a way to route UDP traffic. When combined with - a Gateway listener, it can be used to forward traffic on the port specified - by the listener to a set of backends specified by the UDPRoute. - 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: Spec defines the desired state of UDPRoute. - properties: - parentRefs: - description: "ParentRefs references the resources (usually Gateways) - that a Route wants to be attached to. Note that the referenced parent - resource needs to allow this for the attachment to be complete. - For Gateways, that means the Gateway needs to allow attachment from - Routes of this kind and namespace. \n The only kind of parent resource - with \"Core\" support is Gateway. This API may be extended in the - future to support additional kinds of parent resources such as one - of the route kinds. \n It is invalid to reference an identical parent - more than once. It is valid to reference multiple distinct sections - within the same parent resource, such as 2 Listeners within a Gateway. - \n It is possible to separately reference multiple distinct objects - that may be collapsed by an implementation. For example, some implementations - may choose to merge compatible Gateway Listeners together. If that - is the case, the list of routes attached to those resources should - also be merged." - items: - description: "ParentRef identifies an API object (usually a Gateway) - that can be considered a parent of this resource (usually a route). - The only kind of parent resource with \"Core\" support is Gateway. - This API may be extended in the future to support additional kinds - of parent resources, such as HTTPRoute. \n The API object must - be valid in the cluster; the Group and Kind must be registered - in the cluster for this reference to be valid. \n References to - objects with invalid Group and Kind are not valid, and must be - rejected by the implementation, with appropriate Conditions set - on the containing object." - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. \n Support: - Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: Core - (Gateway) Support: Custom (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: - Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. When - unspecified (or empty string), this refers to the local namespace - of the Route. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - sectionName: - description: "SectionName is the name of a section within the - target resource. In the following resources, SectionName is - interpreted as the following: \n * Gateway: Listener Name - \n Implementations MAY choose to support attaching Routes - to other resources. If that is the case, they MUST clearly - document how SectionName is interpreted. \n When unspecified - (empty string), this will reference the entire resource. For - the purpose of status, an attachment is considered successful - if at least one section in the parent resource accepts it. - For example, Gateway listeners can restrict which Routes can - attach to them by Route kind, namespace, or hostname. If 1 - of 2 Gateway listeners accept attachment from the referencing - Route, the Route MUST be considered successfully attached. - If no Gateway listeners accept attachment from this Route, - the Route MUST be considered detached from the Gateway. \n - Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - maxItems: 32 - type: array - rules: - description: Rules are a list of UDP matchers and actions. - items: - description: UDPRouteRule is the configuration for a given rule. - properties: - backendRefs: - description: "BackendRefs defines the backend(s) where matching - requests should be sent. If unspecified or invalid (refers - to a non-existent resource or a Service with no endpoints), - the underlying implementation MUST actively reject connection - attempts to this backend. Packet drops must respect weight; - if an invalid backend is requested to have 80% of the packets, - then 80% of packets must be dropped instead. \n Support: Core - for Kubernetes Service Support: Custom for any other resource - \n Support for weight: Extended" - items: - description: "BackendRef defines how a Route should forward - a request to a Kubernetes resource. \n Note that when a - namespace is specified, a ReferencePolicy object is required - in the referent namespace to allow that namespace's owner - to accept the reference. See the ReferencePolicy documentation - for details." - properties: - group: - default: "" - description: Group is the group of the referent. For example, - "networking.k8s.io". When unspecified (empty string), - core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Service - description: Kind is kind of the referent. For example - "HTTPRoute" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the backend. - When unspecified, the local namespace is inferred. \n - Note that when a namespace is specified, a ReferencePolicy - object is required in the referent namespace to allow - that namespace's owner to accept the reference. See - the ReferencePolicy documentation for details. \n Support: - Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - port: - description: Port specifies the destination port number - to use for this resource. Port is required when the - referent is a Kubernetes Service. For other resources, - destination port might be derived from the referent - resource or this field. - format: int32 - maximum: 65535 - minimum: 1 - type: integer - weight: - default: 1 - description: "Weight specifies the proportion of requests - forwarded to the referenced backend. This is computed - as weight/(sum of all weights in this BackendRefs list). - For non-zero values, there may be some epsilon from - the exact proportion defined here depending on the precision - an implementation supports. Weight is not a percentage - and the sum of weights does not need to equal 100. \n - If only one backend is specified and it has a weight - greater than 0, 100% of the traffic is forwarded to - that backend. If weight is set to 0, no traffic should - be forwarded for this entry. If unspecified, weight - defaults to 1. \n Support for this field varies based - on the context where used." - format: int32 - maximum: 1000000 - minimum: 0 - type: integer - required: - - name - type: object - maxItems: 16 - minItems: 1 - type: array - type: object - maxItems: 16 - minItems: 1 - type: array - required: - - rules - type: object - status: - description: Status defines the current state of UDPRoute. - properties: - parents: - description: "Parents is a list of parent resources (usually Gateways) - that are associated with the route, and the status of the route - with respect to each parent. When this route attaches to a parent, - the controller that manages the parent must add an entry to this - list when the controller first sees the route and should update - the entry as appropriate when the route or gateway is modified. - \n Note that parent references that cannot be resolved by an implementation - of this API will not be added to this list. Implementations of this - API can only populate Route status for the Gateways/parent resources - they are responsible for. \n A maximum of 32 Gateways will be represented - in this list. An empty list means the route has not been attached - to any Gateway." - items: - description: RouteParentStatus describes the status of a route with - respect to an associated Parent. - properties: - conditions: - description: "Conditions describes the status of the route with - respect to the Gateway. Note that the route's availability - is also subject to the Gateway's own status conditions and - listener status. \n If the Route's ParentRef specifies an - existing Gateway that supports Routes of this kind AND that - Gateway's controller has sufficient access, then that Gateway's - controller MUST set the \"Accepted\" condition on the Route, - to indicate whether the route has been accepted or rejected - by the Gateway, and why. \n A Route MUST be considered \"Accepted\" - if at least one of the Route's rules is implemented by the - Gateway. \n There are a number of cases where the \"Accepted\" - condition may not be set due to lack of controller visibility, - that includes when: \n * The Route refers to a non-existent - parent. * The Route is of a type that the controller does - not support. * The Route is in a namespace the the controller - does not have access to." - items: - description: "Condition contains details for one aspect of - the current state of this API Resource. --- This struct - is intended for direct use as an array at the field path - .status.conditions. For example, type FooStatus struct{ - \ // Represents the observations of a foo's current state. - \ // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type - \ // +patchStrategy=merge // +listType=map // - +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` - \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should - be when the underlying condition changed. If that is - not known, then using the time when the API field changed - is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, - if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the - current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier - indicating the reason for the condition's last transition. - Producers of specific condition types may define expected - values and meanings for this field, and whether the - values are considered a guaranteed API. The value should - be a CamelCase string. This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, - Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across - resources like Available, but because arbitrary conditions - can be useful (see .node.status.conditions), the ability - to deconflict is important. The regex it matches is - (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - maxItems: 8 - minItems: 1 - type: array - x-kubernetes-list-map-keys: - - type - x-kubernetes-list-type: map - controllerName: - description: "ControllerName is a domain/path string that indicates - the name of the controller that wrote this status. This corresponds - with the controllerName field on GatewayClass. \n Example: - \"example.net/gateway-controller\". \n The format of this - field is DOMAIN \"/\" PATH, where DOMAIN and PATH are valid - Kubernetes names (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)." - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ - type: string - parentRef: - description: ParentRef corresponds with a ParentRef in the spec - that this RouteParentStatus struct describes the status of. - properties: - group: - default: gateway.networking.k8s.io - description: "Group is the group of the referent. \n Support: - Core" - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Gateway - description: "Kind is kind of the referent. \n Support: - Core (Gateway) Support: Custom (Other Resources)" - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: "Name is the name of the referent. \n Support: - Core" - maxLength: 253 - minLength: 1 - type: string - namespace: - description: "Namespace is the namespace of the referent. - When unspecified (or empty string), this refers to the - local namespace of the Route. \n Support: Core" - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - sectionName: - description: "SectionName is the name of a section within - the target resource. In the following resources, SectionName - is interpreted as the following: \n * Gateway: Listener - Name \n Implementations MAY choose to support attaching - Routes to other resources. If that is the case, they MUST - clearly document how SectionName is interpreted. \n When - unspecified (empty string), this will reference the entire - resource. For the purpose of status, an attachment is - considered successful if at least one section in the parent - resource accepts it. For example, Gateway listeners can - restrict which Routes can attach to them by Route kind, - namespace, or hostname. If 1 of 2 Gateway listeners accept - attachment from the referencing Route, the Route MUST - be considered successfully attached. If no Gateway listeners - accept attachment from this Route, the Route MUST be considered - detached from the Gateway. \n Support: Core" - maxLength: 253 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - required: - - name - type: object - required: - - controllerName - - parentRef - type: object - maxItems: 32 - type: array - required: - - parents - type: object - required: - - spec - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] - -{{ end }} \ No newline at end of file diff --git a/charts/consul/templates/api-gateway-gatewayclassconfig.yaml b/charts/consul/templates/api-gateway-gatewayclassconfig.yaml index c4ba0348d9..7daf5e3f3c 100644 --- a/charts/consul/templates/api-gateway-gatewayclassconfig.yaml +++ b/charts/consul/templates/api-gateway-gatewayclassconfig.yaml @@ -13,15 +13,12 @@ metadata: spec: consul: authentication: + {{- if .Values.global.acls.manageSystemACLs }} + managed: true + method: {{ template "consul.fullname" . }}-k8s-auth-method + {{- end }} {{- if .Values.global.tls.enabled }} scheme: https - {{- if not (and .Values.externalServers.enabled .Values.externalServers.useSystemRoots) }} - {{- if .Values.global.tls.caCert.secretName }} - caSecret: {{ .Values.global.tls.caCert.secretName }} - {{- else }} - caSecret: {{ template "consul.fullname" . }}-ca-cert - {{- end }} - {{- end }} {{- else }} scheme: http {{- end }} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index a34c6bae99..5cb9a6a4ca 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2509,7 +2509,18 @@ apiGateway: # @type: string logLevel: info - + serviceAccount: + # This value defines additional annotations for the client service account. This should be formatted as a multi-line + # string. + # + # ```yaml + # annotations: | + # "sample/annotation1": "foo" + # "sample/annotation2": "bar" + # ``` + # + # @type: string + annotations: null controller: replicas: 1 diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index 6ef05ab7b7..fe3a09f3ca 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -532,7 +532,12 @@ func (c *Command) Run(args []string) int { } if c.flagCreateAPIGatewayToken { - err := c.createLocalACL("api-gateway-controller", apiGatewayControllerRules, consulDC, isPrimary, consulClient) + apigwRules, err := c.apiGatewayControllerRules() + if err != nil { + c.log.Error("Error templating api gateway rules", "err", err) + return 1 + } + err = c.createLocalACL("api-gateway-controller", apigwRules, consulDC, isPrimary, consulClient) if err != nil { c.log.Error(err.Error()) return 1 diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index 0515715bc9..00536a52de 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -163,7 +163,7 @@ partition "{{ .PartitionName }}" { {{- end }} ` - c.renderRules(apiGatewayRulesTpl) + return c.renderRules(apiGatewayRulesTpl) } // This assumes users are using the default name for the service, i.e. From 9779221fd4d664d362bb796a1c051e69846e47b8 Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Wed, 19 Jan 2022 12:08:23 -0500 Subject: [PATCH 219/418] lint: fix fmt error --- control-plane/subcommand/server-acl-init/command.go | 4 ++-- control-plane/subcommand/server-acl-init/rules.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index fe3a09f3ca..8d4e6ce5f3 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -165,7 +165,7 @@ func (c *Command) init() { "[Enterprise Only] If using Consul namespaces and registering the gateway outside of the "+ "default namespace, specify the value in the form ..") c.flags.BoolVar(&c.flagCreateAPIGatewayToken, "create-api-gateway-token", false, - "Toggle for creating a token for the API Gateway controller integration.") + "Toggle for creating a token for the API Gateway controller integration.") c.flags.Var((*flags.AppendSliceValue)(&c.flagServerAddresses), "server-address", "The IP, DNS name or the cloud auto-join string of the Consul server(s). If providing IPs or DNS names, may be specified multiple times. "+ @@ -533,7 +533,7 @@ func (c *Command) Run(args []string) int { if c.flagCreateAPIGatewayToken { apigwRules, err := c.apiGatewayControllerRules() - if err != nil { + if err != nil { c.log.Error("Error templating api gateway rules", "err", err) return 1 } diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index 00536a52de..d2bdb986f6 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -139,7 +139,7 @@ partition_prefix "" { } func (c *Command) apiGatewayControllerRules() (string, error) { - apiGatewayRulesTpl := ` + apiGatewayRulesTpl := ` {{- if .EnablePartitions }} partition "{{ .PartitionName }}" { mesh = "write" @@ -163,7 +163,7 @@ partition "{{ .PartitionName }}" { {{- end }} ` - return c.renderRules(apiGatewayRulesTpl) + return c.renderRules(apiGatewayRulesTpl) } // This assumes users are using the default name for the service, i.e. From d0d2371324902cac04a8db18f179aaa4b16b6849 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Wed, 19 Jan 2022 10:32:33 -0800 Subject: [PATCH 220/418] Add new value ui.dashboardURLTemplates (#937) * Add new value ui.dashboardURLTemplates This value is used to set Consul's `ui_config.dashboard_url_templates` config. I'm pulling it out as its own value rather than getting users to just use `server.extraConfig` because these template strings always use the characters `{{` and when used within `server.extraConfig`, users need to escape those characters. Before: ```yaml server: extraConfig: | { "ui_config": { "dashboard_url_templates": { "service": "http://grafana/service/{{ "{{" }}Service.Name}}" } } } ``` Now: ```yaml ui: dashboardURLTemplates: service: "http://grafana/service/{{Service.Name}}" ``` --- CHANGELOG.md | 1 + .../consul/templates/server-statefulset.yaml | 3 ++ .../consul/test/unit/server-statefulset.bats | 28 +++++++++++++++++++ charts/consul/values.yaml | 5 ++++ 4 files changed, 37 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d68bbce50..cd6b49bb55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ FEATURES: IMPROVEMENTS: * Helm * Allow customization of `terminationGracePeriodSeconds` on the ingress gateways. [[GH-947](https://github.com/hashicorp/consul-k8s/pull/947)] + * Support `ui.dashboardURLTemplates.service` value for setting [dashboard URL templates](https://www.consul.io/docs/agent/options#ui_config_dashboard_url_templates_service). [[GH-937](https://github.com/hashicorp/consul-k8s/pull/937)] BUG FIXES: * Helm diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 16fae492ef..b0e5798aff 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -295,6 +295,9 @@ spec: {{- end }} {{- if .Values.ui.enabled }} -ui \ + {{- if .Values.ui.dashboardURLTemplates.service }} + -hcl='ui_config { dashboard_url_templates { service = "{{ .Values.ui.dashboardURLTemplates.service }}" } }' \ + {{- end }} {{- end }} {{- $serverSerfLANPort := .Values.server.ports.serflan.port -}} {{- range $index := until (.Values.server.replicas | int) }} diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index c1d260e296..69a507f06a 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -1785,3 +1785,31 @@ load _helpers yq -r '.containers[0].volumeMounts[] | select(.name == "consul-ca-key")' | tee /dev/stderr) [ "${actual}" = "" ] } + +#-------------------------------------------------------------------- +# ui.dashboardURLTemplates.service + +@test "server/StatefulSet: dashboard_url_templates not set by default" { + cd `chart_dir` + + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + . | tee /dev/stderr | + yq -r ".spec.template.spec.containers[0].command | any(contains(\"dashboard_url_templates\"))" | tee /dev/stderr) + + [ "${actual}" = "false" ] +} + +@test "server/StatefulSet: ui.dashboardURLTemplates.service sets the template" { + cd `chart_dir` + + local expected='-hcl='\''ui_config { dashboard_url_templates { service = \"http://localhost:3000/d/WkFEBmF7z/services?orgId=1&var-Service={{Service.Name}}\" } }' + + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'ui.dashboardURLTemplates.service=http://localhost:3000/d/WkFEBmF7z/services?orgId=1&var-Service={{Service.Name}}' \ + . | tee /dev/stderr | + yq -r ".spec.template.spec.containers[0].command | any(contains(\"$expected\"))" | tee /dev/stderr) + + [ "${actual}" = "true" ] +} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 5c2b17f4ad..650db24399 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -1398,6 +1398,11 @@ ui: # @type: string baseURL: http://prometheus-server + # Corresponds to https://www.consul.io/docs/agent/options#ui_config_dashboard_url_templates configuration. + dashboardURLTemplates: + # Sets https://www.consul.io/docs/agent/options#ui_config_dashboard_url_templates_service. + service: "" + # Configure the catalog sync process to sync K8S with Consul # services. This can run bidirectional (default) or unidirectionally (Consul # to K8S or K8S to Consul only). From e22be254b0d1f14adfe647a46aedc9939d993998 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Rondeau?= Date: Wed, 19 Jan 2022 20:59:32 +0100 Subject: [PATCH 221/418] control-plane: Add ability to manage consul sidecar resources with annotations (#956) - default resources are set via flags of the injector - can be overriden with annotations on pods --- .../templates/connect-inject-deployment.yaml | 8 +- .../test/unit/connect-inject-deployment.bats | 40 +-- control-plane/connect-inject/annotations.go | 6 + .../connect-inject/consul_sidecar.go | 74 ++++- .../connect-inject/consul_sidecar_test.go | 298 ++++++++++++++++++ control-plane/connect-inject/handler.go | 2 +- .../subcommand/inject-connect/command.go | 104 +++--- .../subcommand/inject-connect/command_test.go | 36 +-- 8 files changed, 472 insertions(+), 96 deletions(-) diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index 854d6f13e0..d2d8b3e01b 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -201,16 +201,16 @@ spec: {{- if .Values.global.consulSidecarContainer }} {{- $consulSidecarResources := .Values.global.consulSidecarContainer.resources }} {{- if not (kindIs "invalid" $consulSidecarResources.limits.memory) }} - -consul-sidecar-memory-limit={{ $consulSidecarResources.limits.memory }} \ + -default-consul-sidecar-memory-limit={{ $consulSidecarResources.limits.memory }} \ {{- end }} {{- if not (kindIs "invalid" $consulSidecarResources.requests.memory) }} - -consul-sidecar-memory-request={{ $consulSidecarResources.requests.memory }} \ + -default-consul-sidecar-memory-request={{ $consulSidecarResources.requests.memory }} \ {{- end }} {{- if not (kindIs "invalid" $consulSidecarResources.limits.cpu) }} - -consul-sidecar-cpu-limit={{ $consulSidecarResources.limits.cpu }} \ + -default-consul-sidecar-cpu-limit={{ $consulSidecarResources.limits.cpu }} \ {{- end }} {{- if not (kindIs "invalid" $consulSidecarResources.requests.cpu) }} - -consul-sidecar-cpu-request={{ $consulSidecarResources.requests.cpu }} \ + -default-consul-sidecar-cpu-request={{ $consulSidecarResources.requests.cpu }} \ {{- end }} {{- end }} startupProbe: diff --git a/charts/consul/test/unit/connect-inject-deployment.bats b/charts/consul/test/unit/connect-inject-deployment.bats index e5ed980c1f..f818b021c8 100755 --- a/charts/consul/test/unit/connect-inject-deployment.bats +++ b/charts/consul/test/unit/connect-inject-deployment.bats @@ -1165,19 +1165,19 @@ EOF yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-memory-request=25Mi"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-memory-request=25Mi"))' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-cpu-request=20m"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-cpu-request=20m"))' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-memory-limit=50Mi"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-memory-limit=50Mi"))' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-cpu-limit=20m"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-cpu-limit=20m"))' | tee /dev/stderr) [ "${actual}" = "true" ] } @@ -1194,19 +1194,19 @@ EOF yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-memory-request=100Mi"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-memory-request=100Mi"))' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-cpu-request=100m"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-cpu-request=100m"))' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-memory-limit=200Mi"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-memory-limit=200Mi"))' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-cpu-limit=200m"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-cpu-limit=200m"))' | tee /dev/stderr) [ "${actual}" = "true" ] } @@ -1223,19 +1223,19 @@ EOF yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-memory-request=0"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-memory-request=0"))' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-cpu-request=0"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-cpu-request=0"))' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-memory-limit=0"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-memory-limit=0"))' | tee /dev/stderr) [ "${actual}" = "true" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-cpu-limit=0"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-cpu-limit=0"))' | tee /dev/stderr) [ "${actual}" = "true" ] } @@ -1252,19 +1252,19 @@ EOF yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-memory-request"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-memory-request"))' | tee /dev/stderr) [ "${actual}" = "false" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-cpu-request"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-cpu-request"))' | tee /dev/stderr) [ "${actual}" = "false" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-memory-limit"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-memory-limit"))' | tee /dev/stderr) [ "${actual}" = "false" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-cpu-limit"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-cpu-limit"))' | tee /dev/stderr) [ "${actual}" = "false" ] } @@ -1278,19 +1278,19 @@ EOF yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-memory-request"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-memory-request"))' | tee /dev/stderr) [ "${actual}" = "false" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-cpu-request"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-cpu-request"))' | tee /dev/stderr) [ "${actual}" = "false" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-memory-limit"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-memory-limit"))' | tee /dev/stderr) [ "${actual}" = "false" ] local actual=$(echo "$cmd" | - yq 'any(contains("-consul-sidecar-cpu-limit"))' | tee /dev/stderr) + yq 'any(contains("-default-consul-sidecar-cpu-limit"))' | tee /dev/stderr) [ "${actual}" = "false" ] } diff --git a/control-plane/connect-inject/annotations.go b/control-plane/connect-inject/annotations.go index c8bf650e08..8e9730d41a 100644 --- a/control-plane/connect-inject/annotations.go +++ b/control-plane/connect-inject/annotations.go @@ -69,6 +69,12 @@ const ( annotationSidecarProxyMemoryLimit = "consul.hashicorp.com/sidecar-proxy-memory-limit" annotationSidecarProxyMemoryRequest = "consul.hashicorp.com/sidecar-proxy-memory-request" + // annotations for consul sidecar resource limits. + annotationConsulSidecarCPULimit = "consul.hashicorp.com/consul-sidecar-cpu-limit" + annotationConsulSidecarCPURequest = "consul.hashicorp.com/consul-sidecar-cpu-request" + annotationConsulSidecarMemoryLimit = "consul.hashicorp.com/consul-sidecar-memory-limit" + annotationConsulSidecarMemoryRequest = "consul.hashicorp.com/consul-sidecar-memory-request" + // annotations for metrics to configure where Prometheus scrapes // metrics from, whether to run a merged metrics endpoint on the consul // sidecar, and configure the connect service metrics. diff --git a/control-plane/connect-inject/consul_sidecar.go b/control-plane/connect-inject/consul_sidecar.go index bb88224ec6..d296980988 100644 --- a/control-plane/connect-inject/consul_sidecar.go +++ b/control-plane/connect-inject/consul_sidecar.go @@ -4,6 +4,7 @@ import ( "fmt" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" ) // consulSidecar starts the consul-sidecar command to only run @@ -16,6 +17,11 @@ func (h *Handler) consulSidecar(pod corev1.Pod) (corev1.Container, error) { return corev1.Container{}, err } + resources, err := h.consulSidecarResources(pod) + if err != nil { + return corev1.Container{}, err + } + command := []string{ "consul-k8s-control-plane", "consul-sidecar", @@ -38,6 +44,72 @@ func (h *Handler) consulSidecar(pod corev1.Pod) (corev1.Container, error) { }, }, Command: command, - Resources: h.ConsulSidecarResources, + Resources: resources, }, nil } + +func (h *Handler) consulSidecarResources(pod corev1.Pod) (corev1.ResourceRequirements, error) { + resources := corev1.ResourceRequirements{ + Limits: corev1.ResourceList{}, + Requests: corev1.ResourceList{}, + } + // zeroQuantity is used for comparison to see if a quantity was explicitly + // set. + var zeroQuantity resource.Quantity + + // NOTE: We only want to set the limit/request if the default or annotation + // was explicitly set. If it's not explicitly set, it will be the zero value + // which would show up in the pod spec as being explicitly set to zero if we + // set that key, e.g. "cpu" to zero. + // We want it to not show up in the pod spec at all if if it's not explicitly + // set so that users aren't wondering why it's set to 0 when they didn't specify + // a request/limit. If they have explicitly set it to 0 then it will be set + // to 0 in the pod spec because we're doing a comparison to the zero-valued + // struct. + + // CPU Limit. + if anno, ok := pod.Annotations[annotationConsulSidecarCPULimit]; ok { + cpuLimit, err := resource.ParseQuantity(anno) + if err != nil { + return corev1.ResourceRequirements{}, fmt.Errorf("parsing annotation %s:%q: %s", annotationConsulSidecarCPULimit, anno, err) + } + resources.Limits[corev1.ResourceCPU] = cpuLimit + } else if h.DefaultConsulSidecarResources.Limits[corev1.ResourceCPU] != zeroQuantity { + resources.Limits[corev1.ResourceCPU] = h.DefaultConsulSidecarResources.Limits[corev1.ResourceCPU] + } + + // CPU Request. + if anno, ok := pod.Annotations[annotationConsulSidecarCPURequest]; ok { + cpuRequest, err := resource.ParseQuantity(anno) + if err != nil { + return corev1.ResourceRequirements{}, fmt.Errorf("parsing annotation %s:%q: %s", annotationConsulSidecarCPURequest, anno, err) + } + resources.Requests[corev1.ResourceCPU] = cpuRequest + } else if h.DefaultConsulSidecarResources.Requests[corev1.ResourceCPU] != zeroQuantity { + resources.Requests[corev1.ResourceCPU] = h.DefaultConsulSidecarResources.Requests[corev1.ResourceCPU] + } + + // Memory Limit. + if anno, ok := pod.Annotations[annotationConsulSidecarMemoryLimit]; ok { + memoryLimit, err := resource.ParseQuantity(anno) + if err != nil { + return corev1.ResourceRequirements{}, fmt.Errorf("parsing annotation %s:%q: %s", annotationConsulSidecarMemoryLimit, anno, err) + } + resources.Limits[corev1.ResourceMemory] = memoryLimit + } else if h.DefaultConsulSidecarResources.Limits[corev1.ResourceMemory] != zeroQuantity { + resources.Limits[corev1.ResourceMemory] = h.DefaultConsulSidecarResources.Limits[corev1.ResourceMemory] + } + + // Memory Request. + if anno, ok := pod.Annotations[annotationConsulSidecarMemoryRequest]; ok { + memoryRequest, err := resource.ParseQuantity(anno) + if err != nil { + return corev1.ResourceRequirements{}, fmt.Errorf("parsing annotation %s:%q: %s", annotationConsulSidecarMemoryRequest, anno, err) + } + resources.Requests[corev1.ResourceMemory] = memoryRequest + } else if h.DefaultConsulSidecarResources.Requests[corev1.ResourceMemory] != zeroQuantity { + resources.Requests[corev1.ResourceMemory] = h.DefaultConsulSidecarResources.Requests[corev1.ResourceMemory] + } + + return resources, nil +} diff --git a/control-plane/connect-inject/consul_sidecar_test.go b/control-plane/connect-inject/consul_sidecar_test.go index b5f7c80c3b..da3cd5c7e1 100644 --- a/control-plane/connect-inject/consul_sidecar_test.go +++ b/control-plane/connect-inject/consul_sidecar_test.go @@ -6,6 +6,7 @@ import ( logrtest "github.com/go-logr/logr/testing" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -43,3 +44,300 @@ func TestConsulSidecar_MetricsFlags(t *testing.T) { require.Contains(t, container.Command, "-service-metrics-port=8080") require.Contains(t, container.Command, "-service-metrics-path=/metrics") } + +func TestHandlerConsulSidecar_Resources(t *testing.T) { + mem1 := resource.MustParse("100Mi") + mem2 := resource.MustParse("200Mi") + cpu1 := resource.MustParse("100m") + cpu2 := resource.MustParse("200m") + zero := resource.MustParse("0") + + cases := map[string]struct { + handler Handler + annotations map[string]string + expResources corev1.ResourceRequirements + expErr string + }{ + "no defaults, no annotations": { + handler: Handler{ + Log: logrtest.TestLogger{T: t}, + ImageConsulK8S: "hashicorp/consul-k8s:9.9.9", + MetricsConfig: MetricsConfig{ + DefaultEnableMetrics: true, + DefaultEnableMetricsMerging: true, + }, + }, + annotations: map[string]string{ + annotationMergedMetricsPort: "20100", + annotationServiceMetricsPort: "8080", + annotationServiceMetricsPath: "/metrics", + }, + expResources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{}, + Requests: corev1.ResourceList{}, + }, + }, + "all defaults, no annotations": { + handler: Handler{ + Log: logrtest.TestLogger{T: t}, + ImageConsulK8S: "hashicorp/consul-k8s:9.9.9", + MetricsConfig: MetricsConfig{ + DefaultEnableMetrics: true, + DefaultEnableMetricsMerging: true, + }, + DefaultConsulSidecarResources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: cpu1, + corev1.ResourceMemory: mem1, + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: cpu2, + corev1.ResourceMemory: mem2, + }, + }, + }, + annotations: map[string]string{ + annotationMergedMetricsPort: "20100", + annotationServiceMetricsPort: "8080", + annotationServiceMetricsPath: "/metrics", + }, + expResources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: cpu2, + corev1.ResourceMemory: mem2, + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: cpu1, + corev1.ResourceMemory: mem1, + }, + }, + }, + "no defaults, all annotations": { + handler: Handler{ + Log: logrtest.TestLogger{T: t}, + ImageConsulK8S: "hashicorp/consul-k8s:9.9.9", + MetricsConfig: MetricsConfig{ + DefaultEnableMetrics: true, + DefaultEnableMetricsMerging: true, + }, + }, + annotations: map[string]string{ + annotationMergedMetricsPort: "20100", + annotationServiceMetricsPort: "8080", + annotationServiceMetricsPath: "/metrics", + annotationConsulSidecarCPURequest: "100m", + annotationConsulSidecarMemoryRequest: "100Mi", + annotationConsulSidecarCPULimit: "200m", + annotationConsulSidecarMemoryLimit: "200Mi", + }, + expResources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: cpu2, + corev1.ResourceMemory: mem2, + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: cpu1, + corev1.ResourceMemory: mem1, + }, + }, + }, + "annotations override defaults": { + handler: Handler{ + Log: logrtest.TestLogger{T: t}, + ImageConsulK8S: "hashicorp/consul-k8s:9.9.9", + MetricsConfig: MetricsConfig{ + DefaultEnableMetrics: true, + DefaultEnableMetricsMerging: true, + }, + DefaultConsulSidecarResources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: zero, + corev1.ResourceMemory: zero, + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: zero, + corev1.ResourceMemory: zero, + }, + }, + }, + annotations: map[string]string{ + annotationMergedMetricsPort: "20100", + annotationServiceMetricsPort: "8080", + annotationServiceMetricsPath: "/metrics", + annotationConsulSidecarCPURequest: "100m", + annotationConsulSidecarMemoryRequest: "100Mi", + annotationConsulSidecarCPULimit: "200m", + annotationConsulSidecarMemoryLimit: "200Mi", + }, + expResources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: cpu2, + corev1.ResourceMemory: mem2, + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: cpu1, + corev1.ResourceMemory: mem1, + }, + }, + }, + "defaults set to zero, no annotations": { + handler: Handler{ + Log: logrtest.TestLogger{T: t}, + ImageConsulK8S: "hashicorp/consul-k8s:9.9.9", + MetricsConfig: MetricsConfig{ + DefaultEnableMetrics: true, + DefaultEnableMetricsMerging: true, + }, + DefaultConsulSidecarResources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: zero, + corev1.ResourceMemory: zero, + }, + Limits: corev1.ResourceList{ + corev1.ResourceCPU: zero, + corev1.ResourceMemory: zero, + }, + }, + }, + annotations: map[string]string{ + annotationMergedMetricsPort: "20100", + annotationServiceMetricsPort: "8080", + annotationServiceMetricsPath: "/metrics", + }, + expResources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: zero, + corev1.ResourceMemory: zero, + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: zero, + corev1.ResourceMemory: zero, + }, + }, + }, + "annotations set to 0": { + handler: Handler{ + Log: logrtest.TestLogger{T: t}, + ImageConsulK8S: "hashicorp/consul-k8s:9.9.9", + MetricsConfig: MetricsConfig{ + DefaultEnableMetrics: true, + DefaultEnableMetricsMerging: true, + }, + }, + annotations: map[string]string{ + annotationMergedMetricsPort: "20100", + annotationServiceMetricsPort: "8080", + annotationServiceMetricsPath: "/metrics", + annotationConsulSidecarCPURequest: "0", + annotationConsulSidecarMemoryRequest: "0", + annotationConsulSidecarCPULimit: "0", + annotationConsulSidecarMemoryLimit: "0", + }, + expResources: corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: zero, + corev1.ResourceMemory: zero, + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: zero, + corev1.ResourceMemory: zero, + }, + }, + }, + "invalid cpu request": { + handler: Handler{ + Log: logrtest.TestLogger{T: t}, + ImageConsulK8S: "hashicorp/consul-k8s:9.9.9", + MetricsConfig: MetricsConfig{ + DefaultEnableMetrics: true, + DefaultEnableMetricsMerging: true, + }, + }, + annotations: map[string]string{ + annotationMergedMetricsPort: "20100", + annotationServiceMetricsPort: "8080", + annotationServiceMetricsPath: "/metrics", + annotationConsulSidecarCPURequest: "invalid", + }, + expErr: "parsing annotation consul.hashicorp.com/consul-sidecar-cpu-request:\"invalid\": quantities must match the regular expression", + }, + "invalid cpu limit": { + handler: Handler{ + Log: logrtest.TestLogger{T: t}, + ImageConsulK8S: "hashicorp/consul-k8s:9.9.9", + MetricsConfig: MetricsConfig{ + DefaultEnableMetrics: true, + DefaultEnableMetricsMerging: true, + }, + }, + annotations: map[string]string{ + annotationMergedMetricsPort: "20100", + annotationServiceMetricsPort: "8080", + annotationServiceMetricsPath: "/metrics", + annotationConsulSidecarCPULimit: "invalid", + }, + expErr: "parsing annotation consul.hashicorp.com/consul-sidecar-cpu-limit:\"invalid\": quantities must match the regular expression", + }, + "invalid memory request": { + handler: Handler{ + Log: logrtest.TestLogger{T: t}, + ImageConsulK8S: "hashicorp/consul-k8s:9.9.9", + MetricsConfig: MetricsConfig{ + DefaultEnableMetrics: true, + DefaultEnableMetricsMerging: true, + }, + }, + annotations: map[string]string{ + annotationMergedMetricsPort: "20100", + annotationServiceMetricsPort: "8080", + annotationServiceMetricsPath: "/metrics", + annotationConsulSidecarMemoryRequest: "invalid", + }, + expErr: "parsing annotation consul.hashicorp.com/consul-sidecar-memory-request:\"invalid\": quantities must match the regular expression", + }, + "invalid memory limit": { + handler: Handler{ + Log: logrtest.TestLogger{T: t}, + ImageConsulK8S: "hashicorp/consul-k8s:9.9.9", + MetricsConfig: MetricsConfig{ + DefaultEnableMetrics: true, + DefaultEnableMetricsMerging: true, + }, + }, + annotations: map[string]string{ + annotationMergedMetricsPort: "20100", + annotationServiceMetricsPort: "8080", + annotationServiceMetricsPath: "/metrics", + annotationConsulSidecarMemoryLimit: "invalid", + }, + expErr: "parsing annotation consul.hashicorp.com/consul-sidecar-memory-limit:\"invalid\": quantities must match the regular expression", + }, + } + + for name, c := range cases { + t.Run(name, func(tt *testing.T) { + require := require.New(tt) + pod := corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: c.annotations, + }, + + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "web", + }, + }, + }, + } + container, err := c.handler.consulSidecar(pod) + if c.expErr != "" { + require.NotNil(err) + require.Contains(err.Error(), c.expErr) + } else { + require.NoError(err) + require.Equal(c.expResources, container.Resources) + } + }) + } +} diff --git a/control-plane/connect-inject/handler.go b/control-plane/connect-inject/handler.go index da2b4f681d..f172f34e7c 100644 --- a/control-plane/connect-inject/handler.go +++ b/control-plane/connect-inject/handler.go @@ -123,7 +123,7 @@ type Handler struct { // Resource settings for Consul sidecar. All of these fields // will be populated by the defaults provided in the initial flags. - ConsulSidecarResources corev1.ResourceRequirements + DefaultConsulSidecarResources corev1.ResourceRequirements // EnableTransparentProxy enables transparent proxy mode. // This means that the injected init container will apply traffic redirection rules diff --git a/control-plane/subcommand/inject-connect/command.go b/control-plane/subcommand/inject-connect/command.go index abebf69b81..1d4c88a069 100644 --- a/control-plane/subcommand/inject-connect/command.go +++ b/control-plane/subcommand/inject-connect/command.go @@ -77,10 +77,10 @@ type Command struct { flagDefaultPrometheusScrapePath string // Consul sidecar resource settings. - flagConsulSidecarCPULimit string - flagConsulSidecarCPURequest string - flagConsulSidecarMemoryLimit string - flagConsulSidecarMemoryRequest string + flagDefaultConsulSidecarCPULimit string + flagDefaultConsulSidecarCPURequest string + flagDefaultConsulSidecarMemoryLimit string + flagDefaultConsulSidecarMemoryRequest string // Init container resource settings. flagInitContainerCPULimit string @@ -197,10 +197,10 @@ func (c *Command) init() { c.flagSet.StringVar(&c.flagInitContainerMemoryLimit, "init-container-memory-limit", "150Mi", "Init container memory limit.") // Consul sidecar resource setting flags. - c.flagSet.StringVar(&c.flagConsulSidecarCPURequest, "consul-sidecar-cpu-request", "20m", "Consul sidecar CPU request.") - c.flagSet.StringVar(&c.flagConsulSidecarCPULimit, "consul-sidecar-cpu-limit", "20m", "Consul sidecar CPU limit.") - c.flagSet.StringVar(&c.flagConsulSidecarMemoryRequest, "consul-sidecar-memory-request", "25Mi", "Consul sidecar memory request.") - c.flagSet.StringVar(&c.flagConsulSidecarMemoryLimit, "consul-sidecar-memory-limit", "50Mi", "Consul sidecar memory limit.") + c.flagSet.StringVar(&c.flagDefaultConsulSidecarCPURequest, "default-consul-sidecar-cpu-request", "20m", "Default consul sidecar CPU request.") + c.flagSet.StringVar(&c.flagDefaultConsulSidecarCPULimit, "default-consul-sidecar-cpu-limit", "20m", "Default consul sidecar CPU limit.") + c.flagSet.StringVar(&c.flagDefaultConsulSidecarMemoryRequest, "default-consul-sidecar-memory-request", "25Mi", "Default consul sidecar memory request.") + c.flagSet.StringVar(&c.flagDefaultConsulSidecarMemoryLimit, "default-consul-sidecar-memory-limit", "50Mi", "Default consul sidecar memory limit.") c.http = &flags.HTTPFlags{} @@ -453,38 +453,38 @@ func (c *Command) Run(args []string) int { mgr.GetWebhookServer().Register("/mutate", &webhook.Admission{Handler: &connectinject.Handler{ - Clientset: c.clientset, - ConsulClient: c.consulClient, - ImageConsul: c.flagConsulImage, - ImageEnvoy: c.flagEnvoyImage, - EnvoyExtraArgs: c.flagEnvoyExtraArgs, - ImageConsulK8S: c.flagConsulK8sImage, - RequireAnnotation: !c.flagDefaultInject, - AuthMethod: c.flagACLAuthMethod, - ConsulCACert: string(consulCACert), - DefaultProxyCPURequest: sidecarProxyCPURequest, - DefaultProxyCPULimit: sidecarProxyCPULimit, - DefaultProxyMemoryRequest: sidecarProxyMemoryRequest, - DefaultProxyMemoryLimit: sidecarProxyMemoryLimit, - MetricsConfig: metricsConfig, - InitContainerResources: initResources, - ConsulSidecarResources: consulSidecarResources, - ConsulPartition: c.http.Partition(), - AllowK8sNamespacesSet: allowK8sNamespaces, - DenyK8sNamespacesSet: denyK8sNamespaces, - EnableNamespaces: c.flagEnableNamespaces, - ConsulDestinationNamespace: c.flagConsulDestinationNamespace, - EnableK8SNSMirroring: c.flagEnableK8SNSMirroring, - K8SNSMirroringPrefix: c.flagK8SNSMirroringPrefix, - CrossNamespaceACLPolicy: c.flagCrossNamespaceACLPolicy, - EnableTransparentProxy: c.flagDefaultEnableTransparentProxy, - TProxyOverwriteProbes: c.flagTransparentProxyDefaultOverwriteProbes, - EnableConsulDNS: c.flagEnableConsulDNS, - ResourcePrefix: c.flagResourcePrefix, - EnableOpenShift: c.flagEnableOpenShift, - Log: ctrl.Log.WithName("handler").WithName("connect"), - LogLevel: c.flagLogLevel, - LogJSON: c.flagLogJSON, + Clientset: c.clientset, + ConsulClient: c.consulClient, + ImageConsul: c.flagConsulImage, + ImageEnvoy: c.flagEnvoyImage, + EnvoyExtraArgs: c.flagEnvoyExtraArgs, + ImageConsulK8S: c.flagConsulK8sImage, + RequireAnnotation: !c.flagDefaultInject, + AuthMethod: c.flagACLAuthMethod, + ConsulCACert: string(consulCACert), + DefaultProxyCPURequest: sidecarProxyCPURequest, + DefaultProxyCPULimit: sidecarProxyCPULimit, + DefaultProxyMemoryRequest: sidecarProxyMemoryRequest, + DefaultProxyMemoryLimit: sidecarProxyMemoryLimit, + MetricsConfig: metricsConfig, + InitContainerResources: initResources, + DefaultConsulSidecarResources: consulSidecarResources, + ConsulPartition: c.http.Partition(), + AllowK8sNamespacesSet: allowK8sNamespaces, + DenyK8sNamespacesSet: denyK8sNamespaces, + EnableNamespaces: c.flagEnableNamespaces, + ConsulDestinationNamespace: c.flagConsulDestinationNamespace, + EnableK8SNSMirroring: c.flagEnableK8SNSMirroring, + K8SNSMirroringPrefix: c.flagK8SNSMirroringPrefix, + CrossNamespaceACLPolicy: c.flagCrossNamespaceACLPolicy, + EnableTransparentProxy: c.flagDefaultEnableTransparentProxy, + TProxyOverwriteProbes: c.flagTransparentProxyDefaultOverwriteProbes, + EnableConsulDNS: c.flagEnableConsulDNS, + ResourcePrefix: c.flagResourcePrefix, + EnableOpenShift: c.flagEnableOpenShift, + Log: ctrl.Log.WithName("handler").WithName("connect"), + LogLevel: c.flagLogLevel, + LogJSON: c.flagLogJSON, }}) if err := mgr.Start(ctx); err != nil { @@ -548,36 +548,36 @@ func (c *Command) parseAndValidateResourceFlags() (corev1.ResourceRequirements, var consulSidecarCPULimit, consulSidecarCPURequest, consulSidecarMemoryLimit, consulSidecarMemoryRequest resource.Quantity // Parse and validate the Consul sidecar resources - consulSidecarCPURequest, err = resource.ParseQuantity(c.flagConsulSidecarCPURequest) + consulSidecarCPURequest, err = resource.ParseQuantity(c.flagDefaultConsulSidecarCPURequest) if err != nil { return corev1.ResourceRequirements{}, corev1.ResourceRequirements{}, - fmt.Errorf("-consul-sidecar-cpu-request '%s' is invalid: %s", c.flagConsulSidecarCPURequest, err) + fmt.Errorf("-default-consul-sidecar-cpu-request '%s' is invalid: %s", c.flagDefaultConsulSidecarCPURequest, err) } - consulSidecarCPULimit, err = resource.ParseQuantity(c.flagConsulSidecarCPULimit) + consulSidecarCPULimit, err = resource.ParseQuantity(c.flagDefaultConsulSidecarCPULimit) if err != nil { return corev1.ResourceRequirements{}, corev1.ResourceRequirements{}, - fmt.Errorf("-consul-sidecar-cpu-limit '%s' is invalid: %s", c.flagConsulSidecarCPULimit, err) + fmt.Errorf("-default-consul-sidecar-cpu-limit '%s' is invalid: %s", c.flagDefaultConsulSidecarCPULimit, err) } if consulSidecarCPULimit.Value() != 0 && consulSidecarCPURequest.Cmp(consulSidecarCPULimit) > 0 { return corev1.ResourceRequirements{}, corev1.ResourceRequirements{}, fmt.Errorf( - "request must be <= limit: -consul-sidecar-cpu-request value of %q is greater than the -consul-sidecar-cpu-limit value of %q", - c.flagConsulSidecarCPURequest, c.flagConsulSidecarCPULimit) + "request must be <= limit: -default-consul-sidecar-cpu-request value of %q is greater than the -default-consul-sidecar-cpu-limit value of %q", + c.flagDefaultConsulSidecarCPURequest, c.flagDefaultConsulSidecarCPULimit) } - consulSidecarMemoryRequest, err = resource.ParseQuantity(c.flagConsulSidecarMemoryRequest) + consulSidecarMemoryRequest, err = resource.ParseQuantity(c.flagDefaultConsulSidecarMemoryRequest) if err != nil { return corev1.ResourceRequirements{}, corev1.ResourceRequirements{}, - fmt.Errorf("-consul-sidecar-memory-request '%s' is invalid: %s", c.flagConsulSidecarMemoryRequest, err) + fmt.Errorf("-default-consul-sidecar-memory-request '%s' is invalid: %s", c.flagDefaultConsulSidecarMemoryRequest, err) } - consulSidecarMemoryLimit, err = resource.ParseQuantity(c.flagConsulSidecarMemoryLimit) + consulSidecarMemoryLimit, err = resource.ParseQuantity(c.flagDefaultConsulSidecarMemoryLimit) if err != nil { return corev1.ResourceRequirements{}, corev1.ResourceRequirements{}, - fmt.Errorf("-consul-sidecar-memory-limit '%s' is invalid: %s", c.flagConsulSidecarMemoryLimit, err) + fmt.Errorf("-default-consul-sidecar-memory-limit '%s' is invalid: %s", c.flagDefaultConsulSidecarMemoryLimit, err) } if consulSidecarMemoryLimit.Value() != 0 && consulSidecarMemoryRequest.Cmp(consulSidecarMemoryLimit) > 0 { return corev1.ResourceRequirements{}, corev1.ResourceRequirements{}, fmt.Errorf( - "request must be <= limit: -consul-sidecar-memory-request value of %q is greater than the -consul-sidecar-memory-limit value of %q", - c.flagConsulSidecarMemoryRequest, c.flagConsulSidecarMemoryLimit) + "request must be <= limit: -default-consul-sidecar-memory-request value of %q is greater than the -default-consul-sidecar-memory-limit value of %q", + c.flagDefaultConsulSidecarMemoryRequest, c.flagDefaultConsulSidecarMemoryLimit) } // Put into corev1.ResourceRequirements form diff --git a/control-plane/subcommand/inject-connect/command_test.go b/control-plane/subcommand/inject-connect/command_test.go index 88dcd20768..3a2ef4642b 100644 --- a/control-plane/subcommand/inject-connect/command_test.go +++ b/control-plane/subcommand/inject-connect/command_test.go @@ -127,37 +127,37 @@ func TestRun_FlagValidation(t *testing.T) { }, { flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", - "-consul-sidecar-cpu-limit=unparseable"}, - expErr: "-consul-sidecar-cpu-limit 'unparseable' is invalid", + "-default-consul-sidecar-cpu-limit=unparseable"}, + expErr: "-default-consul-sidecar-cpu-limit 'unparseable' is invalid", }, { flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", - "-consul-sidecar-cpu-request=unparseable"}, - expErr: "-consul-sidecar-cpu-request 'unparseable' is invalid", + "-default-consul-sidecar-cpu-request=unparseable"}, + expErr: "-default-consul-sidecar-cpu-request 'unparseable' is invalid", }, { flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", - "-consul-sidecar-memory-limit=unparseable"}, - expErr: "-consul-sidecar-memory-limit 'unparseable' is invalid", + "-default-consul-sidecar-memory-limit=unparseable"}, + expErr: "-default-consul-sidecar-memory-limit 'unparseable' is invalid", }, { flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", - "-consul-sidecar-memory-request=unparseable"}, - expErr: "-consul-sidecar-memory-request 'unparseable' is invalid", + "-default-consul-sidecar-memory-request=unparseable"}, + expErr: "-default-consul-sidecar-memory-request 'unparseable' is invalid", }, { flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", - "-consul-sidecar-memory-request=50Mi", - "-consul-sidecar-memory-limit=25Mi", + "-default-consul-sidecar-memory-request=50Mi", + "-default-consul-sidecar-memory-limit=25Mi", }, - expErr: "request must be <= limit: -consul-sidecar-memory-request value of \"50Mi\" is greater than the -consul-sidecar-memory-limit value of \"25Mi\"", + expErr: "request must be <= limit: -default-consul-sidecar-memory-request value of \"50Mi\" is greater than the -default-consul-sidecar-memory-limit value of \"25Mi\"", }, { flags: []string{"-consul-k8s-image", "foo", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", - "-consul-sidecar-cpu-request=50m", - "-consul-sidecar-cpu-limit=25m", + "-default-consul-sidecar-cpu-request=50m", + "-default-consul-sidecar-cpu-limit=25m", }, - expErr: "request must be <= limit: -consul-sidecar-cpu-request value of \"50m\" is greater than the -consul-sidecar-cpu-limit value of \"25m\"", + expErr: "request must be <= limit: -default-consul-sidecar-cpu-request value of \"50m\" is greater than the -default-consul-sidecar-cpu-limit value of \"25m\"", }, { flags: []string{"-consul-k8s-image", "hashicorp/consul-k8s", "-consul-image", "foo", "-envoy-image", "envoy:1.16.0", @@ -199,10 +199,10 @@ func TestRun_ResourceLimitDefaults(t *testing.T) { require.Equal(t, cmd.flagInitContainerMemoryLimit, "150Mi") // Consul sidecar container defaults - require.Equal(t, cmd.flagConsulSidecarCPURequest, "20m") - require.Equal(t, cmd.flagConsulSidecarCPULimit, "20m") - require.Equal(t, cmd.flagConsulSidecarMemoryRequest, "25Mi") - require.Equal(t, cmd.flagConsulSidecarMemoryLimit, "50Mi") + require.Equal(t, cmd.flagDefaultConsulSidecarCPURequest, "20m") + require.Equal(t, cmd.flagDefaultConsulSidecarCPULimit, "20m") + require.Equal(t, cmd.flagDefaultConsulSidecarMemoryRequest, "25Mi") + require.Equal(t, cmd.flagDefaultConsulSidecarMemoryLimit, "50Mi") } func TestRun_ValidationConsulHTTPAddr(t *testing.T) { From 253f3afdc3a39bdf952b252e16510663abfe8c2a Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Wed, 19 Jan 2022 16:46:16 -0500 Subject: [PATCH 222/418] api-gateway: add unit tests for template files --- .../api-gateway-controller-clusterrole.bats | 20 + ...gateway-controller-clusterrolebinding.bats | 29 ++ .../api-gateway-controller-deployment.bats | 439 ++++++++++++++++++ .../unit/api-gateway-controller-service.bats | 37 ++ ...api-gateway-controller-serviceaccount.bats | 73 +++ .../test/unit/api-gateway-gatewayclass.bats | 46 ++ 6 files changed, 644 insertions(+) create mode 100644 charts/consul/test/unit/api-gateway-controller-clusterrole.bats create mode 100644 charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats create mode 100755 charts/consul/test/unit/api-gateway-controller-deployment.bats create mode 100755 charts/consul/test/unit/api-gateway-controller-service.bats create mode 100644 charts/consul/test/unit/api-gateway-controller-serviceaccount.bats create mode 100755 charts/consul/test/unit/api-gateway-gatewayclass.bats diff --git a/charts/consul/test/unit/api-gateway-controller-clusterrole.bats b/charts/consul/test/unit/api-gateway-controller-clusterrole.bats new file mode 100644 index 0000000000..42d245a1a7 --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-clusterrole.bats @@ -0,0 +1,20 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/ClusterRole: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-clusterrole.yaml \ + . +} + +@test "apiGateway/ClusterRole: enabled with apiGateway.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-clusterrole.yaml \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} diff --git a/charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats b/charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats new file mode 100644 index 0000000000..53c9e84611 --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats @@ -0,0 +1,29 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/ClusterRoleBinding: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-clusterrolebinding.yaml \ + . +} + +@test "apiGateway/ClusterRoleBinding: enabled with global.enabled false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-clusterrolebinding.yaml \ + --set 'global.enabled=false' \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq -s 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/ClusterRoleBinding: disabled with connectInject.enabled false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-clusterrolebinding.yaml \ + --set 'apiGateway.enabled=false' \ + . +} diff --git a/charts/consul/test/unit/api-gateway-controller-deployment.bats b/charts/consul/test/unit/api-gateway-controller-deployment.bats new file mode 100755 index 0000000000..26819a6b58 --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-deployment.bats @@ -0,0 +1,439 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/Deployment: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + . +} + +@test "apiGateway/Deployment: enable with global.enabled false, apiGateway.enabled true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'global.enabled=false' \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: disable with apiGateway.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=false' \ + . +} + +@test "apiGateway/Deployment: disable with global.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'global.enabled=false' \ + . +} + + +@test "apiGateway/Deployment: container image overrides" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].image' | tee /dev/stderr) + [ "${actual}" = "\"foo\"" ] +} + +#-------------------------------------------------------------------- +# nodeSelector + +@test "apiGateway/Deployment: nodeSelector is not set by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.nodeSelector' | tee /dev/stderr) + [ "${actual}" = "null" ] +} + +@test "apiGateway/Deployment: specified nodeSelector" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.controller.nodeSelector=testing' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.nodeSelector' | tee /dev/stderr) + [ "${actual}" = "testing" ] +} + +#-------------------------------------------------------------------- +# global.tls.enabled + +@test "apiGateway/Deployment: Adds tls-ca-cert volume when global.tls.enabled is true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.volumes[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) + [ "${actual}" != "" ] +} + +@test "apiGateway/Deployment: Adds tls-ca-cert volumeMounts when global.tls.enabled is true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) + [ "${actual}" != "" ] +} + +@test "apiGateway/Deployment: can overwrite CA secret with the provided one" { + cd `chart_dir` + local ca_cert_volume=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.caCert.secretName=foo-ca-cert' \ + --set 'global.tls.caCert.secretKey=key' \ + --set 'global.tls.caKey.secretName=foo-ca-key' \ + --set 'global.tls.caKey.secretKey=key' \ + . | tee /dev/stderr | + yq '.spec.template.spec.volumes[] | select(.name=="consul-ca-cert")' | tee /dev/stderr) + + # check that the provided ca cert secret is attached as a volume + local actual + actual=$(echo $ca_cert_volume | jq -r '.secret.secretName' | tee /dev/stderr) + [ "${actual}" = "foo-ca-cert" ] + + # check that the volume uses the provided secret key + actual=$(echo $ca_cert_volume | jq -r '.secret.items[0].key' | tee /dev/stderr) + [ "${actual}" = "key" ] +} + +#-------------------------------------------------------------------- +# global.tls.enableAutoEncrypt + +@test "apiGateway/Deployment: consul-auto-encrypt-ca-cert volume is added when TLS with auto-encrypt is enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.volumes[] | select(.name == "consul-auto-encrypt-ca-cert") | length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: consul-auto-encrypt-ca-cert volumeMount is added when TLS with auto-encrypt is enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-auto-encrypt-ca-cert") | length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: get-auto-encrypt-client-ca init container is created when TLS with auto-encrypt is enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[] | select(.name == "get-auto-encrypt-client-ca") | length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: adds both init containers when TLS with auto-encrypt and ACLs + namespaces are enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers | length == 2' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: consul-ca-cert volume is not added if externalServers.enabled=true and externalServers.useSystemRoots=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'externalServers.enabled=true' \ + --set 'externalServers.hosts[0]=foo.com' \ + --set 'externalServers.useSystemRoots=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.volumes[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + +#-------------------------------------------------------------------- +# global.acls.manageSystemACLs + +@test "apiGateway/Deployment: CONSUL_HTTP_TOKEN env variable created when global.acls.manageSystemACLs=true" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '[.spec.template.spec.containers[0].env[].name] ' | tee /dev/stderr) + + local actual=$(echo $object | + yq 'any(contains("CONSUL_HTTP_TOKEN"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + + local actual=$(echo $object | + yq 'map(select(test("CONSUL_HTTP_TOKEN"))) | length' | tee /dev/stderr) + [ "${actual}" = "1" ] +} + +@test "apiGateway/Deployment: init container is created when global.acls.manageSystemACLs=true" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.initContainers[0]' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.name' | tee /dev/stderr) + [ "${actual}" = "injector-acl-init" ] + + local actual=$(echo $object | + yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# priorityClassName + +@test "apiGateway/Deployment: no priorityClassName by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.priorityClassName' | tee /dev/stderr) + + [ "${actual}" = "null" ] +} + +@test "apiGateway/Deployment: can set a priorityClassName" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.controller.priorityClassName=name' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.priorityClassName' | tee /dev/stderr) + + [ "${actual}" = "name" ] +} + +#-------------------------------------------------------------------- +# logLevel + +@test "apiGateway/Deployment: logLevel info by default from global" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) + + local actual=$(echo "$cmd" | + yq 'any(contains("-log-level info"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: logLevel can be overridden" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.logLevel=debug' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) + + local actual=$(echo "$cmd" | + yq 'any(contains("-log-level debug"))' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# replicas + +@test "apiGateway/Deployment: replicas defaults to 1" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.replicas' | tee /dev/stderr) + + [ "${actual}" = "1" ] +} + +@test "apiGateway/Deployment: replicas can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.controller.replicas=3' \ + . | tee /dev/stderr | + yq '.spec.replicas' | tee /dev/stderr) + + [ "${actual}" = "3" ] +} + +#-------------------------------------------------------------------- +# Vault + +@test "apiGateway/Deployment: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "apiGateway/Deployment: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "apiGateway/Deployment: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "apiGateway/Deployment: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} + +@test "apiGateway/Deployment: vault tls annotations are set when tls is enabled" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=bar' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"pki_int/cert/ca\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr)" + [ "${actual}" = "pki_int/cert/ca" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-init-first"]' | tee /dev/stderr)" + [ "${actual}" = "true" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr)" + [ "${actual}" = "true" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr)" + [ "${actual}" = "test" ] +} diff --git a/charts/consul/test/unit/api-gateway-controller-service.bats b/charts/consul/test/unit/api-gateway-controller-service.bats new file mode 100755 index 0000000000..99aab98842 --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-service.bats @@ -0,0 +1,37 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/Service: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-service.yaml \ + . +} + +@test "apiGateway/Service: enable with global.enabled false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-service.yaml \ + --set 'global.enabled=false' \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Service: disable with apiGateway.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-service.yaml \ + --set 'apiGateway.enabled=false' \ + . +} + +@test "apiGateway/Service: disable with global.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-service.yaml \ + --set 'global.enabled=false' \ + . +} diff --git a/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats b/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats new file mode 100644 index 0000000000..7cd8eef08c --- /dev/null +++ b/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats @@ -0,0 +1,73 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/ServiceAccount: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + . +} + +@test "apiGateway/ServiceAccount: enabled with global.enabled false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + --set 'global.enabled=false' \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq -s 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/ServiceAccount: disabled with apiGateway.enabled false" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + --set 'apiGateway.enabled=false' \ + . +} +#-------------------------------------------------------------------- +# global.imagePullSecrets + +@test "apiGateway/ServiceAccount: can set image pull secrets" { + cd `chart_dir` + local object=$(helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'global.imagePullSecrets[0].name=my-secret' \ + --set 'global.imagePullSecrets[1].name=my-secret2' \ + . | tee /dev/stderr) + + local actual=$(echo "$object" | + yq -r '.imagePullSecrets[0].name' | tee /dev/stderr) + [ "${actual}" = "my-secret" ] + + local actual=$(echo "$object" | + yq -r '.imagePullSecrets[1].name' | tee /dev/stderr) + [ "${actual}" = "my-secret2" ] +} + +#-------------------------------------------------------------------- +# apiGateway.serviceAccount.annotations + +@test "apiGateway/ServiceAccount: no annotations by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq '.metadata.annotations | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "apiGateway/ServiceAccount: annotations when enabled" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-serviceaccount.yaml \ + --set 'apiGateway.enabled=true' \ + --set "apiGateway.serviceAccount.annotations=foo: bar" \ + . | tee /dev/stderr | + yq -r '.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} diff --git a/charts/consul/test/unit/api-gateway-gatewayclass.bats b/charts/consul/test/unit/api-gateway-gatewayclass.bats new file mode 100755 index 0000000000..bdcc3bc4f7 --- /dev/null +++ b/charts/consul/test/unit/api-gateway-gatewayclass.bats @@ -0,0 +1,46 @@ +#!/usr/bin/env bats + +load _helpers + +@test "apiGateway/GatewayClass: disabled by default" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-gatewayclass.yaml \ + . +} + +@test "apiGateway/GatewayClass: enable with global.enabled false" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-gatewayclass.yaml \ + --set 'global.enabled=false' \ + --set 'apiGateway.enabled=true' \ + . | tee /dev/stderr | + yq 'length > 0' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/GatewayClass: disable with apiGateway.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-gatewayclass.yaml \ + --set 'apiGateway.enabled=false' \ + . +} + +@test "apiGateway/GatewayClass: disable with global.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-gatewayclass.yaml \ + --set 'global.enabled=false' \ + . +} + +@test "apiGateway/GatewayClass: disable with apiGateway.managedGatewayClass.enabled" { + cd `chart_dir` + assert_empty helm template \ + -s templates/api-gateway-gatewayclass.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.managedGatewayClass.enabled=false' \ + . +} From 819d3a116008e7850579a0a2ea3a7fe6f7580d88 Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Wed, 19 Jan 2022 16:55:41 -0500 Subject: [PATCH 223/418] api-gateway: remove default image --- .../api-gateway-controller-deployment.yaml | 3 +- .../api-gateway-controller-deployment.bats | 39 ++++++++++++++++++- charts/consul/values.yaml | 2 +- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml index 53ae2d7ac5..b4ef852a5c 100644 --- a/charts/consul/templates/api-gateway-controller-deployment.yaml +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -1,5 +1,6 @@ {{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} {{- if not .Values.client.grpc }}{{ fail "client.grpc must be true for api gateway" }}{{ end }} +{{- if not .Values.apiGateway.image}}{{ fail "apiGateway.image must be set to enable api gateway" }}{{ end }} {{- if and .Values.global.adminPartitions.enabled (not .Values.global.enableConsulNamespaces) }}{{ fail "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" }}{{ end }} apiVersion: apps/v1 kind: Deployment @@ -144,4 +145,4 @@ spec: nodeSelector: {{ tpl .Values.apiGateway.controller.nodeSelector . | indent 8 | trim }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/charts/consul/test/unit/api-gateway-controller-deployment.bats b/charts/consul/test/unit/api-gateway-controller-deployment.bats index 26819a6b58..21c198bcf0 100755 --- a/charts/consul/test/unit/api-gateway-controller-deployment.bats +++ b/charts/consul/test/unit/api-gateway-controller-deployment.bats @@ -9,12 +9,24 @@ load _helpers . } +@test "apiGateway/Deployment: fails if no image is set" { + cd `chart_dir` + run helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + . + + [ "$status" -eq 1 ] + [[ "$output" =~ "apiGateway.image must be set to enable api gateway" ]] +} + @test "apiGateway/Deployment: enable with global.enabled false, apiGateway.enabled true" { cd `chart_dir` local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'global.enabled=false' \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] @@ -42,10 +54,10 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ - --set 'apiGateway.image=foo' \ + --set 'apiGateway.image=bar' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "\"foo\"" ] + [ "${actual}" = "\"bar\"" ] } #-------------------------------------------------------------------- @@ -56,6 +68,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq '.spec.template.spec.nodeSelector' | tee /dev/stderr) [ "${actual}" = "null" ] @@ -66,6 +79,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'apiGateway.controller.nodeSelector=testing' \ . | tee /dev/stderr | yq -r '.spec.template.spec.nodeSelector' | tee /dev/stderr) @@ -80,6 +94,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ . | tee /dev/stderr | yq '.spec.template.spec.volumes[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) @@ -91,6 +106,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-ca-cert")' | tee /dev/stderr) @@ -102,6 +118,7 @@ load _helpers local ca_cert_volume=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.caCert.secretName=foo-ca-cert' \ --set 'global.tls.caCert.secretKey=key' \ @@ -128,6 +145,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ . | tee /dev/stderr | @@ -140,6 +158,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ . | tee /dev/stderr | @@ -152,6 +171,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ . | tee /dev/stderr | @@ -164,6 +184,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.acls.manageSystemACLs=true' \ --set 'global.enableConsulNamespaces=true' \ --set 'global.tls.enabled=true' \ @@ -178,6 +199,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ --set 'externalServers.enabled=true' \ @@ -196,6 +218,7 @@ load _helpers local object=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq '[.spec.template.spec.containers[0].env[].name] ' | tee /dev/stderr) @@ -214,6 +237,7 @@ load _helpers local object=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.acls.manageSystemACLs=true' \ . | tee /dev/stderr | yq '.spec.template.spec.initContainers[0]' | tee /dev/stderr) @@ -235,6 +259,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq -r '.spec.template.spec.priorityClassName' | tee /dev/stderr) @@ -246,6 +271,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'apiGateway.controller.priorityClassName=name' \ . | tee /dev/stderr | yq -r '.spec.template.spec.priorityClassName' | tee /dev/stderr) @@ -261,6 +287,7 @@ load _helpers local cmd=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) @@ -274,6 +301,7 @@ load _helpers local cmd=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'apiGateway.logLevel=debug' \ . | tee /dev/stderr | yq '.spec.template.spec.containers[0].command' | tee /dev/stderr) @@ -291,6 +319,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq '.spec.replicas' | tee /dev/stderr) @@ -302,6 +331,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'apiGateway.controller.replicas=3' \ . | tee /dev/stderr | yq '.spec.replicas' | tee /dev/stderr) @@ -317,6 +347,7 @@ load _helpers local object=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ --set 'global.tls.caCert.secretName=foo' \ @@ -338,6 +369,7 @@ load _helpers local object=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ --set 'global.tls.caCert.secretName=foo' \ @@ -360,6 +392,7 @@ load _helpers local object=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ --set 'global.tls.caCert.secretName=foo' \ @@ -382,6 +415,7 @@ load _helpers local object=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.tls.enabled=true' \ --set 'global.tls.enableAutoEncrypt=true' \ --set 'global.tls.caCert.secretName=foo' \ @@ -405,6 +439,7 @@ load _helpers local cmd=$(helm template \ -s templates/api-gateway-controller-deployment.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.secretsBackend.vault.enabled=true' \ --set 'global.secretsBackend.vault.consulClientRole=foo' \ --set 'global.secretsBackend.vault.consulServerRole=bar' \ diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 5cb9a6a4ca..800d452617 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2465,7 +2465,7 @@ apiGateway: # Image to use for the api-gateway-controller pods and gateway instances # @type: string - image: "hashicorp/consul-api-gateway:0.1.0-techpreview" + image: null # Override global log verbosity level for api-gateway-controller pods. One of "debug", "info", "warn", or "error". From afd4e814fb1ca356b0f0121e8781c14dc1dd0662 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 20 Jan 2022 09:39:31 -0800 Subject: [PATCH 224/418] Move make targets to top-level (#981) * Move make targets from control-plane Makefile to top-level Makefile * leave targets that are needed for CI * remove charts/consul/Makefile because its test-docker target was never used * add help text to all Makefile targets. You can see the help by running `make` or `make help` * Add `control-plane-` prefix to control plane targets * Modify targets that download Go tools to use `go install` instead of `go get` because using go get to download tools is deprecated * Remove `kustomize` install target since we don't need it --- Makefile | 96 +++++++++++++++++++++++++++++++++++++----- charts/consul/Makefile | 6 --- control-plane/Makefile | 86 +++---------------------------------- 3 files changed, 90 insertions(+), 98 deletions(-) delete mode 100644 charts/consul/Makefile diff --git a/Makefile b/Makefile index 90839e82fa..e95e8faf13 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,91 @@ -# Generate Helm reference docs from values.yaml and update Consul website. -# Usage: make gen-docs consul= -gen-docs: +# ===========> Helm Targets + +gen-helm-docs: ## Generate Helm reference docs from values.yaml and update Consul website. Usage: make gen-helm-docs consul=. @cd hack/helm-reference-gen; go run ./... $(consul) -# Copy generated CRD YAML into charts/consul. -# Usage: make copy-crds-to-chart -copy-crds-to-chart: +copy-crds-to-chart: ## Copy generated CRD YAML into charts/consul. Usage: make copy-crds-to-chart @cd hack/copy-crds-to-chart; go run ./... -# Deletes AWS resources left behind after failed acceptance tests. -ci.aws-acceptance-test-cleanup: +bats-tests: ## Run Helm chart bats tests. + bats --jobs 4 charts/consul/test/unit + + + + +# ===========> Control Plane Targets + +control-plane-dev: ## Build consul-k8s-control-plane binary. + @$(SHELL) $(CURDIR)/control-plane/build-support/scripts/build-local.sh -o $(GOOS) -a $(GOARCH) + +control-plane-dev-docker: ## Build consul-k8s-control-plane dev Docker image. + @$(SHELL) $(CURDIR)/control-plane/build-support/scripts/build-local.sh -o linux -a amd64 + @docker build -t '$(DEV_IMAGE)' \ + --build-arg 'GIT_COMMIT=$(GIT_COMMIT)' \ + --build-arg 'GIT_DIRTY=$(GIT_DIRTY)' \ + --build-arg 'GIT_DESCRIBE=$(GIT_DESCRIBE)' \ + -f $(CURDIR)/build-support/docker/Dev.dockerfile $(CURDIR) + +control-plane-test: ## Run go test for the control plane. + cd control-plane; go test ./... + +control-plane-ent-test: ## Run go test with Consul enterprise tests. The consul binary in your PATH must be Consul Enterprise. + cd control-plane; go test ./... -tags=enterprise + +control-plane-cov: ## Run go test with code coverage. + cd control-plane; go test ./... -coverprofile=coverage.out; go tool cover -html=coverage.out + +control-plane-clean: ## Delete bin and pkg dirs. + @rm -rf \ + $(CURDIR)/control-plane/bin \ + $(CURDIR)/control-plane/pkg + +ctrl-generate: get-controller-gen ## Run CRD code generation. + cd control-plane; $(CONTROLLER_GEN) object:headerFile="build-support/controller/boilerplate.go.txt" paths="./..." + + + + +# ===========> Shared Targets + +help: ## Show targets and their descriptions. + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +ctrl-manifests: get-controller-gen ## Generate CRD manifests. + cd control-plane; $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases + make copy-crds-to-chart + +get-controller-gen: ## Download controller-gen program needed for operator SDK. +ifeq (, $(shell which controller-gen)) + @{ \ + set -e ;\ + CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ + cd $$CONTROLLER_GEN_TMP_DIR ;\ + go mod init tmp ;\ + go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.0 ;\ + rm -rf $$CONTROLLER_GEN_TMP_DIR ;\ + } +CONTROLLER_GEN=$(shell go env GOPATH)/bin/controller-gen +else +CONTROLLER_GEN=$(shell which controller-gen) +endif + +# ===========> CI Targets + +ci.aws-acceptance-test-cleanup: ## Deletes AWS resources left behind after failed acceptance tests. @cd hack/aws-acceptance-test-cleanup; go run ./... -auto-approve -# Run bats tests in parallel from the root of the repository. -bats-tests: - bats --jobs 4 charts/consul/test/unit + + + +# ===========> Makefile config + +.DEFAULT_GOAL := help +.PHONY: gen-helm-docs copy-crds-to-chart bats-tests help ci.aws-acceptance-test-cleanup +SHELL = bash +GOOS?=$(shell go env GOOS) +GOARCH?=$(shell go env GOARCH) +DEV_IMAGE?=consul-k8s-control-plane-dev +GIT_COMMIT?=$(shell git rev-parse --short HEAD) +GIT_DIRTY?=$(shell test -n "`git status --porcelain`" && echo "+CHANGES" || true) +GIT_DESCRIBE?=$(shell git describe --tags --always) +CRD_OPTIONS ?= "crd:trivialVersions=true,allowDangerousTypes=true" diff --git a/charts/consul/Makefile b/charts/consul/Makefile deleted file mode 100644 index ec8cd7505f..0000000000 --- a/charts/consul/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -TEST_IMAGE?=consul-helm-test - -test-docker: - @docker build --rm -t '$(TEST_IMAGE)' -f $(CURDIR)/test/docker/Test.dockerfile $(CURDIR) - -.PHONY: test-docker diff --git a/control-plane/Makefile b/control-plane/Makefile index 473fae2dd0..d882018031 100644 --- a/control-plane/Makefile +++ b/control-plane/Makefile @@ -1,8 +1,8 @@ SHELL = bash -GOOS?=$(shell go env GOOS) -GOARCH?=$(shell go env GOARCH) -DEV_IMAGE?=consul-k8s-control-plane-dev +################ +# CI Variables # +################ GIT_COMMIT?=$(shell git rev-parse --short HEAD) GIT_DIRTY?=$(shell test -n "`git status --porcelain`" && echo "+CHANGES" || true) GIT_DESCRIBE?=$(shell git describe --tags --always) @@ -18,83 +18,15 @@ export GIT_COMMIT export GIT_DIRTY export GIT_DESCRIBE -CRD_OPTIONS ?= "crd:trivialVersions=true,allowDangerousTypes=true" - -################ -# CI Variables # -################ CI_DEV_DOCKER_NAMESPACE?=hashicorpdev CI_DEV_DOCKER_IMAGE_NAME?=consul-k8s-control-plane CI_DEV_DOCKER_WORKDIR?=. CONSUL_K8S_IMAGE_VERSION?=latest ################ -dev: - @$(SHELL) $(CURDIR)/build-support/scripts/build-local.sh -o $(GOOS) -a $(GOARCH) - -dev-docker: - @$(SHELL) $(CURDIR)/build-support/scripts/build-local.sh -o linux -a amd64 - @docker build -t '$(DEV_IMAGE)' --build-arg 'GIT_COMMIT=$(GIT_COMMIT)' --build-arg 'GIT_DIRTY=$(GIT_DIRTY)' --build-arg 'GIT_DESCRIBE=$(GIT_DESCRIBE)' -f $(CURDIR)/build-support/docker/Dev.dockerfile $(CURDIR) - -dev-tree: +ci.dev-tree: @$(SHELL) $(CURDIR)/build-support/scripts/dev.sh $(DEV_PUSH_ARG) -test: - go test ./... - -# requires a consul enterprise binary on the path -ent-test: - go test ./... -tags=enterprise - -cov: - go test ./... -coverprofile=coverage.out - go tool cover -html=coverage.out - -clean: - @rm -rf \ - $(CURDIR)/bin \ - $(CURDIR)/pkg - -# Generate manifests e.g. CRD, RBAC etc. -ctrl-manifests: get-controller-gen - $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases - -# Generate code -ctrl-generate: get-controller-gen - $(CONTROLLER_GEN) object:headerFile="build-support/controller/boilerplate.go.txt" paths="./..." - -# find or download controller-gen -# download controller-gen if necessary -get-controller-gen: -ifeq (, $(shell which controller-gen)) - @{ \ - set -e ;\ - CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ - cd $$CONTROLLER_GEN_TMP_DIR ;\ - go mod init tmp ;\ - go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.0 ;\ - rm -rf $$CONTROLLER_GEN_TMP_DIR ;\ - } -CONTROLLER_GEN=$(GOBIN)/controller-gen -else -CONTROLLER_GEN=$(shell which controller-gen) -endif - -get-kustomize: -ifeq (, $(shell which kustomize)) - @{ \ - set -e ;\ - KUSTOMIZE_GEN_TMP_DIR=$$(mktemp -d) ;\ - cd $$KUSTOMIZE_GEN_TMP_DIR ;\ - go mod init tmp ;\ - go get sigs.k8s.io/kustomize/kustomize/v3@v3.5.4 ;\ - rm -rf $$KUSTOMIZE_GEN_TMP_DIR ;\ - } -KUSTOMIZE=$(GOBIN)/kustomize -else -KUSTOMIZE=$(shell which kustomize) -endif - # In CircleCI, the linux binary will be attached from a previous step at pkg/bin/linux_amd64/. This make target # should only run in CI and not locally. ci.dev-docker: @@ -114,13 +46,5 @@ ifeq ($(CIRCLE_BRANCH), main) @docker tag $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest endif -ifeq ($(CIRCLE_BRANCH), crd-controller-base) - @docker tag $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):crd-controller-base-latest - @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):crd-controller-base-latest -endif -ifeq ($(CIRCLE_BRANCH), monorepo) - @docker tag $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):monorepo - @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):monorepo -endif -.PHONY: all bin clean dev dist docker-images go-build-image test tools ci.dev-docker +.PHONY: ci.dev-tree ci.dev-docker From ca980cbec061dd08bb0534deaa2b3352a891924c Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 20 Jan 2022 09:56:51 -0800 Subject: [PATCH 225/418] Add - separated names for config entry crds (#965) * Add - separated names for config entry crds For example allow both kubectl get ingressgateways and kubectl get ingress-gateways. When specified in .hcl or .json the config entries are dash-separated so this makes it consistent if someone uses a dash by mistake after reading our docs. --- CHANGELOG.md | 1 + charts/consul/templates/crd-exportedservices.yaml | 2 ++ charts/consul/templates/crd-ingressgateways.yaml | 2 ++ charts/consul/templates/crd-proxydefaults.yaml | 2 ++ charts/consul/templates/crd-servicedefaults.yaml | 2 ++ charts/consul/templates/crd-serviceintentions.yaml | 2 ++ charts/consul/templates/crd-serviceresolvers.yaml | 2 ++ charts/consul/templates/crd-servicerouters.yaml | 2 ++ charts/consul/templates/crd-servicesplitters.yaml | 2 ++ charts/consul/templates/crd-terminatinggateways.yaml | 2 ++ control-plane/api/v1alpha1/exportedservices_types.go | 1 + control-plane/api/v1alpha1/ingressgateway_types.go | 1 + control-plane/api/v1alpha1/proxydefaults_types.go | 1 + control-plane/api/v1alpha1/servicedefaults_types.go | 1 + control-plane/api/v1alpha1/serviceintentions_types.go | 1 + control-plane/api/v1alpha1/serviceresolver_types.go | 1 + control-plane/api/v1alpha1/servicerouter_types.go | 1 + control-plane/api/v1alpha1/servicesplitter_types.go | 1 + control-plane/api/v1alpha1/terminatinggateway_types.go | 1 + .../config/crd/bases/consul.hashicorp.com_exportedservices.yaml | 2 ++ .../config/crd/bases/consul.hashicorp.com_ingressgateways.yaml | 2 ++ .../config/crd/bases/consul.hashicorp.com_proxydefaults.yaml | 2 ++ .../config/crd/bases/consul.hashicorp.com_servicedefaults.yaml | 2 ++ .../crd/bases/consul.hashicorp.com_serviceintentions.yaml | 2 ++ .../config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml | 2 ++ .../config/crd/bases/consul.hashicorp.com_servicerouters.yaml | 2 ++ .../config/crd/bases/consul.hashicorp.com_servicesplitters.yaml | 2 ++ .../crd/bases/consul.hashicorp.com_terminatinggateways.yaml | 2 ++ 28 files changed, 46 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd6b49bb55..0aed4f74e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ IMPROVEMENTS: * Helm * Allow customization of `terminationGracePeriodSeconds` on the ingress gateways. [[GH-947](https://github.com/hashicorp/consul-k8s/pull/947)] * Support `ui.dashboardURLTemplates.service` value for setting [dashboard URL templates](https://www.consul.io/docs/agent/options#ui_config_dashboard_url_templates_service). [[GH-937](https://github.com/hashicorp/consul-k8s/pull/937)] + * Allow using dash-separated names for config entries when using `kubectl`. [[GH-965](https://github.com/hashicorp/consul-k8s/pull/965)] BUG FIXES: * Helm diff --git a/charts/consul/templates/crd-exportedservices.yaml b/charts/consul/templates/crd-exportedservices.yaml index 67f67e5704..9ddb7d3053 100644 --- a/charts/consul/templates/crd-exportedservices.yaml +++ b/charts/consul/templates/crd-exportedservices.yaml @@ -19,6 +19,8 @@ spec: kind: ExportedServices listKind: ExportedServicesList plural: exportedservices + shortNames: + - exported-services singular: exportedservices scope: Namespaced versions: diff --git a/charts/consul/templates/crd-ingressgateways.yaml b/charts/consul/templates/crd-ingressgateways.yaml index a9e2888ed7..f30e7f7a06 100644 --- a/charts/consul/templates/crd-ingressgateways.yaml +++ b/charts/consul/templates/crd-ingressgateways.yaml @@ -19,6 +19,8 @@ spec: kind: IngressGateway listKind: IngressGatewayList plural: ingressgateways + shortNames: + - ingress-gateway singular: ingressgateway scope: Namespaced versions: diff --git a/charts/consul/templates/crd-proxydefaults.yaml b/charts/consul/templates/crd-proxydefaults.yaml index d60160e260..6e21c89480 100644 --- a/charts/consul/templates/crd-proxydefaults.yaml +++ b/charts/consul/templates/crd-proxydefaults.yaml @@ -19,6 +19,8 @@ spec: kind: ProxyDefaults listKind: ProxyDefaultsList plural: proxydefaults + shortNames: + - proxy-defaults singular: proxydefaults scope: Namespaced versions: diff --git a/charts/consul/templates/crd-servicedefaults.yaml b/charts/consul/templates/crd-servicedefaults.yaml index 329a4d35bd..ab356836d2 100644 --- a/charts/consul/templates/crd-servicedefaults.yaml +++ b/charts/consul/templates/crd-servicedefaults.yaml @@ -19,6 +19,8 @@ spec: kind: ServiceDefaults listKind: ServiceDefaultsList plural: servicedefaults + shortNames: + - service-defaults singular: servicedefaults scope: Namespaced versions: diff --git a/charts/consul/templates/crd-serviceintentions.yaml b/charts/consul/templates/crd-serviceintentions.yaml index 7901083e3f..ffcd44ae5c 100644 --- a/charts/consul/templates/crd-serviceintentions.yaml +++ b/charts/consul/templates/crd-serviceintentions.yaml @@ -19,6 +19,8 @@ spec: kind: ServiceIntentions listKind: ServiceIntentionsList plural: serviceintentions + shortNames: + - service-intentions singular: serviceintentions scope: Namespaced versions: diff --git a/charts/consul/templates/crd-serviceresolvers.yaml b/charts/consul/templates/crd-serviceresolvers.yaml index 2bf85cbf0a..1023b9127f 100644 --- a/charts/consul/templates/crd-serviceresolvers.yaml +++ b/charts/consul/templates/crd-serviceresolvers.yaml @@ -19,6 +19,8 @@ spec: kind: ServiceResolver listKind: ServiceResolverList plural: serviceresolvers + shortNames: + - service-resolver singular: serviceresolver scope: Namespaced versions: diff --git a/charts/consul/templates/crd-servicerouters.yaml b/charts/consul/templates/crd-servicerouters.yaml index ac0f515b8e..15b15e7f6b 100644 --- a/charts/consul/templates/crd-servicerouters.yaml +++ b/charts/consul/templates/crd-servicerouters.yaml @@ -19,6 +19,8 @@ spec: kind: ServiceRouter listKind: ServiceRouterList plural: servicerouters + shortNames: + - service-router singular: servicerouter scope: Namespaced versions: diff --git a/charts/consul/templates/crd-servicesplitters.yaml b/charts/consul/templates/crd-servicesplitters.yaml index e91b16db6c..05b5548ce9 100644 --- a/charts/consul/templates/crd-servicesplitters.yaml +++ b/charts/consul/templates/crd-servicesplitters.yaml @@ -19,6 +19,8 @@ spec: kind: ServiceSplitter listKind: ServiceSplitterList plural: servicesplitters + shortNames: + - service-splitter singular: servicesplitter scope: Namespaced versions: diff --git a/charts/consul/templates/crd-terminatinggateways.yaml b/charts/consul/templates/crd-terminatinggateways.yaml index 518f03fe70..3db27d2bce 100644 --- a/charts/consul/templates/crd-terminatinggateways.yaml +++ b/charts/consul/templates/crd-terminatinggateways.yaml @@ -19,6 +19,8 @@ spec: kind: TerminatingGateway listKind: TerminatingGatewayList plural: terminatinggateways + shortNames: + - terminating-gateway singular: terminatinggateway scope: Namespaced versions: diff --git a/control-plane/api/v1alpha1/exportedservices_types.go b/control-plane/api/v1alpha1/exportedservices_types.go index 5c1e337c2d..7d744c055d 100644 --- a/control-plane/api/v1alpha1/exportedservices_types.go +++ b/control-plane/api/v1alpha1/exportedservices_types.go @@ -29,6 +29,7 @@ func init() { // +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="exported-services" type ExportedServices struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index 82e5026f8b..e5087e2885 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -32,6 +32,7 @@ func init() { // +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="ingress-gateway" type IngressGateway struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/control-plane/api/v1alpha1/proxydefaults_types.go b/control-plane/api/v1alpha1/proxydefaults_types.go index 7d52b32c12..1e38842d4b 100644 --- a/control-plane/api/v1alpha1/proxydefaults_types.go +++ b/control-plane/api/v1alpha1/proxydefaults_types.go @@ -31,6 +31,7 @@ func init() { // +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="proxy-defaults" type ProxyDefaults struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/control-plane/api/v1alpha1/servicedefaults_types.go b/control-plane/api/v1alpha1/servicedefaults_types.go index c2aa1ab61e..f5b0160397 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types.go +++ b/control-plane/api/v1alpha1/servicedefaults_types.go @@ -29,6 +29,7 @@ func init() { // +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="service-defaults" type ServiceDefaults struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/control-plane/api/v1alpha1/serviceintentions_types.go b/control-plane/api/v1alpha1/serviceintentions_types.go index 80b66054f9..2a776e8209 100644 --- a/control-plane/api/v1alpha1/serviceintentions_types.go +++ b/control-plane/api/v1alpha1/serviceintentions_types.go @@ -29,6 +29,7 @@ func init() { // +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="service-intentions" type ServiceIntentions struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/control-plane/api/v1alpha1/serviceresolver_types.go b/control-plane/api/v1alpha1/serviceresolver_types.go index 8def0f2fa4..7ce67cb370 100644 --- a/control-plane/api/v1alpha1/serviceresolver_types.go +++ b/control-plane/api/v1alpha1/serviceresolver_types.go @@ -27,6 +27,7 @@ func init() { // +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="service-resolver" type ServiceResolver struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/control-plane/api/v1alpha1/servicerouter_types.go b/control-plane/api/v1alpha1/servicerouter_types.go index dbe9c15895..cc455a0853 100644 --- a/control-plane/api/v1alpha1/servicerouter_types.go +++ b/control-plane/api/v1alpha1/servicerouter_types.go @@ -30,6 +30,7 @@ const ( // +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="service-router" type ServiceRouter struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/control-plane/api/v1alpha1/servicesplitter_types.go b/control-plane/api/v1alpha1/servicesplitter_types.go index 900cc1c545..fb5ba74d7f 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types.go +++ b/control-plane/api/v1alpha1/servicesplitter_types.go @@ -26,6 +26,7 @@ func init() { // +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="service-splitter" type ServiceSplitter struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/control-plane/api/v1alpha1/terminatinggateway_types.go b/control-plane/api/v1alpha1/terminatinggateway_types.go index 2973e58714..1236307b99 100644 --- a/control-plane/api/v1alpha1/terminatinggateway_types.go +++ b/control-plane/api/v1alpha1/terminatinggateway_types.go @@ -30,6 +30,7 @@ func init() { // +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="terminating-gateway" type TerminatingGateway struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,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 7c9b46192b..c8e10c6f09 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_exportedservices.yaml @@ -13,6 +13,8 @@ spec: kind: ExportedServices listKind: ExportedServicesList plural: exportedservices + shortNames: + - exported-services singular: exportedservices scope: Namespaced versions: 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 ed2114aee9..13513ab65a 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml @@ -13,6 +13,8 @@ spec: kind: IngressGateway listKind: IngressGatewayList plural: ingressgateways + shortNames: + - ingress-gateway singular: ingressgateway scope: Namespaced versions: 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 f440d012c8..520fe95443 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_proxydefaults.yaml @@ -13,6 +13,8 @@ spec: kind: ProxyDefaults listKind: ProxyDefaultsList plural: proxydefaults + shortNames: + - proxy-defaults singular: proxydefaults scope: Namespaced versions: 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 08da8480f1..b29905b01a 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicedefaults.yaml @@ -13,6 +13,8 @@ spec: kind: ServiceDefaults listKind: ServiceDefaultsList plural: servicedefaults + shortNames: + - service-defaults singular: servicedefaults scope: Namespaced versions: 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 d3420d1e77..1593fc86fd 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceintentions.yaml @@ -13,6 +13,8 @@ spec: kind: ServiceIntentions listKind: ServiceIntentionsList plural: serviceintentions + shortNames: + - service-intentions singular: serviceintentions scope: Namespaced versions: 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 87285e8563..c170465322 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_serviceresolvers.yaml @@ -13,6 +13,8 @@ spec: kind: ServiceResolver listKind: ServiceResolverList plural: serviceresolvers + shortNames: + - service-resolver singular: serviceresolver scope: Namespaced versions: 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 ec74f9b63d..77707c0770 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicerouters.yaml @@ -13,6 +13,8 @@ spec: kind: ServiceRouter listKind: ServiceRouterList plural: servicerouters + shortNames: + - service-router singular: servicerouter scope: Namespaced versions: 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 fbbac1010e..204179c000 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_servicesplitters.yaml @@ -13,6 +13,8 @@ spec: kind: ServiceSplitter listKind: ServiceSplitterList plural: servicesplitters + shortNames: + - service-splitter singular: servicesplitter scope: Namespaced versions: 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 ce87093245..716f22e4ef 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_terminatinggateways.yaml @@ -13,6 +13,8 @@ spec: kind: TerminatingGateway listKind: TerminatingGatewayList plural: terminatinggateways + shortNames: + - terminating-gateway singular: terminatinggateway scope: Namespaced versions: From b292168886f1de40fa2bba4114b759287bfd3e2b Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Thu, 20 Jan 2022 13:21:05 -0500 Subject: [PATCH 226/418] Apply suggestions from code review Co-authored-by: Iryna Shustava --- charts/consul/templates/api-gateway-controller-deployment.yaml | 2 +- charts/consul/templates/api-gateway-gatewayclass.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml index b4ef852a5c..6713da87da 100644 --- a/charts/consul/templates/api-gateway-controller-deployment.yaml +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -117,7 +117,7 @@ spec: {{- if or (and .Values.global.acls.manageSystemACLs) (and .Values.global.tls.enabled .Values.global.tls.enableAutoEncrypt) }} initContainers: {{- if .Values.global.acls.manageSystemACLs }} - - name: injector-acl-init + - name: api-gateway-controller-acl-init image: {{ .Values.global.imageK8S }} command: - "/bin/sh" diff --git a/charts/consul/templates/api-gateway-gatewayclass.yaml b/charts/consul/templates/api-gateway-gatewayclass.yaml index 1673102c7c..db8c7736ce 100644 --- a/charts/consul/templates/api-gateway-gatewayclass.yaml +++ b/charts/consul/templates/api-gateway-gatewayclass.yaml @@ -9,7 +9,7 @@ metadata: chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} - component: api-gateway + component: api-gateway-controller spec: controllerName: hashicorp.com/consul-api-gateway-controller parametersRef: From 5cf446195f05959dbfb839ba16c15fd46ce8bc76 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Thu, 20 Jan 2022 11:32:49 -0700 Subject: [PATCH 227/418] Update Consul version to 1.11.2 (#976) --- .circleci/config.yml | 4 ++-- CHANGELOG.md | 1 + charts/consul/Chart.yaml | 4 ++-- charts/consul/values.yaml | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ef506e4ce5..2bf464fc1a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,8 +9,8 @@ executors: - image: docker.mirror.hashicorp.services/cimg/go:1.17.5 environment: TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.11.1 # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.11.1+ent # Consul's enterprise version to use in tests + CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests control-plane-path : &control-plane-path control-plane cli-path : &cli-path cli diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aed4f74e5..b69b34c9ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ FEATURES: * Helm * Support Envoy 1.20.1. [[GH-958](https://github.com/hashicorp/consul-k8s/pull/958)] + * Support Consul 1.11.2. [[GH-976](https://github.com/hashicorp/consul-k8s/pull/976)] IMPROVEMENTS: * Helm diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index e7f331c4ae..75bbd9708f 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: consul version: 0.39.0 -appVersion: 1.11.1 +appVersion: 1.11.2 kubeVersion: ">=1.18.0-0" description: Official HashiCorp Consul Chart home: https://www.consul.io @@ -13,7 +13,7 @@ annotations: artifacthub.io/prerelease: false artifacthub.io/images: | - name: consul - image: hashicorp/consul:1.11.1 + image: hashicorp/consul:1.11.2 - name: consul-k8s-control-plane image: hashicorp/consul-k8s-control-plane:0.39.0 - name: envoy diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 650db24399..243586d10f 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -85,7 +85,7 @@ global: # image: "hashicorp/consul-enterprise:1.10.0-ent" # ``` # @default: hashicorp/consul: - image: "hashicorp/consul:1.11.1" + image: "hashicorp/consul:1.11.2" # Array of objects containing image pull secret names that will be applied to each service account. # This can be used to reference image pull secrets if using a custom consul or consul-k8s-control-plane Docker image. From 13aba1004899f3647cad7f6f51dcca36e6c351e8 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 20 Jan 2022 14:21:41 -0500 Subject: [PATCH 228/418] Support the value `$POD_NAME` for the annotation `consul.hashicorp.com/service-meta-pod_name` (#982) --- CHANGELOG.md | 2 ++ control-plane/connect-inject/endpoints_controller.go | 6 +++++- control-plane/connect-inject/endpoints_controller_test.go | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b69b34c9ef..59c99d3f3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ IMPROVEMENTS: * Allow customization of `terminationGracePeriodSeconds` on the ingress gateways. [[GH-947](https://github.com/hashicorp/consul-k8s/pull/947)] * Support `ui.dashboardURLTemplates.service` value for setting [dashboard URL templates](https://www.consul.io/docs/agent/options#ui_config_dashboard_url_templates_service). [[GH-937](https://github.com/hashicorp/consul-k8s/pull/937)] * Allow using dash-separated names for config entries when using `kubectl`. [[GH-965](https://github.com/hashicorp/consul-k8s/pull/965)] +* Control Plane + * Support the value `$POD_NAME` for the annotation `consul.hashicorp.com/service-meta-pod_name` that will now be interpolated and set to the pod name in the service's metadata. [[GH-982](https://github.com/hashicorp/consul-k8s/pull/982)] BUG FIXES: * Helm diff --git a/control-plane/connect-inject/endpoints_controller.go b/control-plane/connect-inject/endpoints_controller.go index 1712967308..39dbecfeeb 100644 --- a/control-plane/connect-inject/endpoints_controller.go +++ b/control-plane/connect-inject/endpoints_controller.go @@ -413,7 +413,11 @@ func (r *EndpointsController) createServiceRegistrations(pod corev1.Pod, service } for k, v := range pod.Annotations { if strings.HasPrefix(k, annotationMeta) && strings.TrimPrefix(k, annotationMeta) != "" { - meta[strings.TrimPrefix(k, annotationMeta)] = v + if v == "$POD_NAME" { + meta[strings.TrimPrefix(k, annotationMeta)] = pod.Name + } else { + meta[strings.TrimPrefix(k, annotationMeta)] = v + } } } tags := consulTags(pod) diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index 846c1c434e..608b2177a5 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -886,6 +886,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { pod1.Annotations[annotationService] = "different-consul-svc-name" pod1.Annotations[fmt.Sprintf("%sname", annotationMeta)] = "abc" pod1.Annotations[fmt.Sprintf("%sversion", annotationMeta)] = "2" + pod1.Annotations[fmt.Sprintf("%spod_name", annotationMeta)] = "$POD_NAME" pod1.Annotations[annotationTags] = "abc,123,$POD_NAME" pod1.Annotations[annotationConnectTags] = "def,456,$POD_NAME" pod1.Annotations[annotationUpstreams] = "upstream1:1234" @@ -925,6 +926,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { ServiceMeta: map[string]string{ "name": "abc", "version": "2", + "pod_name": "pod1", MetaKeyPodName: "pod1", MetaKeyKubeServiceName: "service-created", MetaKeyKubeNS: "default", @@ -958,6 +960,7 @@ func TestReconcileCreateEndpoint(t *testing.T) { ServiceMeta: map[string]string{ "name": "abc", "version": "2", + "pod_name": "pod1", MetaKeyPodName: "pod1", MetaKeyKubeServiceName: "service-created", MetaKeyKubeNS: "default", From d8e572699b2f2d26ac4bcf26634bae34cee53612 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 20 Jan 2022 16:49:26 -0500 Subject: [PATCH 229/418] fix changelog to be more accurate (#984) --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59c99d3f3c..2f48b6cc47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ IMPROVEMENTS: * Support `ui.dashboardURLTemplates.service` value for setting [dashboard URL templates](https://www.consul.io/docs/agent/options#ui_config_dashboard_url_templates_service). [[GH-937](https://github.com/hashicorp/consul-k8s/pull/937)] * Allow using dash-separated names for config entries when using `kubectl`. [[GH-965](https://github.com/hashicorp/consul-k8s/pull/965)] * Control Plane - * Support the value `$POD_NAME` for the annotation `consul.hashicorp.com/service-meta-pod_name` that will now be interpolated and set to the pod name in the service's metadata. [[GH-982](https://github.com/hashicorp/consul-k8s/pull/982)] + * Support the value `$POD_NAME` for the annotation `consul.hashicorp.com/service-meta-*` that will now be interpolated and set to the pod's name in the service's metadata. [[GH-982](https://github.com/hashicorp/consul-k8s/pull/982)] BUG FIXES: * Helm From 7e4855d3c78176d7902c70877c5534d4b66e9e3e Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Fri, 21 Jan 2022 10:13:53 -0700 Subject: [PATCH 230/418] Make sure vault integration works with PSPs (#985) --- CHANGELOG.md | 1 + acceptance/tests/vault/vault_test.go | 3 --- charts/consul/templates/server-acl-init-podsecuritypolicy.yaml | 1 + charts/consul/test/terraform/gke/main.tf | 3 ++- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f48b6cc47..4abd92e7fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ IMPROVEMENTS: * Allow customization of `terminationGracePeriodSeconds` on the ingress gateways. [[GH-947](https://github.com/hashicorp/consul-k8s/pull/947)] * Support `ui.dashboardURLTemplates.service` value for setting [dashboard URL templates](https://www.consul.io/docs/agent/options#ui_config_dashboard_url_templates_service). [[GH-937](https://github.com/hashicorp/consul-k8s/pull/937)] * Allow using dash-separated names for config entries when using `kubectl`. [[GH-965](https://github.com/hashicorp/consul-k8s/pull/965)] + * Support Pod Security Policies with Vault integration. [[GH-985](https://github.com/hashicorp/consul-k8s/pull/985)] * Control Plane * Support the value `$POD_NAME` for the annotation `consul.hashicorp.com/service-meta-*` that will now be interpolated and set to the pod's name in the service's metadata. [[GH-982](https://github.com/hashicorp/consul-k8s/pull/982)] diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 459ffb53f8..e19e196c84 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -57,9 +57,6 @@ path "pki/cert/ca" { // It then configures Consul to use vault as the backend and checks that it works. func TestVault(t *testing.T) { cfg := suite.Config() - if cfg.EnablePodSecurityPolicies { - t.Skipf("skipping this test because PSPs don't yet work with the acceptance test Vault installation") - } ctx := suite.Environment().DefaultContext(t) ns := ctx.KubectlOptions(t).Namespace diff --git a/charts/consul/templates/server-acl-init-podsecuritypolicy.yaml b/charts/consul/templates/server-acl-init-podsecuritypolicy.yaml index abe46e300a..9bf93e2551 100644 --- a/charts/consul/templates/server-acl-init-podsecuritypolicy.yaml +++ b/charts/consul/templates/server-acl-init-podsecuritypolicy.yaml @@ -18,6 +18,7 @@ spec: # Allow core volume types. volumes: - 'secret' + - 'emptyDir' allowPrivilegeEscalation: false # This is redundant with non-root + disallow privilege escalation, # but we can provide it for defense in depth. diff --git a/charts/consul/test/terraform/gke/main.tf b/charts/consul/test/terraform/gke/main.tf index 45850114fb..7f303639ad 100644 --- a/charts/consul/test/terraform/gke/main.tf +++ b/charts/consul/test/terraform/gke/main.tf @@ -25,7 +25,8 @@ resource "google_container_cluster" "cluster" { min_master_version = data.google_container_engine_versions.main.latest_master_version node_version = data.google_container_engine_versions.main.latest_master_version node_config { - tags = ["consul-k8s-${random_id.suffix[count.index].dec}"] + tags = ["consul-k8s-${random_id.suffix[count.index].dec}"] + machine_type = "e2-standard-4" } pod_security_policy_config { enabled = true From 623cacb77366abf8c8c086eb53606e9479334719 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Fri, 21 Jan 2022 15:53:57 -0800 Subject: [PATCH 231/418] Changelog for #956 (#979) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4abd92e7fb..5da5573269 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ IMPROVEMENTS: * Support Pod Security Policies with Vault integration. [[GH-985](https://github.com/hashicorp/consul-k8s/pull/985)] * Control Plane * Support the value `$POD_NAME` for the annotation `consul.hashicorp.com/service-meta-*` that will now be interpolated and set to the pod's name in the service's metadata. [[GH-982](https://github.com/hashicorp/consul-k8s/pull/982)] + * Allow managing Consul sidecar resources via annotations. [[GH-956](https://github.com/hashicorp/consul-k8s/pull/956)] BUG FIXES: * Helm From 938abbb00d9f7c9939e3e3fcafc42f183232a96d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Rondeau?= Date: Sat, 22 Jan 2022 00:54:15 +0100 Subject: [PATCH 232/418] charts/consul: Add some hints for consul sidecar annotations (#986) --- charts/consul/values.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 243586d10f..8dbd329e68 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -432,6 +432,15 @@ global: # @recurse: false # @type: map consulSidecarContainer: + # Set default resources for consul sidecar. If null, that resource won't + # be set. + # These settings can be overridden on a per-pod basis via these annotations: + # + # - `consul.hashicorp.com/consul-sidecar-cpu-limit` + # - `consul.hashicorp.com/consul-sidecar-cpu-request` + # - `consul.hashicorp.com/consul-sidecar-memory-limit` + # - `consul.hashicorp.com/consul-sidecar-memory-request` + # @type: map resources: requests: memory: "25Mi" From e8be08a6b88c0af1c0df04dc3132e9da0f0ee91e Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Sat, 22 Jan 2022 00:13:27 -0500 Subject: [PATCH 233/418] simplify enabled condition check --- .../templates/api-gateway-controller-clusterrole.yaml | 2 +- .../api-gateway-controller-clusterrolebinding.yaml | 3 +-- .../templates/api-gateway-controller-deployment.yaml | 2 +- .../consul/templates/api-gateway-controller-service.yaml | 2 +- .../templates/api-gateway-controller-serviceaccount.yaml | 2 +- charts/consul/templates/api-gateway-gatewayclass.yaml | 4 +--- .../consul/templates/api-gateway-gatewayclassconfig.yaml | 5 ++--- .../test/unit/api-gateway-controller-clusterrole.bats | 1 + .../unit/api-gateway-controller-clusterrolebinding.bats | 9 +-------- .../consul/test/unit/api-gateway-controller-service.bats | 9 +-------- .../test/unit/api-gateway-controller-serviceaccount.bats | 4 ++++ charts/consul/test/unit/api-gateway-gatewayclass.bats | 2 ++ charts/consul/values.yaml | 8 +++----- 13 files changed, 20 insertions(+), 33 deletions(-) diff --git a/charts/consul/templates/api-gateway-controller-clusterrole.yaml b/charts/consul/templates/api-gateway-controller-clusterrole.yaml index 491f336042..c6a69106c8 100644 --- a/charts/consul/templates/api-gateway-controller-clusterrole.yaml +++ b/charts/consul/templates/api-gateway-controller-clusterrole.yaml @@ -1,4 +1,4 @@ -{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +{{- if .Values.apiGateway.enabled }} # The ClusterRole to enable the API Gateway controller to access required api endpoints. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole diff --git a/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml b/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml index 1c3cba8441..c1c75ebf3f 100644 --- a/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml +++ b/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml @@ -1,4 +1,4 @@ -{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +{{- if .Values.apiGateway.enabled }} apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: @@ -18,4 +18,3 @@ subjects: name: {{ template "consul.fullname" . }}-api-gateway-controller-svc-account namespace: {{ .Release.Namespace }} {{- end }} - diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml index 6713da87da..e931491f05 100644 --- a/charts/consul/templates/api-gateway-controller-deployment.yaml +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -1,4 +1,4 @@ -{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +{{- if .Values.apiGateway.enabled }} {{- if not .Values.client.grpc }}{{ fail "client.grpc must be true for api gateway" }}{{ end }} {{- if not .Values.apiGateway.image}}{{ fail "apiGateway.image must be set to enable api gateway" }}{{ end }} {{- if and .Values.global.adminPartitions.enabled (not .Values.global.enableConsulNamespaces) }}{{ fail "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" }}{{ end }} diff --git a/charts/consul/templates/api-gateway-controller-service.yaml b/charts/consul/templates/api-gateway-controller-service.yaml index ffebbbd50f..aa79ff9fc3 100644 --- a/charts/consul/templates/api-gateway-controller-service.yaml +++ b/charts/consul/templates/api-gateway-controller-service.yaml @@ -1,4 +1,4 @@ -{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +{{- if .Values.apiGateway.enabled }} apiVersion: v1 kind: Service metadata: diff --git a/charts/consul/templates/api-gateway-controller-serviceaccount.yaml b/charts/consul/templates/api-gateway-controller-serviceaccount.yaml index f25a184ad5..55dda34038 100644 --- a/charts/consul/templates/api-gateway-controller-serviceaccount.yaml +++ b/charts/consul/templates/api-gateway-controller-serviceaccount.yaml @@ -1,4 +1,4 @@ -{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} +{{- if .Values.apiGateway.enabled }} apiVersion: v1 kind: ServiceAccount metadata: diff --git a/charts/consul/templates/api-gateway-gatewayclass.yaml b/charts/consul/templates/api-gateway-gatewayclass.yaml index db8c7736ce..61effc57e3 100644 --- a/charts/consul/templates/api-gateway-gatewayclass.yaml +++ b/charts/consul/templates/api-gateway-gatewayclass.yaml @@ -1,5 +1,4 @@ -{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} -{{- if .Values.apiGateway.managedGatewayClass.enabled }} +{{- if (and .Values.apiGateway.enabled .Values.apiGateway.managedGatewayClass.enabled) }} apiVersion: gateway.networking.k8s.io/v1alpha2 kind: GatewayClass metadata: @@ -17,4 +16,3 @@ spec: kind: GatewayClassConfig name: consul-api-gateway-class-config {{- end }} -{{- end }} \ No newline at end of file diff --git a/charts/consul/templates/api-gateway-gatewayclassconfig.yaml b/charts/consul/templates/api-gateway-gatewayclassconfig.yaml index 7daf5e3f3c..7f420a95e1 100644 --- a/charts/consul/templates/api-gateway-gatewayclassconfig.yaml +++ b/charts/consul/templates/api-gateway-gatewayclassconfig.yaml @@ -1,5 +1,4 @@ -{{- if (or (and (ne (.Values.apiGateway.enabled | toString) "-") .Values.apiGateway.enabled) (and (eq (.Values.apiGateway.enabled | toString) "-") .Values.global.enabled)) }} -{{- if .Values.apiGateway.managedGatewayClass.enabled }} +{{- if (and .Values.apiGateway.enabled .Values.apiGateway.managedGatewayClass.enabled) }} apiVersion: api-gateway.consul.hashicorp.com/v1alpha1 kind: GatewayClassConfig metadata: @@ -42,6 +41,6 @@ spec: {{ tpl .Values.apiGateway.managedGatewayClass.copyAnnotations.service.annotations . | nindent 6 | trim }} {{- end }} serviceType: {{ .Values.apiGateway.managedGatewayClass.serviceType }} + useHostPorts: {{ .Values.apiGateway.managedGatewayClass.useHostPorts }} logLevel: {{ default .Values.global.logLevel .Values.apiGateway.managedGatewayClass.logLevel }} {{- end }} -{{- end }} \ No newline at end of file diff --git a/charts/consul/test/unit/api-gateway-controller-clusterrole.bats b/charts/consul/test/unit/api-gateway-controller-clusterrole.bats index 42d245a1a7..a3edec027d 100644 --- a/charts/consul/test/unit/api-gateway-controller-clusterrole.bats +++ b/charts/consul/test/unit/api-gateway-controller-clusterrole.bats @@ -14,6 +14,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-clusterrole.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] diff --git a/charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats b/charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats index 53c9e84611..3dfd94c36f 100644 --- a/charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats +++ b/charts/consul/test/unit/api-gateway-controller-clusterrolebinding.bats @@ -15,15 +15,8 @@ load _helpers -s templates/api-gateway-controller-clusterrolebinding.yaml \ --set 'global.enabled=false' \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq -s 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] } - -@test "apiGateway/ClusterRoleBinding: disabled with connectInject.enabled false" { - cd `chart_dir` - assert_empty helm template \ - -s templates/api-gateway-controller-clusterrolebinding.yaml \ - --set 'apiGateway.enabled=false' \ - . -} diff --git a/charts/consul/test/unit/api-gateway-controller-service.bats b/charts/consul/test/unit/api-gateway-controller-service.bats index 99aab98842..b199203614 100755 --- a/charts/consul/test/unit/api-gateway-controller-service.bats +++ b/charts/consul/test/unit/api-gateway-controller-service.bats @@ -15,6 +15,7 @@ load _helpers -s templates/api-gateway-controller-service.yaml \ --set 'global.enabled=false' \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] @@ -27,11 +28,3 @@ load _helpers --set 'apiGateway.enabled=false' \ . } - -@test "apiGateway/Service: disable with global.enabled" { - cd `chart_dir` - assert_empty helm template \ - -s templates/api-gateway-controller-service.yaml \ - --set 'global.enabled=false' \ - . -} diff --git a/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats b/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats index 7cd8eef08c..cb071f90ef 100644 --- a/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats +++ b/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats @@ -15,6 +15,7 @@ load _helpers -s templates/api-gateway-controller-serviceaccount.yaml \ --set 'global.enabled=false' \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq -s 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] @@ -35,6 +36,7 @@ load _helpers local object=$(helm template \ -s templates/api-gateway-controller-serviceaccount.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'global.imagePullSecrets[0].name=my-secret' \ --set 'global.imagePullSecrets[1].name=my-secret2' \ . | tee /dev/stderr) @@ -56,6 +58,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-serviceaccount.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq '.metadata.annotations | length > 0' | tee /dev/stderr) [ "${actual}" = "false" ] @@ -66,6 +69,7 @@ load _helpers local actual=$(helm template \ -s templates/api-gateway-controller-serviceaccount.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set "apiGateway.serviceAccount.annotations=foo: bar" \ . | tee /dev/stderr | yq -r '.metadata.annotations.foo' | tee /dev/stderr) diff --git a/charts/consul/test/unit/api-gateway-gatewayclass.bats b/charts/consul/test/unit/api-gateway-gatewayclass.bats index bdcc3bc4f7..c79753c2f3 100755 --- a/charts/consul/test/unit/api-gateway-gatewayclass.bats +++ b/charts/consul/test/unit/api-gateway-gatewayclass.bats @@ -15,6 +15,7 @@ load _helpers -s templates/api-gateway-gatewayclass.yaml \ --set 'global.enabled=false' \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ . | tee /dev/stderr | yq 'length > 0' | tee /dev/stderr) [ "${actual}" = "true" ] @@ -41,6 +42,7 @@ load _helpers assert_empty helm template \ -s templates/api-gateway-gatewayclass.yaml \ --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=foo' \ --set 'apiGateway.managedGatewayClass.enabled=false' \ . } diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 800d452617..74c8c5f824 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2467,12 +2467,14 @@ apiGateway: # @type: string image: null - # Override global log verbosity level for api-gateway-controller pods. One of "debug", "info", "warn", or "error". # @type: string logLevel: info + managedGatewayClass: + # When true a GatewayClass is configured to automatically work with Consul as installed by helm. enabled: true + # This value defines `nodeSelector` (https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector) # labels for gateway pod assignment, formatted as a multi-line string. # @@ -2505,10 +2507,6 @@ apiGateway: # @type: string service: null - # Override global log verbosity level for ateway pods. One of "debug", "info", "warn", or "error". - # @type: string - logLevel: info - serviceAccount: # This value defines additional annotations for the client service account. This should be formatted as a multi-line # string. From eb263d93bcdc62beb4d25e56b98e4239fcbc8f3f Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Mon, 24 Jan 2022 09:04:43 -0800 Subject: [PATCH 234/418] Support commas in tag annotation. (#983) * Support commas in tag annotation. Commas can be set by escaping with backslash. Example: annotation: "this,supports,commas\,now" Becomes: ["this", "supports", "commas,now"] --- CHANGELOG.md | 1 + control-plane/catalog/to-consul/resource.go | 56 +++++++++++++++++-- .../catalog/to-consul/resource_test.go | 48 +++++++++++++++- 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5da5573269..aedc614254 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ IMPROVEMENTS: * Control Plane * Support the value `$POD_NAME` for the annotation `consul.hashicorp.com/service-meta-*` that will now be interpolated and set to the pod's name in the service's metadata. [[GH-982](https://github.com/hashicorp/consul-k8s/pull/982)] * Allow managing Consul sidecar resources via annotations. [[GH-956](https://github.com/hashicorp/consul-k8s/pull/956)] + * Support using a backslash to escape commas in `consul.hashicorp.com/service-tags` annotation. [[GH-983](https://github.com/hashicorp/consul-k8s/pull/983)] BUG FIXES: * Helm diff --git a/control-plane/catalog/to-consul/resource.go b/control-plane/catalog/to-consul/resource.go index dd170e4990..5188f2ccb5 100644 --- a/control-plane/catalog/to-consul/resource.go +++ b/control-plane/catalog/to-consul/resource.go @@ -434,10 +434,8 @@ func (t *ServiceResource) generateRegistrations(key string) { } // Parse any additional tags - if tags, ok := svc.Annotations[annotationServiceTags]; ok { - for _, t := range strings.Split(tags, ",") { - baseService.Tags = append(baseService.Tags, strings.TrimSpace(t)) - } + if rawTags, ok := svc.Annotations[annotationServiceTags]; ok { + baseService.Tags = append(baseService.Tags, parseTags(rawTags)...) } // Parse any additional meta @@ -773,3 +771,53 @@ func (t *ServiceResource) addPrefixAndK8SNamespace(name, namespace string) strin return name } + +// parseTags parses the tags annotation into a slice of tags. +// Tags are split on commas (except for escaped commas "\,"). +func parseTags(tagsAnno string) []string { + + // This algorithm parses the tagsAnno string into a slice of strings. + // Ideally we'd just split on commas but since Consul tags support commas, + // we allow users to escape commas so they're included in the tag, e.g. + // the annotation "tag\,with\,commas,tag2" will become the tags: + // ["tag,with,commas", "tag2"]. + + var tags []string + // nextTag is built up char by char until we see a comma. Then we + // append it to tags. + var nextTag string + + for _, runeChar := range tagsAnno { + runeStr := fmt.Sprintf("%c", runeChar) + + // Not a comma, just append to nextTag. + if runeStr != "," { + nextTag += runeStr + continue + } + + // Reached a comma but there's nothing in nextTag, + // skip. (e.g. "a,,b" => ["a", "b"]) + if len(nextTag) == 0 { + continue + } + + // Check if the comma was escaped comma, e.g. "a\,b". + if string(nextTag[len(nextTag)-1]) == `\` { + // Replace the backslash with a comma. + nextTag = nextTag[0:len(nextTag)-1] + "," + continue + } + + // Non-escaped comma. We're ready to push nextTag onto tags and reset nextTag. + tags = append(tags, strings.TrimSpace(nextTag)) + nextTag = "" + } + + // We're done the loop but nextTag still contains the last tag. + if len(nextTag) > 0 { + tags = append(tags, strings.TrimSpace(nextTag)) + } + + return tags +} diff --git a/control-plane/catalog/to-consul/resource_test.go b/control-plane/catalog/to-consul/resource_test.go index 461f87bd0c..6bc99eb5f7 100644 --- a/control-plane/catalog/to-consul/resource_test.go +++ b/control-plane/catalog/to-consul/resource_test.go @@ -566,7 +566,7 @@ func TestServiceResource_lbAnnotatedTags(t *testing.T) { // Insert an LB service svc := lbService("foo", metav1.NamespaceDefault, "1.2.3.4") - svc.Annotations[annotationServiceTags] = "one, two,three" + svc.Annotations[annotationServiceTags] = `one, leadingwhitespace,trailingwhitespace ,\,leadingcomma,trailingcomma\,,middle\,comma,,` _, err := client.CoreV1().Services(metav1.NamespaceDefault).Create(context.Background(), svc, metav1.CreateOptions{}) require.NoError(t, err) @@ -576,7 +576,7 @@ func TestServiceResource_lbAnnotatedTags(t *testing.T) { defer syncer.Unlock() actual := syncer.Registrations require.Len(r, actual, 1) - require.Equal(r, []string{"k8s", "one", "two", "three"}, actual[0].Service.Tags) + require.Equal(r, []string{"k8s", "one", "leadingwhitespace", "trailingwhitespace", ",leadingcomma", "trailingcomma,", "middle,comma"}, actual[0].Service.Tags) }) } @@ -1453,6 +1453,50 @@ func TestServiceResource_MirroredPrefixNamespace(t *testing.T) { }) } +func TestParseTags(t *testing.T) { + cases := []struct { + tagsAnno string + exp []string + }{ + { + "tag", + []string{"tag"}, + }, + { + ",,removes,,empty,elems,,", + []string{"removes", "empty", "elems"}, + }, + { + "removes , white ,space ", + []string{"removes", "white", "space"}, + }, + { + `\,leading,comma`, + []string{",leading", "comma"}, + }, + { + `trailing,comma\,`, + []string{"trailing", "comma,"}, + }, + { + `mid\,dle,com\,ma`, + []string{"mid,dle", "com,ma"}, + }, + { + `\,\,multi\,\,,\,com\,\,ma`, + []string{",,multi,,", ",com,,ma"}, + }, + { + ` every\,\, , thing `, + []string{"every,,", "thing"}, + }, + } + + for _, c := range cases { + require.Equal(t, c.exp, parseTags(c.tagsAnno)) + } +} + // lbService returns a Kubernetes service of type LoadBalancer. func lbService(name, namespace, lbIP string) *apiv1.Service { return &apiv1.Service{ From 37c409d6b4fb00c88d6e3a808fa0cce3d13f0799 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Mon, 24 Jan 2022 13:13:46 -0500 Subject: [PATCH 235/418] Create anonymous-policy and token from non-default partitions. (#966) * Create anonymous-policy and token from non-default partitions. --- CHANGELOG.md | 2 + .../endpoints_controller_ent_test.go | 4 +- .../endpoints_controller_test.go | 6 +- control-plane/go.mod | 2 + control-plane/go.sum | 4 +- control-plane/namespaces/namespaces_test.go | 4 +- .../connect-init/command_ent_test.go | 2 +- .../subcommand/connect-init/command_test.go | 2 +- .../subcommand/server-acl-init/command.go | 22 +++-- .../server-acl-init/command_ent_test.go | 87 +++++++++++++++++++ .../server-acl-init/command_test.go | 4 +- .../server-acl-init/create_or_update_test.go | 2 +- 12 files changed, 120 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aedc614254..bb6fa12d2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ IMPROVEMENTS: BUG FIXES: * Helm * Add `PodDisruptionBudget` Kind when checking for existing versions so that `helm template` can generate the right version. [[GH-923](https://github.com/hashicorp/consul-k8s/pull/923)] +* Control Plane + * Admin Partitions **(Consul Enterprise only)**: Attach anonymous-policy to the anonymous token from non-default partitions to support DNS queries when the default partition is on a VM. [[GH-966](https://github.com/hashicorp/consul-k8s/pull/966)] ## 0.39.0 (December 15, 2021) diff --git a/control-plane/connect-inject/endpoints_controller_ent_test.go b/control-plane/connect-inject/endpoints_controller_ent_test.go index 7d333783c8..5859bd9206 100644 --- a/control-plane/connect-inject/endpoints_controller_ent_test.go +++ b/control-plane/connect-inject/endpoints_controller_ent_test.go @@ -1180,7 +1180,7 @@ func TestReconcileUpdateEndpointWithNamespaces(t *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { if tt.enableACLs { c.ACL.Enabled = true - c.ACL.Tokens.Master = adminToken + c.ACL.Tokens.InitialManagement = adminToken } c.NodeName = nodeName }) @@ -1514,7 +1514,7 @@ func TestReconcileDeleteEndpointWithNamespaces(t *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { if tt.enableACLs { c.ACL.Enabled = true - c.ACL.Tokens.Master = adminToken + c.ACL.Tokens.InitialManagement = adminToken } c.NodeName = nodeName }) diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index 608b2177a5..07c9b3faa1 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -127,7 +127,7 @@ func TestProcessUpstreamsTLSandACLs(t *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true c.ACL.DefaultPolicy = "deny" - c.ACL.Tokens.Master = masterToken + c.ACL.Tokens.InitialManagement = masterToken c.CAFile = caFile c.CertFile = certFile c.KeyFile = keyFile @@ -2343,7 +2343,7 @@ func TestReconcileUpdateEndpoint(t *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { if tt.enableACLs { c.ACL.Enabled = tt.enableACLs - c.ACL.Tokens.Master = adminToken + c.ACL.Tokens.InitialManagement = adminToken } c.NodeName = nodeName }) @@ -2630,7 +2630,7 @@ func TestReconcileDeleteEndpoint(t *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { if tt.enableACLs { c.ACL.Enabled = true - c.ACL.Tokens.Master = adminToken + c.ACL.Tokens.InitialManagement = adminToken } c.NodeName = nodeName }) diff --git a/control-plane/go.mod b/control-plane/go.mod index 93e5bc5c77..e8842f4643 100644 --- a/control-plane/go.mod +++ b/control-plane/go.mod @@ -129,4 +129,6 @@ require ( sigs.k8s.io/yaml v1.2.0 // indirect ) +replace github.com/hashicorp/consul/sdk v0.9.0 => github.com/hashicorp/consul/sdk v0.4.1-0.20220120214936-7568f3a102a8 + go 1.17 diff --git a/control-plane/go.sum b/control-plane/go.sum index 879cb915bf..42ee98bb0f 100644 --- a/control-plane/go.sum +++ b/control-plane/go.sum @@ -300,9 +300,9 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt github.com/hashicorp/consul/api v1.12.0 h1:k3y1FYv6nuKyNTqj6w9gXOx5r5CfLj/k/euUeBXj1OY= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.4.1-0.20220120214936-7568f3a102a8 h1:1O/CANaJGcL6urr47PLoPZ0oQcGLUlGpYoRLYAYFSDs= +github.com/hashicorp/consul/sdk v0.4.1-0.20220120214936-7568f3a102a8/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/consul/sdk v0.9.0 h1:NGSHAU7X3yDCjo8WBUbNOtD3BSqv8u0vu3+zNxgmxQI= -github.com/hashicorp/consul/sdk v0.9.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= diff --git a/control-plane/namespaces/namespaces_test.go b/control-plane/namespaces/namespaces_test.go index 8cd3d316fd..7b6a061a65 100644 --- a/control-plane/namespaces/namespaces_test.go +++ b/control-plane/namespaces/namespaces_test.go @@ -33,7 +33,7 @@ func TestEnsureExists_AlreadyExists(tt *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(cfg *testutil.TestServerConfig) { cfg.ACL.Enabled = c.ACLsEnabled cfg.ACL.DefaultPolicy = "deny" - cfg.ACL.Tokens.Master = masterToken + cfg.ACL.Tokens.InitialManagement = masterToken }) req.NoError(err) defer consul.Stop() @@ -104,7 +104,7 @@ func TestEnsureExists_CreatesNS(tt *testing.T) { consul, err := testutil.NewTestServerConfigT(t, func(cfg *testutil.TestServerConfig) { cfg.ACL.Enabled = c.ACLsEnabled cfg.ACL.DefaultPolicy = "deny" - cfg.ACL.Tokens.Master = masterToken + cfg.ACL.Tokens.InitialManagement = masterToken }) req.NoError(err) defer consul.Stop() diff --git a/control-plane/subcommand/connect-init/command_ent_test.go b/control-plane/subcommand/connect-init/command_ent_test.go index 50b52f44e2..f043542d83 100644 --- a/control-plane/subcommand/connect-init/command_ent_test.go +++ b/control-plane/subcommand/connect-init/command_ent_test.go @@ -136,7 +136,7 @@ func TestRun_ServicePollingWithACLsAndTLSWithNamespaces(t *testing.T) { if c.acls { cfg.ACL.Enabled = true cfg.ACL.DefaultPolicy = "deny" - cfg.ACL.Tokens.Master = masterToken + cfg.ACL.Tokens.InitialManagement = masterToken } if c.tls { caFile, certFile, keyFile = test.GenerateServerCerts(t) diff --git a/control-plane/subcommand/connect-init/command_test.go b/control-plane/subcommand/connect-init/command_test.go index ff847bf0fb..40136b9fd8 100644 --- a/control-plane/subcommand/connect-init/command_test.go +++ b/control-plane/subcommand/connect-init/command_test.go @@ -122,7 +122,7 @@ func TestRun_ServicePollingWithACLsAndTLS(t *testing.T) { server, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true c.ACL.DefaultPolicy = "deny" - c.ACL.Tokens.Master = masterToken + c.ACL.Tokens.InitialManagement = masterToken if tt.tls { caFile, certFile, keyFile = test.GenerateServerCerts(t) c.CAFile = caFile diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index a5daefc8f5..1d710de7e7 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -451,7 +451,21 @@ func (c *Command) Run(args []string) int { } if c.createAnonymousPolicy(isPrimary) { - err := c.configureAnonymousPolicy(consulClient) + // When the default partition is in a VM, the anonymous policy does not allow cross-partition + // DNS lookups. The anonymous policy in the default partition needs to be updated in order to + // support this use-case. Creating a separate anonymous token client that updates the anonymous + // policy and token in the default partition ensures this works. + anonTokenConfig := clientConfig + if c.flagEnablePartitions { + anonTokenConfig.Partition = consulDefaultPartition + } + anonTokenClient, err := consul.NewClient(anonTokenConfig) + if err != nil { + c.log.Error(err.Error()) + return 1 + } + + err = c.configureAnonymousPolicy(anonTokenClient) if err != nil { c.log.Error(err.Error()) return 1 @@ -793,12 +807,6 @@ type Config struct { // createAnonymousPolicy returns whether we should create a policy for the // anonymous ACL token, i.e. queries without ACL tokens. func (c *Command) createAnonymousPolicy(isPrimary bool) bool { - // Don't try to create the anonymous policy in non-default partitions because - // non-default partitions will use the anonymous policy from the default - // partition. - if c.flagEnablePartitions && c.flagPartitionName != "default" { - return false - } // If isPrimary is not set then we're in a secondary DC. // In this case we assume that the primary datacenter has already created // the anonymous policy and attached it to the anonymous token. diff --git a/control-plane/subcommand/server-acl-init/command_ent_test.go b/control-plane/subcommand/server-acl-init/command_ent_test.go index af240e4960..5824d4af9b 100644 --- a/control-plane/subcommand/server-acl-init/command_ent_test.go +++ b/control-plane/subcommand/server-acl-init/command_ent_test.go @@ -7,6 +7,8 @@ import ( "strings" "testing" + "github.com/hashicorp/consul-k8s/control-plane/consul" + "github.com/hashicorp/consul-k8s/control-plane/subcommand/common" "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil" "github.com/mitchellh/cli" @@ -206,6 +208,54 @@ func TestRun_ConnectInject_NamespaceMirroring(t *testing.T) { } } +// Test that the anonymous token policy is created in the default partition from +// a non-default partition. +func TestRun_AnonymousToken_CreatedFromNonDefaultPartition(t *testing.T) { + bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" + tokenFile := common.WriteTempFile(t, bootToken) + server, stopFn := partitionedSetup(t, bootToken, "test") + defer stopFn() + k8s := fake.NewSimpleClientset() + setUpK8sServiceAccount(t, k8s, ns) + + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + clientset: k8s, + } + cmd.init() + args := []string{ + "-server-address=" + strings.Split(server.HTTPAddr, ":")[0], + "-server-port=" + strings.Split(server.HTTPAddr, ":")[1], + "-resource-prefix=" + resourcePrefix, + "-k8s-namespace=" + ns, + "-bootstrap-token-file", tokenFile, + "-enable-partitions", + "-allow-dns", + "-partition=test", + "-enable-namespaces", + } + responseCode := cmd.Run(args) + require.Equal(t, 0, responseCode, ui.ErrorWriter.String()) + + consul, err := api.NewClient(&api.Config{ + Address: server.HTTPAddr, + Token: bootToken, + }) + require.NoError(t, err) + + anonPolicyName := "anonymous-token-policy" + // Check that the anonymous token policy was created. + policy := policyExists(t, anonPolicyName, consul) + // Should be a global policy. + require.Len(t, policy.Datacenters, 0) + + // Check that the anonymous token has the policy. + tokenData, _, err := consul.ACL().TokenReadSelf(&api.QueryOptions{Token: "anonymous"}) + require.NoError(t, err) + require.Equal(t, anonPolicyName, tokenData.Policies[0].Name) +} + // Test that ACL policies get updated if namespaces/partition config changes. func TestRun_ACLPolicyUpdates(t *testing.T) { t.Parallel() @@ -1037,3 +1087,40 @@ func completeEnterpriseSetup(t *testing.T) (*fake.Clientset, *testutil.TestServe return k8s, svr } + +// partitionedSetup is a helper function which creates a server and a consul agent that runs as +// a client in the provided partitionName. The bootToken is the token used as the bootstrap token +// for both the client and the server. The helper creates a server, then creates a partition with +// the provided partitionName and then creates a client in said partition. +func partitionedSetup(t *testing.T, bootToken string, partitionName string) (*testutil.TestServer, func()) { + server, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { + c.ACL.Enabled = true + c.ACL.Tokens.InitialManagement = bootToken + }) + require.NoError(t, err) + server.WaitForLeader(t) + + serverAPIClient, err := consul.NewClient(&api.Config{ + Address: server.HTTPAddr, + Token: bootToken, + }) + require.NoError(t, err) + + _, _, err = serverAPIClient.Partitions().Create(context.Background(), &api.Partition{Name: partitionName}, &api.WriteOptions{}) + require.NoError(t, err) + + partitionedClient, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { + c.Server = false + c.Bootstrap = false + c.Partition = partitionName + c.RetryJoin = []string{server.LANAddr} + c.ACL.Enabled = true + c.ACL.Tokens.Agent = bootToken + }) + require.NoError(t, err) + + return server, func() { + server.Stop() + partitionedClient.Stop() + } +} diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index efcfaacac0..8ca8974182 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -2108,7 +2108,7 @@ func completeBootstrappedSetup(t *testing.T, masterToken string) (*fake.Clientse svr, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true - c.ACL.Tokens.Master = masterToken + c.ACL.Tokens.InitialManagement = masterToken }) require.NoError(t, err) svr.WaitForActiveCARoot(t) @@ -2153,7 +2153,7 @@ func replicatedSetup(t *testing.T, bootToken string) (*fake.Clientset, *api.Clie primarySvr, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true if bootToken != "" { - c.ACL.Tokens.Master = bootToken + c.ACL.Tokens.InitialManagement = bootToken } }) require.NoError(t, err) diff --git a/control-plane/subcommand/server-acl-init/create_or_update_test.go b/control-plane/subcommand/server-acl-init/create_or_update_test.go index 62775e786c..57cdffa2a1 100644 --- a/control-plane/subcommand/server-acl-init/create_or_update_test.go +++ b/control-plane/subcommand/server-acl-init/create_or_update_test.go @@ -30,7 +30,7 @@ func TestCreateOrUpdateACLPolicy_ErrorsIfDescriptionDoesNotMatch(t *testing.T) { bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" svr, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { c.ACL.Enabled = true - c.ACL.Tokens.Master = bootToken + c.ACL.Tokens.InitialManagement = bootToken }) require.NoError(err) svr.WaitForLeader(t) From 8d2c72869a46cb1577eb6b7ed99782fe00c1ad3d Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Mon, 24 Jan 2022 15:18:38 -0500 Subject: [PATCH 236/418] skip namespace check for gateway and gatewayclass crds --- charts/consul/test/unit/api-gateway-controller-deployment.bats | 2 +- charts/consul/test/unit/helpers.bats | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/consul/test/unit/api-gateway-controller-deployment.bats b/charts/consul/test/unit/api-gateway-controller-deployment.bats index 21c198bcf0..52769e3328 100755 --- a/charts/consul/test/unit/api-gateway-controller-deployment.bats +++ b/charts/consul/test/unit/api-gateway-controller-deployment.bats @@ -244,7 +244,7 @@ load _helpers local actual=$(echo $object | yq -r '.name' | tee /dev/stderr) - [ "${actual}" = "injector-acl-init" ] + [ "${actual}" = "api-gateway-controller-acl-init" ] local actual=$(echo $object | yq -r '.command | any(contains("consul-k8s-control-plane acl-init"))' | tee /dev/stderr) diff --git a/charts/consul/test/unit/helpers.bats b/charts/consul/test/unit/helpers.bats index 63148e3424..ee524a6842 100644 --- a/charts/consul/test/unit/helpers.bats +++ b/charts/consul/test/unit/helpers.bats @@ -115,7 +115,7 @@ load _helpers @test "helper/namespace: used everywhere" { cd `chart_dir` # Grep for files that don't have 'namespace: ' in them - local actual=$(grep -L 'namespace: ' templates/*.yaml | grep -v 'crd' | grep -v 'clusterrole' | tee /dev/stderr ) + local actual=$(grep -L 'namespace: ' templates/*.yaml | grep -v 'crd' | grep -v 'clusterrole' | grep -v 'api-gateway-gateway' | tee /dev/stderr ) [ "${actual}" = '' ] } From 181707e17f1ca2c508e2d8aed2e0418bb935d28f Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 25 Jan 2022 10:24:30 -0700 Subject: [PATCH 237/418] Fix control-plane-dev-docker in the Makefile (#987) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e95e8faf13..49b8822d1b 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ control-plane-dev-docker: ## Build consul-k8s-control-plane dev Docker image. --build-arg 'GIT_COMMIT=$(GIT_COMMIT)' \ --build-arg 'GIT_DIRTY=$(GIT_DIRTY)' \ --build-arg 'GIT_DESCRIBE=$(GIT_DESCRIBE)' \ - -f $(CURDIR)/build-support/docker/Dev.dockerfile $(CURDIR) + -f $(CURDIR)/control-plane/build-support/docker/Dev.dockerfile $(CURDIR)/control-plane control-plane-test: ## Run go test for the control plane. cd control-plane; go test ./... From c33d3bc62c396cf83749e52bdf445bcb06077b52 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Tue, 25 Jan 2022 10:41:46 -0800 Subject: [PATCH 238/418] tweak sidecar resources helm chart docs (#988) Allow resources to show up in helm docs, but don't recurse further --- charts/consul/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 8dbd329e68..30e23c92eb 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -429,7 +429,6 @@ global: # For connect-injected pods, the consul sidecar is responsible for metrics merging. For ingress/mesh/terminating # gateways, it additionally ensures the Consul services are always registered with their local Consul client. - # @recurse: false # @type: map consulSidecarContainer: # Set default resources for consul sidecar. If null, that resource won't @@ -440,6 +439,7 @@ global: # - `consul.hashicorp.com/consul-sidecar-cpu-request` # - `consul.hashicorp.com/consul-sidecar-memory-limit` # - `consul.hashicorp.com/consul-sidecar-memory-request` + # @recurse: false # @type: map resources: requests: From bf04b9914d7d85c4792c18098d8503d63247dc4a Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Tue, 25 Jan 2022 15:14:51 -0800 Subject: [PATCH 239/418] Add contrib docs checklist for adding new acl token (#994) * Add contrib docs for adding new acl token --- CONTRIBUTING.md | 87 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2fe51207ae..eb60a3d423 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,8 +16,9 @@ 1. [Generating YAML](#generating-yaml) 1. [Updating consul-helm](#updating-consul-helm) 1. [Testing a new CRD](#testing-a-new-crd) - 1. [Update Consul K8s accpetance tests](#update-consul-k8s-acceptance-tests) -5. [Testing the Helm chart](#testing-the-helm-chart) + 1. [Update Consul K8s acceptance tests](#update-consul-k8s-acceptance-tests) +1. [Adding a new ACL Token](#adding-a-new-acl-token) +1. [Testing the Helm chart](#testing-the-helm-chart) 1. [Running the tests](#running-the-tests) 1. [Writing Unit tests](#writing-unit-tests) 1. [Writing Acceptance tests](#writing-acceptance-tests) @@ -497,6 +498,88 @@ rebase the branch on main, fixing any conflicts along the way before the code ca --- +## Adding a new ACL Token + +Checklist for getting server-acl-init to generate a new ACL token. The examples in this checklist use +a token named `foo`. + +### Control Plane + +* `control-plane/subcommand/server-acl-init/command.go` + * Add `flagCreateFooToken bool` to vars list + * Initialize flag in `init` + + ```go + c.flags.BoolVar(&c.flagCreateFooToken, "create-foo-token", false, + "") + ``` + * Add `if` statement in `Run` to create your token (follow placement of other tokens). + You'll need to decide if you need a local token (use `createLocalACL()`) or a global token (use `createGlobalACL()`). + + ```go + if c.flagCreateFooToken { + err := c.createLocalACL("foo", fooRules, consulDC, isPrimary, consulClient) + if err != nil { + c.log.Error(err.Error()) + return 1 + } + } + ``` +* `control-plane/subcommand/server-acl-init/rules.go` + * Add a function that outputs your rules using a template + (if the rules don't need to be templated just use a `const string`): + ```go + func (c *Command) fooRules() (string, error) { + ``` +* `control-plane/subcommand/server-acl-init/rules_test.go` + * Add test following the pattern of other tests (`TestFooRules`) +* `control-plane/subcommand/server-acl-init/command_test.go` + * Add test cases using your flag to the following tests: + * `TestRun_TokensPrimaryDC` + * `TestRun_TokensReplicatedDC` + * `TestRun_TokensWithProvidedBootstrapToken` + +### Helm + +* `charts/consul/templates/server-acl-init-job.yaml` + * Add conditional to set your flag: + + ```yaml + {{- if .Values.foo.enabled }} + -create-foo-token=true \ + {{- end }} +* `charts/consul/test/unit/server-acl-init-job.bats` + * Test the conditional: + + ```bash + #-------------------------------------------------------------------- + # foo + + @test "serverACLInit/Job: -create-foo-token not set by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | any(contains("create-foo-token"))' | tee /dev/stderr) + [ "${actual}" = "false" ] + } + + @test "serverACLInit/Job: -create-foo-token set when foo.enabled=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'foo.enabled=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | any(contains("create-foo-token"))' | tee /dev/stderr) + [ "${actual}" = "true" ] + } + ``` + + + + ## Testing the Helm Chart The Helm chart ships with both unit and acceptance tests. From 683978eddbaaa56d1b5b4cb5259db06f3797367d Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Wed, 26 Jan 2022 12:45:25 -0500 Subject: [PATCH 240/418] Apply suggestions from code review Co-authored-by: Iryna Shustava --- charts/consul/test/unit/api-gateway-controller-service.bats | 2 +- .../test/unit/api-gateway-controller-serviceaccount.bats | 3 +-- charts/consul/values.yaml | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/charts/consul/test/unit/api-gateway-controller-service.bats b/charts/consul/test/unit/api-gateway-controller-service.bats index b199203614..47cb7ff9aa 100755 --- a/charts/consul/test/unit/api-gateway-controller-service.bats +++ b/charts/consul/test/unit/api-gateway-controller-service.bats @@ -9,7 +9,7 @@ load _helpers . } -@test "apiGateway/Service: enable with global.enabled false" { +@test "apiGateway/Service: enable with apiGateway.enabled set to true" { cd `chart_dir` local actual=$(helm template \ -s templates/api-gateway-controller-service.yaml \ diff --git a/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats b/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats index cb071f90ef..22486799b2 100644 --- a/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats +++ b/charts/consul/test/unit/api-gateway-controller-serviceaccount.bats @@ -9,11 +9,10 @@ load _helpers . } -@test "apiGateway/ServiceAccount: enabled with global.enabled false" { +@test "apiGateway/ServiceAccount: enabled with apiGateway.enabled true" { cd `chart_dir` local actual=$(helm template \ -s templates/api-gateway-controller-serviceaccount.yaml \ - --set 'global.enabled=false' \ --set 'apiGateway.enabled=true' \ --set 'apiGateway.image=foo' \ . | tee /dev/stderr | diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 74c8c5f824..aa4924d9fa 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2458,7 +2458,7 @@ terminatingGateways: gateways: - name: terminating-gateway -# Conffiguration setings for the Consul API Gateway integration +# Configuration settings for the Consul API Gateway integration apiGateway: # When true the helm chart will install the Consul API Gateway controller enabled: false From 67448831ae09112fc0c82caef3a578da09e811fd Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 26 Jan 2022 13:01:25 -0500 Subject: [PATCH 241/418] Show diff when upgrading (#934) * Made an initial try at the consul-k8s upgrade command. Running into issues with the connect-injector webhook not starting on an install? * notes from sync with Saad on what's left * Made an initial try at the consul-k8s upgrade command. Running into issues with the connect-injector webhook not starting on an install? * First pass at upgrade was successful. * notes from sync with Saad on what's left * Some basic cleanup * Add the namespace and install flags * Add flag test and remove install option * Move presets into a config package * Add Changelog * Made an initial try at the consul-k8s upgrade command. Running into issues with the connect-injector webhook not starting on an install? * Upgrade commit * notes from sync with Saad on what's left * This commit contains the MapDiff function to compare the YAML of the previous Release and the new upgrade. * Remove double comment on name setting * Clean up some merge issues from rebase * Move MergeMaps to util * Reduce indent on check for installation * Clean up Help fn * Use Synopsis in Help * Remove duplicated MapMerge from git rebase * Add IsValidLabel to utils * Move chart loading code to chart file * Use the IsValidLabel in common * Use LoadChart * Move create UI logger closer to it's first call * Rename vals to chartValues * Add godebug dep * Add WithDiff{Added,Removed}Style * Run go mod tidy * Remove double k8serrors from git * Run go mod tidy * Remove errant changelog entry for upgrade * Fix some issues from the Git rebase * Show a diff using a simple YAML differ * Fix a val to chartValues misnaming from Git * Add the diffing dependency * Clean up comments and move some non-validating behavior out of the validation method * Start writing my own diff * `go mod tidy` 2k22 * Add several diff testing scenarios * Handle diffs using YAML parsing * Get diff working with more complex maps * Move FetchChartValues so that public functions are at the top of the chart file * Handle error on invalid timeout flag * Undo that weird indent change. * Catch the diff error * Modify chart fixtures to be loadable * Test loading charts * Check the error returned from diffRecursively. * Update changelog * Update cli/cmd/common/chart.go Co-authored-by: Nitya Dhanushkodi * TestReadChartFiles checks contents of files * Test uppercase and underscores * Test removal scenarios * Fix formatting * Update cli/cmd/common/diff.go Co-authored-by: Iryna Shustava * Change aMapSlice to aMapWithKey * `go mod tidy` * Replace "reflection" with better code * Remove double printing config * Return string, err from diffRecursively * Move common package up to cli root * Move chart to helm package * Fix error string on install * Delete the binary I added accidentally * Move diff to helm pkg * Match the update to /x/sys * Move diffing code back to common * Fix indentation on the diff and add a header explaining * Remove extra name/namespace print * Remove extra dry-run printing * Fix comment on WithDiffUnchangedStyle * Remove unused constants * Add a test case for valid label with leading numbers * Add test for MergeMaps * Reassure users with a dry run header Co-authored-by: Saad Co-authored-by: Nitya Dhanushkodi Co-authored-by: Iryna Shustava --- CHANGELOG.md | 2 + cli/cmd/common/fixtures/consul/Chart.yaml | 1 - .../common/fixtures/consul/templates/foo.yaml | 1 - cli/cmd/common/fixtures/consul/values.yaml | 1 - cli/cmd/common/utils.go | 136 ------------- cli/cmd/common/utils_test.go | 39 ---- cli/cmd/install/install.go | 59 ++---- cli/cmd/install/install_test.go | 50 +---- cli/cmd/status/status.go | 9 +- cli/cmd/status/status_test.go | 2 +- cli/cmd/uninstall/uninstall.go | 11 +- cli/cmd/uninstall/uninstall_test.go | 2 +- cli/cmd/upgrade/upgrade.go | 179 +++++++++--------- cli/cmd/upgrade/upgrade_test.go | 2 +- cli/cmd/version/version.go | 2 +- cli/commands.go | 2 +- cli/{cmd => }/common/base.go | 2 +- cli/common/diff.go | 148 +++++++++++++++ cli/common/diff_test.go | 171 +++++++++++++++++ cli/{cmd => }/common/flag/doc.go | 0 cli/{cmd => }/common/flag/flag.go | 0 cli/{cmd => }/common/flag/flag_bool.go | 0 cli/{cmd => }/common/flag/flag_enum.go | 0 cli/{cmd => }/common/flag/flag_enum_single.go | 0 cli/{cmd => }/common/flag/flag_float.go | 0 cli/{cmd => }/common/flag/flag_int.go | 0 cli/{cmd => }/common/flag/flag_string.go | 0 cli/{cmd => }/common/flag/flag_string_map.go | 0 .../common/flag/flag_string_slice.go | 0 .../common/flag/flag_string_slice_test.go | 0 cli/{cmd => }/common/flag/flag_time.go | 0 cli/{cmd => }/common/flag/flag_var.go | 0 cli/{cmd => }/common/flag/set.go | 0 cli/{cmd => }/common/flag/set_test.go | 0 cli/{cmd => }/common/terminal/basic.go | 6 + cli/{cmd => }/common/terminal/doc.go | 0 cli/{cmd => }/common/terminal/table.go | 0 cli/{cmd => }/common/terminal/ui.go | 68 +++++-- cli/{cmd => }/common/usage.go | 0 cli/common/utils.go | 108 +++++++++++ cli/common/utils_test.go | 67 +++++++ cli/go.mod | 54 +++--- cli/go.sum | 114 +++++++---- cli/helm/action.go | 24 +++ cli/helm/chart.go | 98 ++++++++++ cli/helm/chart_test.go | 56 ++++++ cli/helm/fixtures/consul/Chart.yaml | 5 + .../fixtures/consul/templates/_helpers.tpl | 0 cli/helm/fixtures/consul/templates/foo.yaml | 1 + cli/helm/fixtures/consul/values.yaml | 2 + 50 files changed, 960 insertions(+), 462 deletions(-) delete mode 100644 cli/cmd/common/fixtures/consul/Chart.yaml delete mode 100644 cli/cmd/common/fixtures/consul/templates/foo.yaml delete mode 100644 cli/cmd/common/fixtures/consul/values.yaml delete mode 100644 cli/cmd/common/utils.go delete mode 100644 cli/cmd/common/utils_test.go rename cli/{cmd => }/common/base.go (94%) create mode 100644 cli/common/diff.go create mode 100644 cli/common/diff_test.go rename cli/{cmd => }/common/flag/doc.go (100%) rename cli/{cmd => }/common/flag/flag.go (100%) rename cli/{cmd => }/common/flag/flag_bool.go (100%) rename cli/{cmd => }/common/flag/flag_enum.go (100%) rename cli/{cmd => }/common/flag/flag_enum_single.go (100%) rename cli/{cmd => }/common/flag/flag_float.go (100%) rename cli/{cmd => }/common/flag/flag_int.go (100%) rename cli/{cmd => }/common/flag/flag_string.go (100%) rename cli/{cmd => }/common/flag/flag_string_map.go (100%) rename cli/{cmd => }/common/flag/flag_string_slice.go (100%) rename cli/{cmd => }/common/flag/flag_string_slice_test.go (100%) rename cli/{cmd => }/common/flag/flag_time.go (100%) rename cli/{cmd => }/common/flag/flag_var.go (100%) rename cli/{cmd => }/common/flag/set.go (100%) rename cli/{cmd => }/common/flag/set_test.go (100%) rename cli/{cmd => }/common/terminal/basic.go (94%) rename cli/{cmd => }/common/terminal/doc.go (100%) rename cli/{cmd => }/common/terminal/table.go (100%) rename cli/{cmd => }/common/terminal/ui.go (72%) rename cli/{cmd => }/common/usage.go (100%) create mode 100644 cli/common/utils.go create mode 100644 cli/common/utils_test.go create mode 100644 cli/helm/action.go create mode 100644 cli/helm/chart.go create mode 100644 cli/helm/chart_test.go create mode 100644 cli/helm/fixtures/consul/Chart.yaml rename cli/{cmd/common => helm}/fixtures/consul/templates/_helpers.tpl (100%) create mode 100644 cli/helm/fixtures/consul/templates/foo.yaml create mode 100644 cli/helm/fixtures/consul/values.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index bb6fa12d2d..4dc453eb70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ IMPROVEMENTS: * Support `ui.dashboardURLTemplates.service` value for setting [dashboard URL templates](https://www.consul.io/docs/agent/options#ui_config_dashboard_url_templates_service). [[GH-937](https://github.com/hashicorp/consul-k8s/pull/937)] * Allow using dash-separated names for config entries when using `kubectl`. [[GH-965](https://github.com/hashicorp/consul-k8s/pull/965)] * Support Pod Security Policies with Vault integration. [[GH-985](https://github.com/hashicorp/consul-k8s/pull/985)] +* CLI + * Show a diff when upgrading a Consul installation on Kubernetes [[GH-934](https://github.com/hashicorp/consul-k8s/pull/934)] * Control Plane * Support the value `$POD_NAME` for the annotation `consul.hashicorp.com/service-meta-*` that will now be interpolated and set to the pod's name in the service's metadata. [[GH-982](https://github.com/hashicorp/consul-k8s/pull/982)] * Allow managing Consul sidecar resources via annotations. [[GH-956](https://github.com/hashicorp/consul-k8s/pull/956)] diff --git a/cli/cmd/common/fixtures/consul/Chart.yaml b/cli/cmd/common/fixtures/consul/Chart.yaml deleted file mode 100644 index 54c6e609d9..0000000000 --- a/cli/cmd/common/fixtures/consul/Chart.yaml +++ /dev/null @@ -1 +0,0 @@ -chart \ No newline at end of file diff --git a/cli/cmd/common/fixtures/consul/templates/foo.yaml b/cli/cmd/common/fixtures/consul/templates/foo.yaml deleted file mode 100644 index 1910281566..0000000000 --- a/cli/cmd/common/fixtures/consul/templates/foo.yaml +++ /dev/null @@ -1 +0,0 @@ -foo \ No newline at end of file diff --git a/cli/cmd/common/fixtures/consul/values.yaml b/cli/cmd/common/fixtures/consul/values.yaml deleted file mode 100644 index 972ac6208d..0000000000 --- a/cli/cmd/common/fixtures/consul/values.yaml +++ /dev/null @@ -1 +0,0 @@ -values \ No newline at end of file diff --git a/cli/cmd/common/utils.go b/cli/cmd/common/utils.go deleted file mode 100644 index 2cff8eccec..0000000000 --- a/cli/cmd/common/utils.go +++ /dev/null @@ -1,136 +0,0 @@ -package common - -import ( - "embed" - "errors" - "fmt" - "os" - "path/filepath" - "strings" - - "helm.sh/helm/v3/pkg/action" - "helm.sh/helm/v3/pkg/chart/loader" - helmCLI "helm.sh/helm/v3/pkg/cli" - "k8s.io/cli-runtime/pkg/genericclioptions" -) - -const ( - DefaultReleaseName = "consul" - DefaultReleaseNamespace = "consul" - chartFileName = "Chart.yaml" - valuesFileName = "values.yaml" - templatesDirName = "templates" - TopLevelChartDirName = "consul" - - // CLILabelKey and CLILabelValue are added to each secret on creation so the CLI knows - // which key to delete on an uninstall. - CLILabelKey = "managed-by" - CLILabelValue = "consul-k8s" -) - -// ReadChartFiles reads the chart files from the embedded file system, and loads their contents into -// []*loader.BufferedFile. This is a format that the Helm Go SDK functions can read from to create a chart to install -// from. The names of these files are important, as there are case statements in the Helm Go SDK looking for files named -// "Chart.yaml" or "templates/.yaml", which is why even though the embedded file system has them named -// "consul/Chart.yaml" we have to strip the "consul" prefix out, which is done by the call to the helper method readFile. -func ReadChartFiles(chart embed.FS, chartDirName string) ([]*loader.BufferedFile, error) { - var chartFiles []*loader.BufferedFile - - // Load Chart.yaml and values.yaml first. - for _, f := range []string{chartFileName, valuesFileName} { - file, err := readFile(chart, filepath.Join(chartDirName, f), chartDirName) - if err != nil { - return nil, err - } - chartFiles = append(chartFiles, file) - } - - // Now load everything under templates/. - dirs, err := chart.ReadDir(filepath.Join(chartDirName, templatesDirName)) - if err != nil { - return nil, err - } - for _, f := range dirs { - if f.IsDir() { - // We only need to include files in the templates directory. - continue - } - - file, err := readFile(chart, filepath.Join(chartDirName, templatesDirName, f.Name()), chartDirName) - if err != nil { - return nil, err - } - chartFiles = append(chartFiles, file) - } - - return chartFiles, nil -} - -func readFile(chart embed.FS, f string, pathPrefix string) (*loader.BufferedFile, error) { - bytes, err := chart.ReadFile(f) - if err != nil { - return nil, err - } - // Remove the path prefix. - rel, err := filepath.Rel(pathPrefix, f) - if err != nil { - return nil, err - } - return &loader.BufferedFile{ - Name: rel, - Data: bytes, - }, nil -} - -// Abort returns true if the raw input string is not equal to "y" or "yes". -func Abort(raw string) bool { - confirmation := strings.TrimSuffix(raw, "\n") - return !(strings.ToLower(confirmation) == "y" || strings.ToLower(confirmation) == "yes") -} - -// InitActionConfig initializes a Helm Go SDK action configuration. This function currently uses a hack to override the -// namespace field that gets set in the K8s client set up by the SDK. -func InitActionConfig(actionConfig *action.Configuration, namespace string, settings *helmCLI.EnvSettings, logger action.DebugLog) (*action.Configuration, error) { - getter := settings.RESTClientGetter() - configFlags := getter.(*genericclioptions.ConfigFlags) - configFlags.Namespace = &namespace - err := actionConfig.Init(settings.RESTClientGetter(), namespace, - os.Getenv("HELM_DRIVER"), logger) - if err != nil { - return nil, fmt.Errorf("error setting up helm action configuration to find existing installations: %s", err) - } - return actionConfig, nil -} - -// CheckForInstallations uses the helm Go SDK to find helm releases in all namespaces where the chart name is -// "consul", and returns the release name and namespace if found, or an error if not found. -func CheckForInstallations(settings *helmCLI.EnvSettings, uiLogger action.DebugLog) (string, string, error) { - // Need a specific action config to call helm list, where namespace is NOT specified. - listConfig := new(action.Configuration) - if err := listConfig.Init(settings.RESTClientGetter(), "", - os.Getenv("HELM_DRIVER"), uiLogger); err != nil { - return "", "", fmt.Errorf("couldn't initialize helm config: %s", err) - } - - lister := action.NewList(listConfig) - lister.AllNamespaces = true - lister.StateMask = action.ListAll - res, err := lister.Run() - if err != nil { - return "", "", fmt.Errorf("couldn't check for installations: %s", err) - } - - for _, rel := range res { - if rel.Chart.Metadata.Name == "consul" { - return rel.Name, rel.Namespace, nil - } - } - return "", "", errors.New("couldn't find consul installation") -} - -func CloseWithError(c *BaseCommand) { - if err := c.Close(); err != nil { - c.Log.Error(err.Error()) - os.Exit(1) - } -} diff --git a/cli/cmd/common/utils_test.go b/cli/cmd/common/utils_test.go deleted file mode 100644 index fc9bf5292c..0000000000 --- a/cli/cmd/common/utils_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package common - -import ( - "embed" - "testing" - - "github.com/stretchr/testify/require" -) - -//go:embed fixtures/consul/* fixtures/consul/templates/_helpers.tpl -var testChart embed.FS - -func TestReadChartFiles(t *testing.T) { - files, err := ReadChartFiles(testChart, "fixtures/consul") - require.NoError(t, err) - var foundChart, foundValues, foundTemplate, foundHelper bool - for _, f := range files { - if f.Name == "Chart.yaml" { - require.Equal(t, "chart", string(f.Data)) - foundChart = true - } - if f.Name == "values.yaml" { - require.Equal(t, "values", string(f.Data)) - foundValues = true - } - if f.Name == "templates/foo.yaml" { - require.Equal(t, "foo", string(f.Data)) - foundTemplate = true - } - if f.Name == "templates/_helpers.tpl" { - require.Equal(t, "helpers", string(f.Data)) - foundHelper = true - } - } - require.True(t, foundChart) - require.True(t, foundValues) - require.True(t, foundTemplate) - require.True(t, foundHelper) -} diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index edc9308481..dd9f9f7abc 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -9,10 +9,11 @@ import ( "time" consulChart "github.com/hashicorp/consul-k8s/charts" - "github.com/hashicorp/consul-k8s/cli/cmd/common" - "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" - "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + "github.com/hashicorp/consul-k8s/cli/common" + "github.com/hashicorp/consul-k8s/cli/common/flag" + "github.com/hashicorp/consul-k8s/cli/common/terminal" "github.com/hashicorp/consul-k8s/cli/config" + "github.com/hashicorp/consul-k8s/cli/helm" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart/loader" helmCLI "helm.sh/helm/v3/pkg/cli" @@ -313,7 +314,7 @@ func (c *Command) Run(args []string) int { // Without informing the user, default global.name to consul if it hasn't been set already. We don't allow setting // the release name, and since that is hardcoded to "consul", setting global.name to "consul" makes it so resources // aren't double prefixed with "consul-consul-...". - vals = MergeMaps(config.Convert(config.GlobalNameConsul), vals) + vals = common.MergeMaps(config.Convert(config.GlobalNameConsul), vals) // Dry Run should exit here, no need to actual locate/download the charts. if c.flagDryRun { @@ -342,7 +343,7 @@ func (c *Command) Run(args []string) int { // Setup action configuration for Helm Go SDK function calls. actionConfig := new(action.Configuration) - actionConfig, err = common.InitActionConfig(actionConfig, c.flagNamespace, settings, uiLogger) + actionConfig, err = helm.InitActionConfig(actionConfig, c.flagNamespace, settings, uiLogger) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 @@ -357,7 +358,7 @@ func (c *Command) Run(args []string) int { install.Timeout = c.timeoutDuration // Read the embedded chart files into []*loader.BufferedFile. - chartFiles, err := common.ReadChartFiles(consulChart.ConsulHelmChart, common.TopLevelChartDirName) + chartFiles, err := helm.ReadChartFiles(consulChart.ConsulHelmChart, common.TopLevelChartDirName) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 @@ -455,32 +456,11 @@ func (c *Command) mergeValuesFlagsWithPrecedence(settings *helmCLI.EnvSettings) if c.flagPreset != defaultPreset { // Note the ordering of the function call, presets have lower precedence than set vals. presetMap := config.Presets[c.flagPreset].(map[string]interface{}) - vals = MergeMaps(presetMap, vals) + vals = common.MergeMaps(presetMap, vals) } return vals, err } -// MergeMaps is a helper function used in Run. Merges two maps giving b precedent. -// @source: https://github.com/helm/helm/blob/main/pkg/cli/values/options.go -func MergeMaps(a, b map[string]interface{}) map[string]interface{} { - out := make(map[string]interface{}, len(a)) - for k, v := range a { - out[k] = v - } - for k, v := range b { - if v, ok := v.(map[string]interface{}); ok { - if bv, ok := out[k]; ok { - if bv, ok := bv.(map[string]interface{}); ok { - out[k] = MergeMaps(bv, v) - continue - } - } - } - out[k] = v - } - return out -} - // validateFlags is a helper function that performs sanity checks on the user's provided flags. func (c *Command) validateFlags(args []string) error { if err := c.set.Parse(args); err != nil { @@ -490,14 +470,14 @@ func (c *Command) validateFlags(args []string) error { return errors.New("should have no non-flag arguments") } if len(c.flagValueFiles) != 0 && c.flagPreset != defaultPreset { - return fmt.Errorf("Cannot set both -%s and -%s", flagNameConfigFile, flagNamePreset) + return fmt.Errorf("cannot set both -%s and -%s", flagNameConfigFile, flagNamePreset) } if _, ok := config.Presets[c.flagPreset]; c.flagPreset != defaultPreset && !ok { return fmt.Errorf("'%s' is not a valid preset", c.flagPreset) } - if !validLabel(c.flagNamespace) { + if !common.IsValidLabel(c.flagNamespace) { return fmt.Errorf("'%s' is an invalid namespace. Namespaces follow the RFC 1123 label convention and must "+ - "consist of a lower case alphanumeric character or '-' and must start/end with an alphanumeric", c.flagNamespace) + "consist of a lower case alphanumeric character or '-' and must start/end with an alphanumeric character", c.flagNamespace) } duration, err := time.ParseDuration(c.flagTimeout) if err != nil { @@ -507,7 +487,7 @@ func (c *Command) validateFlags(args []string) error { if len(c.flagValueFiles) != 0 { for _, filename := range c.flagValueFiles { if _, err := os.Stat(filename); err != nil && os.IsNotExist(err) { - return fmt.Errorf("File '%s' does not exist.", filename) + return fmt.Errorf("file '%s' does not exist", filename) } } } @@ -518,21 +498,6 @@ func (c *Command) validateFlags(args []string) error { return nil } -// validLabel is a helper function that checks if a string follows RFC 1123 labels. -func validLabel(s string) bool { - for i, c := range s { - alphanum := ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') - // If the character is not the last or first, it can be a dash. - if i != 0 && i != (len(s)-1) { - alphanum = alphanum || (c == '-') - } - if !alphanum { - return false - } - } - return true -} - // checkValidEnterprise checks and validates an enterprise installation. // When an enterprise license secret is provided, check that the secret exists // in the "consul" namespace. diff --git a/cli/cmd/install/install_test.go b/cli/cmd/install/install_test.go index ba6608d256..005e711adb 100644 --- a/cli/cmd/install/install_test.go +++ b/cli/cmd/install/install_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/common" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" @@ -121,54 +121,6 @@ func TestValidateFlags(t *testing.T) { } } -// TestValidLabel calls validLabel() which checks strings match RFC 1123 label convention. -func TestValidLabel(t *testing.T) { - testCases := []struct { - description string - input string - expected bool - }{ - { - "Standard name with leading numbers works.", - "1234-abc", - true, - }, - { - "All lower case letters works.", - "peppertrout", - true, - }, - { - "Test that dashes in the middle are allowed.", - "pepper-trout", - true, - }, - { - "Capitals violate RFC 1123 lower case label.", - "Peppertrout", - false, - }, - { - "Underscores are not permitted anywhere.", - "ab_cd", - false, - }, - { - "The dash must be in the middle of the word, not on the start/end character.", - "peppertrout-", - false, - }, - } - - for _, testCase := range testCases { - t.Run(testCase.description, func(t *testing.T) { - if result := validLabel(testCase.input); result != testCase.expected { - t.Errorf("Incorrect output, got %v and expected %v", result, testCase.expected) - } - }) - } -} - // getInitializedCommand sets up a command struct for tests. func getInitializedCommand(t *testing.T) *Command { t.Helper() diff --git a/cli/cmd/status/status.go b/cli/cmd/status/status.go index 6d8e636b31..7b7a02a03d 100644 --- a/cli/cmd/status/status.go +++ b/cli/cmd/status/status.go @@ -9,9 +9,10 @@ import ( "helm.sh/helm/v3/pkg/release" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/hashicorp/consul-k8s/cli/cmd/common" - "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" - "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + "github.com/hashicorp/consul-k8s/cli/common" + "github.com/hashicorp/consul-k8s/cli/common/flag" + "github.com/hashicorp/consul-k8s/cli/common/terminal" + "github.com/hashicorp/consul-k8s/cli/helm" "helm.sh/helm/v3/pkg/action" helmCLI "helm.sh/helm/v3/pkg/cli" "k8s.io/client-go/kubernetes" @@ -137,7 +138,7 @@ func (c *Command) validateFlags(args []string) error { func (c *Command) checkHelmInstallation(settings *helmCLI.EnvSettings, uiLogger action.DebugLog, releaseName, namespace string) error { // Need a specific action config to call helm status, where namespace comes from the previous call to list. statusConfig := new(action.Configuration) - statusConfig, err := common.InitActionConfig(statusConfig, namespace, settings, uiLogger) + statusConfig, err := helm.InitActionConfig(statusConfig, namespace, settings, uiLogger) if err != nil { return err } diff --git a/cli/cmd/status/status_test.go b/cli/cmd/status/status_test.go index e369555143..79f908654f 100644 --- a/cli/cmd/status/status_test.go +++ b/cli/cmd/status/status_test.go @@ -6,7 +6,7 @@ import ( "os" "testing" - "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/common" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" diff --git a/cli/cmd/uninstall/uninstall.go b/cli/cmd/uninstall/uninstall.go index 11d68aab7b..288f97823b 100644 --- a/cli/cmd/uninstall/uninstall.go +++ b/cli/cmd/uninstall/uninstall.go @@ -7,9 +7,10 @@ import ( "time" "github.com/cenkalti/backoff" - "github.com/hashicorp/consul-k8s/cli/cmd/common" - "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" - "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + "github.com/hashicorp/consul-k8s/cli/common" + "github.com/hashicorp/consul-k8s/cli/common/flag" + "github.com/hashicorp/consul-k8s/cli/common/terminal" + "github.com/hashicorp/consul-k8s/cli/helm" "helm.sh/helm/v3/pkg/action" helmCLI "helm.sh/helm/v3/pkg/cli" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -176,7 +177,7 @@ func (c *Command) Run(args []string) int { // Search for Consul installation by calling `helm list`. Depends on what's already specified. actionConfig := new(action.Configuration) - actionConfig, err = common.InitActionConfig(actionConfig, c.flagNamespace, settings, uiLogger) + actionConfig, err = helm.InitActionConfig(actionConfig, c.flagNamespace, settings, uiLogger) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 @@ -210,7 +211,7 @@ func (c *Command) Run(args []string) int { } // Actually call out to `helm delete`. - actionConfig, err = common.InitActionConfig(actionConfig, foundReleaseNamespace, settings, uiLogger) + actionConfig, err = helm.InitActionConfig(actionConfig, foundReleaseNamespace, settings, uiLogger) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 diff --git a/cli/cmd/uninstall/uninstall_test.go b/cli/cmd/uninstall/uninstall_test.go index faf3a132c1..8f1df8de80 100644 --- a/cli/cmd/uninstall/uninstall_test.go +++ b/cli/cmd/uninstall/uninstall_test.go @@ -5,7 +5,7 @@ import ( "os" "testing" - "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/common" "github.com/hashicorp/go-hclog" "github.com/stretchr/testify/require" batchv1 "k8s.io/api/batch/v1" diff --git a/cli/cmd/upgrade/upgrade.go b/cli/cmd/upgrade/upgrade.go index 27771a8ab6..5c9cf80651 100644 --- a/cli/cmd/upgrade/upgrade.go +++ b/cli/cmd/upgrade/upgrade.go @@ -9,18 +9,16 @@ import ( "time" consulChart "github.com/hashicorp/consul-k8s/charts" - "github.com/hashicorp/consul-k8s/cli/cmd/common" - "github.com/hashicorp/consul-k8s/cli/cmd/common/flag" - "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" - "github.com/hashicorp/consul-k8s/cli/cmd/install" + "github.com/hashicorp/consul-k8s/cli/common" + "github.com/hashicorp/consul-k8s/cli/common/flag" + "github.com/hashicorp/consul-k8s/cli/common/terminal" "github.com/hashicorp/consul-k8s/cli/config" + "github.com/hashicorp/consul-k8s/cli/helm" "helm.sh/helm/v3/pkg/action" - "helm.sh/helm/v3/pkg/chart/loader" helmCLI "helm.sh/helm/v3/pkg/cli" "helm.sh/helm/v3/pkg/cli/values" "helm.sh/helm/v3/pkg/getter" "k8s.io/client-go/kubernetes" - "sigs.k8s.io/yaml" ) const ( @@ -170,11 +168,22 @@ func (c *Command) Run(args []string) int { defer common.CloseWithError(c.BaseCommand) - if err := c.validateFlags(args); err != nil { + err := c.validateFlags(args) + if err != nil { c.UI.Output(err.Error()) return 1 } + if c.flagDryRun { + c.UI.Output("Dry Run Upgrade: No changes will be made to the cluster.") + } + + c.timeoutDuration, err = time.ParseDuration(c.flagTimeout) + if err != nil { + c.UI.Output(fmt.Sprintf("Invalid timeout: %s", err)) + return 1 + } + // helmCLI.New() will create a settings object which is used by the Helm Go SDK calls. settings := helmCLI.New() @@ -188,21 +197,6 @@ func (c *Command) Run(args []string) int { settings.KubeContext = c.flagKubeContext } - // Setup logger to stream Helm library logs - var uiLogger = func(s string, args ...interface{}) { - logMsg := fmt.Sprintf(s, args...) - - if c.flagVerbose { - // Only output all logs when verbose is enabled - c.UI.Output(logMsg, terminal.WithLibraryStyle()) - } else { - // When verbose is not enabled, output all logs except not ready messages for resources - if !strings.Contains(logMsg, "not ready") { - c.UI.Output(logMsg, terminal.WithLibraryStyle()) - } - } - } - // Set up the kubernetes client to use for non Helm SDK calls to the Kubernetes API // The Helm SDK will use settings.RESTClientGetter for its calls as well, so this will // use a consistent method to target the right cluster for both Helm SDK and non Helm SDK calls. @@ -220,51 +214,47 @@ func (c *Command) Run(args []string) int { } c.UI.Output("Pre-Upgrade Checks", terminal.WithHeaderStyle()) - - // Note the logic here, common's CheckForInstallations function returns an error if - // the release is not found. In `upgrade` we should indeed error if a user doesn't currently have a release. - var foundNamespace string - if name, ns, err := common.CheckForInstallations(settings, uiLogger); err != nil { - c.UI.Output("could not find existing Consul installation - run `consul-k8s install`") + uiLogger := c.createUILogger() + name, namespace, err := common.CheckForInstallations(settings, uiLogger) + if err != nil { + c.UI.Output("Could not find existing Consul installation. Run 'consul-k8s install' to create one.") return 1 - } else { - c.UI.Output("Existing installation found to be upgraded.", terminal.WithSuccessStyle()) - c.UI.Output("Name: %s", name, terminal.WithInfoStyle()) - c.UI.Output("Namespace: %s", ns, terminal.WithInfoStyle()) - - foundNamespace = ns } + c.UI.Output("Existing installation found to be upgraded.", terminal.WithSuccessStyle()) + c.UI.Output("Name: %s\nNamespace: %s", name, namespace, terminal.WithInfoStyle()) - // Handle preset, value files, and set values logic. - vals, err := c.mergeValuesFlagsWithPrecedence(settings) + chart, err := helm.LoadChart(consulChart.ConsulHelmChart, common.TopLevelChartDirName) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 } - valuesYaml, err := yaml.Marshal(vals) + c.UI.Output("Loaded charts", terminal.WithSuccessStyle()) + + currentChartValues, err := helm.FetchChartValues(namespace, settings, uiLogger) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 } - // Print out the upgrade summary. - if !c.flagAutoApprove { - c.UI.Output("Consul Upgrade Summary", terminal.WithHeaderStyle()) - c.UI.Output("Installation name: %s", common.DefaultReleaseName, terminal.WithInfoStyle()) - c.UI.Output("Namespace: %s", foundNamespace, terminal.WithInfoStyle()) - - if len(vals) == 0 { - c.UI.Output("Overrides: "+string(valuesYaml), terminal.WithInfoStyle()) - } else { - c.UI.Output("Overrides:"+"\n"+string(valuesYaml), terminal.WithInfoStyle()) - } + // Handle preset, value files, and set values logic. + chartValues, err := c.mergeValuesFlagsWithPrecedence(settings) + if err != nil { + c.UI.Output(err.Error(), terminal.WithErrorStyle()) + return 1 } // Without informing the user, default global.name to consul if it hasn't been set already. We don't allow setting // the release name, and since that is hardcoded to "consul", setting global.name to "consul" makes it so resources // aren't double prefixed with "consul-consul-...". - vals = install.MergeMaps(config.Convert(config.GlobalNameConsul), vals) + chartValues = common.MergeMaps(config.Convert(config.GlobalNameConsul), chartValues) + // Print out the upgrade summary. + if err = c.printDiff(currentChartValues, chartValues); err != nil { + c.UI.Output("Could not print diff between charts.", terminal.WithErrorStyle()) + return 1 + } + + // Check if the user is OK with the upgrade unless the auto approve or dry run flags are true. if !c.flagAutoApprove && !c.flagDryRun { confirmation, err := c.UI.Input(&terminal.Input{ Prompt: "Proceed with upgrade? (y/N)", @@ -290,7 +280,7 @@ func (c *Command) Run(args []string) int { // Setup action configuration for Helm Go SDK function calls. actionConfig := new(action.Configuration) - actionConfig, err = common.InitActionConfig(actionConfig, foundNamespace, settings, uiLogger) + actionConfig, err = helm.InitActionConfig(actionConfig, namespace, settings, uiLogger) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 @@ -298,28 +288,13 @@ func (c *Command) Run(args []string) int { // Setup the upgrade action. upgrade := action.NewUpgrade(actionConfig) - upgrade.Namespace = foundNamespace + upgrade.Namespace = namespace upgrade.DryRun = c.flagDryRun upgrade.Wait = c.flagWait upgrade.Timeout = c.timeoutDuration - // Read the embedded chart files into []*loader.BufferedFile. - chartFiles, err := common.ReadChartFiles(consulChart.ConsulHelmChart, common.TopLevelChartDirName) - if err != nil { - c.UI.Output(err.Error(), terminal.WithErrorStyle()) - return 1 - } - - // Create a *chart.Chart object from the files to run the upgrade from. - chart, err := loader.LoadFiles(chartFiles) - if err != nil { - c.UI.Output(err.Error(), terminal.WithErrorStyle()) - return 1 - } - c.UI.Output("Loaded charts", terminal.WithSuccessStyle()) - // Run the upgrade. Note that the dry run config is passed into the upgrade action, so upgrade.Run is called even during a dry run. - re, err := upgrade.Run(common.DefaultReleaseName, chart, vals) + _, err = upgrade.Run(common.DefaultReleaseName, chart, chartValues) if err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 @@ -327,23 +302,11 @@ func (c *Command) Run(args []string) int { // Dry Run should exit here, printing the release's config. if c.flagDryRun { - configYaml, err := yaml.Marshal(re.Config) - if err != nil { - c.UI.Output(err.Error(), terminal.WithErrorStyle()) - return 1 - } - - if len(re.Config) == 0 { - c.UI.Output("Config: "+string(configYaml), terminal.WithInfoStyle()) - } else { - c.UI.Output("Config:"+"\n"+string(configYaml), terminal.WithInfoStyle()) - } - c.UI.Output("Dry run complete - upgrade can proceed.", terminal.WithSuccessStyle()) + c.UI.Output("Dry run complete - upgrade can proceed.", terminal.WithInfoStyle()) return 0 } - c.UI.Output("Upgraded Consul into namespace %q", foundNamespace, terminal.WithSuccessStyle()) - + c.UI.Output("Upgraded Consul into namespace %q", namespace, terminal.WithSuccessStyle()) return 0 } @@ -361,11 +324,9 @@ func (c *Command) validateFlags(args []string) error { if _, ok := config.Presets[c.flagPreset]; c.flagPreset != defaultPreset && !ok { return fmt.Errorf("'%s' is not a valid preset", c.flagPreset) } - duration, err := time.ParseDuration(c.flagTimeout) - if err != nil { + if _, err := time.ParseDuration(c.flagTimeout); err != nil { return fmt.Errorf("unable to parse -%s: %s", flagNameTimeout, err) } - c.timeoutDuration = duration if len(c.flagValueFiles) != 0 { for _, filename := range c.flagValueFiles { if _, err := os.Stat(filename); err != nil && os.IsNotExist(err) { @@ -374,9 +335,6 @@ func (c *Command) validateFlags(args []string) error { } } - if c.flagDryRun { - c.UI.Output("Performing dry run upgrade.", terminal.WithInfoStyle()) - } return nil } @@ -404,17 +362,56 @@ func (c *Command) mergeValuesFlagsWithPrecedence(settings *helmCLI.EnvSettings) if c.flagPreset != defaultPreset { // Note the ordering of the function call, presets have lower precedence than set vals. presetMap := config.Presets[c.flagPreset].(map[string]interface{}) - vals = install.MergeMaps(presetMap, vals) + vals = common.MergeMaps(presetMap, vals) } return vals, err } +// Help returns a description of this command and how it can be used. func (c *Command) Help() string { c.once.Do(c.init) - s := "Usage: consul-k8s upgrade [flags]" + "\n" + "Upgrade Consul from an existing installation." + "\n" - return s + "\n" + c.help + return fmt.Sprintf("Usage: consul-k8s upgrade [flags]\n%s\n\n%s", c.Synopsis(), c.help) } +// Synopsis returns a short string describing the command. func (c *Command) Synopsis() string { - return "Upgrade Consul on Kubernetes." + return "Upgrade Consul on Kubernetes from an existing installation." +} + +// createUILogger creates a logger that will write to the UI. +func (c *Command) createUILogger() func(string, ...interface{}) { + return func(s string, args ...interface{}) { + logMsg := fmt.Sprintf(s, args...) + + if c.flagVerbose { + // Only output all logs when verbose is enabled + c.UI.Output(logMsg, terminal.WithLibraryStyle()) + } else { + // When verbose is not enabled, output all logs except not ready messages for resources + if !strings.Contains(logMsg, "not ready") { + c.UI.Output(logMsg, terminal.WithLibraryStyle()) + } + } + } +} + +// printDiff marshals both maps to YAML and prints the diff between the two. +func (c *Command) printDiff(old, new map[string]interface{}) error { + diff, err := common.Diff(old, new) + if err != nil { + return err + } + + c.UI.Output("Diff between user overrides", terminal.WithHeaderStyle()) + for _, line := range strings.Split(diff, "\n") { + if strings.HasPrefix(line, "+") { + c.UI.Output(line, terminal.WithDiffAddedStyle()) + } else if strings.HasPrefix(line, "-") { + c.UI.Output(line, terminal.WithDiffRemovedStyle()) + } else { + c.UI.Output(line, terminal.WithDiffUnchangedStyle()) + } + } + + return nil } diff --git a/cli/cmd/upgrade/upgrade_test.go b/cli/cmd/upgrade/upgrade_test.go index ab6e830259..f70496bda6 100644 --- a/cli/cmd/upgrade/upgrade_test.go +++ b/cli/cmd/upgrade/upgrade_test.go @@ -4,7 +4,7 @@ import ( "os" "testing" - "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/common" "github.com/hashicorp/go-hclog" ) diff --git a/cli/cmd/version/version.go b/cli/cmd/version/version.go index 417baaff4a..d565309b5a 100644 --- a/cli/cmd/version/version.go +++ b/cli/cmd/version/version.go @@ -4,7 +4,7 @@ import ( "fmt" "sync" - "github.com/hashicorp/consul-k8s/cli/cmd/common" + "github.com/hashicorp/consul-k8s/cli/common" ) type Command struct { diff --git a/cli/commands.go b/cli/commands.go index 17726ac5aa..681421c502 100644 --- a/cli/commands.go +++ b/cli/commands.go @@ -3,12 +3,12 @@ package main import ( "context" - "github.com/hashicorp/consul-k8s/cli/cmd/common" "github.com/hashicorp/consul-k8s/cli/cmd/install" "github.com/hashicorp/consul-k8s/cli/cmd/status" "github.com/hashicorp/consul-k8s/cli/cmd/uninstall" "github.com/hashicorp/consul-k8s/cli/cmd/upgrade" cmdversion "github.com/hashicorp/consul-k8s/cli/cmd/version" + "github.com/hashicorp/consul-k8s/cli/common" "github.com/hashicorp/consul-k8s/cli/version" "github.com/hashicorp/go-hclog" "github.com/mitchellh/cli" diff --git a/cli/cmd/common/base.go b/cli/common/base.go similarity index 94% rename from cli/cmd/common/base.go rename to cli/common/base.go index 60f0096850..81bb360267 100644 --- a/cli/cmd/common/base.go +++ b/cli/common/base.go @@ -4,7 +4,7 @@ import ( "context" "io" - "github.com/hashicorp/consul-k8s/cli/cmd/common/terminal" + "github.com/hashicorp/consul-k8s/cli/common/terminal" "github.com/hashicorp/go-hclog" ) diff --git a/cli/common/diff.go b/cli/common/diff.go new file mode 100644 index 0000000000..30d03e2968 --- /dev/null +++ b/cli/common/diff.go @@ -0,0 +1,148 @@ +package common + +import ( + "sort" + "strings" + + "github.com/google/go-cmp/cmp" + "sigs.k8s.io/yaml" +) + +// Diff returns a string representation of the difference between two maps as YAML. +// The returned string is sorted alphabetically by key. If the maps are identical, the returned string is empty. +func Diff(a, b map[string]interface{}) (string, error) { + if len(a) == 0 && len(b) == 0 { + return "", nil + } + + return diffRecursively(a, b, 0) +} + +// diffRecursively iterates over maps `a` and `b` and returns a string representation of the difference between them as YAML. +// The returned string is sorted alphabetically by key with `+` and `-` prefixed to "diffed" lines. +// `c` is a map of the default values for the chart. If a key is present in `a`, but not `b` (i.e. removed), +// the value is compared with the default value in `c` to prevent a false positive "removed" line. +func diffRecursively(a, b map[string]interface{}, recurseDepth int) (string, error) { + buf := new(strings.Builder) + + // Get the union of keys in a and b sorted alphabetically. + keys := collectKeys(a, b) + + for _, key := range keys { + valueInA, inA := a[key] + valueInB, inB := b[key] + + aMapWithKey := map[string]interface{}{ + key: valueInA, + } + bMapWithKey := map[string]interface{}{ + key: valueInB, + } + + // If the key is in both a and b, compare the values. + if inA && inB { + // If the map slices are the same, write as unchanged YAML. + if cmp.Equal(aMapWithKey, bMapWithKey) { + asYaml, err := yaml.Marshal(aMapWithKey) + if err != nil { + return "", err + } + + writeWithPrepend(" ", string(asYaml), recurseDepth, buf) + continue + } + + // If the maps are different and there is another level of depth to the map, recurse. + if !isMaxDepth(aMapWithKey) && !isMaxDepth(bMapWithKey) { + writeWithPrepend(" ", key+":", recurseDepth, buf) + + childDiff, err := diffRecursively(valueInA.(map[string]interface{}), valueInB.(map[string]interface{}), recurseDepth+1) + if err != nil { + return "", err + } + + buf.WriteString(childDiff) + + continue + } + + // If the map slices are different and there is no other level of depth to the map, write as changed YAML. + aSliceAsYaml, err := yaml.Marshal(aMapWithKey) + if err != nil { + return "", err + } + + bSliceAsYaml, err := yaml.Marshal(bMapWithKey) + if err != nil { + return "", err + } + + writeWithPrepend("- ", string(aSliceAsYaml), recurseDepth, buf) + writeWithPrepend("+ ", string(bSliceAsYaml), recurseDepth, buf) + } + + // If the key is in `a` but not in `b`, write as removed unless `a` matches the value in `c`. + if inA && !inB { + asYaml, err := yaml.Marshal(aMapWithKey) + if err != nil { + return "", err + } + + writeWithPrepend("- ", string(asYaml), recurseDepth, buf) + continue + } + + // If the key is in b but not in a, write as added. + if !inA && inB { + asYaml, err := yaml.Marshal(bMapWithKey) + if err != nil { + return "", err + } + + writeWithPrepend("+ ", string(asYaml), recurseDepth, buf) + continue + } + } + + return buf.String(), nil +} + +// collectKeys iterates over both maps and collects all keys sorted alphabetically, ignoring duplicates. +func collectKeys(a, b map[string]interface{}) []string { + keys := make([]string, 0, len(a)+len(b)) + for key := range a { + keys = append(keys, key) + } + for key := range b { + if _, ok := a[key]; !ok { + keys = append(keys, key) + } + } + + sort.Strings(keys) + return keys +} + +// writeWithPrepend writes each line to the buffer with the given prefix and indentation matching the recurse depth. +func writeWithPrepend(prepend, text string, recurseDepth int, buf *strings.Builder) { + lines := strings.Split(strings.TrimSpace(text), "\n") + for _, line := range lines { + buf.WriteString(prepend) + for i := 0; i < recurseDepth; i++ { + buf.WriteString(" ") + } + buf.WriteString(line) + buf.WriteString("\n") + } +} + +// isMaxDepth returns false if any of the values in the map are maps. +func isMaxDepth(m map[string]interface{}) bool { + for _, value := range m { + if _, ok := value.(map[string]interface{}); ok { + return false + } + } + + return true +} diff --git a/cli/common/diff_test.go b/cli/common/diff_test.go new file mode 100644 index 0000000000..31563e0b6b --- /dev/null +++ b/cli/common/diff_test.go @@ -0,0 +1,171 @@ +package common + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestDiff(t *testing.T) { + type args struct { + a map[string]interface{} + b map[string]interface{} + } + + tests := []struct { + name string + args args + expected string + }{ + { + name: "Two empty maps should return an empty string", + args: args{ + a: map[string]interface{}{}, + b: map[string]interface{}{}, + }, + expected: "", + }, + { + name: "Two equal maps should return the map parsed as YAML", + args: args{ + a: map[string]interface{}{ + "foo": "bar", + "baz": "qux", + "liz": map[string]interface{}{"qux": []string{"quux", "quuz"}}, + }, + b: map[string]interface{}{ + "foo": "bar", + "baz": "qux", + "liz": map[string]interface{}{"qux": []string{"quux", "quuz"}}, + }, + }, + expected: " baz: qux\n foo: bar\n liz:\n qux:\n - quux\n - quuz\n", + }, + { + name: "New elements should be prefixed with a plus sign", + args: args{ + a: map[string]interface{}{ + "foo": "bar", + }, + b: map[string]interface{}{ + "foo": "bar", + "baz": "qux", + }, + }, + expected: "+ baz: qux\n foo: bar\n", + }, + { + name: "New non-string elements should be prefixed with a plus sign", + args: args{ + a: map[string]interface{}{ + "foo": "bar", + }, + b: map[string]interface{}{ + "foo": "bar", + "baz": []string{"qux"}, + "qux": map[string]string{ + "quux": "corge", + }, + }, + }, + expected: "+ baz:\n+ - qux\n foo: bar\n+ qux:\n+ quux: corge\n", + }, + { + name: "Deleted elements should be prefixed with a minus sign", + args: args{ + a: map[string]interface{}{ + "foo": "bar", + "baz": "qux", + }, + b: map[string]interface{}{ + "foo": "bar", + }, + }, + expected: "- baz: qux\n foo: bar\n", + }, + { + name: "Deleted non-string elements should be prefixed with a minus sign", + args: args{ + a: map[string]interface{}{ + "foo": "bar", + "baz": []string{"qux"}, + "qux": map[string]string{ + "quux": "corge", + }, + }, + b: map[string]interface{}{ + "foo": "bar", + }, + }, + expected: "- baz:\n- - qux\n foo: bar\n- qux:\n- quux: corge\n", + }, + { + name: "Diff between two complex maps should be correct", + args: args{ + a: map[string]interface{}{ + "global": map[string]interface{}{ + "name": "consul", + "metrics": map[string]interface{}{ + "enabled": true, + "enableAgentMetrics": true, + }, + }, + "connectInject": map[string]interface{}{ + "enabled": true, + "metrics": map[string]interface{}{ + "defaultEnabled": true, + "defaultEnableMerging": true, + "enableGatewayMetrics": true, + }, + }, + "server": map[string]interface{}{ + "replicas": 1, + }, + "controller": map[string]interface{}{ + "enabled": true, + }, + "ui": map[string]interface{}{ + "enabled": true, + "service": map[string]interface{}{ + "enabled": true, + }, + }, + "prometheus": map[string]interface{}{ + "enabled": true, + }, + }, + b: map[string]interface{}{ + "global": map[string]interface{}{ + "name": "consul", + "gossipEncryption": map[string]interface{}{ + "autoGenerate": true, + }, + "tls": map[string]interface{}{ + "enabled": true, + "enableAutoEncrypt": true, + }, + "acls": map[string]interface{}{ + "manageSystemACLs": true, + }, + }, + "server": map[string]interface{}{"replicas": 1}, + "connectInject": map[string]interface{}{ + "enabled": true, + }, + "controller": map[string]interface{}{ + "enabled": true, + }, + }, + }, + expected: " connectInject:\n enabled: true\n- metrics:\n- defaultEnableMerging: true\n- defaultEnabled: true\n- enableGatewayMetrics: true\n controller:\n enabled: true\n global:\n+ acls:\n+ manageSystemACLs: true\n+ gossipEncryption:\n+ autoGenerate: true\n- metrics:\n- enableAgentMetrics: true\n- enabled: true\n name: consul\n+ tls:\n+ enableAutoEncrypt: true\n+ enabled: true\n- prometheus:\n- enabled: true\n server:\n replicas: 1\n- ui:\n- enabled: true\n- service:\n- enabled: true\n", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actual, err := Diff(tt.args.a, tt.args.b) + require.NoError(t, err) + require.Equal(t, tt.expected, actual) + }) + } +} diff --git a/cli/cmd/common/flag/doc.go b/cli/common/flag/doc.go similarity index 100% rename from cli/cmd/common/flag/doc.go rename to cli/common/flag/doc.go diff --git a/cli/cmd/common/flag/flag.go b/cli/common/flag/flag.go similarity index 100% rename from cli/cmd/common/flag/flag.go rename to cli/common/flag/flag.go diff --git a/cli/cmd/common/flag/flag_bool.go b/cli/common/flag/flag_bool.go similarity index 100% rename from cli/cmd/common/flag/flag_bool.go rename to cli/common/flag/flag_bool.go diff --git a/cli/cmd/common/flag/flag_enum.go b/cli/common/flag/flag_enum.go similarity index 100% rename from cli/cmd/common/flag/flag_enum.go rename to cli/common/flag/flag_enum.go diff --git a/cli/cmd/common/flag/flag_enum_single.go b/cli/common/flag/flag_enum_single.go similarity index 100% rename from cli/cmd/common/flag/flag_enum_single.go rename to cli/common/flag/flag_enum_single.go diff --git a/cli/cmd/common/flag/flag_float.go b/cli/common/flag/flag_float.go similarity index 100% rename from cli/cmd/common/flag/flag_float.go rename to cli/common/flag/flag_float.go diff --git a/cli/cmd/common/flag/flag_int.go b/cli/common/flag/flag_int.go similarity index 100% rename from cli/cmd/common/flag/flag_int.go rename to cli/common/flag/flag_int.go diff --git a/cli/cmd/common/flag/flag_string.go b/cli/common/flag/flag_string.go similarity index 100% rename from cli/cmd/common/flag/flag_string.go rename to cli/common/flag/flag_string.go diff --git a/cli/cmd/common/flag/flag_string_map.go b/cli/common/flag/flag_string_map.go similarity index 100% rename from cli/cmd/common/flag/flag_string_map.go rename to cli/common/flag/flag_string_map.go diff --git a/cli/cmd/common/flag/flag_string_slice.go b/cli/common/flag/flag_string_slice.go similarity index 100% rename from cli/cmd/common/flag/flag_string_slice.go rename to cli/common/flag/flag_string_slice.go diff --git a/cli/cmd/common/flag/flag_string_slice_test.go b/cli/common/flag/flag_string_slice_test.go similarity index 100% rename from cli/cmd/common/flag/flag_string_slice_test.go rename to cli/common/flag/flag_string_slice_test.go diff --git a/cli/cmd/common/flag/flag_time.go b/cli/common/flag/flag_time.go similarity index 100% rename from cli/cmd/common/flag/flag_time.go rename to cli/common/flag/flag_time.go diff --git a/cli/cmd/common/flag/flag_var.go b/cli/common/flag/flag_var.go similarity index 100% rename from cli/cmd/common/flag/flag_var.go rename to cli/common/flag/flag_var.go diff --git a/cli/cmd/common/flag/set.go b/cli/common/flag/set.go similarity index 100% rename from cli/cmd/common/flag/set.go rename to cli/common/flag/set.go diff --git a/cli/cmd/common/flag/set_test.go b/cli/common/flag/set_test.go similarity index 100% rename from cli/cmd/common/flag/set_test.go rename to cli/common/flag/set_test.go diff --git a/cli/cmd/common/terminal/basic.go b/cli/common/terminal/basic.go similarity index 94% rename from cli/cmd/common/terminal/basic.go rename to cli/common/terminal/basic.go index 37562d7598..2425b2d53c 100644 --- a/cli/cmd/common/terminal/basic.go +++ b/cli/common/terminal/basic.go @@ -93,6 +93,12 @@ func (ui *basicUI) Output(msg string, raw ...interface{}) { msg = colorSuccessBold.Sprintf(" ✓ %s", msg) case LibraryStyle: msg = colorLibrary.Sprintf(" --> %s", msg) + case DiffUnchangedStyle: + msg = colorDiffUnchanged.Sprintf(" %s", msg) + case DiffAddedStyle: + msg = colorDiffAdded.Sprintf(" %s", msg) + case DiffRemovedStyle: + msg = colorDiffRemoved.Sprintf(" %s", msg) case InfoStyle: lines := strings.Split(msg, "\n") for i, line := range lines { diff --git a/cli/cmd/common/terminal/doc.go b/cli/common/terminal/doc.go similarity index 100% rename from cli/cmd/common/terminal/doc.go rename to cli/common/terminal/doc.go diff --git a/cli/cmd/common/terminal/table.go b/cli/common/terminal/table.go similarity index 100% rename from cli/cmd/common/terminal/table.go rename to cli/common/terminal/table.go diff --git a/cli/cmd/common/terminal/ui.go b/cli/common/terminal/ui.go similarity index 72% rename from cli/cmd/common/terminal/ui.go rename to cli/common/terminal/ui.go index 38922d6399..e7d938a408 100644 --- a/cli/cmd/common/terminal/ui.go +++ b/cli/common/terminal/ui.go @@ -92,15 +92,18 @@ func Interpret(msg string, raw ...interface{}) (string, string, io.Writer) { } const ( - HeaderStyle = "header" - ErrorStyle = "error" - ErrorBoldStyle = "error-bold" - WarningStyle = "warning" - WarningBoldStyle = "warning-bold" - InfoStyle = "info" - LibraryStyle = "library" - SuccessStyle = "success" - SuccessBoldStyle = "success-bold" + HeaderStyle = "header" + ErrorStyle = "error" + ErrorBoldStyle = "error-bold" + WarningStyle = "warning" + WarningBoldStyle = "warning-bold" + InfoStyle = "info" + LibraryStyle = "library" + SuccessStyle = "success" + SuccessBoldStyle = "success-bold" + DiffUnchangedStyle = "diff-unchanged" + DiffAddedStyle = "diff-added" + DiffRemovedStyle = "diff-removed" ) type config struct { @@ -137,7 +140,7 @@ func WithErrorStyle() Option { } } -// WithWarningStyle styles the output as an error message. +// WithWarningStyle styles the output as an warning message. func WithWarningStyle() Option { return func(c *config) { c.Style = WarningStyle @@ -151,13 +154,35 @@ func WithSuccessStyle() Option { } } -// WithLibraryStyle styles the output as a success message. +// WithLibraryStyle styles the output with an arrow pointing to a section. func WithLibraryStyle() Option { return func(c *config) { c.Style = LibraryStyle } } +// WithDiffUnchangedStyle colors the diff style in white. +func WithDiffUnchangedStyle() Option { + return func(c *config) { + c.Style = DiffUnchangedStyle + } +} + +// WithDiffAddedStyle colors the output in green. +func WithDiffAddedStyle() Option { + return func(c *config) { + c.Style = DiffAddedStyle + } +} + +// WithDiffRemovedStyle colors the output in red. +func WithDiffRemovedStyle() Option { + return func(c *config) { + c.Style = DiffRemovedStyle + } +} + +// WithStyle allows for setting a style by passing a string. func WithStyle(style string) Option { return func(c *config) { c.Style = style @@ -170,13 +195,16 @@ func WithWriter(w io.Writer) Option { } var ( - colorHeader = color.New(color.Bold) - colorInfo = color.New() - colorError = color.New(color.FgRed) - colorErrorBold = color.New(color.FgRed, color.Bold) - colorLibrary = color.New(color.FgCyan) - colorSuccess = color.New(color.FgGreen) - colorSuccessBold = color.New(color.FgGreen, color.Bold) - colorWarning = color.New(color.FgYellow) - colorWarningBold = color.New(color.FgYellow, color.Bold) + colorHeader = color.New(color.Bold) + colorInfo = color.New() + colorError = color.New(color.FgRed) + colorErrorBold = color.New(color.FgRed, color.Bold) + colorLibrary = color.New(color.FgCyan) + colorSuccess = color.New(color.FgGreen) + colorSuccessBold = color.New(color.FgGreen, color.Bold) + colorWarning = color.New(color.FgYellow) + colorWarningBold = color.New(color.FgYellow, color.Bold) + colorDiffUnchanged = color.New() + colorDiffAdded = color.New(color.FgGreen) + colorDiffRemoved = color.New(color.FgRed) ) diff --git a/cli/cmd/common/usage.go b/cli/common/usage.go similarity index 100% rename from cli/cmd/common/usage.go rename to cli/common/usage.go diff --git a/cli/common/utils.go b/cli/common/utils.go new file mode 100644 index 0000000000..3d7df71433 --- /dev/null +++ b/cli/common/utils.go @@ -0,0 +1,108 @@ +package common + +import ( + "errors" + "fmt" + "os" + "strings" + + "helm.sh/helm/v3/pkg/action" + helmCLI "helm.sh/helm/v3/pkg/cli" +) + +const ( + DefaultReleaseName = "consul" + DefaultReleaseNamespace = "consul" + TopLevelChartDirName = "consul" + + // CLILabelKey and CLILabelValue are added to each secret on creation so the CLI knows + // which key to delete on an uninstall. + CLILabelKey = "managed-by" + CLILabelValue = "consul-k8s" +) + +// Abort returns true if the raw input string is not equal to "y" or "yes". +func Abort(raw string) bool { + confirmation := strings.TrimSuffix(raw, "\n") + return !(strings.ToLower(confirmation) == "y" || strings.ToLower(confirmation) == "yes") +} + +// CheckForInstallations uses the helm Go SDK to find helm releases in all namespaces where the chart name is +// "consul", and returns the release name and namespace if found, or an error if not found. +func CheckForInstallations(settings *helmCLI.EnvSettings, uiLogger action.DebugLog) (string, string, error) { + // Need a specific action config to call helm list, where namespace is NOT specified. + listConfig := new(action.Configuration) + if err := listConfig.Init(settings.RESTClientGetter(), "", + os.Getenv("HELM_DRIVER"), uiLogger); err != nil { + return "", "", fmt.Errorf("couldn't initialize helm config: %s", err) + } + + lister := action.NewList(listConfig) + lister.AllNamespaces = true + lister.StateMask = action.ListAll + res, err := lister.Run() + if err != nil { + return "", "", fmt.Errorf("couldn't check for installations: %s", err) + } + + for _, rel := range res { + if rel.Chart.Metadata.Name == "consul" { + return rel.Name, rel.Namespace, nil + } + } + return "", "", errors.New("couldn't find consul installation") +} + +// MergeMaps merges two maps giving b precedent. +// @source: https://github.com/helm/helm/blob/main/pkg/cli/values/options.go +func MergeMaps(a, b map[string]interface{}) map[string]interface{} { + out := make(map[string]interface{}, len(a)) + for k, v := range a { + out[k] = v + } + for k, v := range b { + if v, ok := v.(map[string]interface{}); ok { + if bv, ok := out[k]; ok { + if bv, ok := bv.(map[string]interface{}); ok { + out[k] = MergeMaps(bv, v) + continue + } + } + } + out[k] = v + } + return out +} + +func CloseWithError(c *BaseCommand) { + if err := c.Close(); err != nil { + c.Log.Error(err.Error()) + os.Exit(1) + } +} + +// IsValidLabel checks if a given label conforms to RFC 1123 https://datatracker.ietf.org/doc/html/rfc1123. +// This standard requires that the label begins and ends with an alphanumeric character, does not exceed 63 characters, +// and contains only alphanumeric characters and '-'. +func IsValidLabel(label string) bool { + if len(label) > 63 || len(label) == 0 { + return false + } + + for i, c := range label { + isAlphaNumeric := c >= '0' && c <= '9' || c >= 'a' && c <= 'z' + isTerminal := i == 0 || i == len(label)-1 + + // First and last character must be alphanumeric. + if isTerminal && !isAlphaNumeric { + return false + } + + // All other characters must be alphanumeric or '-'. + if !isAlphaNumeric && c != '-' { + return false + } + } + + return true +} diff --git a/cli/common/utils_test.go b/cli/common/utils_test.go new file mode 100644 index 0000000000..c15397e4a3 --- /dev/null +++ b/cli/common/utils_test.go @@ -0,0 +1,67 @@ +package common + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMergeMaps(t *testing.T) { + cases := map[string]struct { + a map[string]interface{} + b map[string]interface{} + expected map[string]interface{} + }{ + "a is empty": { + a: map[string]interface{}{}, + b: map[string]interface{}{"foo": "bar"}, + expected: map[string]interface{}{"foo": "bar"}, + }, + "b is empty": { + a: map[string]interface{}{"foo": "bar"}, + b: map[string]interface{}{}, + expected: map[string]interface{}{"foo": "bar"}, + }, + "b overrides a": { + a: map[string]interface{}{"foo": "bar"}, + b: map[string]interface{}{"foo": "baz"}, + expected: map[string]interface{}{"foo": "baz"}, + }, + "b partially overrides a": { + a: map[string]interface{}{"foo": "bar", "baz": "qux"}, + b: map[string]interface{}{"foo": "baz"}, + expected: map[string]interface{}{"foo": "baz", "baz": "qux"}, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + actual := MergeMaps(tc.a, tc.b) + require.Equal(t, tc.expected, actual) + }) + } +} + +func TestIsValidLabel(t *testing.T) { + cases := []struct { + name string + label string + expected bool + }{ + {"Valid label", "such-a-good-label", true}, + {"Valid label with leading numbers", "123-such-a-good-label", true}, + {"Invalid label empty", "", false}, + {"Invalid label contains capital letters", "Peppertrout", false}, + {"Invalid label contains underscores", "this_is_not_python", false}, + {"Invalid label too long", "a-very-very-very-long-label-that-is-more-than-63-characters-long", false}, + {"Invalid label starts with a dash", "-invalid-label", false}, + {"Invalid label ends with a dash", "invalid-label-", false}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + actual := IsValidLabel(tc.label) + require.Equal(t, tc.expected, actual) + }) + } +} diff --git a/cli/go.mod b/cli/go.mod index 5bab90cae6..fa8cdf886a 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -6,6 +6,7 @@ require ( github.com/bgentry/speakeasy v0.1.0 github.com/cenkalti/backoff v2.2.1+incompatible github.com/fatih/color v1.9.0 + github.com/google/go-cmp v0.5.5 github.com/hashicorp/consul-k8s/charts v0.0.0-00010101000000-000000000000 github.com/hashicorp/go-hclog v0.16.2 github.com/kr/text v0.2.0 @@ -15,21 +16,21 @@ require ( github.com/posener/complete v1.1.1 github.com/stretchr/testify v1.7.0 helm.sh/helm/v3 v3.6.1 - k8s.io/api v0.21.2 - k8s.io/apimachinery v0.21.2 + k8s.io/api v0.22.2 + k8s.io/apimachinery v0.22.2 k8s.io/cli-runtime v0.21.0 - k8s.io/client-go v0.21.2 + k8s.io/client-go v0.22.2 sigs.k8s.io/yaml v1.2.0 ) require ( cloud.google.com/go v0.54.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.12 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.5 // indirect + github.com/Azure/go-autorest/autorest v0.11.18 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect - github.com/Azure/go-autorest/logger v0.2.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/BurntSushi/toml v0.3.1 // indirect github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect @@ -60,41 +61,40 @@ require ( github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916 // indirect github.com/docker/go-units v0.4.0 // indirect - github.com/evanphx/json-patch v4.9.0+incompatible // indirect + github.com/evanphx/json-patch v4.11.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect - github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect + github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect github.com/go-errors/errors v1.0.1 // indirect github.com/go-logr/logr v0.4.0 // indirect github.com/go-openapi/jsonpointer v0.19.3 // indirect github.com/go-openapi/jsonreference v0.19.3 // indirect github.com/go-openapi/spec v0.19.5 // indirect - github.com/go-openapi/swag v0.19.5 // indirect + github.com/go-openapi/swag v0.19.14 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/btree v1.0.0 // indirect - github.com/google/go-cmp v0.5.5 // indirect + github.com/google/btree v1.0.1 // indirect github.com/google/gofuzz v1.1.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.1.2 // indirect - github.com/googleapis/gnostic v0.4.1 // indirect + github.com/googleapis/gnostic v0.5.5 // indirect github.com/gorilla/mux v1.7.3 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.0 // indirect - github.com/hashicorp/golang-lru v0.5.1 // indirect github.com/huandu/xstrings v1.3.2 // indirect github.com/imdario/mergo v0.3.11 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmoiron/sqlx v1.3.1 // indirect - github.com/json-iterator/go v1.1.10 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.11 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/lib/pq v1.10.0 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect - github.com/mailru/easyjson v0.7.0 // indirect + github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-runewidth v0.0.7 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect @@ -102,7 +102,7 @@ require ( github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect + github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect @@ -113,10 +113,10 @@ require ( github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.7.1 // indirect + github.com/prometheus/client_golang v1.11.0 // indirect github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.10.0 // indirect - github.com/prometheus/procfs v0.2.0 // indirect + github.com/prometheus/common v0.26.0 // indirect + github.com/prometheus/procfs v0.6.0 // indirect github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351 // indirect github.com/russross/blackfriday v1.5.2 // indirect github.com/shopspring/decimal v1.2.0 // indirect @@ -137,7 +137,7 @@ require ( golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect golang.org/x/text v0.3.6 // indirect - golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect + golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect google.golang.org/appengine v1.6.5 // indirect google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect google.golang.org/grpc v1.33.1 // indirect @@ -145,18 +145,18 @@ require ( gopkg.in/gorp.v1 v1.7.2 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect k8s.io/apiextensions-apiserver v0.21.0 // indirect k8s.io/apiserver v0.21.0 // indirect k8s.io/component-base v0.21.0 // indirect - k8s.io/klog/v2 v2.8.0 // indirect - k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 // indirect + k8s.io/klog/v2 v2.9.0 // indirect + k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect k8s.io/kubectl v0.21.0 // indirect - k8s.io/utils v0.0.0-20201110183641-67b214c5f920 // indirect + k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a // indirect rsc.io/letsencrypt v0.0.3 // indirect sigs.k8s.io/kustomize/api v0.8.5 // indirect sigs.k8s.io/kustomize/kyaml v0.10.15 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect ) // This replace directive is to avoid having to manually bump the version of the charts module upon changes to the Helm diff --git a/cli/go.sum b/cli/go.sum index e80ec5eba6..d6ada483c0 100644 --- a/cli/go.sum +++ b/cli/go.sum @@ -25,21 +25,26 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE= github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= -github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= +github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= +github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= +github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= -github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= +github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= @@ -88,6 +93,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -223,19 +229,22 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7 h1:LofdAjjjqCSXMwLGgOgnE+rdPuvX9DxCqaHwKy7i/ko= @@ -252,6 +261,7 @@ github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -299,8 +309,9 @@ github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= +github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= @@ -337,8 +348,9 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -363,8 +375,9 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -392,8 +405,10 @@ github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo= @@ -436,14 +451,12 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= @@ -464,15 +477,20 @@ github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXL github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -507,8 +525,9 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= @@ -557,8 +576,9 @@ github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY7 github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -572,6 +592,7 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= @@ -583,6 +604,8 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -594,12 +617,16 @@ github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FW github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -647,8 +674,9 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -663,8 +691,9 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -672,8 +701,9 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -732,6 +762,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -885,9 +916,12 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -929,6 +963,7 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -936,6 +971,7 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -949,6 +985,7 @@ golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -959,8 +996,8 @@ golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= -golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= @@ -979,8 +1016,9 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1073,6 +1111,7 @@ google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -1113,7 +1152,6 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gorp.v1 v1.7.2 h1:j3DWlAyGVv8whO7AcIWznQ2Yj7yJkn34B8s63GViAAw= @@ -1137,8 +1175,10 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= @@ -1154,20 +1194,20 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU= -k8s.io/api v0.21.2 h1:vz7DqmRsXTCSa6pNxXwQ1IYeAZgdIsua+DZU+o+SX3Y= -k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU= +k8s.io/api v0.22.2 h1:M8ZzAD0V6725Fjg53fKeTJxGsJvRbk4TEm/fexHMtfw= +k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8= k8s.io/apiextensions-apiserver v0.21.0 h1:Nd4uBuweg6ImzbxkC1W7xUNZcCV/8Vt10iTdTIVF3hw= k8s.io/apiextensions-apiserver v0.21.0/go.mod h1:gsQGNtGkc/YoDG9loKI0V+oLZM4ljRPjc/sql5tmvzc= k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= -k8s.io/apimachinery v0.21.2 h1:vezUc/BHqWlQDnZ+XkrpXSmnANSLbpnlpwo0Lhk0gpc= -k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM= +k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= +k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apiserver v0.21.0 h1:1hWMfsz+cXxB77k6/y0XxWxwl6l9OF26PC9QneUVn1Q= k8s.io/apiserver v0.21.0/go.mod h1:w2YSn4/WIwYuxG5zJmcqtRdtqgW/J2JRgFAqps3bBpg= k8s.io/cli-runtime v0.21.0 h1:/V2Kkxtf6x5NI2z+Sd/mIrq4FQyQ8jzZAUD6N5RnN7Y= k8s.io/cli-runtime v0.21.0/go.mod h1:XoaHP93mGPF37MkLbjGVYqg3S1MnsFdKtiA/RZzzxOo= k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA= -k8s.io/client-go v0.21.2 h1:Q1j4L/iMN4pTw6Y4DWppBoUxgKO8LbffEMVEV00MUp0= -k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA= +k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= +k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= k8s.io/code-generator v0.21.0/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= k8s.io/component-base v0.21.0 h1:tLLGp4BBjQaCpS/KiuWh7m2xqvAdsxLm4ATxHSe5Zpg= k8s.io/component-base v0.21.0/go.mod h1:qvtjz6X0USWXbgmbfXR+Agik4RZ3jv2Bgr5QnZzdPYw= @@ -1176,15 +1216,18 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= +k8s.io/klog/v2 v2.9.0 h1:D7HV+n1V57XeZ0m6tdRkfknthUaM06VFbWldOFh8kzM= +k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= +k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kubectl v0.21.0 h1:WZXlnG/yjcE4LWO2g6ULjFxtzK6H1TKzsfaBFuVIhNg= k8s.io/kubectl v0.21.0/go.mod h1:EU37NukZRXn1TpAkMUoy8Z/B2u6wjHDS4aInsDzVvks= k8s.io/metrics v0.21.0/go.mod h1:L3Ji9EGPP1YBbfm9sPfEXSpnj8i24bfQbAFAsW0NueQ= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= +k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/letsencrypt v0.0.3 h1:H7xDfhkaFFSYEJlKeq38RwX2jYcnTeHuDQyT+mMNMwM= rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= @@ -1198,8 +1241,9 @@ sigs.k8s.io/kustomize/kustomize/v4 v4.0.5/go.mod h1:C7rYla7sI8EnxHE/xEhRBSHMNfcL sigs.k8s.io/kustomize/kyaml v0.10.15 h1:dSLgG78KyaxN4HylPXdK+7zB3k7sW6q3IcCmcfKA+aI= sigs.k8s.io/kustomize/kyaml v0.10.15/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/cli/helm/action.go b/cli/helm/action.go new file mode 100644 index 0000000000..c4d9de9650 --- /dev/null +++ b/cli/helm/action.go @@ -0,0 +1,24 @@ +package helm + +import ( + "fmt" + "os" + + "helm.sh/helm/v3/pkg/action" + helmCLI "helm.sh/helm/v3/pkg/cli" + "k8s.io/cli-runtime/pkg/genericclioptions" +) + +// InitActionConfig initializes a Helm Go SDK action configuration. This function currently uses a hack to override the +// namespace field that gets set in the K8s client set up by the SDK. +func InitActionConfig(actionConfig *action.Configuration, namespace string, settings *helmCLI.EnvSettings, logger action.DebugLog) (*action.Configuration, error) { + getter := settings.RESTClientGetter() + configFlags := getter.(*genericclioptions.ConfigFlags) + configFlags.Namespace = &namespace + err := actionConfig.Init(settings.RESTClientGetter(), namespace, + os.Getenv("HELM_DRIVER"), logger) + if err != nil { + return nil, fmt.Errorf("error setting up helm action configuration to find existing installations: %s", err) + } + return actionConfig, nil +} diff --git a/cli/helm/chart.go b/cli/helm/chart.go new file mode 100644 index 0000000000..3558e688ca --- /dev/null +++ b/cli/helm/chart.go @@ -0,0 +1,98 @@ +package helm + +import ( + "embed" + "path/filepath" + + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" + helmCLI "helm.sh/helm/v3/pkg/cli" +) + +const ( + chartFileName = "Chart.yaml" + valuesFileName = "values.yaml" + templatesDirName = "templates" +) + +// LoadChart will attempt to load a chart from the embedded file system. +func LoadChart(chart embed.FS, chartDirName string) (*chart.Chart, error) { + chartFiles, err := ReadChartFiles(chart, chartDirName) + if err != nil { + return nil, err + } + + return loader.LoadFiles(chartFiles) +} + +// ReadChartFiles reads the chart files from the embedded file system, and loads their contents into +// []*loader.BufferedFile. This is a format that the Helm Go SDK functions can read from to create a chart to install +// from. The names of these files are important, as there are case statements in the Helm Go SDK looking for files named +// "Chart.yaml" or "templates/.yaml", which is why even though the embedded file system has them named +// "consul/Chart.yaml" we have to strip the "consul" prefix out, which is done by the call to the helper method readFile. +func ReadChartFiles(chart embed.FS, chartDirName string) ([]*loader.BufferedFile, error) { + var chartFiles []*loader.BufferedFile + + // Load Chart.yaml and values.yaml first. + for _, f := range []string{chartFileName, valuesFileName} { + file, err := readFile(chart, filepath.Join(chartDirName, f), chartDirName) + if err != nil { + return nil, err + } + chartFiles = append(chartFiles, file) + } + + // Now load everything under templates/. + dirs, err := chart.ReadDir(filepath.Join(chartDirName, templatesDirName)) + if err != nil { + return nil, err + } + for _, f := range dirs { + if f.IsDir() { + // We only need to include files in the templates directory. + continue + } + + file, err := readFile(chart, filepath.Join(chartDirName, templatesDirName, f.Name()), chartDirName) + if err != nil { + return nil, err + } + chartFiles = append(chartFiles, file) + } + + return chartFiles, nil +} + +// FetchChartValues will attempt to fetch the values from the currently installed Helm chart. +func FetchChartValues(namespace string, settings *helmCLI.EnvSettings, uiLogger action.DebugLog) (map[string]interface{}, error) { + cfg := new(action.Configuration) + cfg, err := InitActionConfig(cfg, namespace, settings, uiLogger) + if err != nil { + return nil, err + } + + status := action.NewStatus(cfg) + release, err := status.Run(namespace) + if err != nil { + return nil, err + } + + return release.Config, nil +} + +func readFile(chart embed.FS, f string, pathPrefix string) (*loader.BufferedFile, error) { + bytes, err := chart.ReadFile(f) + if err != nil { + return nil, err + } + // Remove the path prefix. + rel, err := filepath.Rel(pathPrefix, f) + if err != nil { + return nil, err + } + return &loader.BufferedFile{ + Name: rel, + Data: bytes, + }, nil +} diff --git a/cli/helm/chart_test.go b/cli/helm/chart_test.go new file mode 100644 index 0000000000..1bed8bbdbe --- /dev/null +++ b/cli/helm/chart_test.go @@ -0,0 +1,56 @@ +package helm + +import ( + "embed" + "testing" + + "github.com/stretchr/testify/require" +) + +// Embed a test chart to test against. +//go:embed fixtures/consul/* fixtures/consul/templates/_helpers.tpl +var testChartFiles embed.FS + +func TestLoadChart(t *testing.T) { + directory := "fixtures/consul" + + expectedApiVersion := "v2" + expectedName := "Foo" + expectedVersion := "0.1.0" + expectedDescription := "Mock Helm Chart for testing." + expectedValues := map[string]interface{}{ + "key": "value", + } + + actual, err := LoadChart(testChartFiles, directory) + require.NoError(t, err) + require.Equal(t, expectedApiVersion, actual.Metadata.APIVersion) + require.Equal(t, expectedName, actual.Metadata.Name) + require.Equal(t, expectedVersion, actual.Metadata.Version) + require.Equal(t, expectedDescription, actual.Metadata.Description) + require.Equal(t, expectedValues, actual.Values) +} + +func TestReadChartFiles(t *testing.T) { + directory := "fixtures/consul" + expectedFiles := map[string]string{ + "Chart.yaml": "# This is a mock Helm Chart.yaml file used for testing.\napiVersion: v2\nname: Foo\nversion: 0.1.0\ndescription: Mock Helm Chart for testing.", + "values.yaml": "# This is a mock Helm values.yaml file used for testing.\nkey: value", + "templates/_helpers.tpl": "helpers", + "templates/foo.yaml": "foo: bar\n", + } + + files, err := ReadChartFiles(testChartFiles, directory) + require.NoError(t, err) + + actualFiles := make(map[string]string, len(files)) + for _, f := range files { + actualFiles[f.Name] = string(f.Data) + } + + for expectedName, expectedContents := range expectedFiles { + actualContents, ok := actualFiles[expectedName] + require.True(t, ok, "Expected file %s not found", expectedName) + require.Equal(t, expectedContents, actualContents) + } +} diff --git a/cli/helm/fixtures/consul/Chart.yaml b/cli/helm/fixtures/consul/Chart.yaml new file mode 100644 index 0000000000..72cdfea793 --- /dev/null +++ b/cli/helm/fixtures/consul/Chart.yaml @@ -0,0 +1,5 @@ +# This is a mock Helm Chart.yaml file used for testing. +apiVersion: v2 +name: Foo +version: 0.1.0 +description: Mock Helm Chart for testing. \ No newline at end of file diff --git a/cli/cmd/common/fixtures/consul/templates/_helpers.tpl b/cli/helm/fixtures/consul/templates/_helpers.tpl similarity index 100% rename from cli/cmd/common/fixtures/consul/templates/_helpers.tpl rename to cli/helm/fixtures/consul/templates/_helpers.tpl diff --git a/cli/helm/fixtures/consul/templates/foo.yaml b/cli/helm/fixtures/consul/templates/foo.yaml new file mode 100644 index 0000000000..20e9ff3fea --- /dev/null +++ b/cli/helm/fixtures/consul/templates/foo.yaml @@ -0,0 +1 @@ +foo: bar diff --git a/cli/helm/fixtures/consul/values.yaml b/cli/helm/fixtures/consul/values.yaml new file mode 100644 index 0000000000..e8062923bc --- /dev/null +++ b/cli/helm/fixtures/consul/values.yaml @@ -0,0 +1,2 @@ +# This is a mock Helm values.yaml file used for testing. +key: value \ No newline at end of file From 505bf65c9e0acf335276c707b04748d167526412 Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Wed, 26 Jan 2022 14:17:11 -0500 Subject: [PATCH 242/418] add token tests for api gateway controller --- .../api-gateway-controller-deployment.bats | 12 ----- charts/consul/values.yaml | 7 +++ .../server-acl-init/command_test.go | 21 ++++++--- .../subcommand/server-acl-init/rules.go | 19 ++++---- .../subcommand/server-acl-init/rules_test.go | 46 +++++++++++++++++++ 5 files changed, 77 insertions(+), 28 deletions(-) diff --git a/charts/consul/test/unit/api-gateway-controller-deployment.bats b/charts/consul/test/unit/api-gateway-controller-deployment.bats index 52769e3328..434c7dbd7b 100755 --- a/charts/consul/test/unit/api-gateway-controller-deployment.bats +++ b/charts/consul/test/unit/api-gateway-controller-deployment.bats @@ -20,18 +20,6 @@ load _helpers [[ "$output" =~ "apiGateway.image must be set to enable api gateway" ]] } -@test "apiGateway/Deployment: enable with global.enabled false, apiGateway.enabled true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/api-gateway-controller-deployment.yaml \ - --set 'global.enabled=false' \ - --set 'apiGateway.enabled=true' \ - --set 'apiGateway.image=foo' \ - . | tee /dev/stderr | - yq 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - @test "apiGateway/Deployment: disable with apiGateway.enabled" { cd `chart_dir` assert_empty helm template \ diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index aa4924d9fa..a406b54e22 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2471,6 +2471,7 @@ apiGateway: # @type: string logLevel: info + # Configuration settings for the optional GatewayClass installed by consul-k8s (enabled by default) managedGatewayClass: # When true a GatewayClass is configured to automatically work with Consul as installed by helm. enabled: true @@ -2494,6 +2495,7 @@ apiGateway: # This value toggles if the gateway ports should be mapped to host ports useHostPorts: false + # Configuration settings for annotations to be copied from the Gateway to other child resources. copyAnnotations: # This value defines a list of annotations to be copied from the Gateway to the Service created, formatted as a multi-line string. # @@ -2507,6 +2509,7 @@ apiGateway: # @type: string service: null + # Configuration for the ServiceAccount created for the api-gateway component serviceAccount: # This value defines additional annotations for the client service account. This should be formatted as a multi-line # string. @@ -2520,7 +2523,9 @@ apiGateway: # @type: string annotations: null + # Configuration for the api-gateway controller component controller: + # This value sets the number of controller replicas to deploy. replicas: 1 # Annotations to apply to the api-gateway-controller pods. @@ -2550,6 +2555,8 @@ apiGateway: # # @type: string nodeSelector: null + + # Configuration for the Service created for the api-gateway-controller service: # Annotations to apply to the api-gateway-controller service. # diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index efcfaacac0..dc8b8461b9 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -15,12 +15,6 @@ import ( "testing" "time" - "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/sdk/freeport" - "github.com/hashicorp/consul/sdk/testutil" - "github.com/hashicorp/consul/sdk/testutil/retry" - "github.com/hashicorp/go-discover" - "github.com/hashicorp/go-hclog" "github.com/mitchellh/cli" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -28,6 +22,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" + "github.com/hashicorp/consul/api" + "github.com/hashicorp/consul/sdk/freeport" + "github.com/hashicorp/consul/sdk/testutil" + "github.com/hashicorp/consul/sdk/testutil/retry" + "github.com/hashicorp/go-discover" + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/consul-k8s/control-plane/helper/cert" "github.com/hashicorp/consul-k8s/control-plane/helper/go-discover/mocks" "github.com/hashicorp/consul-k8s/control-plane/helper/test" @@ -189,6 +190,14 @@ func TestRun_TokensPrimaryDC(t *testing.T) { SecretNames: []string{resourcePrefix + "-client-snapshot-agent-acl-token"}, LocalToken: true, }, + { + TestName: "API gateway token", + TokenFlags: []string{"-create-api-gateway-token"}, + PolicyNames: []string{"api-gateway-controller-token"}, + PolicyDCs: []string{"dc1"}, + SecretNames: []string{resourcePrefix + "-api-gateway-controller-acl-token"}, + LocalToken: true, + }, { TestName: "Mesh gateway token", TokenFlags: []string{"-create-mesh-gateway-token"}, diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index d2bdb986f6..07e25b96f5 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -139,24 +139,23 @@ partition_prefix "" { } func (c *Command) apiGatewayControllerRules() (string, error) { - apiGatewayRulesTpl := ` -{{- if .EnablePartitions }} + apiGatewayRulesTpl := `{{- if .EnablePartitions }} partition "{{ .PartitionName }}" { mesh = "write" acl = "write" {{- else }} - operator = "write" - acl = "write" +operator = "write" +acl = "write" {{- end }} {{- if .EnableNamespaces }} - namespace_prefix "" { +namespace_prefix "" { {{- end }} - service_prefix "" { - policy = "write" - intentions = "write" - } -{{- if .EnableNamespaces }} + service_prefix "" { + policy = "write" + intentions = "write" } +{{- if .EnableNamespaces }} +} {{- end }} {{- if .EnablePartitions }} } diff --git a/control-plane/subcommand/server-acl-init/rules_test.go b/control-plane/subcommand/server-acl-init/rules_test.go index ad3d385121..95c6e06f69 100644 --- a/control-plane/subcommand/server-acl-init/rules_test.go +++ b/control-plane/subcommand/server-acl-init/rules_test.go @@ -2,6 +2,7 @@ package serveraclinit import ( "fmt" + "strings" "testing" "github.com/stretchr/testify/require" @@ -139,6 +140,51 @@ partition_prefix "" { } } +func TestAPIGatewayControllerRules(t *testing.T) { + cases := []struct { + Name string + EnableNamespaces bool + Expected string + }{ + { + Name: "Namespaces are disabled", + Expected: ` +operator = "write" +acl = "write" + service_prefix "" { + policy = "write" + intentions = "write" + }`, + }, + { + Name: "Namespaces are enabled", + EnableNamespaces: true, + Expected: ` +operator = "write" +acl = "write" +namespace_prefix "" { + service_prefix "" { + policy = "write" + intentions = "write" + } +}`, + }, + } + + for _, tt := range cases { + t.Run(tt.Name, func(t *testing.T) { + cmd := Command{ + flagEnableNamespaces: tt.EnableNamespaces, + } + + meshGatewayRules, err := cmd.apiGatewayControllerRules() + + require.NoError(t, err) + require.Equal(t, tt.Expected, strings.Trim(meshGatewayRules, " ")) + }) + } +} + func TestMeshGatewayRules(t *testing.T) { cases := []struct { Name string From 1fd1b53c72cea34d7f3b1bfc24b41170d7ee5df8 Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Wed, 26 Jan 2022 14:22:09 -0500 Subject: [PATCH 243/418] add token tests for api gateway controller --- .../subcommand/server-acl-init/command_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index dc8b8461b9..1b0d4d0c55 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -369,6 +369,14 @@ func TestRun_TokensReplicatedDC(t *testing.T) { SecretNames: []string{resourcePrefix + "-client-snapshot-agent-acl-token"}, LocalToken: true, }, + { + TestName: "API Gateway token", + TokenFlags: []string{"-create-api-gateway-token"}, + PolicyNames: []string{"api-gateway-controller-token-dc2"}, + PolicyDCs: []string{"dc2"}, + SecretNames: []string{resourcePrefix + "-api-gateway-controller-acl-token"}, + LocalToken: true, + }, { TestName: "Mesh gateway token", TokenFlags: []string{"-create-mesh-gateway-token"}, @@ -515,6 +523,12 @@ func TestRun_TokensWithProvidedBootstrapToken(t *testing.T) { PolicyNames: []string{"client-snapshot-agent-token"}, SecretNames: []string{resourcePrefix + "-client-snapshot-agent-acl-token"}, }, + { + TestName: "API Gateway token", + TokenFlags: []string{"-create-api-gateway-token"}, + PolicyNames: []string{"api-gateway-controller-token"}, + SecretNames: []string{resourcePrefix + "-api-gateway-controller-acl-token"}, + }, { TestName: "Mesh gateway token", TokenFlags: []string{"-create-mesh-gateway-token"}, From f107e5f3e5610676aa8f0f558875b40387074d28 Mon Sep 17 00:00:00 2001 From: Nick Ethier Date: Wed, 26 Jan 2022 14:24:37 -0500 Subject: [PATCH 244/418] Apply suggestions from code review Co-authored-by: Ashwin Venkatesh --- .../templates/api-gateway-controller-clusterrolebinding.yaml | 4 ++-- .../consul/templates/api-gateway-controller-deployment.yaml | 2 +- .../templates/api-gateway-controller-serviceaccount.yaml | 2 +- charts/consul/templates/api-gateway-gatewayclass.yaml | 2 +- charts/consul/templates/api-gateway-gatewayclassconfig.yaml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml b/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml index c1c75ebf3f..d083a08129 100644 --- a/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml +++ b/charts/consul/templates/api-gateway-controller-clusterrolebinding.yaml @@ -2,7 +2,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: {{ template "consul.fullname" . }}-api-gateway-controller-role-binding + name: {{ template "consul.fullname" . }}-api-gateway-controller labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} @@ -15,6 +15,6 @@ roleRef: name: {{ template "consul.fullname" . }}-api-gateway-controller subjects: - kind: ServiceAccount - name: {{ template "consul.fullname" . }}-api-gateway-controller-svc-account + name: {{ template "consul.fullname" . }}-api-gateway-controller namespace: {{ .Release.Namespace }} {{- end }} diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml index e931491f05..aee171e6da 100644 --- a/charts/consul/templates/api-gateway-controller-deployment.yaml +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -42,7 +42,7 @@ spec: release: {{ .Release.Name }} component: api-gateway-controller spec: - serviceAccountName: {{ template "consul.fullname" . }}-api-gateway-controller-svc-account + serviceAccountName: {{ template "consul.fullname" . }}-api-gateway-controller containers: - name: api-gateway-controller image: {{ .Values.apiGateway.image }} diff --git a/charts/consul/templates/api-gateway-controller-serviceaccount.yaml b/charts/consul/templates/api-gateway-controller-serviceaccount.yaml index 55dda34038..98292a8dbe 100644 --- a/charts/consul/templates/api-gateway-controller-serviceaccount.yaml +++ b/charts/consul/templates/api-gateway-controller-serviceaccount.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ template "consul.fullname" . }}-api-gateway-controller-svc-account + name: {{ template "consul.fullname" . }}-api-gateway-controller namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} diff --git a/charts/consul/templates/api-gateway-gatewayclass.yaml b/charts/consul/templates/api-gateway-gatewayclass.yaml index 61effc57e3..d9ba85e633 100644 --- a/charts/consul/templates/api-gateway-gatewayclass.yaml +++ b/charts/consul/templates/api-gateway-gatewayclass.yaml @@ -14,5 +14,5 @@ spec: parametersRef: group: api-gateway.consul.hashicorp.com kind: GatewayClassConfig - name: consul-api-gateway-class-config + name: consul-api-gateway {{- end }} diff --git a/charts/consul/templates/api-gateway-gatewayclassconfig.yaml b/charts/consul/templates/api-gateway-gatewayclassconfig.yaml index 7f420a95e1..d0e6e453ae 100644 --- a/charts/consul/templates/api-gateway-gatewayclassconfig.yaml +++ b/charts/consul/templates/api-gateway-gatewayclassconfig.yaml @@ -2,7 +2,7 @@ apiVersion: api-gateway.consul.hashicorp.com/v1alpha1 kind: GatewayClassConfig metadata: - name: consul-api-gateway-class-config + name: consul-api-gateway labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} From cabb83e44bbb553022e8a739c0634caa6acd6d7f Mon Sep 17 00:00:00 2001 From: David Yu Date: Wed, 26 Jan 2022 12:06:47 -0800 Subject: [PATCH 245/418] CHANGELOG: Add Consul API Gateway to features to Changelog (#997) --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dc453eb70..a551877492 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ FEATURES: * Helm * Support Envoy 1.20.1. [[GH-958](https://github.com/hashicorp/consul-k8s/pull/958)] * Support Consul 1.11.2. [[GH-976](https://github.com/hashicorp/consul-k8s/pull/976)] + * Support [Consul API Gateway](https://github.com/hashicorp/consul-api-gateway) Controller deployment through the Helm chart and provision an ACL token to for API Gateway via server-acl-init [[GH-925](https://github.com/hashicorp/consul-k8s/pull/925)] IMPROVEMENTS: * Helm From 040b55aaf1db7e6652b5bb423c054a3da94f2489 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 26 Jan 2022 15:25:24 -0500 Subject: [PATCH 246/418] Standardize resource names across the helm chart (#993) * Standardize resource names across the helm chart. --- .circleci/config.yml | 2 +- CHANGELOG.md | 6 ++++++ .../connect-inject-authmethod-clusterrole.yaml | 2 +- ...connect-inject-authmethod-clusterrolebinding.yaml | 10 +++++----- .../connect-inject-authmethod-serviceaccount.yaml | 2 +- .../consul/templates/connect-inject-clusterrole.yaml | 4 ++-- .../templates/connect-inject-clusterrolebinding.yaml | 6 +++--- .../consul/templates/connect-inject-deployment.yaml | 4 ++-- .../connect-inject-leader-election-rolebinding.yaml | 2 +- .../connect-inject-mutatingwebhookconfiguration.yaml | 4 ++-- .../templates/connect-inject-podsecuritypolicy.yaml | 2 +- charts/consul/templates/connect-inject-service.yaml | 2 +- .../templates/connect-inject-serviceaccount.yaml | 2 +- .../controller-mutatingwebhookconfiguration.yaml | 2 +- charts/consul/templates/enterprise-license-job.yaml | 2 +- charts/consul/templates/partition-init-role.yaml | 2 +- charts/consul/templates/partition-service.yaml | 2 +- charts/consul/templates/server-acl-init-role.yaml | 2 +- charts/consul/templates/ui-ingress.yaml | 2 +- .../templates/webhook-cert-manager-clusterrole.yaml | 2 +- .../templates/webhook-cert-manager-configmap.yaml | 12 ++++++------ .../test/unit/webhook-cert-manager-configmap.bats | 8 ++++---- .../subcommand/server-acl-init/command_test.go | 6 +++--- .../subcommand/server-acl-init/connect_inject.go | 2 +- .../server-acl-init/connect_inject_test.go | 6 +++--- 25 files changed, 51 insertions(+), 45 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2bf464fc1a..20b255d402 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,7 +70,7 @@ commands: type: string consul-k8s-image: type: string - default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" + default: "ashwinvenkatesh/consul-k8s@sha256:33f14b9acffd2d403b45da9bb2330b84bb103caa7a700cda7619416f33d47f1a" go-path: type: string default: "/home/circleci/.go_workspace" diff --git a/CHANGELOG.md b/CHANGELOG.md index a551877492..2b5b1a1843 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## UNRELEASED +BREAKING CHANGES: +* Helm + * Some Consul components from the Helm chart have been renamed to ensure consistency in naming across the components. + This will not be a breaking change if Consul components are not referred to by name externally. Check the PR for the list of renamed components. [[GH-993](https://github.com/hashicorp/consul-k8s/pull/985)] + FEATURES: * Helm * Support Envoy 1.20.1. [[GH-958](https://github.com/hashicorp/consul-k8s/pull/958)] @@ -12,6 +17,7 @@ IMPROVEMENTS: * Support `ui.dashboardURLTemplates.service` value for setting [dashboard URL templates](https://www.consul.io/docs/agent/options#ui_config_dashboard_url_templates_service). [[GH-937](https://github.com/hashicorp/consul-k8s/pull/937)] * Allow using dash-separated names for config entries when using `kubectl`. [[GH-965](https://github.com/hashicorp/consul-k8s/pull/965)] * Support Pod Security Policies with Vault integration. [[GH-985](https://github.com/hashicorp/consul-k8s/pull/985)] + * Rename Consul resources to remove resource kind suffixes from the resource names to standardize resource names across the Helm chart. [[GH-993](https://github.com/hashicorp/consul-k8s/pull/985)] * CLI * Show a diff when upgrading a Consul installation on Kubernetes [[GH-934](https://github.com/hashicorp/consul-k8s/pull/934)] * Control Plane diff --git a/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml b/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml index 6655de5e84..173c2f86aa 100644 --- a/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml +++ b/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml @@ -3,7 +3,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: {{ template "consul.fullname" . }}-connect-injector-authmethod-role + name: {{ template "consul.fullname" . }}-connect-injector labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} diff --git a/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml b/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml index ff2b5548c6..7be84fdd00 100644 --- a/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml +++ b/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml @@ -3,7 +3,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: {{ template "consul.fullname" . }}-connect-injector-authmethod-authdelegator-role-binding + name: {{ template "consul.fullname" . }}-connect-injector-authdelegator labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} @@ -16,13 +16,13 @@ roleRef: name: "system:auth-delegator" subjects: - kind: ServiceAccount - name: {{ template "consul.fullname" . }}-connect-injector-authmethod-svc-account + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: {{ template "consul.fullname" . }}-connect-injector-authmethod-serviceaccount-role-binding + name: {{ template "consul.fullname" . }}-connect-injector labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} @@ -31,10 +31,10 @@ metadata: roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: {{ template "consul.fullname" . }}-connect-injector-authmethod-role + name: {{ template "consul.fullname" . }}-connect-injector subjects: - kind: ServiceAccount - name: {{ template "consul.fullname" . }}-connect-injector-authmethod-svc-account + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} {{- end }} {{- end }} diff --git a/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml b/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml index 98c7b209be..b8a8330334 100644 --- a/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml +++ b/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml @@ -3,7 +3,7 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ template "consul.fullname" . }}-connect-injector-authmethod-svc-account + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} diff --git a/charts/consul/templates/connect-inject-clusterrole.yaml b/charts/consul/templates/connect-inject-clusterrole.yaml index 873623cd84..0c2a068c31 100644 --- a/charts/consul/templates/connect-inject-clusterrole.yaml +++ b/charts/consul/templates/connect-inject-clusterrole.yaml @@ -3,7 +3,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - name: {{ template "consul.fullname" . }}-connect-injector-webhook + name: {{ template "consul.fullname" . }}-connect-injector labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} @@ -30,7 +30,7 @@ rules: - apiGroups: ["policy"] resources: ["podsecuritypolicies"] resourceNames: - - {{ template "consul.fullname" . }}-connect-injector-webhook + - {{ template "consul.fullname" . }}-connect-injector verbs: - use {{- end }} diff --git a/charts/consul/templates/connect-inject-clusterrolebinding.yaml b/charts/consul/templates/connect-inject-clusterrolebinding.yaml index fd8e320a65..64bff8269f 100644 --- a/charts/consul/templates/connect-inject-clusterrolebinding.yaml +++ b/charts/consul/templates/connect-inject-clusterrolebinding.yaml @@ -2,7 +2,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: - name: {{ template "consul.fullname" . }}-connect-injector-webhook-admin-role-binding + name: {{ template "consul.fullname" . }}-connect-injector labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} @@ -12,9 +12,9 @@ metadata: roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole - name: {{ template "consul.fullname" . }}-connect-injector-webhook + name: {{ template "consul.fullname" . }}-connect-injector subjects: - kind: ServiceAccount - name: {{ template "consul.fullname" . }}-connect-injector-webhook-svc-account + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} {{- end }} diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index d2d8b3e01b..552b51f8ae 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -13,7 +13,7 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ template "consul.fullname" . }}-connect-injector-webhook-deployment + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} @@ -50,7 +50,7 @@ spec: {{- end }} {{- end }} spec: - serviceAccountName: {{ template "consul.fullname" . }}-connect-injector-webhook-svc-account + serviceAccountName: {{ template "consul.fullname" . }}-connect-injector containers: - name: sidecar-injector image: "{{ default .Values.global.imageK8S .Values.connectInject.image }}" diff --git a/charts/consul/templates/connect-inject-leader-election-rolebinding.yaml b/charts/consul/templates/connect-inject-leader-election-rolebinding.yaml index bb903c719b..9a27d3c868 100644 --- a/charts/consul/templates/connect-inject-leader-election-rolebinding.yaml +++ b/charts/consul/templates/connect-inject-leader-election-rolebinding.yaml @@ -16,6 +16,6 @@ roleRef: name: {{ template "consul.fullname" . }}-connect-inject-leader-election subjects: - kind: ServiceAccount - name: {{ template "consul.fullname" . }}-connect-injector-webhook-svc-account + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} {{- end }} diff --git a/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml b/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml index ad8ea41b10..c3164bab24 100644 --- a/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml +++ b/charts/consul/templates/connect-inject-mutatingwebhookconfiguration.yaml @@ -3,7 +3,7 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - name: {{ template "consul.fullname" . }}-connect-injector-cfg + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} @@ -26,7 +26,7 @@ webhooks: - "v1" clientConfig: service: - name: {{ template "consul.fullname" . }}-connect-injector-svc + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} path: "/mutate" rules: diff --git a/charts/consul/templates/connect-inject-podsecuritypolicy.yaml b/charts/consul/templates/connect-inject-podsecuritypolicy.yaml index 45fd6afc27..0fafef7c40 100644 --- a/charts/consul/templates/connect-inject-podsecuritypolicy.yaml +++ b/charts/consul/templates/connect-inject-podsecuritypolicy.yaml @@ -2,7 +2,7 @@ apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: - name: {{ template "consul.fullname" . }}-connect-injector-webhook + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} diff --git a/charts/consul/templates/connect-inject-service.yaml b/charts/consul/templates/connect-inject-service.yaml index 497ea14547..b0284af74d 100644 --- a/charts/consul/templates/connect-inject-service.yaml +++ b/charts/consul/templates/connect-inject-service.yaml @@ -3,7 +3,7 @@ apiVersion: v1 kind: Service metadata: - name: {{ template "consul.fullname" . }}-connect-injector-svc + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} diff --git a/charts/consul/templates/connect-inject-serviceaccount.yaml b/charts/consul/templates/connect-inject-serviceaccount.yaml index f615c42bc1..250b23d6c3 100644 --- a/charts/consul/templates/connect-inject-serviceaccount.yaml +++ b/charts/consul/templates/connect-inject-serviceaccount.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ template "consul.fullname" . }}-connect-injector-webhook-svc-account + name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} diff --git a/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml b/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml index 03f4ce15c4..bf31ea862f 100644 --- a/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml +++ b/charts/consul/templates/controller-mutatingwebhookconfiguration.yaml @@ -2,7 +2,7 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - name: {{ template "consul.fullname" . }}-controller-mutating-webhook-configuration + name: {{ template "consul.fullname" . }}-controller namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} diff --git a/charts/consul/templates/enterprise-license-job.yaml b/charts/consul/templates/enterprise-license-job.yaml index 1509d9479e..287b30dcc4 100644 --- a/charts/consul/templates/enterprise-license-job.yaml +++ b/charts/consul/templates/enterprise-license-job.yaml @@ -4,7 +4,7 @@ apiVersion: batch/v1 kind: Job metadata: - name: {{ template "consul.fullname" . }}-license + name: {{ template "consul.fullname" . }}-enterprise-license namespace: {{ .Release.Namespace }} labels: app.kubernetes.io/managed-by: {{.Release.Service | quote }} diff --git a/charts/consul/templates/partition-init-role.yaml b/charts/consul/templates/partition-init-role.yaml index 1223e18e5d..c13a5378eb 100644 --- a/charts/consul/templates/partition-init-role.yaml +++ b/charts/consul/templates/partition-init-role.yaml @@ -26,7 +26,7 @@ rules: resources: - serviceaccounts resourceNames: - - {{ template "consul.fullname" . }}-connect-injector-authmethod-svc-account + - {{ template "consul.fullname" . }}-connect-injector verbs: - get {{- end }} diff --git a/charts/consul/templates/partition-service.yaml b/charts/consul/templates/partition-service.yaml index d417c9d348..b9266a11c7 100644 --- a/charts/consul/templates/partition-service.yaml +++ b/charts/consul/templates/partition-service.yaml @@ -5,7 +5,7 @@ apiVersion: v1 kind: Service metadata: - name: {{ template "consul.fullname" . }}-partition-service + name: {{ template "consul.fullname" . }}-partition namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} diff --git a/charts/consul/templates/server-acl-init-role.yaml b/charts/consul/templates/server-acl-init-role.yaml index d1fae46cff..e828ae9b3f 100644 --- a/charts/consul/templates/server-acl-init-role.yaml +++ b/charts/consul/templates/server-acl-init-role.yaml @@ -24,7 +24,7 @@ rules: resources: - serviceaccounts resourceNames: - - {{ template "consul.fullname" . }}-connect-injector-authmethod-svc-account + - {{ template "consul.fullname" . }}-connect-injector verbs: - get {{- end }} diff --git a/charts/consul/templates/ui-ingress.yaml b/charts/consul/templates/ui-ingress.yaml index 7b6e6bab4f..473acd3469 100644 --- a/charts/consul/templates/ui-ingress.yaml +++ b/charts/consul/templates/ui-ingress.yaml @@ -12,7 +12,7 @@ apiVersion: networking.k8s.io/v1beta1 {{- end }} kind: Ingress metadata: - name: {{ template "consul.fullname" . }}-ingress + name: {{ template "consul.fullname" . }}-ui namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} diff --git a/charts/consul/templates/webhook-cert-manager-clusterrole.yaml b/charts/consul/templates/webhook-cert-manager-clusterrole.yaml index fd4e819d03..9708380617 100644 --- a/charts/consul/templates/webhook-cert-manager-clusterrole.yaml +++ b/charts/consul/templates/webhook-cert-manager-clusterrole.yaml @@ -45,7 +45,7 @@ rules: resources: - podsecuritypolicies resourceNames: - - {{ template "consul.fullname" . }}-connect-injector-webhook + - {{ template "consul.fullname" . }}-connect-injector verbs: - use {{- end }} diff --git a/charts/consul/templates/webhook-cert-manager-configmap.yaml b/charts/consul/templates/webhook-cert-manager-configmap.yaml index cbf8770d04..e13d14a7ab 100644 --- a/charts/consul/templates/webhook-cert-manager-configmap.yaml +++ b/charts/consul/templates/webhook-cert-manager-configmap.yaml @@ -15,19 +15,19 @@ data: [ {{- if .Values.connectInject.enabled }} { - "name": "{{ template "consul.fullname" . }}-connect-injector-cfg", + "name": "{{ template "consul.fullname" . }}-connect-injector", "tlsAutoHosts": [ - "{{ template "consul.fullname" . }}-connect-injector-svc", - "{{ template "consul.fullname" . }}-connect-injector-svc.{{ .Release.Namespace }}", - "{{ template "consul.fullname" . }}-connect-injector-svc.{{ .Release.Namespace }}.svc", - "{{ template "consul.fullname" . }}-connect-injector-svc.{{ .Release.Namespace }}.svc.cluster.local" + "{{ template "consul.fullname" . }}-connect-injector", + "{{ template "consul.fullname" . }}-connect-injector.{{ .Release.Namespace }}", + "{{ template "consul.fullname" . }}-connect-injector.{{ .Release.Namespace }}.svc", + "{{ template "consul.fullname" . }}-connect-injector.{{ .Release.Namespace }}.svc.cluster.local" ], "secretName": "{{ template "consul.fullname" . }}-connect-inject-webhook-cert", "secretNamespace": "{{ .Release.Namespace }}" }{{- if and .Values.controller.enabled }},{{- end }}{{- end }} {{- if and .Values.controller.enabled }} { - "name": "{{ template "consul.fullname" . }}-controller-mutating-webhook-configuration", + "name": "{{ template "consul.fullname" . }}-controller", "tlsAutoHosts": [ "{{ template "consul.fullname" . }}-controller-webhook", "{{ template "consul.fullname" . }}-controller-webhook.{{ .Release.Namespace }}", diff --git a/charts/consul/test/unit/webhook-cert-manager-configmap.bats b/charts/consul/test/unit/webhook-cert-manager-configmap.bats index 62a7a4a5c4..31ec074f8a 100644 --- a/charts/consul/test/unit/webhook-cert-manager-configmap.bats +++ b/charts/consul/test/unit/webhook-cert-manager-configmap.bats @@ -52,7 +52,7 @@ load _helpers local actual=$(echo $cfg | jq '. | length == 1') [ "${actual}" = "true" ] - local actual=$(echo $cfg | jq '.[0].name | contains("controller-mutating-webhook-configuration")') + local actual=$(echo $cfg | jq '.[0].name | contains("controller")') [ "${actual}" = "true" ] } @@ -68,7 +68,7 @@ load _helpers local actual=$(echo $cfg | jq '. | length == 1') [ "${actual}" = "true" ] - local actual=$(echo $cfg | jq '.[0].name | contains("controller-mutating-webhook-configuration")') + local actual=$(echo $cfg | jq '.[0].name | contains("controller")') [ "${actual}" = "false" ] } @@ -85,9 +85,9 @@ load _helpers local actual=$(echo $cfg | jq '. | length == 2') [ "${actual}" = "true" ] - local actual=$(echo $cfg | jq '.[0].name | contains("connect-injector-cfg")') + local actual=$(echo $cfg | jq '.[0].name | contains("connect-injector")') [ "${actual}" = "true" ] - local actual=$(echo $cfg | jq '.[1].name | contains("controller-mutating-webhook-configuration")') + local actual=$(echo $cfg | jq '.[1].name | contains("controller")') [ "${actual}" = "true" ] } \ No newline at end of file diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index b79651c8f6..da3cfc3de3 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -2288,7 +2288,7 @@ func getBootToken(t *testing.T, k8s *fake.Clientset, prefix string, k8sNamespace func setUpK8sServiceAccount(t *testing.T, k8s *fake.Clientset, namespace string) (string, string) { // Create ServiceAccount for the kubernetes auth method if it doesn't exist, // otherwise, do nothing. - serviceAccountName := resourcePrefix + "-connect-injector-authmethod-svc-account" + serviceAccountName := resourcePrefix + "-connect-injector" sa, _ := k8s.CoreV1().ServiceAccounts(namespace).Get(context.Background(), serviceAccountName, metav1.GetOptions{}) if sa == nil { // Create a service account that references two secrets. @@ -2305,7 +2305,7 @@ func setUpK8sServiceAccount(t *testing.T, k8s *fake.Clientset, namespace string) Name: resourcePrefix + "-some-other-secret", }, { - Name: resourcePrefix + "-connect-injector-authmethod-svc-account", + Name: resourcePrefix + "-connect-injector", }, }, }, @@ -2320,7 +2320,7 @@ func setUpK8sServiceAccount(t *testing.T, k8s *fake.Clientset, namespace string) require.NoError(t, err) // Create a Kubernetes secret if it doesn't exist, otherwise update it - secretName := resourcePrefix + "-connect-injector-authmethod-svc-account" + secretName := resourcePrefix + "-connect-injector" secret := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: secretName, diff --git a/control-plane/subcommand/server-acl-init/connect_inject.go b/control-plane/subcommand/server-acl-init/connect_inject.go index 4764517ea6..abd10f9f7f 100644 --- a/control-plane/subcommand/server-acl-init/connect_inject.go +++ b/control-plane/subcommand/server-acl-init/connect_inject.go @@ -139,7 +139,7 @@ func (c *Command) configureConnectInjectAuthMethod(consulClient *api.Client) err func (c *Command) createAuthMethodTmpl(authMethodName string) (api.ACLAuthMethod, error) { // Get the Secret name for the auth method ServiceAccount. var authMethodServiceAccount *apiv1.ServiceAccount - saName := c.withPrefix("connect-injector-authmethod-svc-account") + saName := c.withPrefix("connect-injector") err := c.untilSucceeds(fmt.Sprintf("getting %s ServiceAccount", saName), func() error { var err error diff --git a/control-plane/subcommand/server-acl-init/connect_inject_test.go b/control-plane/subcommand/server-acl-init/connect_inject_test.go index 3dde30ae2b..a17d635bc1 100644 --- a/control-plane/subcommand/server-acl-init/connect_inject_test.go +++ b/control-plane/subcommand/server-acl-init/connect_inject_test.go @@ -30,8 +30,8 @@ func TestCommand_createAuthMethodTmpl_SecretNotFound(t *testing.T) { ctx: ctx, } - serviceAccountName := resourcePrefix + "-connect-injector-authmethod-svc-account" - secretName := resourcePrefix + "-connect-injector-authmethod-svc-account" + serviceAccountName := resourcePrefix + "-connect-injector" + secretName := resourcePrefix + "-connect-injector" // Create a service account referencing secretName sa, _ := k8s.CoreV1().ServiceAccounts(ns).Get(ctx, serviceAccountName, metav1.GetOptions{}) @@ -65,5 +65,5 @@ func TestCommand_createAuthMethodTmpl_SecretNotFound(t *testing.T) { require.NoError(t, err) _, err = cmd.createAuthMethodTmpl("test") - require.EqualError(t, err, "found no secret of type 'kubernetes.io/service-account-token' associated with the release-name-consul-connect-injector-authmethod-svc-account service account") + require.EqualError(t, err, "found no secret of type 'kubernetes.io/service-account-token' associated with the release-name-consul-connect-injector service account") } From bfd2b448b733c8b5b75562e57d422633ce2044b3 Mon Sep 17 00:00:00 2001 From: David Yu Date: Wed, 26 Jan 2022 12:31:18 -0800 Subject: [PATCH 247/418] CHANGELOG: update PR link (#998) Update PR link to https://github.com/hashicorp/consul-k8s/pull/993 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b5b1a1843..8b2ddbe087 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ BREAKING CHANGES: * Helm * Some Consul components from the Helm chart have been renamed to ensure consistency in naming across the components. - This will not be a breaking change if Consul components are not referred to by name externally. Check the PR for the list of renamed components. [[GH-993](https://github.com/hashicorp/consul-k8s/pull/985)] + This will not be a breaking change if Consul components are not referred to by name externally. Check the PR for the list of renamed components. [[GH-993](https://github.com/hashicorp/consul-k8s/pull/993)] FEATURES: * Helm From 5133f095087bfb1c9a8e9998813d6aaa2ac3f5a5 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Wed, 26 Jan 2022 13:31:53 -0700 Subject: [PATCH 248/418] connect: Avoid making unnecessary calls to Consul in the endpoints controller (#991) This is so that we can avoid slowing down events processing in endpoints controller when consul clients are unavailable --- CHANGELOG.md | 1 + .../connect-inject/endpoints_controller.go | 54 ++++-- .../endpoints_controller_test.go | 176 +++++++++++++++--- 3 files changed, 192 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b2ddbe087..9cae483f64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ IMPROVEMENTS: * Support the value `$POD_NAME` for the annotation `consul.hashicorp.com/service-meta-*` that will now be interpolated and set to the pod's name in the service's metadata. [[GH-982](https://github.com/hashicorp/consul-k8s/pull/982)] * Allow managing Consul sidecar resources via annotations. [[GH-956](https://github.com/hashicorp/consul-k8s/pull/956)] * Support using a backslash to escape commas in `consul.hashicorp.com/service-tags` annotation. [[GH-983](https://github.com/hashicorp/consul-k8s/pull/983)] + * Avoid making unnecessary calls to Consul in the endpoints controller to improve application startup time when Consul is down. [[GH-779](https://github.com/hashicorp/consul-k8s/issues/779)] BUG FIXES: * Helm diff --git a/control-plane/connect-inject/endpoints_controller.go b/control-plane/connect-inject/endpoints_controller.go index 39dbecfeeb..7dcca14091 100644 --- a/control-plane/connect-inject/endpoints_controller.go +++ b/control-plane/connect-inject/endpoints_controller.go @@ -141,24 +141,24 @@ func (r *EndpointsController) Reconcile(ctx context.Context, req ctrl.Request) ( if k8serrors.IsNotFound(err) { // Deregister all instances in Consul for this service. The function deregisterServiceOnAllAgents handles // the case where the Consul service name is different from the Kubernetes service name. - err = r.deregisterServiceOnAllAgents(ctx, req.Name, req.Namespace, nil, endpointPods) + err = r.deregisterServiceOnAllAgents(ctx, req.Name, req.Namespace, nil) return ctrl.Result{}, err } else if err != nil { r.Log.Error(err, "failed to get Endpoints", "name", req.Name, "ns", req.Namespace) return ctrl.Result{}, err } + r.Log.Info("retrieved", "name", serviceEndpoints.Name, "ns", serviceEndpoints.Namespace) + // If the endpoints object has the label "consul.hashicorp.com/service-ignore" set to true, deregister all instances in Consul for this service. // It is possible that the endpoints object has never been registered, in which case deregistration is a no-op. if isLabeledIgnore(serviceEndpoints.Labels) { // We always deregister the service to handle the case where a user has registered the service, then added the label later. r.Log.Info("Ignoring endpoint labeled with `consul.hashicorp.com/service-ignore: \"true\"`", "name", req.Name, "namespace", req.Namespace) - err = r.deregisterServiceOnAllAgents(ctx, req.Name, req.Namespace, nil, endpointPods) + err = r.deregisterServiceOnAllAgents(ctx, req.Name, req.Namespace, nil) return ctrl.Result{}, err } - r.Log.Info("retrieved", "name", serviceEndpoints.Name, "ns", serviceEndpoints.Namespace) - // endpointAddressMap stores every IP that corresponds to a Pod in the Endpoints object. It is used to compare // against service instances in Consul to deregister them if they are not in the map. endpointAddressMap := map[string]bool{} @@ -167,10 +167,25 @@ func (r *EndpointsController) Reconcile(ctx context.Context, req ctrl.Request) ( for _, subset := range serviceEndpoints.Subsets { for address, healthStatus := range mapAddresses(subset) { if address.TargetRef != nil && address.TargetRef.Kind == "Pod" { - endpointPods.Add(address.TargetRef.Name) - if err := r.registerServicesAndHealthCheck(ctx, serviceEndpoints, address, healthStatus, endpointAddressMap); err != nil { - r.Log.Error(err, "failed to register services or health check", "name", serviceEndpoints.Name, "ns", serviceEndpoints.Namespace) + var pod corev1.Pod + objectKey := types.NamespacedName{Name: address.TargetRef.Name, Namespace: address.TargetRef.Namespace} + if err := r.Client.Get(ctx, objectKey, &pod); err != nil { + r.Log.Error(err, "failed to get pod", "name", address.TargetRef.Name) errs = multierror.Append(errs, err) + continue + } + + if hasBeenInjected(pod) { + endpointPods.Add(address.TargetRef.Name) + if err := r.registerServicesAndHealthCheck(pod, serviceEndpoints, healthStatus, endpointAddressMap); err != nil { + r.Log.Error(err, "failed to register services or health check", "name", serviceEndpoints.Name, "ns", serviceEndpoints.Namespace) + errs = multierror.Append(errs, err) + } + } else { + // If this endpoints object points to a pod that has injection disabled, + // then we want to ignore it for any further processing and exit early. + r.Log.Info("ignoring because endpoints pods have not been injected", "name", serviceEndpoints.Name, "ns", serviceEndpoints.Namespace) + return ctrl.Result{}, nil } } } @@ -179,7 +194,7 @@ func (r *EndpointsController) Reconcile(ctx context.Context, req ctrl.Request) ( // Compare service instances in Consul with addresses in Endpoints. If an address is not in Endpoints, deregister // from Consul. This uses endpointAddressMap which is populated with the addresses in the Endpoints object during // the registration codepath. - if err = r.deregisterServiceOnAllAgents(ctx, serviceEndpoints.Name, serviceEndpoints.Namespace, endpointAddressMap, endpointPods); err != nil { + if err = r.deregisterServiceOnAllAgents(ctx, serviceEndpoints.Name, serviceEndpoints.Namespace, endpointAddressMap); err != nil { r.Log.Error(err, "failed to deregister endpoints on all agents", "name", serviceEndpoints.Name, "ns", serviceEndpoints.Namespace) errs = multierror.Append(errs, err) } @@ -203,14 +218,7 @@ func (r *EndpointsController) SetupWithManager(mgr ctrl.Manager) error { // registerServicesAndHealthCheck creates Consul registrations for the service and proxy and registers them with Consul. // It also upserts a Kubernetes health check for the service based on whether the endpoint address is ready. -func (r *EndpointsController) registerServicesAndHealthCheck(ctx context.Context, serviceEndpoints corev1.Endpoints, address corev1.EndpointAddress, healthStatus string, endpointAddressMap map[string]bool) error { - // Get pod associated with this address. - var pod corev1.Pod - objectKey := types.NamespacedName{Name: address.TargetRef.Name, Namespace: address.TargetRef.Namespace} - if err := r.Client.Get(ctx, objectKey, &pod); err != nil { - r.Log.Error(err, "failed to get pod", "name", address.TargetRef.Name) - return err - } +func (r *EndpointsController) registerServicesAndHealthCheck(pod corev1.Pod, serviceEndpoints corev1.Endpoints, healthStatus string, endpointAddressMap map[string]bool) error { podHostIP := pod.Status.HostIP if hasBeenInjected(pod) { @@ -654,7 +662,7 @@ func getHealthCheckStatusReason(healthCheckStatus, podName, podNamespace string) // The argument endpointsAddressesMap decides whether to deregister *all* service instances or selectively deregister // them only if they are not in endpointsAddressesMap. If the map is nil, it will deregister all instances. If the map // has addresses, it will only deregister instances not in the map. -func (r *EndpointsController) deregisterServiceOnAllAgents(ctx context.Context, k8sSvcName, k8sSvcNamespace string, endpointsAddressesMap map[string]bool, endpointPods mapset.Set) error { +func (r *EndpointsController) deregisterServiceOnAllAgents(ctx context.Context, k8sSvcName, k8sSvcNamespace string, endpointsAddressesMap map[string]bool) error { // Get all agents by getting pods with label component=client, app=consul and release= agents := corev1.PodList{} listOptions := client.ListOptions{ @@ -672,6 +680,18 @@ func (r *EndpointsController) deregisterServiceOnAllAgents(ctx context.Context, // On each agent, we need to get services matching "k8s-service-name" and "k8s-namespace" metadata. for _, agent := range agents.Items { + ready := false + for _, status := range agent.Status.Conditions { + if status.Type == corev1.PodReady { + ready = status.Status == corev1.ConditionTrue + } + } + if !ready { + // We can ignore this client agent here because once it switches its status from not-ready to ready, + // we will reconcile all services as part of that event. + r.Log.Info("Consul client agent is not ready, skipping deregistration", "consul-agent", agent.Name, "svc", k8sSvcName) + continue + } client, err := r.remoteConsulClient(agent.Status.PodIP, r.consulNamespace(k8sSvcNamespace)) if err != nil { r.Log.Error(err, "failed to create a new Consul client", "address", agent.Status.PodIP) diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index 07c9b3faa1..98351c3f39 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -3,6 +3,9 @@ package connectinject import ( "context" "fmt" + "net/http" + "net/http/httptest" + "net/url" "strings" "testing" @@ -2492,16 +2495,17 @@ func TestReconcileDeleteEndpoint(t *testing.T) { t.Parallel() nodeName := "test-node" cases := []struct { - name string - consulSvcName string - legacyService bool - initialConsulSvcs []*api.AgentServiceRegistration - enableACLs bool + name string + consulSvcName string + expectServicesToBeDeleted bool + initialConsulSvcs []*api.AgentServiceRegistration + enableACLs bool + consulClientReady bool }{ { - name: "Legacy service: does not delete", - consulSvcName: "service-deleted", - legacyService: true, + name: "Legacy service: does not delete", + consulSvcName: "service-deleted", + expectServicesToBeDeleted: false, initialConsulSvcs: []*api.AgentServiceRegistration{ { ID: "pod1-service-deleted", @@ -2523,10 +2527,12 @@ func TestReconcileDeleteEndpoint(t *testing.T) { Meta: map[string]string{"k8s-service-name": "service-deleted", "k8s-namespace": "default"}, }, }, + consulClientReady: true, }, { - name: "Consul service name matches K8s service name", - consulSvcName: "service-deleted", + name: "Consul service name matches K8s service name", + consulSvcName: "service-deleted", + expectServicesToBeDeleted: true, initialConsulSvcs: []*api.AgentServiceRegistration{ { ID: "pod1-service-deleted", @@ -2548,10 +2554,12 @@ func TestReconcileDeleteEndpoint(t *testing.T) { Meta: map[string]string{"k8s-service-name": "service-deleted", "k8s-namespace": "default", MetaKeyManagedBy: managedByValue}, }, }, + consulClientReady: true, }, { - name: "Consul service name does not match K8s service name", - consulSvcName: "different-consul-svc-name", + name: "Consul service name does not match K8s service name", + consulSvcName: "different-consul-svc-name", + expectServicesToBeDeleted: true, initialConsulSvcs: []*api.AgentServiceRegistration{ { ID: "pod1-different-consul-svc-name", @@ -2573,10 +2581,12 @@ func TestReconcileDeleteEndpoint(t *testing.T) { Meta: map[string]string{"k8s-service-name": "service-deleted", "k8s-namespace": "default", MetaKeyManagedBy: managedByValue}, }, }, + consulClientReady: true, }, { - name: "When ACLs are enabled, the token should be deleted", - consulSvcName: "service-deleted", + name: "When ACLs are enabled, the token should be deleted", + consulSvcName: "service-deleted", + expectServicesToBeDeleted: true, initialConsulSvcs: []*api.AgentServiceRegistration{ { ID: "pod1-service-deleted", @@ -2608,7 +2618,45 @@ func TestReconcileDeleteEndpoint(t *testing.T) { }, }, }, - enableACLs: true, + enableACLs: true, + consulClientReady: true, + }, + { + name: "When Consul client pod is not ready, services are not deleted", + consulSvcName: "service-deleted", + expectServicesToBeDeleted: false, + initialConsulSvcs: []*api.AgentServiceRegistration{ + { + ID: "pod1-service-deleted", + Name: "service-deleted", + Port: 80, + Address: "1.2.3.4", + Meta: map[string]string{ + MetaKeyKubeServiceName: "service-deleted", + MetaKeyKubeNS: "default", + MetaKeyManagedBy: managedByValue, + MetaKeyPodName: "pod1", + }, + }, + { + Kind: api.ServiceKindConnectProxy, + ID: "pod1-service-deleted-sidecar-proxy", + Name: "service-deleted-sidecar-proxy", + Port: 20000, + Address: "1.2.3.4", + Proxy: &api.AgentServiceConnectProxyConfig{ + DestinationServiceName: "service-deleted", + DestinationServiceID: "pod1-service-deleted", + }, + Meta: map[string]string{ + MetaKeyKubeServiceName: "service-deleted", + MetaKeyKubeNS: "default", + MetaKeyManagedBy: managedByValue, + MetaKeyPodName: "pod1", + }, + }, + }, + consulClientReady: false, }, } for _, tt := range cases { @@ -2619,6 +2667,9 @@ func TestReconcileDeleteEndpoint(t *testing.T) { // test server we have on localhost. fakeClientPod := createPod("fake-consul-client", "127.0.0.1", false, true) fakeClientPod.Labels = map[string]string{"component": "client", "app": "consul", "release": "consul"} + if !tt.consulClientReady { + fakeClientPod.Status.Conditions = []corev1.PodCondition{{Type: corev1.PodReady, Status: corev1.ConditionFalse}} + } // Add the default namespace. ns := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}} @@ -2701,16 +2752,16 @@ func TestReconcileDeleteEndpoint(t *testing.T) { // After reconciliation, Consul should not have any instances of service-deleted serviceInstances, _, err := consulClient.Catalog().Service(tt.consulSvcName, "", nil) // If it's not managed by endpoints controller (legacy service), Consul should have service instances - if tt.legacyService { + if tt.expectServicesToBeDeleted { + require.NoError(t, err) + require.Empty(t, serviceInstances) + proxyServiceInstances, _, err := consulClient.Catalog().Service(fmt.Sprintf("%s-sidecar-proxy", tt.consulSvcName), "", nil) + require.NoError(t, err) + require.Empty(t, proxyServiceInstances) + } else { require.NoError(t, err) require.NotEmpty(t, serviceInstances) - return } - require.NoError(t, err) - require.Empty(t, serviceInstances) - proxyServiceInstances, _, err := consulClient.Catalog().Service(fmt.Sprintf("%s-sidecar-proxy", tt.consulSvcName), "", nil) - require.NoError(t, err) - require.Empty(t, proxyServiceInstances) if tt.enableACLs { _, _, err = consulClient.ACL().TokenRead(token.AccessorID, nil) @@ -2863,6 +2914,81 @@ func TestReconcileIgnoresServiceIgnoreLabel(t *testing.T) { } } +// Test that when endpoints pods have not been connect-injected (i.e. not in the service mesh) +// we don't make any API calls to Consul. +// This is because we want to avoid any unnecessary calls. Especially if the client agent is unreachable +// and any calls to it will result in an i/o timeout errors, it will +// slow down processing of the events by the endpoints controller making unnecessary calls and waiting for ~30sec. +func TestReconcile_endpointsIgnoredWhenNotInjected(t *testing.T) { + nodeName := "test-node" + namespace := "default" + + // Set up the fake Kubernetes client with an endpoint, pod, consul client, and the default namespace. + endpoint := &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "not-in-mesh", + Namespace: namespace, + }, + Subsets: []corev1.EndpointSubset{ + { + Addresses: []corev1.EndpointAddress{ + { + IP: "1.2.3.4", + NodeName: &nodeName, + TargetRef: &corev1.ObjectReference{ + Kind: "Pod", + Name: "pod1", + Namespace: namespace, + }, + }, + }, + }, + }, + } + pod1 := createPod("pod1", "1.2.3.4", false, true) + fakeClientPod := createPod("fake-consul-client", "127.0.0.1", false, true) + fakeClientPod.Labels = map[string]string{"component": "client", "app": "consul", "release": "consul"} + ns := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}} + k8sObjects := []runtime.Object{endpoint, pod1, fakeClientPod, &ns} + fakeClient := fake.NewClientBuilder().WithRuntimeObjects(k8sObjects...).Build() + + // Create test Consul server. + consul := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("content-type", "application/json") + if r != nil { + t.Fatalf("should not receive any calls to Consul client") + } + })) + t.Cleanup(consul.Close) + + cfg := &api.Config{Address: consul.URL} + consulClient, err := api.NewClient(cfg) + require.NoError(t, err) + parsedURL, err := url.Parse(consul.URL) + require.NoError(t, err) + consulPort := parsedURL.Port() + + // Create the endpoints controller. + ep := &EndpointsController{ + Client: fakeClient, + Log: logrtest.TestLogger{T: t}, + ConsulClient: consulClient, + ConsulPort: consulPort, + ConsulScheme: "http", + AllowK8sNamespacesSet: mapset.NewSetWith("*"), + DenyK8sNamespacesSet: mapset.NewSetWith(), + ReleaseName: "consul", + ReleaseNamespace: namespace, + ConsulClientCfg: cfg, + } + + // Run the reconcile process to deregister the service if it was registered before. + namespacedName := types.NamespacedName{Namespace: namespace, Name: "not-in-mesh"} + resp, err := ep.Reconcile(context.Background(), ctrl.Request{NamespacedName: namespacedName}) + require.NoError(t, err) + require.False(t, resp.Requeue) +} + func TestFilterAgentPods(t *testing.T) { t.Parallel() cases := map[string]struct { @@ -4986,6 +5112,12 @@ func createPod(name, ip string, inject bool, managedByEndpointsController bool) Status: corev1.PodStatus{ PodIP: ip, HostIP: "127.0.0.1", + Conditions: []corev1.PodCondition{ + { + Type: corev1.PodReady, + Status: corev1.ConditionTrue, + }, + }, }, } if inject { From 4fa2d230c03f73e7eeb2a2f13c844967f1844378 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 26 Jan 2022 15:34:04 -0500 Subject: [PATCH 249/418] Fix changelog and circle ci config (#999) --- .circleci/config.yml | 2 +- CHANGELOG.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 20b255d402..2bf464fc1a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,7 +70,7 @@ commands: type: string consul-k8s-image: type: string - default: "ashwinvenkatesh/consul-k8s@sha256:33f14b9acffd2d403b45da9bb2330b84bb103caa7a700cda7619416f33d47f1a" + default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" go-path: type: string default: "/home/circleci/.go_workspace" diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cae483f64..a29d9d080a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ IMPROVEMENTS: * Support `ui.dashboardURLTemplates.service` value for setting [dashboard URL templates](https://www.consul.io/docs/agent/options#ui_config_dashboard_url_templates_service). [[GH-937](https://github.com/hashicorp/consul-k8s/pull/937)] * Allow using dash-separated names for config entries when using `kubectl`. [[GH-965](https://github.com/hashicorp/consul-k8s/pull/965)] * Support Pod Security Policies with Vault integration. [[GH-985](https://github.com/hashicorp/consul-k8s/pull/985)] - * Rename Consul resources to remove resource kind suffixes from the resource names to standardize resource names across the Helm chart. [[GH-993](https://github.com/hashicorp/consul-k8s/pull/985)] + * Rename Consul resources to remove resource kind suffixes from the resource names to standardize resource names across the Helm chart. [[GH-993](https://github.com/hashicorp/consul-k8s/pull/993)] * CLI * Show a diff when upgrading a Consul installation on Kubernetes [[GH-934](https://github.com/hashicorp/consul-k8s/pull/934)] * Control Plane From c06e501662ce1589e6fc213e2fa0ea691d6d6267 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Wed, 26 Jan 2022 23:45:00 -0500 Subject: [PATCH 250/418] Rename consul client daemonset. (#1000) --- CHANGELOG.md | 3 +- .../tests/connect/connect_inject_test.go | 4 +- charts/consul/templates/client-daemonset.yaml | 2 +- ...connect-inject-authmethod-clusterrole.yaml | 20 ------ ...-inject-authmethod-clusterrolebinding.yaml | 18 ----- ...nect-inject-authmethod-serviceaccount.yaml | 21 ------ .../templates/connect-inject-clusterrole.yaml | 7 ++ ...connect-inject-authmethod-clusterrole.bats | 42 ------------ ...nect-inject-authmethod-serviceaccount.bats | 65 ------------------- 9 files changed, 12 insertions(+), 170 deletions(-) delete mode 100644 charts/consul/templates/connect-inject-authmethod-clusterrole.yaml delete mode 100644 charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml delete mode 100644 charts/consul/test/unit/connect-inject-authmethod-clusterrole.bats delete mode 100644 charts/consul/test/unit/connect-inject-authmethod-serviceaccount.bats diff --git a/CHANGELOG.md b/CHANGELOG.md index a29d9d080a..cfcf2d9349 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ BREAKING CHANGES: * Helm * Some Consul components from the Helm chart have been renamed to ensure consistency in naming across the components. - This will not be a breaking change if Consul components are not referred to by name externally. Check the PR for the list of renamed components. [[GH-993](https://github.com/hashicorp/consul-k8s/pull/993)] + This will not be a breaking change if Consul components are not referred to by name externally. Check the PR for the list of renamed components. [[GH-993](https://github.com/hashicorp/consul-k8s/pull/993)][[GH-1000](https://github.com/hashicorp/consul-k8s/pull/1000)] FEATURES: * Helm @@ -18,6 +18,7 @@ IMPROVEMENTS: * Allow using dash-separated names for config entries when using `kubectl`. [[GH-965](https://github.com/hashicorp/consul-k8s/pull/965)] * Support Pod Security Policies with Vault integration. [[GH-985](https://github.com/hashicorp/consul-k8s/pull/985)] * Rename Consul resources to remove resource kind suffixes from the resource names to standardize resource names across the Helm chart. [[GH-993](https://github.com/hashicorp/consul-k8s/pull/993)] + * Append `-client` to the Consul Daemonset name to standardize resource names across the Helm chart. [[GH-1000](https://github.com/hashicorp/consul-k8s/pull/1000)] * CLI * Show a diff when upgrading a Consul installation on Kubernetes [[GH-934](https://github.com/hashicorp/consul-k8s/pull/934)] * Control Plane diff --git a/acceptance/tests/connect/connect_inject_test.go b/acceptance/tests/connect/connect_inject_test.go index 464c134702..ef3a95a6be 100644 --- a/acceptance/tests/connect/connect_inject_test.go +++ b/acceptance/tests/connect/connect_inject_test.go @@ -143,8 +143,8 @@ func TestConnectInject_RestartConsulClients(t *testing.T) { } logger.Log(t, "restarting Consul client daemonset") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "rollout", "restart", fmt.Sprintf("ds/%s-consul", releaseName)) - k8s.RunKubectl(t, ctx.KubectlOptions(t), "rollout", "status", fmt.Sprintf("ds/%s-consul", releaseName)) + k8s.RunKubectl(t, ctx.KubectlOptions(t), "rollout", "restart", fmt.Sprintf("ds/%s-consul-client", releaseName)) + k8s.RunKubectl(t, ctx.KubectlOptions(t), "rollout", "status", fmt.Sprintf("ds/%s-consul-client", releaseName)) logger.Log(t, "checking that connection is still successful") if cfg.EnableTransparentProxy { diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index 9517d8d974..7c9c08d91f 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -11,7 +11,7 @@ apiVersion: apps/v1 kind: DaemonSet metadata: - name: {{ template "consul.fullname" . }} + name: {{ template "consul.fullname" . }}-client namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} diff --git a/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml b/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml deleted file mode 100644 index 173c2f86aa..0000000000 --- a/charts/consul/templates/connect-inject-authmethod-clusterrole.yaml +++ /dev/null @@ -1,20 +0,0 @@ -{{- if or (and (ne (.Values.connectInject.enabled | toString) "-") .Values.connectInject.enabled) (and (eq (.Values.connectInject.enabled | toString) "-") .Values.global.enabled) }} -{{- if .Values.global.acls.manageSystemACLs }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ template "consul.fullname" . }}-connect-injector - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: connect-injector -rules: - - apiGroups: [""] - resources: - - serviceaccounts - verbs: - - get -{{- end }} -{{- end }} diff --git a/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml b/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml index 7be84fdd00..4f9d7c8083 100644 --- a/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml +++ b/charts/consul/templates/connect-inject-authmethod-clusterrolebinding.yaml @@ -18,23 +18,5 @@ subjects: - kind: ServiceAccount name: {{ template "consul.fullname" . }}-connect-injector namespace: {{ .Release.Namespace }} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ template "consul.fullname" . }}-connect-injector - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ template "consul.fullname" . }}-connect-injector -subjects: - - kind: ServiceAccount - name: {{ template "consul.fullname" . }}-connect-injector - namespace: {{ .Release.Namespace }} {{- end }} {{- end }} diff --git a/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml b/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml deleted file mode 100644 index b8a8330334..0000000000 --- a/charts/consul/templates/connect-inject-authmethod-serviceaccount.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- if or (and (ne (.Values.connectInject.enabled | toString) "-") .Values.connectInject.enabled) (and (eq (.Values.connectInject.enabled | toString) "-") .Values.global.enabled) }} -{{- if .Values.global.acls.manageSystemACLs }} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ template "consul.fullname" . }}-connect-injector - namespace: {{ .Release.Namespace }} - labels: - app: {{ template "consul.name" . }} - chart: {{ template "consul.chart" . }} - heritage: {{ .Release.Service }} - release: {{ .Release.Name }} - component: connect-injector -{{- with .Values.global.imagePullSecrets }} -imagePullSecrets: -{{- range . }} - - name: {{ .name }} -{{- end }} -{{- end }} -{{- end }} -{{- end }} diff --git a/charts/consul/templates/connect-inject-clusterrole.yaml b/charts/consul/templates/connect-inject-clusterrole.yaml index 0c2a068c31..892ef8f406 100644 --- a/charts/consul/templates/connect-inject-clusterrole.yaml +++ b/charts/consul/templates/connect-inject-clusterrole.yaml @@ -11,6 +11,13 @@ metadata: release: {{ .Release.Name }} component: connect-injector rules: +{{- if .Values.global.acls.manageSystemACLs }} +- apiGroups: [""] + resources: + - serviceaccounts + verbs: + - get +{{- end }} - apiGroups: [""] resources: ["pods", "endpoints", "services", "namespaces"] verbs: diff --git a/charts/consul/test/unit/connect-inject-authmethod-clusterrole.bats b/charts/consul/test/unit/connect-inject-authmethod-clusterrole.bats deleted file mode 100644 index 2437522441..0000000000 --- a/charts/consul/test/unit/connect-inject-authmethod-clusterrole.bats +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "connectInjectAuthMethod/ClusterRole: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s templates/connect-inject-authmethod-clusterrole.yaml \ - . -} - -@test "connectInjectAuthMethod/ClusterRole: enabled with global.enabled false" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/connect-inject-authmethod-clusterrole.yaml \ - --set 'global.enabled=false' \ - --set 'client.enabled=true' \ - --set 'connectInject.enabled=true' \ - --set 'global.acls.manageSystemACLs=true' \ - . | tee /dev/stderr | - yq -s 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "connectInjectAuthMethod/ClusterRole: disabled with connectInject.enabled" { - cd `chart_dir` - assert_empty helm template \ - -s templates/connect-inject-authmethod-clusterrole.yaml \ - --set 'connectInject.enabled=true' \ - . -} - -@test "connectInjectAuthMethod/ClusterRole: enabled with global.acls.manageSystemACLs.enabled=true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/connect-inject-authmethod-clusterrole.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.acls.manageSystemACLs=true' \ - . | tee /dev/stderr | - yq -s 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} diff --git a/charts/consul/test/unit/connect-inject-authmethod-serviceaccount.bats b/charts/consul/test/unit/connect-inject-authmethod-serviceaccount.bats deleted file mode 100644 index 68788cadc5..0000000000 --- a/charts/consul/test/unit/connect-inject-authmethod-serviceaccount.bats +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bats - -load _helpers - -@test "connectInjectAuthMethod/ServiceAccount: disabled by default" { - cd `chart_dir` - assert_empty helm template \ - -s templates/connect-inject-authmethod-serviceaccount.yaml \ - . -} - -@test "connectInjectAuthMethod/ServiceAccount: enabled with global.enabled false" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/connect-inject-authmethod-serviceaccount.yaml \ - --set 'global.enabled=false' \ - --set 'client.enabled=true' \ - --set 'connectInject.enabled=true' \ - --set 'global.acls.manageSystemACLs=true' \ - . | tee /dev/stderr | - yq -s 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -@test "connectInjectAuthMethod/ServiceAccount: disabled with connectInject.enabled" { - cd `chart_dir` - assert_empty helm template \ - -s templates/connect-inject-authmethod-serviceaccount.yaml \ - --set 'connectInject.enabled=true' \ - . -} - -@test "connectInjectAuthMethod/ServiceAccount: enabled with global.acls.manageSystemACLs.enabled=true" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/connect-inject-authmethod-serviceaccount.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.acls.manageSystemACLs=true' \ - . | tee /dev/stderr | - yq -s 'length > 0' | tee /dev/stderr) - [ "${actual}" = "true" ] -} - -#-------------------------------------------------------------------- -# global.imagePullSecrets - -@test "connectInjectAuthMethod/ServiceAccount: can set image pull secrets" { - cd `chart_dir` - local object=$(helm template \ - -s templates/connect-inject-authmethod-serviceaccount.yaml \ - --set 'connectInject.enabled=true' \ - --set 'global.acls.manageSystemACLs=true' \ - --set 'global.imagePullSecrets[0].name=my-secret' \ - --set 'global.imagePullSecrets[1].name=my-secret2' \ - . | tee /dev/stderr) - - local actual=$(echo "$object" | - yq -r '.imagePullSecrets[0].name' | tee /dev/stderr) - [ "${actual}" = "my-secret" ] - - local actual=$(echo "$object" | - yq -r '.imagePullSecrets[1].name' | tee /dev/stderr) - [ "${actual}" = "my-secret2" ] -} - From 8fece7986ddc82a56aa10bdcac347a7c569b4597 Mon Sep 17 00:00:00 2001 From: Ashwin Venkatesh Date: Thu, 27 Jan 2022 13:17:37 -0500 Subject: [PATCH 251/418] update partition service name to the correct service name. (#1003) --- acceptance/tests/partitions/partitions_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index e7dc0934ff..5fd19af3ce 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -162,7 +162,7 @@ func TestPartitions(t *testing.T) { partitionSvcAddress = nodeList.Items[0].Status.Addresses[0].Address } else { // Get the IP of the partition service to configure the external server address in the values file for the clients cluster. - partitionServiceName := fmt.Sprintf("%s-consul-partition-service", releaseName) + partitionServiceName := fmt.Sprintf("%s-consul-partition", releaseName) logger.Logf(t, "retrieving partition service to determine external address for servers") // It can take some time for the load balancers to be ready and have an IP/Hostname. From e2bb3d0f439a8eead9019495814d36092e73cd46 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Thu, 27 Jan 2022 14:42:23 -0500 Subject: [PATCH 252/418] Set chart version to 0.40.0 (#1004) * Set chart version to 0.40.0 * Fix image too * Fix one more thing. --- charts/consul/Chart.yaml | 4 ++-- charts/consul/values.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index 75bbd9708f..d5c1f18444 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: consul -version: 0.39.0 +version: 0.40.0 appVersion: 1.11.2 kubeVersion: ">=1.18.0-0" description: Official HashiCorp Consul Chart @@ -15,7 +15,7 @@ annotations: - name: consul image: hashicorp/consul:1.11.2 - name: consul-k8s-control-plane - image: hashicorp/consul-k8s-control-plane:0.39.0 + image: hashicorp/consul-k8s-control-plane:0.40.0 - name: envoy image: envoyproxy/envoy-alpine:v1.20.1 artifacthub.io/license: MPL-2.0 diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 7617e0a679..2f8841028b 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -105,7 +105,7 @@ global: # image that is used for functionality such as catalog sync. # This can be overridden per component. # @default: hashicorp/consul-k8s-control-plane: - imageK8S: "hashicorp/consul-k8s-control-plane:0.39.0" + imageK8S: "hashicorp/consul-k8s-control-plane:0.40.0" # The name of the datacenter that the agents should # register as. This can't be changed once the Consul cluster is up and running From ecee60bec432c3a5adba5bff7f6531a183f8831e Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Thu, 27 Jan 2022 19:43:18 +0000 Subject: [PATCH 253/418] Release v0.40.0 --- CHANGELOG.md | 2 +- cli/version/version.go | 4 ++-- control-plane/version/version.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfcf2d9349..6e796720c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.40.0 (January 27, 2022) BREAKING CHANGES: * Helm diff --git a/cli/version/version.go b/cli/version/version.go index 9f9594da46..d3eba8e85d 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.39.0" + Version = "0.40.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 9f9594da46..d3eba8e85d 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.39.0" + Version = "0.40.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From b419bc09d9be9344d4a065f5d158b49ed2bea439 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Thu, 27 Jan 2022 20:01:51 +0000 Subject: [PATCH 254/418] Putting source back into Dev Mode --- CHANGELOG.md | 2 ++ cli/version/version.go | 2 +- control-plane/version/version.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e796720c9..4e0df7c547 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## UNRELEASED + ## 0.40.0 (January 27, 2022) BREAKING CHANGES: diff --git a/cli/version/version.go b/cli/version/version.go index d3eba8e85d..1c0fec12d8 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index d3eba8e85d..1c0fec12d8 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable From bdaf0b99ba16dd9910583a6048c7a1fa6dceea01 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Fri, 28 Jan 2022 11:56:00 -0500 Subject: [PATCH 255/418] Fix Makefile Contrib Instructions (#1002) --- CONTRIBUTING.md | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb60a3d423..a4ee4db86a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,31 +39,25 @@ You will also need to install the Docker engine: Clone the repository: ```shell -$ git clone https://github.com/hashicorp/consul-k8s.git +git clone https://github.com/hashicorp/consul-k8s.git ``` -Change directories into the appropriate folder: +Compile the `consul-k8s-control-plane` binary for your local machine: ```shell -$ cd control-plane +make control-plane-dev ``` -To compile the `consul-k8s-control-plane` binary for your local machine: - -```shell -$ make dev -``` - -This will compile the `consul-k8s-control-plane` binary into `bin/consul-k8s-control-plane` as +This will compile the `consul-k8s-control-plane` binary into `control-plane/bin/consul-k8s-control-plane` as well as your `$GOPATH` and run the test suite. -If you just want to run the tests: +Run the tests: ```shell -$ make test +make control-plane-test ``` -Or to run a specific test in the suite: +Run a specific test in the suite. Change directory into `control-plane`. ```shell go test ./... -run SomeTestFunction_name @@ -72,22 +66,14 @@ go test ./... -run SomeTestFunction_name To create a docker image with your local changes: ```shell -$ make dev-docker +make control-plane-dev-docker ``` -If you'd like to use your docker images in a dev deployment of Consul K8s, you would need to push those images to Docker Hub since -deploying off of local images is not supported unless you host your own local Docker registry: +To use your Docker image in a dev deployment of Consul K8s, push the image to Docker Hub or your own registry. Deploying from local images is not supported. ``` -$ docker tag consul-k8s-control-plane-dev /consul-k8s-control-plane-dev -$ docker push /consul-k8s-control-plane-dev -Using default tag: latest -The push refers to repository [docker.io//consul-k8s-control-plane-dev] -4c5225fbac5e: Pushed -737cd00c4260: Pushed -7a9c7d9855c2: Pushed -e2eb06d8af82: Pushed -latest: digest: sha256:0b3e90e0b32da8aba1b11cda6a6a768a5eb4d83664a408d53f1502db8703ef8a size: 1160 +docker tag consul-k8s-control-plane-dev /consul-k8s-control-plane-dev +docker push /consul-k8s-control-plane-dev ``` Create a `values.dev.yaml` file that includes the `global.imageK8S` flag to point to dev images you just pushed: @@ -96,7 +82,7 @@ Create a `values.dev.yaml` file that includes the `global.imageK8S` flag to poin global: tls: enabled: true - imageK8S: /consul-k8s-control-plane-dev + imageK8S: /consul-k8s-control-plane-dev server: replicas: 1 connectInject: From 6f0fae90ba40d8416032e31e286fd1bc377ae30e Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Fri, 28 Jan 2022 13:49:53 -0800 Subject: [PATCH 256/418] Use kube svc dns for api gateway sds (#1007) * Use kube svc dns for api gateway sds Previously it was using the pod IP of the controller and then when gateways were created they were hardcoded to use that pod IP. This was an issue because if the controller pod dies then there will be a new pod IP and the gateway will lose its connection to the SDS service. Instead, this PR changes it to use the kube dns url. * Changelog * Remove unused IP env var --- CHANGELOG.md | 4 ++++ .../templates/api-gateway-controller-deployment.yaml | 6 +----- .../test/unit/api-gateway-controller-deployment.bats | 11 +++++++++++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e0df7c547..646519a72e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## UNRELEASED +BUG FIXES: +* API Gateway + * Fix issue where if the API gateway controller pods restarted, gateway pods would become disconnected from the secret discovery service. [[GH-1007](https://github.com/hashicorp/consul-k8s/pull/1007)] + ## 0.40.0 (January 27, 2022) BREAKING CHANGES: diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml index aee171e6da..2622fec731 100644 --- a/charts/consul/templates/api-gateway-controller-deployment.yaml +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -59,10 +59,6 @@ spec: valueFrom: fieldRef: fieldPath: status.hostIP - - name: IP - valueFrom: - fieldRef: - fieldPath: status.podIP {{- if .Values.global.acls.manageSystemACLs }} - name: CONSUL_HTTP_TOKEN valueFrom: @@ -81,7 +77,7 @@ spec: - "-ec" - | consul-api-gateway server \ - -sds-server-host $(IP) \ + -sds-server-host {{ template "consul.fullname" . }}-api-gateway-controller.{{ .Release.Namespace }}.svc \ -k8s-namespace {{ .Release.Namespace }} \ -log-level {{ default .Values.global.logLevel .Values.apiGateway.logLevel }} \ volumeMounts: diff --git a/charts/consul/test/unit/api-gateway-controller-deployment.bats b/charts/consul/test/unit/api-gateway-controller-deployment.bats index 434c7dbd7b..73b23e26ef 100755 --- a/charts/consul/test/unit/api-gateway-controller-deployment.bats +++ b/charts/consul/test/unit/api-gateway-controller-deployment.bats @@ -48,6 +48,17 @@ load _helpers [ "${actual}" = "\"bar\"" ] } +@test "apiGateway/Deployment: SDS host set correctly" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | join(" ") | contains("-sds-server-host RELEASE-NAME-consul-api-gateway-controller.default.svc")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + #-------------------------------------------------------------------- # nodeSelector From 3214b444e14a5650c7f5204a876f9c01c83d5f1a Mon Sep 17 00:00:00 2001 From: David Yu Date: Mon, 31 Jan 2022 12:27:11 -0800 Subject: [PATCH 257/418] values.yaml: feedback from consul PR#12224 (#1010) * values.yaml: feedback from consul PR#12224 https://github.com/hashicorp/consul/pull/12224 feedback from @karl-cardenas-coding * add more formatting --- charts/consul/values.yaml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 2f8841028b..d77f01dbf8 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -122,9 +122,9 @@ global: # and have necessary secrets, policies and roles created prior to installing Consul. # See https://www.consul.io/docs/k8s/installation/vault for full instructions. # - # The Vault cluster *must* not have the Consul cluster installed by this Helm chart as its storage backend + # The Vault cluster _must_ not have the Consul cluster installed by this Helm chart as its storage backend # as that would cause a circular dependency. - # It can have Consul as its storage backend as long as that Consul cluster is not running on this Kubernetes cluster + # Vault can have Consul as its storage backend as long as that Consul cluster is not running on this Kubernetes cluster # and is being managed separately from this Helm installation. # # Note: When using Vault KV2 secrets engines the "data" field is implicitly required for Vault API calls, @@ -140,8 +140,8 @@ global: # have a policy with read capabilities for the following secrets: # - gossip encryption key defined by `global.gossipEncryption.secretName`. # To discover the service account name of the Consul server, run - # ``` - # helm template -s templates/server-serviceaccount.yaml hashicorp/consul + # ```shell-session + # $ helm template --show-only templates/server-serviceaccount.yaml hashicorp/consul # ``` # and check the name of `metadata.name`. consulServerRole: "" @@ -151,8 +151,8 @@ global: # have a policy with read capabilities for the following secrets: # - gossip encryption key defined by `global.gossipEncryption.secretName`. # To discover the service account name of the Consul server, run - # ``` - # helm template -s templates/client-daemonset.yaml charts/consul + # ```shell-session + # $ helm template --show-only templates/client-daemonset.yaml charts/consul # ``` # and check the name of `metadata.name`. consulClientRole: "" @@ -220,12 +220,12 @@ global: # If `global.secretsBackend.vault.enabled=true`, be sure to add the "data" component of the secretName path as required by # the Vault KV-2 secrets engine [see example]. # - # ``` + # ```shell-session # $ kubectl create secret generic consul-gossip-encryption-key --from-literal=key=$(consul keygen) # ``` # # Vault CLI Example: - # ``` + # ```shell-session # $ vault kv put consul/secrets/gossip key=$(consul keygen) # ``` # `gossipEncryption.secretName="consul/data/secrets/gossip"` @@ -289,8 +289,8 @@ global: # If you have generated the CA yourself with the consul CLI, you could use the following command to create the secret # in Kubernetes: # - # ```bash - # kubectl create secret generic consul-ca-cert \ + # ```shell-session + # $ kubectl create secret generic consul-ca-cert \ # --from-file='tls.crt=./consul-agent-ca.pem' # ``` # If you are using Vault as a secrets backend with TLS, `caCert.secretName` must be provided and should reference @@ -309,8 +309,8 @@ global: # with the consul CLI, you could use the following command to create the secret # in Kubernetes: # - # ```bash - # kubectl create secret generic consul-ca-key \ + # ```shell-session + # $ kubectl create secret generic consul-ca-key \ # --from-file='tls.key=./consul-agent-ca-key.pem' # ``` # @@ -682,7 +682,7 @@ server: # # This can also be set using Helm's `--set` flag using the following syntax: # - # ```shell + # ```shell-session # --set 'server.extraConfig="{"log_level": "DEBUG"}"' # ``` extraConfig: | @@ -889,8 +889,8 @@ externalServers: # # You could retrieve this value from your `kubeconfig` by running: # - # ```shell - # kubectl config view \ + # ```shell-session + # $ kubectl config view \ # -o jsonpath="{.clusters[?(@.name=='')].cluster.server}" # ``` # @@ -1024,7 +1024,7 @@ client: # # This can also be set using Helm's `--set` flag using the following syntax: # - # ```shell + # ```shell-session # --set 'client.extraConfig="{"log_level": "DEBUG"}"' # ``` extraConfig: | From b27524321c126241b16ff929161bac9c52bfcdd4 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 1 Feb 2022 12:46:02 -0500 Subject: [PATCH 258/418] Clarify flags and output for CLI (#1009) * Clarify install command flags and output * Clarify status command flags and output * Clarify upgrade command flags and output * Clarify version flags and output * Add a pretty line above the diff * Fix failing test --- cli/cmd/install/install.go | 94 ++++++++++++++++----------------- cli/cmd/install/install_test.go | 2 +- cli/cmd/status/status.go | 18 ++++--- cli/cmd/upgrade/upgrade.go | 52 +++++++++--------- cli/cmd/version/version.go | 19 ++++--- 5 files changed, 97 insertions(+), 88 deletions(-) diff --git a/cli/cmd/install/install.go b/cli/cmd/install/install.go index dd9f9f7abc..f33b044ef8 100644 --- a/cli/cmd/install/install.go +++ b/cli/cmd/install/install.go @@ -99,19 +99,19 @@ func (c *Command) init() { Name: flagNameDryRun, Target: &c.flagDryRun, Default: defaultDryRun, - Usage: "Run pre-install checks and display summary of installation.", + Usage: "Perform pre-install checks and display a summary of the installation.", }) f.StringSliceVar(&flag.StringSliceVar{ Name: flagNameConfigFile, Aliases: []string{"f"}, Target: &c.flagValueFiles, - Usage: "Path to a file to customize the installation, such as Consul Helm chart values file. Can be specified multiple times.", + Usage: "Set the path to a file to customize the installation, such as Consul Helm chart values file. Can be specified multiple times.", }) f.StringVar(&flag.StringVar{ Name: flagNameNamespace, Target: &c.flagNamespace, Default: common.DefaultReleaseNamespace, - Usage: "Namespace for the Consul installation.", + Usage: "Set the namespace for the Consul installation.", }) f.StringVar(&flag.StringVar{ Name: flagNamePreset, @@ -127,8 +127,8 @@ func (c *Command) init() { f.StringSliceVar(&flag.StringSliceVar{ Name: flagNameFileValues, Target: &c.flagFileValues, - Usage: "Set a value to customize via a file. The contents of the file will be set as the value. Can be " + - "specified multiple times. Supports Consul Helm chart values.", + Usage: "Set a value to customize using a file. The contents of the file will be set as the value." + + "Can be specified multiple times. Supports Consul Helm chart values.", }) f.StringSliceVar(&flag.StringSliceVar{ Name: flagNameSetStringValues, @@ -139,20 +139,20 @@ func (c *Command) init() { Name: flagNameTimeout, Target: &c.flagTimeout, Default: defaultTimeout, - Usage: "Timeout to wait for installation to be ready.", + Usage: "Set a timeout to wait for installation to be ready.", }) f.BoolVar(&flag.BoolVar{ Name: flagNameVerbose, Aliases: []string{"v"}, Target: &c.flagVerbose, Default: defaultVerbose, - Usage: "Output verbose logs from the install command with the status of resources being installed.", + Usage: "Output verbose logs from the command with the status of resources being installed.", }) f.BoolVar(&flag.BoolVar{ Name: flagNameWait, Target: &c.flagWait, Default: defaultWait, - Usage: "Determines whether to wait for resources in installation to be ready before exiting command.", + Usage: "Wait for Kubernetes resources in installation to be ready before exiting command.", }) f = c.set.NewSet("Global Options") @@ -161,13 +161,13 @@ func (c *Command) init() { Aliases: []string{"c"}, Target: &c.flagKubeConfig, Default: "", - Usage: "Path to kubeconfig file.", + Usage: "Set the path to kubeconfig file.", }) f.StringVar(&flag.StringVar{ Name: "context", Target: &c.flagKubeContext, Default: "", - Usage: "Kubernetes context to use.", + Usage: "Set the Kubernetes context to use.", }) c.help = c.set.Help() @@ -189,6 +189,7 @@ type enterpriseLicense struct { SecretKey string `yaml:"secretKey"` } +// Run installs Consul into a Kubernetes cluster. func (c *Command) Run(args []string) int { c.once.Do(c.init) @@ -202,6 +203,10 @@ func (c *Command) Run(args []string) int { return 1 } + if c.flagDryRun { + c.UI.Output("Performing dry run install. No changes will be made to the cluster.", terminal.WithHeaderStyle()) + } + // helmCLI.New() will create a settings object which is used by the Helm Go SDK calls. settings := helmCLI.New() @@ -236,39 +241,39 @@ func (c *Command) Run(args []string) int { if c.kubernetes == nil { restConfig, err := settings.RESTClientGetter().ToRESTConfig() if err != nil { - c.UI.Output("Retrieving Kubernetes auth: %v", err, terminal.WithErrorStyle()) + c.UI.Output("Error retrieving Kubernetes authentication:\n%v", err, terminal.WithErrorStyle()) return 1 } c.kubernetes, err = kubernetes.NewForConfig(restConfig) if err != nil { - c.UI.Output("Initializing Kubernetes client: %v", err, terminal.WithErrorStyle()) + c.UI.Output("Error initializing Kubernetes client:\n%v", err, terminal.WithErrorStyle()) return 1 } } - c.UI.Output("Pre-Install Checks", terminal.WithHeaderStyle()) + c.UI.Output("Checking if Consul can be installed", terminal.WithHeaderStyle()) - // Note the logic here, common's CheckForInstallations function returns an error if - // the release is not found, which in the install command is what we need for a successful install. + // Ensure there is not an existing Consul installation which would cause a conflict. if name, ns, err := common.CheckForInstallations(settings, uiLogger); err == nil { - c.UI.Output(fmt.Sprintf("existing Consul installation found (name=%s, namespace=%s) - run "+ - "consul-k8s uninstall if you wish to re-install", name, ns), terminal.WithErrorStyle()) + c.UI.Output("Cannot install Consul. A Consul cluster is already installed in namespace %s with name %s.", ns, name, terminal.WithErrorStyle()) + c.UI.Output("Use the command `consul-k8s uninstall` to uninstall Consul from the cluster.", terminal.WithInfoStyle()) return 1 - } else { - c.UI.Output("No existing installations found.") } + c.UI.Output("No existing Consul installations found.", terminal.WithSuccessStyle()) // Ensure there's no previous PVCs lying around. if err := c.checkForPreviousPVCs(); err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 } + c.UI.Output("No existing Consul persistent volume claims found", terminal.WithSuccessStyle()) // Ensure there's no previous bootstrap secret lying around. if err := c.checkForPreviousSecrets(); err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 } + c.UI.Output("No existing Consul secrets found", terminal.WithSuccessStyle()) // Handle preset, value files, and set values logic. vals, err := c.mergeValuesFlagsWithPrecedence(settings) @@ -289,25 +294,25 @@ func (c *Command) Run(args []string) int { return 1 } - // If an enterprise license secret was provided check that the secret exists - // and that the enterprise Consul image is set. + // If an enterprise license secret was provided, check that the secret exists and that the enterprise Consul image is set. if v.Global.EnterpriseLicense.SecretName != "" { if err := c.checkValidEnterprise(v.Global.EnterpriseLicense.SecretName); err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 } + c.UI.Output("Valid enterprise Consul secret found.", terminal.WithSuccessStyle()) } // Print out the installation summary. if !c.flagAutoApprove { c.UI.Output("Consul Installation Summary", terminal.WithHeaderStyle()) - c.UI.Output("Installation name: %s", common.DefaultReleaseName, terminal.WithInfoStyle()) + c.UI.Output("Name: %s", common.DefaultReleaseName, terminal.WithInfoStyle()) c.UI.Output("Namespace: %s", c.flagNamespace, terminal.WithInfoStyle()) if len(vals) == 0 { - c.UI.Output("Overrides: "+string(valuesYaml), terminal.WithInfoStyle()) + c.UI.Output("\nNo overrides provided, using the default Helm values.", terminal.WithInfoStyle()) } else { - c.UI.Output("Overrides:"+"\n"+string(valuesYaml), terminal.WithInfoStyle()) + c.UI.Output("\nHelm value overrides\n-------------------\n"+string(valuesYaml), terminal.WithInfoStyle()) } } @@ -316,9 +321,9 @@ func (c *Command) Run(args []string) int { // aren't double prefixed with "consul-consul-...". vals = common.MergeMaps(config.Convert(config.GlobalNameConsul), vals) - // Dry Run should exit here, no need to actual locate/download the charts. if c.flagDryRun { - c.UI.Output("Dry run complete - installation can proceed.", terminal.WithInfoStyle()) + c.UI.Output("Dry run complete. No changes were made to the Kubernetes cluster.\n"+ + "Installation can proceed with this configuration.", terminal.WithInfoStyle()) return 0 } @@ -334,12 +339,13 @@ func (c *Command) Run(args []string) int { return 1 } if common.Abort(confirmation) { - c.UI.Output("Install aborted. To learn how to customize your installation, run:\nconsul-k8s install --help", terminal.WithInfoStyle()) + c.UI.Output("Install aborted. Use the command `consul-k8s install -help` to learn how to customize your installation.", + terminal.WithInfoStyle()) return 1 } } - c.UI.Output("Running Installation", terminal.WithHeaderStyle()) + c.UI.Output("Installing Consul", terminal.WithHeaderStyle()) // Setup action configuration for Helm Go SDK function calls. actionConfig := new(action.Configuration) @@ -373,31 +379,32 @@ func (c *Command) Run(args []string) int { c.UI.Output("Downloaded charts", terminal.WithSuccessStyle()) // Run the install. - _, err = install.Run(chart, vals) - if err != nil { + if _, err = install.Run(chart, vals); err != nil { c.UI.Output(err.Error(), terminal.WithErrorStyle()) return 1 } - c.UI.Output("Consul installed into namespace %q", c.flagNamespace, terminal.WithSuccessStyle()) + c.UI.Output("Consul installed in namespace %q.", c.flagNamespace, terminal.WithSuccessStyle()) return 0 } + +// Help returns a description of the command and how it is used. func (c *Command) Help() string { c.once.Do(c.init) - s := "Usage: consul-k8s install [flags]" + "\n" + "Install Consul onto a Kubernetes cluster." + "\n" - return s + "\n" + c.help + return c.Synopsis() + "\n\nUsage: consul-k8s install [flags]\n\n" + c.help } +// Synopsis returns a one-line command summary. func (c *Command) Synopsis() string { return "Install Consul on Kubernetes." } -// checkForPreviousPVCs checks for existing PVCs with a name containing "consul-server" and returns an error and lists -// the PVCs it finds matches. +// checkForPreviousPVCs checks for existing Kubernetes persistent volume claims with a name containing "consul-server" +// and returns an error with a list of PVCs it finds if any match. func (c *Command) checkForPreviousPVCs() error { pvcs, err := c.kubernetes.CoreV1().PersistentVolumeClaims("").List(c.Ctx, metav1.ListOptions{}) if err != nil { - return fmt.Errorf("error listing PVCs: %s", err) + return fmt.Errorf("error listing persistent volume claims: %s", err) } var previousPVCs []string for _, pvc := range pvcs.Items { @@ -407,10 +414,9 @@ func (c *Command) checkForPreviousPVCs() error { } if len(previousPVCs) > 0 { - return fmt.Errorf("found PVCs from previous installations (%s), delete before re-installing", + return fmt.Errorf("found persistent volume claims from previous installations, delete before reinstalling: %s", strings.Join(previousPVCs, ",")) } - c.UI.Output("No previous persistent volume claims found", terminal.WithSuccessStyle()) return nil } @@ -423,12 +429,11 @@ func (c *Command) checkForPreviousSecrets() error { for _, secret := range secrets.Items { // future TODO: also check for federation secret if secret.ObjectMeta.Labels[common.CLILabelKey] == common.CLILabelValue { - return fmt.Errorf("found Consul secret from previous installation: %q in namespace %q. To delete, run kubectl delete secret %s --namespace %s", + return fmt.Errorf("found Consul secret from previous installation: %q in namespace %q. Use the command `kubectl delete secret %s --namespace %s` to delete", secret.Name, secret.Namespace, secret.Name, secret.Namespace) } } - c.UI.Output("No previous secrets found", terminal.WithSuccessStyle()) return nil } @@ -461,7 +466,7 @@ func (c *Command) mergeValuesFlagsWithPrecedence(settings *helmCLI.EnvSettings) return vals, err } -// validateFlags is a helper function that performs sanity checks on the user's provided flags. +// validateFlags checks the command line flags and values for errors. func (c *Command) validateFlags(args []string) error { if err := c.set.Parse(args); err != nil { return err @@ -492,15 +497,11 @@ func (c *Command) validateFlags(args []string) error { } } - if c.flagDryRun { - c.UI.Output("Performing dry run installation.", terminal.WithInfoStyle()) - } return nil } // checkValidEnterprise checks and validates an enterprise installation. -// When an enterprise license secret is provided, check that the secret exists -// in the "consul" namespace. +// When an enterprise license secret is provided, check that the secret exists in the "consul" namespace. func (c *Command) checkValidEnterprise(secretName string) error { _, err := c.kubernetes.CoreV1().Secrets(c.flagNamespace).Get(c.Ctx, secretName, metav1.GetOptions{}) @@ -509,6 +510,5 @@ func (c *Command) checkValidEnterprise(secretName string) error { } else if err != nil { return fmt.Errorf("error getting the enterprise license secret %q in the %q namespace: %s", secretName, c.flagNamespace, err) } - c.UI.Output("Valid enterprise Consul secret found.", terminal.WithSuccessStyle()) return nil } diff --git a/cli/cmd/install/install_test.go b/cli/cmd/install/install_test.go index 005e711adb..b38af685fc 100644 --- a/cli/cmd/install/install_test.go +++ b/cli/cmd/install/install_test.go @@ -30,7 +30,7 @@ func TestCheckForPreviousPVCs(t *testing.T) { c.kubernetes.CoreV1().PersistentVolumeClaims("default").Create(context.Background(), pvc2, metav1.CreateOptions{}) err := c.checkForPreviousPVCs() require.Error(t, err) - require.Contains(t, err.Error(), "found PVCs from previous installations (default/consul-server-test1,default/consul-server-test2), delete before re-installing") + require.Equal(t, err.Error(), "found persistent volume claims from previous installations, delete before reinstalling: default/consul-server-test1,default/consul-server-test2") // Clear out the client and make sure the check now passes. c.kubernetes = fake.NewSimpleClientset() diff --git a/cli/cmd/status/status.go b/cli/cmd/status/status.go index 7b7a02a03d..5c148e9921 100644 --- a/cli/cmd/status/status.go +++ b/cli/cmd/status/status.go @@ -57,6 +57,7 @@ func (c *Command) init() { c.Init() } +// Run checks the status of a Consul installation on Kubernetes. func (c *Command) Run(args []string) int { c.once.Do(c.init) @@ -95,7 +96,7 @@ func (c *Command) Run(args []string) int { c.UI.Output(logMsg, terminal.WithLibraryStyle()) } - c.UI.Output("Consul-K8s Status Summary", terminal.WithHeaderStyle()) + c.UI.Output("Consul Status Summary", terminal.WithHeaderStyle()) releaseName, namespace, err := common.CheckForInstallations(settings, uiLogger) if err != nil { @@ -125,7 +126,7 @@ func (c *Command) Run(args []string) int { return 0 } -// validateFlags is a helper function that performs checks on the user's provided flags. +// validateFlags checks the command line flags and values for errors. func (c *Command) validateFlags(args []string) error { if len(c.set.Args()) > 0 { return errors.New("should have no non-flag arguments") @@ -151,7 +152,7 @@ func (c *Command) checkHelmInstallation(settings *helmCLI.EnvSettings, uiLogger timezone, _ := rel.Info.LastDeployed.Zone() - tbl := terminal.NewTable([]string{"Name", "Namespace", "Status", "ChartVersion", "AppVersion", "Revision", "Last Updated"}...) + tbl := terminal.NewTable([]string{"Name", "Namespace", "Status", "Chart Version", "AppVersion", "Revision", "Last Updated"}...) trow := []terminal.TableEntry{ { Value: releaseName, @@ -264,12 +265,12 @@ func (c *Command) setupKubeClient(settings *helmCLI.EnvSettings) error { if c.kubernetes == nil { restConfig, err := settings.RESTClientGetter().ToRESTConfig() if err != nil { - c.UI.Output("Retrieving Kubernetes auth: %v", err, terminal.WithErrorStyle()) + c.UI.Output("Error retrieving Kubernetes authentication: %v", err, terminal.WithErrorStyle()) return err } c.kubernetes, err = kubernetes.NewForConfig(restConfig) if err != nil { - c.UI.Output("Initializing Kubernetes client: %v", err, terminal.WithErrorStyle()) + c.UI.Output("Error initializing Kubernetes client: %v", err, terminal.WithErrorStyle()) return err } } @@ -277,12 +278,13 @@ func (c *Command) setupKubeClient(settings *helmCLI.EnvSettings) error { return nil } +// Help returns a description of the command and how it is used. func (c *Command) Help() string { c.once.Do(c.init) - s := "Usage: consul-k8s status" + "\n\n" + "Get the status of the current Consul installation." + "\n" - return s + return c.Synopsis() + "\n\nUsage: consul-k8s status [flags]\n\n" + c.help } +// Synopsis returns a one-line command summary. func (c *Command) Synopsis() string { - return "Status of Consul-K8s installation." + return "Check the status of a Consul installation on Kubernetes." } diff --git a/cli/cmd/upgrade/upgrade.go b/cli/cmd/upgrade/upgrade.go index 5c9cf80651..a0923e3089 100644 --- a/cli/cmd/upgrade/upgrade.go +++ b/cli/cmd/upgrade/upgrade.go @@ -91,13 +91,13 @@ func (c *Command) init() { Name: flagNameDryRun, Target: &c.flagDryRun, Default: defaultDryRun, - Usage: "Run pre-upgrade checks and display summary of upgrade.", + Usage: "Perform pre-upgrade checks and display summary of upgrade.", }) f.StringSliceVar(&flag.StringSliceVar{ Name: flagNameConfigFile, Aliases: []string{"f"}, Target: &c.flagValueFiles, - Usage: "Path to a file to customize the upgrade, such as Consul Helm chart values file. Can be specified multiple times.", + Usage: "Set the path to a file to customize the upgrade, such as Consul Helm chart values file. Can be specified multiple times.", }) f.StringVar(&flag.StringVar{ Name: flagNamePreset, @@ -113,8 +113,8 @@ func (c *Command) init() { f.StringSliceVar(&flag.StringSliceVar{ Name: flagNameFileValues, Target: &c.flagFileValues, - Usage: "Set a value to customize via a file. The contents of the file will be set as the value. Can be " + - "specified multiple times. Supports Consul Helm chart values.", + Usage: "Set a value to customize using a file. The contents of the file will be set as the value." + + "Can be specified multiple times. Supports Consul Helm chart values.", }) f.StringSliceVar(&flag.StringSliceVar{ Name: flagNameSetStringValues, @@ -125,20 +125,20 @@ func (c *Command) init() { Name: flagNameTimeout, Target: &c.flagTimeout, Default: defaultTimeout, - Usage: "Timeout to wait for upgrade to be ready.", + Usage: "Set a timeout to wait for upgrade to be ready.", }) f.BoolVar(&flag.BoolVar{ Name: flagNameVerbose, Aliases: []string{"v"}, Target: &c.flagVerbose, Default: defaultVerbose, - Usage: "Output verbose logs from the upgrade command with the status of resources being upgraded.", + Usage: "Output verbose logs from the command with the status of resources being upgraded.", }) f.BoolVar(&flag.BoolVar{ Name: flagNameWait, Target: &c.flagWait, Default: defaultWait, - Usage: "Determines whether to wait for resources in upgrade to be ready before exiting command.", + Usage: "Wait for Kubernetes resources in upgrade to be ready before exiting command.", }) f = c.set.NewSet("Global Options") @@ -147,13 +147,13 @@ func (c *Command) init() { Aliases: []string{"c"}, Target: &c.flagKubeConfig, Default: "", - Usage: "Path to kubeconfig file.", + Usage: "Set the path to kubeconfig file.", }) f.StringVar(&flag.StringVar{ Name: "context", Target: &c.flagKubeContext, Default: "", - Usage: "Kubernetes context to use.", + Usage: "Set the Kubernetes context to use.", }) c.help = c.set.Help() @@ -175,7 +175,7 @@ func (c *Command) Run(args []string) int { } if c.flagDryRun { - c.UI.Output("Dry Run Upgrade: No changes will be made to the cluster.") + c.UI.Output("Performing dry run upgrade. No changes will be made to the cluster.", terminal.WithInfoStyle()) } c.timeoutDuration, err = time.ParseDuration(c.flagTimeout) @@ -203,24 +203,24 @@ func (c *Command) Run(args []string) int { if c.kubernetes == nil { restConfig, err := settings.RESTClientGetter().ToRESTConfig() if err != nil { - c.UI.Output("Retrieving Kubernetes auth: %v", err, terminal.WithErrorStyle()) + c.UI.Output("Error retrieving Kubernetes authentication:\n%v", err, terminal.WithErrorStyle()) return 1 } c.kubernetes, err = kubernetes.NewForConfig(restConfig) if err != nil { - c.UI.Output("Initializing Kubernetes client: %v", err, terminal.WithErrorStyle()) + c.UI.Output("Error initializing Kubernetes client:\n%v", err, terminal.WithErrorStyle()) return 1 } } - c.UI.Output("Pre-Upgrade Checks", terminal.WithHeaderStyle()) + c.UI.Output("Checking if Consul can be upgraded", terminal.WithHeaderStyle()) uiLogger := c.createUILogger() name, namespace, err := common.CheckForInstallations(settings, uiLogger) if err != nil { - c.UI.Output("Could not find existing Consul installation. Run 'consul-k8s install' to create one.") + c.UI.Output("Cannot upgrade Consul. Existing Consul installation not found. Use the command `consul-k8s install` to install Consul.", terminal.WithErrorStyle()) return 1 } - c.UI.Output("Existing installation found to be upgraded.", terminal.WithSuccessStyle()) + c.UI.Output("Existing Consul installation found to be upgraded.", terminal.WithSuccessStyle()) c.UI.Output("Name: %s\nNamespace: %s", name, namespace, terminal.WithInfoStyle()) chart, err := helm.LoadChart(consulChart.ConsulHelmChart, common.TopLevelChartDirName) @@ -250,7 +250,7 @@ func (c *Command) Run(args []string) int { // Print out the upgrade summary. if err = c.printDiff(currentChartValues, chartValues); err != nil { - c.UI.Output("Could not print diff between charts.", terminal.WithErrorStyle()) + c.UI.Output("Could not print the different between current and upgraded charts: %v", err, terminal.WithErrorStyle()) return 1 } @@ -267,13 +267,14 @@ func (c *Command) Run(args []string) int { return 1 } if common.Abort(confirmation) { - c.UI.Output("Upgrade aborted. To learn how to customize your upgrade, run:\nconsul-k8s upgrade --help", terminal.WithInfoStyle()) + c.UI.Output("Upgrade aborted. Use the command `consul-k8s upgrade -help` to learn how to customize your upgrade.", + terminal.WithInfoStyle()) return 1 } } if !c.flagDryRun { - c.UI.Output("Running Upgrade", terminal.WithHeaderStyle()) + c.UI.Output("Upgrading Consul", terminal.WithHeaderStyle()) } else { c.UI.Output("Performing Dry Run Upgrade", terminal.WithHeaderStyle()) } @@ -300,13 +301,13 @@ func (c *Command) Run(args []string) int { return 1 } - // Dry Run should exit here, printing the release's config. if c.flagDryRun { - c.UI.Output("Dry run complete - upgrade can proceed.", terminal.WithInfoStyle()) + c.UI.Output("Dry run complete. No changes were made to the Kubernetes cluster.\n"+ + "Upgrade can proceed with this configuration.", terminal.WithInfoStyle()) return 0 } - c.UI.Output("Upgraded Consul into namespace %q", namespace, terminal.WithSuccessStyle()) + c.UI.Output("Consul upgraded in namespace %q.", namespace, terminal.WithSuccessStyle()) return 0 } @@ -367,13 +368,13 @@ func (c *Command) mergeValuesFlagsWithPrecedence(settings *helmCLI.EnvSettings) return vals, err } -// Help returns a description of this command and how it can be used. +// Help returns a description of the command and how it is used. func (c *Command) Help() string { c.once.Do(c.init) - return fmt.Sprintf("Usage: consul-k8s upgrade [flags]\n%s\n\n%s", c.Synopsis(), c.help) + return c.Synopsis() + "\n\nUsage: consul-k8s upgrade [flags]\n\n" + c.help } -// Synopsis returns a short string describing the command. +// Synopsis returns a one-line command summary. func (c *Command) Synopsis() string { return "Upgrade Consul on Kubernetes from an existing installation." } @@ -402,7 +403,8 @@ func (c *Command) printDiff(old, new map[string]interface{}) error { return err } - c.UI.Output("Diff between user overrides", terminal.WithHeaderStyle()) + c.UI.Output("\nDifference between user overrides for current and upgraded charts"+ + "\n--------------------------------------------------------------", terminal.WithInfoStyle()) for _, line := range strings.Split(diff, "\n") { if strings.HasPrefix(line, "+") { c.UI.Output(line, terminal.WithDiffAddedStyle()) diff --git a/cli/cmd/version/version.go b/cli/cmd/version/version.go index d565309b5a..b8b2235f46 100644 --- a/cli/cmd/version/version.go +++ b/cli/cmd/version/version.go @@ -1,33 +1,38 @@ package version import ( - "fmt" "sync" "github.com/hashicorp/consul-k8s/cli/common" + "github.com/hashicorp/consul-k8s/cli/common/terminal" ) type Command struct { *common.BaseCommand + // Version is the Consul on Kubernetes CLI version. Version string - once sync.Once + + once sync.Once } func (c *Command) init() { c.Init() } +// Run prints the version of the Consul on Kubernetes CLI. func (c *Command) Run(_ []string) int { c.once.Do(c.init) - c.UI.Output(fmt.Sprintf("consul-k8s %s", c.Version)) + c.UI.Output("consul-k8s %s", c.Version, terminal.WithInfoStyle()) return 0 } -func (c *Command) Synopsis() string { - return "Prints the version of the CLI." +// Help returns a description of the command and how it is used. +func (c *Command) Help() string { + return "Usage: consul-k8s version\n\n" + c.Synopsis() } -func (c *Command) Help() string { - return "Usage: consul version [options]\n" +// Synopsis returns a one-line command summary. +func (c *Command) Synopsis() string { + return "Print the version of the Consul on Kubernetes CLI." } From e82abe6122efa46c3ed9ffc825a4044c0b9328e1 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Tue, 1 Feb 2022 12:46:46 -0500 Subject: [PATCH 259/418] Add CLI link to Helm startup (#1011) * Remove index.html from docs link * Add CLI reference --- charts/consul/templates/NOTES.txt | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/charts/consul/templates/NOTES.txt b/charts/consul/templates/NOTES.txt index f14c2e7b43..135948a375 100644 --- a/charts/consul/templates/NOTES.txt +++ b/charts/consul/templates/NOTES.txt @@ -1,12 +1,6 @@ Thank you for installing HashiCorp Consul! -Now that you have deployed Consul, you should look over the docs on using -Consul with Kubernetes available here: - -https://www.consul.io/docs/platform/k8s/index.html - - Your release is named {{ .Release.Name }}. To learn more about the release, run: @@ -14,6 +8,11 @@ To learn more about the release, run: $ helm status {{ .Release.Name }} $ helm get all {{ .Release.Name }} +Consul on Kubernetes Documentation: +https://www.consul.io/docs/platform/k8s + +Consul on Kubernetes CLI Reference: +https://www.consul.io/docs/k8s/k8s-cli {{- if (and .Values.global.acls.manageSystemACLs (gt (len .Values.server.extraConfig) 3)) }} Warning: Defining server extraConfig potentially disrupts the automatic ACL From e0db0c1f873873ba20565dac1f45332d0a6bb7d7 Mon Sep 17 00:00:00 2001 From: Nathan Coleman Date: Wed, 2 Feb 2022 17:56:20 -0500 Subject: [PATCH 260/418] Allow API Gateway controller to update k8s Deployments + Services (#1014) * Allow ClusterRole for API gateway to update existing Service * Allow ClusterRole for API gateway to update existing Deployment * Update CHANGELOG --- CHANGELOG.md | 1 + charts/consul/templates/api-gateway-controller-clusterrole.yaml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 646519a72e..381e2f3b0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ BUG FIXES: * API Gateway * Fix issue where if the API gateway controller pods restarted, gateway pods would become disconnected from the secret discovery service. [[GH-1007](https://github.com/hashicorp/consul-k8s/pull/1007)] + * Fix issue where the API gateway controller could not update existing Deployments or Services. [[GH-1014](https://github.com/hashicorp/consul-k8s/pull/1014)] ## 0.40.0 (January 27, 2022) diff --git a/charts/consul/templates/api-gateway-controller-clusterrole.yaml b/charts/consul/templates/api-gateway-controller-clusterrole.yaml index c6a69106c8..143d7a09e6 100644 --- a/charts/consul/templates/api-gateway-controller-clusterrole.yaml +++ b/charts/consul/templates/api-gateway-controller-clusterrole.yaml @@ -34,6 +34,7 @@ rules: - create - get - list + - update - watch - apiGroups: - coordination.k8s.io @@ -94,6 +95,7 @@ rules: - create - get - list + - update - watch - apiGroups: - "" From 5027066696e2a95fea6342da96081c1581574149 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Thu, 3 Feb 2022 10:28:03 -0700 Subject: [PATCH 261/418] vault: allow passing arbitrary vault agent annotations (#1015) --- CHANGELOG.md | 3 ++ charts/consul/templates/client-daemonset.yaml | 3 ++ .../client-snapshot-agent-deployment.yaml | 3 ++ .../templates/connect-inject-deployment.yaml | 3 ++ .../templates/controller-deployment.yaml | 3 ++ .../ingress-gateways-deployment.yaml | 3 ++ .../consul/templates/server-acl-init-job.yaml | 3 ++ .../consul/templates/server-statefulset.yaml | 3 ++ .../templates/sync-catalog-deployment.yaml | 3 ++ .../terminating-gateways-deployment.yaml | 3 ++ charts/consul/test/unit/client-daemonset.bats | 28 ++++++++++++++ .../client-snapshot-agent-deployment.bats | 36 ++++++++++++++++++ .../test/unit/connect-inject-deployment.bats | 36 ++++++++++++++++++ .../test/unit/controller-deployment.bats | 36 ++++++++++++++++++ .../unit/ingress-gateways-deployment.bats | 38 +++++++++++++++++++ .../consul/test/unit/server-acl-init-job.bats | 36 ++++++++++++++++++ .../consul/test/unit/server-statefulset.bats | 28 ++++++++++++++ .../test/unit/sync-catalog-deployment.bats | 36 ++++++++++++++++++ .../unit/terminating-gateways-deployment.bats | 38 +++++++++++++++++++ charts/consul/values.yaml | 13 +++++++ 20 files changed, 355 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 381e2f3b0f..bebe8d2d37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ ## UNRELEASED +IMPROVEMENTS: +* Helm + * Vault: Allow passing arbitrary annotations to the vault agent. [[GH-1015](https://github.com/hashicorp/consul-k8s/pull/1015)] BUG FIXES: * API Gateway diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index 7c9c08d91f..9c7a8076d2 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -60,6 +60,9 @@ spec: "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} {{- end }} + {{- if .Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} + {{- end }} {{- end }} "consul.hashicorp.com/connect-inject": "false" "consul.hashicorp.com/config-checksum": {{ include (print $.Template.BasePath "/client-config-configmap.yaml") . | sha256sum }} diff --git a/charts/consul/templates/client-snapshot-agent-deployment.yaml b/charts/consul/templates/client-snapshot-agent-deployment.yaml index e9377b49e9..fd6266e803 100644 --- a/charts/consul/templates/client-snapshot-agent-deployment.yaml +++ b/charts/consul/templates/client-snapshot-agent-deployment.yaml @@ -38,6 +38,9 @@ spec: "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" {{- end }} + {{- if .Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} + {{- end }} {{- end }} spec: {{- if .Values.client.tolerations }} diff --git a/charts/consul/templates/connect-inject-deployment.yaml b/charts/consul/templates/connect-inject-deployment.yaml index 552b51f8ae..cd5ad9ddd2 100644 --- a/charts/consul/templates/connect-inject-deployment.yaml +++ b/charts/consul/templates/connect-inject-deployment.yaml @@ -48,6 +48,9 @@ spec: "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" {{- end }} + {{- if .Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} + {{- end }} {{- end }} spec: serviceAccountName: {{ template "consul.fullname" . }}-connect-injector diff --git a/charts/consul/templates/controller-deployment.yaml b/charts/consul/templates/controller-deployment.yaml index 5caf5e6a48..e5ed0d74f5 100644 --- a/charts/consul/templates/controller-deployment.yaml +++ b/charts/consul/templates/controller-deployment.yaml @@ -40,6 +40,9 @@ spec: "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" {{- end }} + {{- if .Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} + {{- end }} {{- end }} spec: {{- if or .Values.global.acls.manageSystemACLs (and .Values.global.tls.enabled .Values.global.tls.enableAutoEncrypt) }} diff --git a/charts/consul/templates/ingress-gateways-deployment.yaml b/charts/consul/templates/ingress-gateways-deployment.yaml index 8d0ba09cdb..d520bd9845 100644 --- a/charts/consul/templates/ingress-gateways-deployment.yaml +++ b/charts/consul/templates/ingress-gateways-deployment.yaml @@ -65,6 +65,9 @@ spec: "vault.hashicorp.com/agent-extra-secret": {{ $root.Values.global.secretsBackend.vault.ca.secretName }} "vault.hashicorp.com/ca-cert": /vault/custom/{{ $root.Values.global.secretsBackend.vault.ca.secretKey }} {{- end }} + {{- if $root.Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl $root.Values.global.secretsBackend.vault.agentAnnotations $root | nindent 8 | trim }} + {{- end }} {{- end }} "consul.hashicorp.com/connect-inject": "false" {{- if (and $root.Values.global.metrics.enabled $root.Values.global.metrics.enableGatewayMetrics) }} diff --git a/charts/consul/templates/server-acl-init-job.yaml b/charts/consul/templates/server-acl-init-job.yaml index 191338d41d..5195e7975e 100644 --- a/charts/consul/templates/server-acl-init-job.yaml +++ b/charts/consul/templates/server-acl-init-job.yaml @@ -44,6 +44,9 @@ spec: "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" {{- end }} + {{- if .Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} + {{- end }} {{- end }} spec: restartPolicy: Never diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index b0e5798aff..0a6c16778b 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -75,6 +75,9 @@ spec: "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ include "consul.serverTLSCATemplate" . }} {{- end }} + {{- if .Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} + {{- end }} {{- end }} "consul.hashicorp.com/connect-inject": "false" "consul.hashicorp.com/config-checksum": {{ include (print $.Template.BasePath "/server-config-configmap.yaml") . | sha256sum }} diff --git a/charts/consul/templates/sync-catalog-deployment.yaml b/charts/consul/templates/sync-catalog-deployment.yaml index 863eab2b10..2aedc54460 100644 --- a/charts/consul/templates/sync-catalog-deployment.yaml +++ b/charts/consul/templates/sync-catalog-deployment.yaml @@ -43,6 +43,9 @@ spec: "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" {{- end }} + {{- if .Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} + {{- end }} {{- end }} spec: serviceAccountName: {{ template "consul.fullname" . }}-sync-catalog diff --git a/charts/consul/templates/terminating-gateways-deployment.yaml b/charts/consul/templates/terminating-gateways-deployment.yaml index f99d9f1c26..902329a74a 100644 --- a/charts/consul/templates/terminating-gateways-deployment.yaml +++ b/charts/consul/templates/terminating-gateways-deployment.yaml @@ -63,6 +63,9 @@ spec: "vault.hashicorp.com/agent-extra-secret": {{ $root.Values.global.secretsBackend.vault.ca.secretName }} "vault.hashicorp.com/ca-cert": /vault/custom/{{ $root.Values.global.secretsBackend.vault.ca.secretKey }} {{- end }} + {{- if $root.Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl $root.Values.global.secretsBackend.vault.agentAnnotations $root | nindent 8 | trim }} + {{- end }} {{- end }} "consul.hashicorp.com/connect-inject": "false" {{- if (and $root.Values.global.metrics.enabled $root.Values.global.metrics.enableGatewayMetrics) }} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index c7fbf11c9c..2da0d4d9a0 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1834,4 +1834,32 @@ rollingUpdate: local actual=$(echo $object | yq -r '.containers[0].command | any(contains("ca_file = \"/vault/secrets/serverca.crt\""))' | tee /dev/stderr) [ "${actual}" = "true" ] +} + +#-------------------------------------------------------------------- +# Vault agent annotations + +@test "client/DaemonSet: no vault agent annotations defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."consul.hashicorp.com/config-checksum") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/role")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "client/DaemonSet: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] } \ No newline at end of file diff --git a/charts/consul/test/unit/client-snapshot-agent-deployment.bats b/charts/consul/test/unit/client-snapshot-agent-deployment.bats index 50781a8f23..4f3deb6bde 100644 --- a/charts/consul/test/unit/client-snapshot-agent-deployment.bats +++ b/charts/consul/test/unit/client-snapshot-agent-deployment.bats @@ -582,3 +582,39 @@ exec /bin/consul snapshot agent \' local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') [ "${actual}" = "/vault/custom/tls.crt" ] } + +#-------------------------------------------------------------------- +# Vault agent annotations + +@test "client/SnapshotAgentDeployment: no vault agent annotations defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/role")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "client/SnapshotAgentDeployment: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} \ No newline at end of file diff --git a/charts/consul/test/unit/connect-inject-deployment.bats b/charts/consul/test/unit/connect-inject-deployment.bats index f818b021c8..a3da403005 100755 --- a/charts/consul/test/unit/connect-inject-deployment.bats +++ b/charts/consul/test/unit/connect-inject-deployment.bats @@ -1677,6 +1677,42 @@ EOF [ "${actual}" = "test" ] } +#-------------------------------------------------------------------- +# Vault agent annotations + +@test "connectInject/Deployment: no vault agent annotations defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/role")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "connectInject/Deployment: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/connect-inject-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + # consulDestinationNamespace reserved name @test "connectInject/Deployment: fails when consulDestinationNamespace=system" { diff --git a/charts/consul/test/unit/controller-deployment.bats b/charts/consul/test/unit/controller-deployment.bats index 29cd9a1026..248811867d 100644 --- a/charts/consul/test/unit/controller-deployment.bats +++ b/charts/consul/test/unit/controller-deployment.bats @@ -679,4 +679,40 @@ load _helpers [ "${actual}" = "test" ] } +#-------------------------------------------------------------------- +# Vault agent annotations + +@test "controller/Deployment: no vault agent annotations defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/controller-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/role")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "controller/Deployment: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/controller-deployment.yaml \ + --set 'controller.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + diff --git a/charts/consul/test/unit/ingress-gateways-deployment.bats b/charts/consul/test/unit/ingress-gateways-deployment.bats index 4ee307058d..d2c02d1dda 100644 --- a/charts/consul/test/unit/ingress-gateways-deployment.bats +++ b/charts/consul/test/unit/ingress-gateways-deployment.bats @@ -1611,6 +1611,44 @@ EOF [ "${actual}" = "/vault/custom/tls.crt" ] } +#-------------------------------------------------------------------- +# Vault agent annotations + +@test "ingressGateway/Deployment: no vault agent annotations defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/role")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "ingressGateway/Deployment: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/ingress-gateways-deployment.yaml \ + --set 'ingressGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + #-------------------------------------------------------------------- # terminationGracePeriodSeconds diff --git a/charts/consul/test/unit/server-acl-init-job.bats b/charts/consul/test/unit/server-acl-init-job.bats index cc878e81c8..1b84b5860b 100644 --- a/charts/consul/test/unit/server-acl-init-job.bats +++ b/charts/consul/test/unit/server-acl-init-job.bats @@ -726,6 +726,42 @@ load _helpers [ "${actual}" = "/vault/custom/tls.crt" ] } +#-------------------------------------------------------------------- +# Vault agent annotations + +@test "serverACLInit/Job: no vault agent annotations defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/role")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "serverACLInit/Job: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + #-------------------------------------------------------------------- # namespaces diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 69a507f06a..9cfec30a88 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -1786,6 +1786,34 @@ load _helpers [ "${actual}" = "" ] } +#-------------------------------------------------------------------- +# Vault agent annotations + +@test "server/StatefulSet: no vault agent annotations defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."consul.hashicorp.com/config-checksum") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/role")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "server/StatefulSet: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + #-------------------------------------------------------------------- # ui.dashboardURLTemplates.service diff --git a/charts/consul/test/unit/sync-catalog-deployment.bats b/charts/consul/test/unit/sync-catalog-deployment.bats index aac942894d..8beead1564 100755 --- a/charts/consul/test/unit/sync-catalog-deployment.bats +++ b/charts/consul/test/unit/sync-catalog-deployment.bats @@ -1102,6 +1102,42 @@ load _helpers [ "${actual}" = "/vault/custom/tls.crt" ] } +#-------------------------------------------------------------------- +# Vault agent annotations + +@test "syncCatalog/Deployment: no vault agent annotations defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/sync-catalog-deployment.yaml \ + --set 'syncCatalog.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/role")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "syncCatalog/Deployment: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/sync-catalog-deployment.yaml \ + --set 'syncCatalog.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} + # consulDestinationNamespace reserved name @test "syncCatalog/Deployment: fails when consulDestinationNamespace=system" { diff --git a/charts/consul/test/unit/terminating-gateways-deployment.bats b/charts/consul/test/unit/terminating-gateways-deployment.bats index 76e5917a81..1cc2fbdd16 100644 --- a/charts/consul/test/unit/terminating-gateways-deployment.bats +++ b/charts/consul/test/unit/terminating-gateways-deployment.bats @@ -1419,3 +1419,41 @@ EOF local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') [ "${actual}" = "/vault/custom/tls.crt" ] } + +#-------------------------------------------------------------------- +# Vault agent annotations + +@test "terminatingGateway/Deployment: no vault agent annotations defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/terminating-gateways-deployment.yaml \ + --set 'terminatingGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/role")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "terminatingGateway/Deployment: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/terminating-gateways-deployment.yaml \ + --set 'terminatingGateways.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index d77f01dbf8..fac5b836be 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -157,6 +157,19 @@ global: # and check the name of `metadata.name`. consulClientRole: "" + # This value defines additional annotations for + # Vault agent on any pods where it'll be running. + # This should be formatted as a multi-line string. + # + # ```yaml + # annotations: | + # "sample/annotation1": "foo" + # "sample/annotation2": "bar" + # ``` + # + # @type: string + agentAnnotations: null + # The Vault role for all Consul components to read the Consul's server's CA Certificate (unauthenticated). # The role should be connected to the service accounts of all Consul components, or alternatively `*` since it # will be used only against the `pki/cert/ca` endpoint which is unauthenticated. A policy must be created which grants From 2e7c611715217c161033d0ae4d3bc79728ed9784 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Thu, 3 Feb 2022 13:36:11 -0800 Subject: [PATCH 262/418] Fix incorrect CRD field names (#1017) * Fix incorrect CRD field names gatewayTLSConfig => tls gatewayTLSSDSConfig => sds --- CHANGELOG.md | 4 ++++ charts/consul/templates/crd-ingressgateways.yaml | 10 +++++----- control-plane/api/v1alpha1/ingressgateway_types.go | 8 ++++---- .../bases/consul.hashicorp.com_ingressgateways.yaml | 10 +++++----- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bebe8d2d37..aeb492cb40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ BUG FIXES: * Fix issue where if the API gateway controller pods restarted, gateway pods would become disconnected from the secret discovery service. [[GH-1007](https://github.com/hashicorp/consul-k8s/pull/1007)] * Fix issue where the API gateway controller could not update existing Deployments or Services. [[GH-1014](https://github.com/hashicorp/consul-k8s/pull/1014)] +BREAKING CHANGES: +* Helm + * Rename fields of IngressGateway CRD to fix incorrect names (`gatewayTLSConfig` => `tls`, `gatewayServiceTLSConfig` => `tls`, `gatewayTLSSDSConfig` => `sds`). [[GH-1017](https://github.com/hashicorp/consul-k8s/pull/1017)] + ## 0.40.0 (January 27, 2022) BREAKING CHANGES: diff --git a/charts/consul/templates/crd-ingressgateways.yaml b/charts/consul/templates/crd-ingressgateways.yaml index f30e7f7a06..4ff360456e 100644 --- a/charts/consul/templates/crd-ingressgateways.yaml +++ b/charts/consul/templates/crd-ingressgateways.yaml @@ -64,14 +64,14 @@ spec: description: IngressListener manages the configuration for a listener on a specific port. properties: - gatewayTLSConfig: + tls: description: TLS config for this listener. properties: enabled: description: Indicates that TLS should be enabled for this gateway service. type: boolean - gatewayTLSSDSConfig: + sds: description: SDS allows configuring TLS certificate from an SDS service. properties: @@ -103,11 +103,11 @@ spec: description: IngressService manages configuration for services that are exposed to ingress traffic. properties: - gatewayServiceTLSConfig: + tls: description: TLS allows specifying some TLS configuration per listener. properties: - gatewayTLSSDSConfig: + sds: description: SDS allows configuring TLS certificate from an SDS service. properties: @@ -212,7 +212,7 @@ spec: description: Indicates that TLS should be enabled for this gateway service. type: boolean - gatewayTLSSDSConfig: + sds: description: SDS allows configuring TLS certificate from an SDS service. properties: diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index e5087e2885..ca32e72dd0 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -64,12 +64,12 @@ type GatewayTLSConfig struct { Enabled bool `json:"enabled"` // SDS allows configuring TLS certificate from an SDS service. - SDS *GatewayTLSSDSConfig `json:"gatewayTLSSDSConfig,omitempty"` + SDS *GatewayTLSSDSConfig `json:"sds,omitempty"` } type GatewayServiceTLSConfig struct { // SDS allows configuring TLS certificate from an SDS service. - SDS *GatewayTLSSDSConfig `json:"gatewayTLSSDSConfig,omitempty"` + SDS *GatewayTLSSDSConfig `json:"sds,omitempty"` } type GatewayTLSSDSConfig struct { @@ -89,7 +89,7 @@ type IngressListener struct { Protocol string `json:"protocol,omitempty"` // TLS config for this listener. - TLS *GatewayTLSConfig `json:"gatewayTLSConfig,omitempty"` + TLS *GatewayTLSConfig `json:"tls,omitempty"` // Services declares the set of services to which the listener forwards // traffic. @@ -134,7 +134,7 @@ type IngressService struct { Partition string `json:"partition,omitempty"` // TLS allows specifying some TLS configuration per listener. - TLS *GatewayServiceTLSConfig `json:"gatewayServiceTLSConfig,omitempty"` + TLS *GatewayServiceTLSConfig `json:"tls,omitempty"` // Allow HTTP header manipulation to be configured. RequestHeaders *HTTPHeaderModifiers `json:"requestHeaders,omitempty"` 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 13513ab65a..7ea78b875b 100644 --- a/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml +++ b/control-plane/config/crd/bases/consul.hashicorp.com_ingressgateways.yaml @@ -58,14 +58,14 @@ spec: description: IngressListener manages the configuration for a listener on a specific port. properties: - gatewayTLSConfig: + tls: description: TLS config for this listener. properties: enabled: description: Indicates that TLS should be enabled for this gateway service. type: boolean - gatewayTLSSDSConfig: + sds: description: SDS allows configuring TLS certificate from an SDS service. properties: @@ -97,11 +97,11 @@ spec: description: IngressService manages configuration for services that are exposed to ingress traffic. properties: - gatewayServiceTLSConfig: + tls: description: TLS allows specifying some TLS configuration per listener. properties: - gatewayTLSSDSConfig: + sds: description: SDS allows configuring TLS certificate from an SDS service. properties: @@ -206,7 +206,7 @@ spec: description: Indicates that TLS should be enabled for this gateway service. type: boolean - gatewayTLSSDSConfig: + sds: description: SDS allows configuring TLS certificate from an SDS service. properties: From 8c5c627a296ea2f020a78027fdb203b1e0c7620c Mon Sep 17 00:00:00 2001 From: Mike Morris Date: Mon, 7 Feb 2022 10:14:24 -0500 Subject: [PATCH 263/418] api-gateway: add node:read policy (#1018) * api-gateway: add node:read policy To avoid silently filtering all nodes when ACLs are enabled and returning an empty set when attempting to map routes to Consul services registered in consul-k8s * api-gateway: update tests to reflect node:read ACL * changelog: add entry for API Gateway node:read ACL fix * api-gateway: update node:read test fixture for namespaces disabled --- CHANGELOG.md | 1 + control-plane/subcommand/server-acl-init/rules.go | 3 +++ control-plane/subcommand/server-acl-init/rules_test.go | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index aeb492cb40..074882f43c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ BUG FIXES: * API Gateway * Fix issue where if the API gateway controller pods restarted, gateway pods would become disconnected from the secret discovery service. [[GH-1007](https://github.com/hashicorp/consul-k8s/pull/1007)] * Fix issue where the API gateway controller could not update existing Deployments or Services. [[GH-1014](https://github.com/hashicorp/consul-k8s/pull/1014)] + * Fix issue where the API gateway controller lacked sufficient permissions to bind routes when ACLs were enabled. [[GH-1018](https://github.com/hashicorp/consul-k8s/pull/1018)] BREAKING CHANGES: * Helm diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index 07e25b96f5..83d836cd6d 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -154,6 +154,9 @@ namespace_prefix "" { policy = "write" intentions = "write" } + node_prefix "" { + policy = "read" + } {{- if .EnableNamespaces }} } {{- end }} diff --git a/control-plane/subcommand/server-acl-init/rules_test.go b/control-plane/subcommand/server-acl-init/rules_test.go index 95c6e06f69..ba4eb88c1a 100644 --- a/control-plane/subcommand/server-acl-init/rules_test.go +++ b/control-plane/subcommand/server-acl-init/rules_test.go @@ -154,6 +154,9 @@ acl = "write" service_prefix "" { policy = "write" intentions = "write" + } + node_prefix "" { + policy = "read" }`, }, { @@ -167,6 +170,9 @@ namespace_prefix "" { policy = "write" intentions = "write" } + node_prefix "" { + policy = "read" + } }`, }, } From 155e63c7752fee180029a5bc429fb146dc7ea709 Mon Sep 17 00:00:00 2001 From: John Murret Date: Mon, 7 Feb 2022 13:50:50 -0700 Subject: [PATCH 264/418] Correcting connect-init documentation that said it creates the service rather than listening for so it can extract the proxy id for bootstrapping envoy. --- control-plane/connect-inject/container_init.go | 4 ++-- control-plane/connect-inject/handler.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/control-plane/connect-inject/container_init.go b/control-plane/connect-inject/container_init.go index 18831fa57b..c258203c9a 100644 --- a/control-plane/connect-inject/container_init.go +++ b/control-plane/connect-inject/container_init.go @@ -104,8 +104,8 @@ func (h *Handler) initCopyContainer() corev1.Container { return container } -// containerInit returns the init container spec for registering the Consul -// service, setting up the Envoy bootstrap, etc. +// containerInit returns the init container spec for that polls for the service and the connect proxy service to be registered +// so that it can save theproxy service id to the shared volume and boostrap Envoy with the proxy-id func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod) (corev1.Container, error) { // Check if tproxy is enabled on this pod. tproxyEnabled, err := transparentProxyEnabled(namespace, pod, h.EnableTransparentProxy) diff --git a/control-plane/connect-inject/handler.go b/control-plane/connect-inject/handler.go index f172f34e7c..8e7eb48a63 100644 --- a/control-plane/connect-inject/handler.go +++ b/control-plane/connect-inject/handler.go @@ -225,7 +225,7 @@ func (h *Handler) Handle(ctx context.Context, req admission.Request) admission.R return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error getting namespace metadata for container: %s", err)) } - // Add the init container that registers the service and sets up the Envoy configuration. + // Add the init container that listens for the service and proxy service and sets up the Envoy configuration. initContainer, err := h.containerInit(*ns, pod) if err != nil { h.Log.Error(err, "error configuring injection init container", "request name", req.Name) From 6f2431d29189b022243ee597a3ff6844adc2c4bf Mon Sep 17 00:00:00 2001 From: Andrew Stucki Date: Tue, 8 Feb 2022 12:54:53 -0500 Subject: [PATCH 265/418] Add support for api gateway + consul namespaces --- .../api-gateway-controller-deployment.yaml | 11 ++++++ .../api-gateway-controller-deployment.bats | 38 +++++++++++++++++++ charts/consul/values.yaml | 23 +++++++++++ 3 files changed, 72 insertions(+) diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml index 2622fec731..c76cd9a29e 100644 --- a/charts/consul/templates/api-gateway-controller-deployment.yaml +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -79,6 +79,17 @@ spec: consul-api-gateway server \ -sds-server-host {{ template "consul.fullname" . }}-api-gateway-controller.{{ .Release.Namespace }}.svc \ -k8s-namespace {{ .Release.Namespace }} \ + {{- if .Values.global.enableConsulNamespaces }} + {{- if .Values.apiGateway.consulNamespaces.consulDestinationNamespace }} + -consul-destination-namespace={{ .Values.apiGateway.consulNamespaces.consulDestinationNamespace }} \ + {{- end }} + {{- if .Values.apiGateway.consulNamespaces.mirroringK8S }} + -mirror-k8s-namespaces=true \ + {{- if .Values.apiGateway.consulNamespaces.mirroringK8SPrefix }} + -mirror-k8s-namespace-prefix={{ .Values.apiGateway.consulNamespaces.mirroringK8SPrefix }} \ + {{- end }} + {{- end }} + {{- end }} -log-level {{ default .Values.global.logLevel .Values.apiGateway.logLevel }} \ volumeMounts: {{- if .Values.global.tls.enabled }} diff --git a/charts/consul/test/unit/api-gateway-controller-deployment.bats b/charts/consul/test/unit/api-gateway-controller-deployment.bats index 73b23e26ef..bea24daad7 100755 --- a/charts/consul/test/unit/api-gateway-controller-deployment.bats +++ b/charts/consul/test/unit/api-gateway-controller-deployment.bats @@ -36,6 +36,44 @@ load _helpers . } +@test "apiGateway/Deployment: enable namespaces" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.enableConsulNamespaces=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | join(" ") | contains("-consul-destination-namespace=default")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: enable namespace mirroring" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'apiGateway.consulNamespaces.mirroringK8S=true' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | join(" ") | contains("-mirror-k8s-namespaces=true")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} + +@test "apiGateway/Deployment: enable namespace mirroring prefixes" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/api-gateway-controller-deployment.yaml \ + --set 'apiGateway.enabled=true' \ + --set 'apiGateway.image=bar' \ + --set 'global.enableConsulNamespaces=true' \ + --set 'apiGateway.consulNamespaces.mirroringK8S=true' \ + --set 'apiGateway.consulNamespaces.mirroringK8SPrefix=foo' \ + . | tee /dev/stderr | + yq '.spec.template.spec.containers[0].command | join(" ") | contains("-mirror-k8s-namespace-prefix=foo")' | tee /dev/stderr) + [ "${actual}" = "true" ] +} @test "apiGateway/Deployment: container image overrides" { cd `chart_dir` diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index fac5b836be..5a512ffa4b 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2536,6 +2536,29 @@ apiGateway: # @type: string service: null + # [Enterprise Only] These settings manage the api gateway's interaction with + # Consul namespaces (requires consul-ent v1.7+). + # Also, `global.enableConsulNamespaces` must be true. + consulNamespaces: + # Name of the Consul namespace to register all + # k8s services into. If the Consul namespace does not already exist, + # it will be created. This will be ignored if `mirroringK8S` is true. + consulDestinationNamespace: "default" + + # If true, k8s services will be registered into a Consul namespace + # of the same name as their k8s namespace, optionally prefixed if + # `mirroringK8SPrefix` is set below. If the Consul namespace does not + # already exist, it will be created. Turning this on overrides the + # `consulDestinationNamespace` setting. + # `addK8SNamespaceSuffix` may no longer be needed if enabling this option. + mirroringK8S: false + + # If `mirroringK8S` is set to true, `mirroringK8SPrefix` allows each Consul namespace + # to be given a prefix. For example, if `mirroringK8SPrefix` is set to "k8s-", a + # service in the k8s `staging` namespace will be registered into the + # `k8s-staging` Consul namespace. + mirroringK8SPrefix: "" + # Configuration for the ServiceAccount created for the api-gateway component serviceAccount: # This value defines additional annotations for the client service account. This should be formatted as a multi-line From 3fef80dc49bf6523dff8c5f8802189c0a7e2c235 Mon Sep 17 00:00:00 2001 From: John Murret Date: Tue, 8 Feb 2022 16:45:48 -0700 Subject: [PATCH 266/418] Add support customized IPSans and DNSSans for server-tls server cert for vault (#1020) * Set up broken test with new expectations. * Modify template helpers to inject additional Sans and IP Sans. * Adding Changelog for Add support customized IPSans and DNSSans for server-tls server cert for vault * Fixing nil pointer issue * Removing debugging echo statementsleft in server-statefulset.bats * Extracting ip_sans and alt_names code intohelper functions. * Update CHANGELOG.md description for IP Sans and DNS Sans Co-authored-by: Iryna Shustava Co-authored-by: Iryna Shustava --- CHANGELOG.md | 1 + charts/consul/templates/_helpers.tpl | 14 ++++- .../consul/test/unit/server-statefulset.bats | 58 +++++++++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 074882f43c..6e24788482 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ IMPROVEMENTS: * Helm * Vault: Allow passing arbitrary annotations to the vault agent. [[GH-1015](https://github.com/hashicorp/consul-k8s/pull/1015)] + * Vault: Add support for customized IP and DNS SANs for server cert in Vault. [[GH-1020](https://github.com/hashicorp/consul-k8s/pull/1020)] BUG FIXES: * API Gateway diff --git a/charts/consul/templates/_helpers.tpl b/charts/consul/templates/_helpers.tpl index 42b49f0aa1..277f744d08 100644 --- a/charts/consul/templates/_helpers.tpl +++ b/charts/consul/templates/_helpers.tpl @@ -32,7 +32,7 @@ as well as the global.name setting. {{- define "consul.serverTLSCertTemplate" -}} | {{ "{{" }}- with secret "{{ .Values.server.serverCert.secretName }}" "{{ printf "common_name=server.%s.%s" .Values.global.datacenter .Values.global.domain }}" - "ttl=1h" "alt_names={{ include "consul.serverTLSAltNames" . }}" "ip_sans=127.0.0.1" -{{ "}}" }} + "ttl=1h" "alt_names={{ include "consul.serverTLSAltNames" . }}" "ip_sans=127.0.0.1{{ include "consul.serverAdditionalIPSANs" . }}" -{{ "}}" }} {{ "{{" }}- .Data.certificate -{{ "}}" }} {{ "{{" }}- end -{{ "}}" }} {{- end -}} @@ -40,7 +40,7 @@ as well as the global.name setting. {{- define "consul.serverTLSKeyTemplate" -}} | {{ "{{" }}- with secret "{{ .Values.server.serverCert.secretName }}" "{{ printf "common_name=server.%s.%s" .Values.global.datacenter .Values.global.domain }}" - "ttl=1h" "alt_names={{ include "consul.serverTLSAltNames" . }}" "ip_sans=127.0.0.1" -{{ "}}" }} + "ttl=1h" "alt_names={{ include "consul.serverTLSAltNames" . }}" "ip_sans=127.0.0.1{{ include "consul.serverAdditionalIPSANs" . }}" -{{ "}}" }} {{ "{{" }}- .Data.private_key -{{ "}}" }} {{ "{{" }}- end -{{ "}}" }} {{- end -}} @@ -48,7 +48,15 @@ as well as the global.name setting. {{- define "consul.serverTLSAltNames" -}} {{- $name := include "consul.fullname" . -}} {{- $ns := .Release.Namespace -}} -{{ printf "localhost,%s-server,*.%s-server,*.%s-server.%s,*.%s-server.%s.svc,*.server.%s.%s" $name $name $name $ns $name $ns (.Values.global.datacenter ) (.Values.global.domain) }} +{{ printf "localhost,%s-server,*.%s-server,*.%s-server.%s,*.%s-server.%s.svc,*.server.%s.%s" $name $name $name $ns $name $ns (.Values.global.datacenter ) (.Values.global.domain) }}{{ include "consul.serverAdditionalDNSSANs" . }} +{{- end -}} + +{{- define "consul.serverAdditionalDNSSANs" -}} +{{- if .Values.global.tls -}}{{- if .Values.global.tls.serverAdditionalDNSSANs -}}{{- range $san := .Values.global.tls.serverAdditionalDNSSANs }},{{ $san }} {{- end -}}{{- end -}}{{- end -}} +{{- end -}} + +{{- define "consul.serverAdditionalIPSANs" -}} +{{- if .Values.global.tls -}}{{- if .Values.global.tls.serverAdditionalIPSANs -}}{{- range $ipsan := .Values.global.tls.serverAdditionalIPSANs }},{{ $ipsan }} {{- end -}}{{- end -}}{{- end -}} {{- end -}} {{/* diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 9cfec30a88..65e3abe511 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -1786,6 +1786,64 @@ load _helpers [ "${actual}" = "" ] } +@test "server/StatefulSet: vault - can set additional alt_names on server cert when tls is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc2' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.serverAdditionalDNSSANs[0]=*.foo.com' \ + --set 'global.tls.serverAdditionalDNSSANs[1]=*.bar.com' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-servercert.crt"]' | tee /dev/stderr) + local expected=$'{{- with secret \"pki_int/issue/test\" \"common_name=server.dc2.consul\"\n\"ttl=1h\" \"alt_names=localhost,RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server.default,*.RELEASE-NAME-consul-server.default.svc,*.server.dc2.consul,*.foo.com,*.bar.com\" \"ip_sans=127.0.0.1\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + local actual="$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-servercert.key"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"pki_int/issue/test\" \"common_name=server.dc2.consul\"\n\"ttl=1h\" \"alt_names=localhost,RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server.default,*.RELEASE-NAME-consul-server.default.svc,*.server.dc2.consul,*.foo.com,*.bar.com\" \"ip_sans=127.0.0.1\" -}}\n{{- .Data.private_key -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] +} + +@test "server/StatefulSet: vault - can set additional ip_sans on server cert when tls is enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.datacenter=dc2' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.serverAdditionalIPSANs[0]=1.1.1.1' \ + --set 'global.tls.serverAdditionalIPSANs[1]=2.2.2.2' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-servercert.crt"]' | tee /dev/stderr) + local expected=$'{{- with secret \"pki_int/issue/test\" \"common_name=server.dc2.consul\"\n\"ttl=1h\" \"alt_names=localhost,RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server.default,*.RELEASE-NAME-consul-server.default.svc,*.server.dc2.consul\" \"ip_sans=127.0.0.1,1.1.1.1,2.2.2.2\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + local actual="$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-servercert.key"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"pki_int/issue/test\" \"common_name=server.dc2.consul\"\n\"ttl=1h\" \"alt_names=localhost,RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server,*.RELEASE-NAME-consul-server.default,*.RELEASE-NAME-consul-server.default.svc,*.server.dc2.consul\" \"ip_sans=127.0.0.1,1.1.1.1,2.2.2.2\" -}}\n{{- .Data.private_key -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] +} + #-------------------------------------------------------------------- # Vault agent annotations From f3428c23cf010b08e20397add4a1cf3cbdae3bfd Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 9 Feb 2022 15:20:00 -0500 Subject: [PATCH 267/418] Add logo to header of README (#1028) * Add logo to header of README * Update README.md Co-authored-by: David Yu Co-authored-by: David Yu --- README.md | 5 ++++- assets/logo.svg | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 assets/logo.svg diff --git a/README.md b/README.md index 86ec8f355d..6a25910b9a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -# Consul + Kubernetes (consul-k8s) +

+ Consul logo + Consul on Kubernetes +

**We're looking for feedback on how folks are using Consul on Kubernetes. Please fill out our brief [survey](https://hashicorp.sjc1.qualtrics.com/jfe/form/SV_4MANbw1BUku7YhL)!** diff --git a/assets/logo.svg b/assets/logo.svg new file mode 100644 index 0000000000..c8346c9217 --- /dev/null +++ b/assets/logo.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + \ No newline at end of file From f7e829d647289f72f0156a972c0995a3207330f7 Mon Sep 17 00:00:00 2001 From: David Yu Date: Tue, 15 Feb 2022 16:12:39 -0800 Subject: [PATCH 268/418] ISSUE_TEMPLATE: update labels per new GH labeling recommendations (#1033) * ISSUE_TEMPLATE: update labels per new GH labeling recommendations * Update feature_request.md * Update question.md * Update .github/ISSUE_TEMPLATE/bug_report.md Co-authored-by: Thomas Eckert * Update .github/ISSUE_TEMPLATE/question.md Co-authored-by: Thomas Eckert Co-authored-by: Thomas Eckert --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- .github/ISSUE_TEMPLATE/question.md | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 35dac8bb77..7809f17ebe 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,7 +1,7 @@ --- name: Bug Report -about: You're experiencing an issue with the Consul Helm chart or consul-k8s-control-plane binary that is different than the documented behavior. -labels: bug +about: You're experiencing an issue with the Consul Helm chart, consul-k8s CLI, or consul-k8s-control-plane binary that is different than the documented behavior. +labels: type/bug --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 0141ec32d7..3296821690 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,7 +1,7 @@ --- name: Feature Request about: If you have something you think Consul on Kubernetes could improve or add support for. -labels: enhancement +labels: type/enhancement --- diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index e25acb2416..4cb0c8338c 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,7 +1,7 @@ --- name: Question -about: You'd like to clarify your understanding about a particular area within Consul K8s. We'd like to help and engage the community through Github! -labels: question +about: You'd like to clarify your understanding about a particular area within Consul on Kubernetes. We'd like to help and engage the community through Github! +labels: type/question --- From 3ad09f72f9df397e163abcc24b36feffbb35d454 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Thu, 17 Feb 2022 09:20:29 -0700 Subject: [PATCH 269/418] vault: Initial wan fed support (tls and gossip only) (#1016) This is the initial support for the Consul WAN federation which includes only gossip and TLS credentials. Other credentials will be added in a separate PR. * Modify mesh gateway deployment to use Consul server's CA when it's stored in Vault. * Add acceptance test for WAN federation with Vault * Refactor common functions that are now shared between vault tests as well as other tests --- acceptance/framework/consul/cli_cluster.go | 10 +- acceptance/framework/consul/consul_cluster.go | 18 +- .../framework/environment/environment.go | 40 ++- acceptance/framework/helpers/helpers.go | 128 +++------ acceptance/framework/k8s/debug.go | 6 +- acceptance/framework/k8s/helpers.go | 127 +++++++++ acceptance/framework/vault/vault_cluster.go | 89 ++++-- .../tests/mesh-gateway/mesh_gateway_test.go | 41 +-- .../tests/partitions/partitions_test.go | 46 +-- acceptance/tests/vault/helpers.go | 180 ++++++++++++ acceptance/tests/vault/vault_test.go | 159 +---------- acceptance/tests/vault/vault_wan_fed_test.go | 267 ++++++++++++++++++ .../templates/mesh-gateway-deployment.yaml | 14 + .../test/unit/mesh-gateway-deployment.bats | 172 +++++++++++ 14 files changed, 923 insertions(+), 374 deletions(-) create mode 100644 acceptance/framework/k8s/helpers.go create mode 100644 acceptance/tests/vault/helpers.go create mode 100644 acceptance/tests/vault/vault_wan_fed_test.go diff --git a/acceptance/framework/consul/cli_cluster.go b/acceptance/framework/consul/cli_cluster.go index bc5f7dde14..5493533909 100644 --- a/acceptance/framework/consul/cli_cluster.go +++ b/acceptance/framework/consul/cli_cluster.go @@ -74,8 +74,8 @@ func NewCLICluster( require.NoError(t, err) // Merge all helm values - MergeMaps(values, valuesFromConfig) - MergeMaps(values, helmValues) + helpers.MergeMaps(values, valuesFromConfig) + helpers.MergeMaps(values, helmValues) logger := terratestLogger.New(logger.TestLogger{}) @@ -144,7 +144,7 @@ func (h *CLICluster) Create(t *testing.T) { } require.NoError(t, err) - helpers.WaitForAllPodsToBeReady(t, h.kubernetesClient, consulNS, fmt.Sprintf("release=%s", h.releaseName)) + k8s.WaitForAllPodsToBeReady(t, h.kubernetesClient, consulNS, fmt.Sprintf("release=%s", h.releaseName)) } func (h *CLICluster) Destroy(t *testing.T) { @@ -179,9 +179,9 @@ func (h *CLICluster) Destroy(t *testing.T) { func (h *CLICluster) Upgrade(t *testing.T, helmValues map[string]string) { t.Helper() - MergeMaps(h.helmOptions.SetValues, helmValues) + helpers.MergeMaps(h.helmOptions.SetValues, helmValues) helm.Upgrade(t, h.helmOptions, config.HelmChartPath, h.releaseName) - helpers.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) + k8s.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) } func (h *CLICluster) SetupConsulClient(t *testing.T, secure bool) *api.Client { diff --git a/acceptance/framework/consul/consul_cluster.go b/acceptance/framework/consul/consul_cluster.go index 74c018093d..cda22d9322 100644 --- a/acceptance/framework/consul/consul_cluster.go +++ b/acceptance/framework/consul/consul_cluster.go @@ -75,8 +75,8 @@ func NewHelmCluster( require.NoError(t, err) // Merge all helm values - MergeMaps(values, valuesFromConfig) - MergeMaps(values, helmValues) + helpers.MergeMaps(values, valuesFromConfig) + helpers.MergeMaps(values, helmValues) logger := terratestLogger.New(logger.TestLogger{}) @@ -118,7 +118,7 @@ func (h *HelmCluster) Create(t *testing.T) { helm.Install(t, h.helmOptions, config.HelmChartPath, h.releaseName) - helpers.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) + k8s.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) } func (h *HelmCluster) Destroy(t *testing.T) { @@ -213,9 +213,9 @@ func (h *HelmCluster) Destroy(t *testing.T) { func (h *HelmCluster) Upgrade(t *testing.T, helmValues map[string]string) { t.Helper() - MergeMaps(h.helmOptions.SetValues, helmValues) + helpers.MergeMaps(h.helmOptions.SetValues, helmValues) helm.Upgrade(t, h.helmOptions, config.HelmChartPath, h.releaseName) - helpers.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) + k8s.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) } func (h *HelmCluster) SetupConsulClient(t *testing.T, secure bool) *api.Client { @@ -472,11 +472,3 @@ func defaultValues() map[string]string { } return values } - -// MergeMaps will merge the values in b with values in a and save in a. -// If there are conflicts, the values in b will overwrite the values in a. -func MergeMaps(a, b map[string]string) { - for k, v := range b { - a[k] = v - } -} diff --git a/acceptance/framework/environment/environment.go b/acceptance/framework/environment/environment.go index ad39a09a04..7c8a89e15b 100644 --- a/acceptance/framework/environment/environment.go +++ b/acceptance/framework/environment/environment.go @@ -6,7 +6,6 @@ import ( "github.com/gruntwork-io/terratest/modules/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/config" - "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" @@ -87,6 +86,27 @@ type kubernetesContext struct { options *k8s.KubectlOptions } +// KubernetesContextFromOptions returns the Kubernetes context from options. +// If context is explicitly set in options, it returns that context. +// Otherwise, it returns the current context. +func KubernetesContextFromOptions(t *testing.T, options *k8s.KubectlOptions) string { + t.Helper() + + // First, check if context set in options and return that + if options.ContextName != "" { + return options.ContextName + } + + // Otherwise, get current context from config + configPath, err := options.GetConfigPath(t) + require.NoError(t, err) + + rawConfig, err := k8s.LoadConfigFromPath(configPath).RawConfig() + require.NoError(t, err) + + return rawConfig.CurrentContext +} + func (k kubernetesContext) KubectlOptions(t *testing.T) *k8s.KubectlOptions { if k.options != nil { return k.options @@ -107,7 +127,7 @@ func (k kubernetesContext) KubectlOptions(t *testing.T) *k8s.KubectlOptions { rawConfig, err := k8s.LoadConfigFromPath(configPath).RawConfig() require.NoError(t, err) - contextName := helpers.KubernetesContextFromOptions(t, k.options) + contextName := KubernetesContextFromOptions(t, k.options) if rawConfig.Contexts[contextName].Namespace != "" { k.options.Namespace = rawConfig.Contexts[contextName].Namespace } else { @@ -117,12 +137,26 @@ func (k kubernetesContext) KubectlOptions(t *testing.T) *k8s.KubectlOptions { return k.options } +// KubernetesClientFromOptions takes KubectlOptions and returns Kubernetes API client. +func KubernetesClientFromOptions(t *testing.T, options *k8s.KubectlOptions) kubernetes.Interface { + configPath, err := options.GetConfigPath(t) + require.NoError(t, err) + + config, err := k8s.LoadApiClientConfigE(configPath, options.ContextName) + require.NoError(t, err) + + client, err := kubernetes.NewForConfig(config) + require.NoError(t, err) + + return client +} + func (k kubernetesContext) KubernetesClient(t *testing.T) kubernetes.Interface { if k.client != nil { return k.client } - k.client = helpers.KubernetesClientFromOptions(t, k.KubectlOptions(t)) + k.client = KubernetesClientFromOptions(t, k.KubectlOptions(t)) return k.client } diff --git a/acceptance/framework/helpers/helpers.go b/acceptance/framework/helpers/helpers.go index b80e0ca383..17dd805123 100644 --- a/acceptance/framework/helpers/helpers.go +++ b/acceptance/framework/helpers/helpers.go @@ -12,13 +12,12 @@ import ( "time" "github.com/gruntwork-io/terratest/modules/helm" + "github.com/hashicorp/consul/api" - terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" "github.com/gruntwork-io/terratest/modules/random" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) @@ -70,37 +69,6 @@ func CheckForPriorInstallations(t *testing.T, client kubernetes.Interface, optio }) } -// WaitForAllPodsToBeReady waits until all pods with the provided podLabelSelector -// are in the ready status. It checks every 5 seconds for a total of 20 tries. -// If there is at least one container in a pod that isn't ready after that, -// it fails the test. -func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespace, podLabelSelector string) { - t.Helper() - - logger.Logf(t, "Waiting for pods with label %q to be ready.", podLabelSelector) - - // Wait up to 10m. - // On Azure, volume provisioning can sometimes take close to 5 min, - // so we need to give a bit more time for pods to become healthy. - counter := &retry.Counter{Count: 600, Wait: 1 * time.Second} - retry.RunWith(counter, t, func(r *retry.R) { - pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) - require.NoError(r, err) - require.NotEmpty(r, pods.Items) - - var notReadyPods []string - for _, pod := range pods.Items { - if !IsReady(pod) { - notReadyPods = append(notReadyPods, pod.Name) - } - } - if len(notReadyPods) > 0 { - r.Errorf("%d pods are not ready: %s", len(notReadyPods), strings.Join(notReadyPods, ",")) - } - }) - logger.Log(t, "Finished waiting for pods to be ready.") -} - // SetupInterruptHandler sets up a goroutine that will wait for interrupt signals // and call cleanup function when it catches it. func SetupInterruptHandler(cleanup func()) { @@ -138,69 +106,45 @@ func Cleanup(t *testing.T, noCleanupOnFailure bool, cleanup func()) { t.Cleanup(wrappedCleanupFunc) } -// KubernetesClientFromOptions takes KubectlOptions and returns Kubernetes API client. -func KubernetesClientFromOptions(t *testing.T, options *terratestk8s.KubectlOptions) kubernetes.Interface { - configPath, err := options.GetConfigPath(t) - require.NoError(t, err) - - config, err := terratestk8s.LoadApiClientConfigE(configPath, options.ContextName) - require.NoError(t, err) - - client, err := kubernetes.NewForConfig(config) - require.NoError(t, err) - - return client -} - -// KubernetesContextFromOptions returns the Kubernetes context from options. -// If context is explicitly set in options, it returns that context. -// Otherwise, it returns the current context. -func KubernetesContextFromOptions(t *testing.T, options *terratestk8s.KubectlOptions) string { - t.Helper() - - // First, check if context set in options and return that - if options.ContextName != "" { - return options.ContextName - } - - // Otherwise, get current context from config - configPath, err := options.GetConfigPath(t) - require.NoError(t, err) - - rawConfig, err := terratestk8s.LoadConfigFromPath(configPath).RawConfig() - require.NoError(t, err) - - return rawConfig.CurrentContext -} - -// KubernetesAPIServerHostFromOptions returns the Kubernetes API server host from options. -func KubernetesAPIServerHostFromOptions(t *testing.T, options *terratestk8s.KubectlOptions) string { - t.Helper() +// VerifyFederation checks that the WAN federation between servers is successful +// by first checking members are alive from the perspective of both servers. +// If secure is true, it will also check that the ACL replication is running on the secondary server. +func VerifyFederation(t *testing.T, primaryClient, secondaryClient *api.Client, releaseName string, secure bool) { + retrier := &retry.Timer{Timeout: 5 * time.Minute, Wait: 1 * time.Second} + start := time.Now() + + // Check that server in dc1 is healthy from the perspective of the server in dc2, and vice versa. + // We're calling the Consul health API, as opposed to checking serf membership status, + // because we need to make sure that the federated servers can make API calls and forward requests + // from one server to another. From running tests in CI for a while and using serf membership status before, + // we've noticed that the status could be "alive" as soon as the server in the secondary cluster joins the primary + // and then switch to "failed". This would require us to check that the status is "alive" is showing consistently for + // some amount of time, which could be quite flakey. Calling the API in another datacenter allows us to check that + // each server can forward calls to another, which is what we need for connect. + retry.RunWith(retrier, t, func(r *retry.R) { + secondaryServerHealth, _, err := primaryClient.Health().Node(fmt.Sprintf("%s-consul-server-0", releaseName), &api.QueryOptions{Datacenter: "dc2"}) + require.NoError(r, err) + require.Equal(r, secondaryServerHealth.AggregatedStatus(), api.HealthPassing) - configPath, err := options.GetConfigPath(t) - require.NoError(t, err) + primaryServerHealth, _, err := secondaryClient.Health().Node(fmt.Sprintf("%s-consul-server-0", releaseName), &api.QueryOptions{Datacenter: "dc1"}) + require.NoError(r, err) + require.Equal(r, primaryServerHealth.AggregatedStatus(), api.HealthPassing) - config, err := terratestk8s.LoadApiClientConfigE(configPath, options.ContextName) - require.NoError(t, err) + if secure { + replicationStatus, _, err := secondaryClient.ACL().Replication(nil) + require.NoError(r, err) + require.True(r, replicationStatus.Enabled) + require.True(r, replicationStatus.Running) + } + }) - return config.Host + logger.Logf(t, "Took %s to verify federation", time.Since(start)) } -// IsReady returns true if pod is ready. -func IsReady(pod corev1.Pod) bool { - if pod.Status.Phase == corev1.PodPending { - return false - } - - for _, cond := range pod.Status.Conditions { - if cond.Type == corev1.PodReady { - if cond.Status == corev1.ConditionTrue { - return true - } else { - return false - } - } +// MergeMaps will merge the values in b with values in a and save in a. +// If there are conflicts, the values in b will overwrite the values in a. +func MergeMaps(a, b map[string]string) { + for k, v := range b { + a[k] = v } - - return false } diff --git a/acceptance/framework/k8s/debug.go b/acceptance/framework/k8s/debug.go index c01101c6dc..0754f24131 100644 --- a/acceptance/framework/k8s/debug.go +++ b/acceptance/framework/k8s/debug.go @@ -10,7 +10,7 @@ import ( "github.com/gruntwork-io/terratest/modules/k8s" terratestLogger "github.com/gruntwork-io/terratest/modules/logger" - "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -23,9 +23,9 @@ func WritePodsDebugInfoIfFailed(t *testing.T, kubectlOptions *k8s.KubectlOptions if t.Failed() { // Create k8s client from kubectl options. - client := helpers.KubernetesClientFromOptions(t, kubectlOptions) + client := environment.KubernetesClientFromOptions(t, kubectlOptions) - contextName := helpers.KubernetesContextFromOptions(t, kubectlOptions) + contextName := environment.KubernetesContextFromOptions(t, kubectlOptions) // Create a directory for the test. testDebugDirectory := filepath.Join(debugDirectory, t.Name(), contextName) diff --git a/acceptance/framework/k8s/helpers.go b/acceptance/framework/k8s/helpers.go new file mode 100644 index 0000000000..dabb617876 --- /dev/null +++ b/acceptance/framework/k8s/helpers.go @@ -0,0 +1,127 @@ +package k8s + +import ( + "context" + "fmt" + "strings" + "testing" + "time" + + terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/config" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/consul/sdk/testutil/retry" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" +) + +// KubernetesAPIServerHostFromOptions returns the Kubernetes API server host from options. +func KubernetesAPIServerHostFromOptions(t *testing.T, options *terratestk8s.KubectlOptions) string { + t.Helper() + + configPath, err := options.GetConfigPath(t) + require.NoError(t, err) + + config, err := terratestk8s.LoadApiClientConfigE(configPath, options.ContextName) + require.NoError(t, err) + + return config.Host +} + +// WaitForAllPodsToBeReady waits until all pods with the provided podLabelSelector +// are in the ready status. It checks every 5 seconds for a total of 20 tries. +// If there is at least one container in a pod that isn't ready after that, +// it fails the test. +func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespace, podLabelSelector string) { + t.Helper() + + logger.Logf(t, "Waiting for pods with label %q to be ready.", podLabelSelector) + + // Wait up to 10m. + // On Azure, volume provisioning can sometimes take close to 5 min, + // so we need to give a bit more time for pods to become healthy. + counter := &retry.Counter{Count: 600, Wait: 1 * time.Second} + retry.RunWith(counter, t, func(r *retry.R) { + pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) + require.NoError(r, err) + require.NotEmpty(r, pods.Items) + + var notReadyPods []string + for _, pod := range pods.Items { + if !IsReady(pod) { + notReadyPods = append(notReadyPods, pod.Name) + } + } + if len(notReadyPods) > 0 { + r.Errorf("%d pods are not ready: %s", len(notReadyPods), strings.Join(notReadyPods, ",")) + } + }) + logger.Log(t, "Finished waiting for pods to be ready.") +} + +// IsReady returns true if pod is ready. +func IsReady(pod corev1.Pod) bool { + if pod.Status.Phase == corev1.PodPending { + return false + } + + for _, cond := range pod.Status.Conditions { + if cond.Type == corev1.PodReady { + if cond.Status == corev1.ConditionTrue { + return true + } else { + return false + } + } + } + + return false +} + +// KubernetesAPIServerHost returns the Kubernetes API server URL depending on test configuration. +func KubernetesAPIServerHost(t *testing.T, cfg *config.TestConfig, ctx environment.TestContext) string { + var k8sAPIHost string + // When running on kind, the kube API address in kubeconfig will have a localhost address + // which will not work from inside the container. That's why we need to use the endpoints address instead + // which will point the node IP. + if cfg.UseKind { + // The Kubernetes AuthMethod host is read from the endpoints for the Kubernetes service. + kubernetesEndpoint, err := ctx.KubernetesClient(t).CoreV1().Endpoints("default").Get(context.Background(), "kubernetes", metav1.GetOptions{}) + require.NoError(t, err) + k8sAPIHost = fmt.Sprintf("https://%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) + } else { + k8sAPIHost = KubernetesAPIServerHostFromOptions(t, ctx.KubectlOptions(t)) + } + + return k8sAPIHost +} + +// ServiceHost returns a host for a Kubernetes service depending on test configuration. +func ServiceHost(t *testing.T, cfg *config.TestConfig, ctx environment.TestContext, serviceName string) string { + if cfg.UseKind { + nodeList, err := ctx.KubernetesClient(t).CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) + require.NoError(t, err) + // Get the address of the (only) node from the Kind cluster. + return nodeList.Items[0].Status.Addresses[0].Address + } else { + var host string + // It can take some time for the load balancers to be ready and have an IP/Hostname. + // Wait for 60 seconds before failing. + retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { + svc, err := ctx.KubernetesClient(t).CoreV1().Services(ctx.KubectlOptions(t).Namespace).Get(context.Background(), serviceName, metav1.GetOptions{}) + require.NoError(t, err) + require.NotEmpty(r, svc.Status.LoadBalancer.Ingress) + // On AWS, load balancers have a hostname for ingress, while on Azure and GCP + // load balancers have IPs. + if svc.Status.LoadBalancer.Ingress[0].Hostname != "" { + host = svc.Status.LoadBalancer.Ingress[0].Hostname + } else { + host = svc.Status.LoadBalancer.Ingress[0].IP + } + }) + return host + } +} diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index bab5fbb753..d42a4fb896 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -45,20 +45,24 @@ type VaultCluster struct { } // NewVaultCluster creates a VaultCluster which will be used to install Vault using Helm. -func NewVaultCluster(t *testing.T, ctx environment.TestContext, cfg *config.TestConfig, releaseName string) *VaultCluster { +func NewVaultCluster(t *testing.T, ctx environment.TestContext, cfg *config.TestConfig, releaseName string, helmValues map[string]string) *VaultCluster { logger := terratestLogger.New(logger.TestLogger{}) kopts := ctx.KubectlOptions(t) + values := defaultHelmValues(releaseName) + if cfg.EnablePodSecurityPolicies { + values["global.psp.enable"] = "true" + } + + helpers.MergeMaps(values, helmValues) vaultHelmOpts := &helm.Options{ - SetValues: defaultHelmValues(releaseName), + SetValues: values, KubectlOptions: kopts, Logger: logger, } - if cfg.EnablePodSecurityPolicies { - vaultHelmOpts.SetValues["global.psp.enable"] = "true" - } + helm.AddRepo(t, vaultHelmOpts, "hashicorp", "https://helm.releases.hashicorp.com") // Ignoring the error from `helm repo update` as it could fail due to stale cache or unreachable servers and we're // asserting a chart version on Install which would fail in an obvious way should this not succeed. @@ -80,7 +84,7 @@ func NewVaultCluster(t *testing.T, ctx environment.TestContext, cfg *config.Test } // VaultClient returns the vault client. -func (v *VaultCluster) VaultClient(t *testing.T) *vapi.Client { return v.vaultClient } +func (v *VaultCluster) VaultClient(*testing.T) *vapi.Client { return v.vaultClient } // SetupVaultClient sets up and returns a Vault Client. func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { @@ -125,8 +129,11 @@ func (v *VaultCluster) SetupVaultClient(t *testing.T) *vapi.Client { } // bootstrap sets up Kubernetes auth method and enables secrets engines. -func (v *VaultCluster) bootstrap(t *testing.T, ctx environment.TestContext) { - +func (v *VaultCluster) bootstrap(t *testing.T) { + if !v.serverEnabled() { + v.logger.Logf(t, "skipping bootstrapping Vault because Vault server is not enabled") + return + } v.vaultClient = v.SetupVaultClient(t) // Enable the KV-V2 Secrets engine. @@ -143,26 +150,39 @@ func (v *VaultCluster) bootstrap(t *testing.T, ctx environment.TestContext) { }) require.NoError(t, err) - // Enable Kube Auth. - err = v.vaultClient.Sys().EnableAuthWithOptions("kubernetes", &vapi.EnableAuthOptions{ + namespace := v.helmOptions.KubectlOptions.Namespace + vaultServerServiceAccountName := fmt.Sprintf("%s-vault", v.releaseName) + v.ConfigureAuthMethod(t, v.vaultClient, "kubernetes", "https://kubernetes.default.svc", vaultServerServiceAccountName, namespace) +} + +// ConfigureAuthMethod configures the auth method in Vault from the provided service account name and namespace, +// kubernetes host and auth path. +// We need to take vaultClient here in case this Vault cluster does not have a server to run API commands against. +func (v *VaultCluster) ConfigureAuthMethod(t *testing.T, vaultClient *vapi.Client, authPath, k8sHost, saName, saNS string) { + v.logger.Logf(t, "enabling kubernetes auth method on %s path", authPath) + err := vaultClient.Sys().EnableAuthWithOptions(authPath, &vapi.EnableAuthOptions{ Type: "kubernetes", }) require.NoError(t, err) - v.logger.Logf(t, "updating vault kube auth config") - - // To configure the auth method, we need to read the token and the ca cert from the Vault's server + // To configure the auth method, we need to read the token and the CA cert from the auth method's // service account token. - namespace := v.helmOptions.KubectlOptions.Namespace - sa, err := v.kubernetesClient.CoreV1().ServiceAccounts(namespace).Get(context.Background(), fmt.Sprintf("%s-vault", v.releaseName), metav1.GetOptions{}) - require.NoError(t, err) - require.Len(t, sa.Secrets, 1) - tokenSecret, err := v.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), sa.Secrets[0].Name, metav1.GetOptions{}) + // The JWT token and CA cert is what Vault server will use to validate service account token + // with the Kubernetes API. + var sa *corev1.ServiceAccount + retry.Run(t, func(r *retry.R) { + sa, err = v.kubernetesClient.CoreV1().ServiceAccounts(saNS).Get(context.Background(), saName, metav1.GetOptions{}) + require.NoError(t, err) + require.Len(t, sa.Secrets, 1) + }) + + v.logger.Logf(t, "updating vault kubernetes auth config for %s auth path", authPath) + tokenSecret, err := v.kubernetesClient.CoreV1().Secrets(saNS).Get(context.Background(), sa.Secrets[0].Name, metav1.GetOptions{}) require.NoError(t, err) - _, err = v.vaultClient.Logical().Write("auth/kubernetes/config", map[string]interface{}{ - "token_reviewer_jwt": tokenSecret.StringData["token"], - "kubernetes_ca_cert": tokenSecret.StringData["ca.crt"], - "kubernetes_host": "https://kubernetes.default.svc", + _, err = vaultClient.Logical().Write(fmt.Sprintf("auth/%s/config", authPath), map[string]interface{}{ + "token_reviewer_jwt": string(tokenSecret.Data["token"]), + "kubernetes_ca_cert": string(tokenSecret.Data["ca.crt"]), + "kubernetes_host": k8sHost, }) require.NoError(t, err) } @@ -188,10 +208,10 @@ func (v *VaultCluster) Create(t *testing.T, ctx environment.TestContext) { v.initAndUnseal(t) // Wait for the injector and vault server pods to become Ready. - helpers.WaitForAllPodsToBeReady(t, v.kubernetesClient, v.helmOptions.KubectlOptions.Namespace, v.releaseLabelSelector()) + k8s.WaitForAllPodsToBeReady(t, v.kubernetesClient, v.helmOptions.KubectlOptions.Namespace, v.releaseLabelSelector()) // Now call bootstrap(). - v.bootstrap(t, ctx) + v.bootstrap(t) } // Destroy issues a helm delete and deletes the PVC + any helm secrets related to the release that are leftover. @@ -261,10 +281,23 @@ func (v *VaultCluster) releaseLabelSelector() string { return fmt.Sprintf("%s=%s", releaseLabel, v.releaseName) } +// serverEnabled returns true if this Vault cluster has a server. +func (v *VaultCluster) serverEnabled() bool { + serverEnabled, ok := v.helmOptions.SetValues["server.enabled"] + // Server is enabled by default in the Vault Helm chart, so it's enabled either when that helm value is + // not provided or when it's not explicitly disabled. + return !ok || serverEnabled != "false" +} + // createTLSCerts generates a self-signed CA and uses it to generate -// certificate and key for the Vault server. It then saves those as +// certificate and key for the Vault server. It then saves those as // Kubernetes secrets. func (v *VaultCluster) createTLSCerts(t *testing.T) { + if !v.serverEnabled() { + v.logger.Logf(t, "skipping generating Vault TLS certificates because Vault server is not enabled") + return + } + v.logger.Logf(t, "generating Vault TLS certificates") namespace := v.helmOptions.KubectlOptions.Namespace @@ -318,8 +351,12 @@ func (v *VaultCluster) createTLSCerts(t *testing.T) { // initAndUnseal initializes and unseals Vault. // Once initialized, it saves the Vault root token into a Kubernetes secret. func (v *VaultCluster) initAndUnseal(t *testing.T) { - v.logger.Logf(t, "initializing and unsealing Vault") + if !v.serverEnabled() { + v.logger.Logf(t, "skipping initializing and unsealing Vault because Vault server is not enabled") + return + } + v.logger.Logf(t, "initializing and unsealing Vault") namespace := v.helmOptions.KubectlOptions.Namespace retrier := &retry.Timer{Timeout: 2 * time.Minute, Wait: 1 * time.Second} retry.RunWith(retrier, t, func(r *retry.R) { diff --git a/acceptance/tests/mesh-gateway/mesh_gateway_test.go b/acceptance/tests/mesh-gateway/mesh_gateway_test.go index c989535b90..ed67252670 100644 --- a/acceptance/tests/mesh-gateway/mesh_gateway_test.go +++ b/acceptance/tests/mesh-gateway/mesh_gateway_test.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "testing" - "time" "github.com/hashicorp/consul-k8s/acceptance/framework/consul" "github.com/hashicorp/consul-k8s/acceptance/framework/environment" @@ -12,7 +11,6 @@ import ( "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul/api" - "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -108,7 +106,7 @@ func TestMeshGatewayDefault(t *testing.T) { // Verify federation between servers logger.Log(t, "verifying federation was successful") - verifyFederation(t, primaryClient, secondaryClient, releaseName, false) + helpers.VerifyFederation(t, primaryClient, secondaryClient, releaseName, false) // Create a ProxyDefaults resource to configure services to use the mesh // gateways. @@ -244,7 +242,7 @@ func TestMeshGatewaySecure(t *testing.T) { // Verify federation between servers logger.Log(t, "verifying federation was successful") - verifyFederation(t, primaryClient, secondaryClient, releaseName, true) + helpers.VerifyFederation(t, primaryClient, secondaryClient, releaseName, true) // Create a ProxyDefaults resource to configure services to use the mesh // gateways. @@ -280,38 +278,3 @@ func TestMeshGatewaySecure(t *testing.T) { }) } } - -// verifyFederation checks that the WAN federation between servers is successful -// by first checking members are alive from the perspective of both servers. -// If secure is true, it will also check that the ACL replication is running on the secondary server. -func verifyFederation(t *testing.T, primaryClient, secondaryClient *api.Client, releaseName string, secure bool) { - retrier := &retry.Timer{Timeout: 5 * time.Minute, Wait: 1 * time.Second} - start := time.Now() - - // Check that server in dc1 is healthy from the perspective of the server in dc2, and vice versa. - // We're calling the Consul health API, as opposed to checking serf membership status, - // because we need to make sure that the federated servers can make API calls and forward requests - // from one server to another. From running tests in CI for a while and using serf membership status before, - // we've noticed that the status could be "alive" as soon as the server in the secondary cluster joins the primary - // and then switch to "failed". This would require us to check that the status is "alive" is showing consistently for - // some amount of time, which could be quite flakey. Calling the API in another datacenter allows us to check that - // each server can forward calls to another, which is what we need for connect. - retry.RunWith(retrier, t, func(r *retry.R) { - secondaryServerHealth, _, err := primaryClient.Health().Node(fmt.Sprintf("%s-consul-server-0", releaseName), &api.QueryOptions{Datacenter: "dc2"}) - require.NoError(r, err) - require.Equal(r, secondaryServerHealth.AggregatedStatus(), api.HealthPassing) - - primaryServerHealth, _, err := secondaryClient.Health().Node(fmt.Sprintf("%s-consul-server-0", releaseName), &api.QueryOptions{Datacenter: "dc1"}) - require.NoError(r, err) - require.Equal(r, primaryServerHealth.AggregatedStatus(), api.HealthPassing) - - if secure { - replicationStatus, _, err := secondaryClient.ACL().Replication(nil) - require.NoError(r, err) - require.True(r, replicationStatus.Enabled) - require.True(r, replicationStatus.Running) - } - }) - - logger.Logf(t, "Took %s to verify federation", time.Since(start)) -} diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index 5fd19af3ce..a4a95e7078 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -5,7 +5,6 @@ import ( "fmt" "strconv" "testing" - "time" terratestk8s "github.com/gruntwork-io/terratest/modules/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/consul" @@ -128,7 +127,7 @@ func TestPartitions(t *testing.T) { releaseName := helpers.RandomName() - consul.MergeMaps(serverHelmValues, commonHelmValues) + helpers.MergeMaps(serverHelmValues, commonHelmValues) // Install the consul cluster with servers in the default kubernetes context. serverConsulCluster := consul.NewHelmCluster(t, serverHelmValues, serverClusterContext, cfg, releaseName) @@ -154,45 +153,10 @@ func TestPartitions(t *testing.T) { moveSecret(t, serverClusterContext, clientClusterContext, partitionToken) } - var partitionSvcAddress string - if cfg.UseKind { - nodeList, err := serverClusterContext.KubernetesClient(t).CoreV1().Nodes().List(context.Background(), metav1.ListOptions{}) - require.NoError(t, err) - // Get the address of the (only) node from the Kind cluster. - partitionSvcAddress = nodeList.Items[0].Status.Addresses[0].Address - } else { - // Get the IP of the partition service to configure the external server address in the values file for the clients cluster. - partitionServiceName := fmt.Sprintf("%s-consul-partition", releaseName) - logger.Logf(t, "retrieving partition service to determine external address for servers") - - // It can take some time for the load balancers to be ready and have an IP/Hostname. - // Wait for 60 seconds before failing. - retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 60}, t, func(r *retry.R) { - partitionsSvc, err := serverClusterContext.KubernetesClient(t).CoreV1().Services(serverClusterContext.KubectlOptions(t).Namespace).Get(ctx, partitionServiceName, metav1.GetOptions{}) - require.NoError(t, err) - require.NotEmpty(r, partitionsSvc.Status.LoadBalancer.Ingress) - // On AWS, load balancers have a hostname for ingress, while on Azure and GCP - // load balancers have IPs. - if partitionsSvc.Status.LoadBalancer.Ingress[0].Hostname != "" { - partitionSvcAddress = partitionsSvc.Status.LoadBalancer.Ingress[0].Hostname - } else { - partitionSvcAddress = partitionsSvc.Status.LoadBalancer.Ingress[0].IP - } - }) - } + partitionServiceName := fmt.Sprintf("%s-consul-partition", releaseName) + partitionSvcAddress := k8s.ServiceHost(t, cfg, serverClusterContext, partitionServiceName) - var k8sAuthMethodHost string - // When running on kind, the kube API address in kubeconfig will have a localhost address - // which will not work from inside the container. That's why we need to use the endpoints address instead - // which will point the node IP. - if cfg.UseKind { - // The Kubernetes AuthMethod host is read from the endpoints for the Kubernetes service. - kubernetesEndpoint, err := clientClusterContext.KubernetesClient(t).CoreV1().Endpoints(defaultNamespace).Get(ctx, "kubernetes", metav1.GetOptions{}) - require.NoError(t, err) - k8sAuthMethodHost = fmt.Sprintf("%s:%d", kubernetesEndpoint.Subsets[0].Addresses[0].IP, kubernetesEndpoint.Subsets[0].Ports[0].Port) - } else { - k8sAuthMethodHost = helpers.KubernetesAPIServerHostFromOptions(t, clientClusterContext.KubectlOptions(t)) - } + k8sAuthMethodHost := k8s.KubernetesAPIServerHost(t, cfg, clientClusterContext) // Create client cluster. clientHelmValues := map[string]string{ @@ -229,7 +193,7 @@ func TestPartitions(t *testing.T) { clientHelmValues["meshGateway.service.nodePort"] = "30100" } - consul.MergeMaps(clientHelmValues, commonHelmValues) + helpers.MergeMaps(clientHelmValues, commonHelmValues) // Install the consul cluster without servers in the client cluster kubernetes context. clientConsulCluster := consul.NewHelmCluster(t, clientHelmValues, clientClusterContext, cfg, releaseName) diff --git a/acceptance/tests/vault/helpers.go b/acceptance/tests/vault/helpers.go new file mode 100644 index 0000000000..d1439ee32e --- /dev/null +++ b/acceptance/tests/vault/helpers.go @@ -0,0 +1,180 @@ +package vault + +import ( + "crypto/rand" + "encoding/base64" + "fmt" + "testing" + + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + vapi "github.com/hashicorp/vault/api" + "github.com/stretchr/testify/require" +) + +const ( + gossipPolicy = ` +path "consul/data/secret/gossip" { + capabilities = ["read"] +}` + + // connectCAPolicy allows Consul to bootstrap all certificates for the service mesh in Vault. + // Adapted from https://www.consul.io/docs/connect/ca/vault#consul-managed-pki-paths. + connectCAPolicy = ` +path "/sys/mounts" { + capabilities = [ "read" ] +} + +path "/sys/mounts/connect_root" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +path "/sys/mounts/connect_inter" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +path "/connect_root/*" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} + +path "/connect_inter/*" { + capabilities = [ "create", "read", "update", "delete", "list" ] +} +` + caPolicy = ` +path "pki/cert/ca" { + capabilities = ["read"] +}` +) + +// generateGossipSecret generates a random 32 byte secret returned as a base64 encoded string. +func generateGossipSecret() (string, error) { + // This code was copied from Consul's Keygen command: + // https://github.com/hashicorp/consul/blob/d652cc86e3d0322102c2b5e9026c6a60f36c17a5/command/keygen/keygen.go + + key := make([]byte, 32) + n, err := rand.Reader.Read(key) + if err != nil { + return "", fmt.Errorf("error reading random data: %s", err) + } + if n != 32 { + return "", fmt.Errorf("couldn't read enough entropy") + } + + return base64.StdEncoding.EncodeToString(key), nil +} + +// configureGossipVaultSecret generates a gossip encryption key, +// stores it in vault as a secret and configures a policy to access it. +func configureGossipVaultSecret(t *testing.T, vaultClient *vapi.Client) string { + // Create the Vault Policy for the gossip key. + logger.Log(t, "Creating gossip policy") + err := vaultClient.Sys().PutPolicy("consul-gossip", gossipPolicy) + require.NoError(t, err) + + // Generate the gossip secret. + gossipKey, err := generateGossipSecret() + require.NoError(t, err) + + // Create the gossip secret. + logger.Log(t, "Creating the gossip secret") + params := map[string]interface{}{ + "data": map[string]interface{}{ + "gossip": gossipKey, + }, + } + _, err = vaultClient.Logical().Write("consul/data/secret/gossip", params) + require.NoError(t, err) + + return gossipKey +} + +// configureKubernetesAuthRoles configures roles for the Kubernetes auth method +// that will be used by the test Helm chart installation. +func configureKubernetesAuthRoles(t *testing.T, vaultClient *vapi.Client, consulReleaseName, ns, authPath, datacenter string) { + consulClientServiceAccountName := fmt.Sprintf("%s-consul-client", consulReleaseName) + consulServerServiceAccountName := fmt.Sprintf("%s-consul-server", consulReleaseName) + + // Create the Auth Roles for consul-server and consul-client. + // Auth roles bind policies to Kubernetes service accounts, which + // then enables the Vault agent init container to call 'vault login' + // with the Kubernetes auth method to obtain a Vault token. + // Please see https://www.vaultproject.io/docs/auth/kubernetes#configuration + // for more details. + logger.Log(t, "Creating the consul-server and consul-client roles") + params := map[string]interface{}{ + "bound_service_account_names": consulClientServiceAccountName, + "bound_service_account_namespaces": ns, + "policies": "consul-gossip", + "ttl": "24h", + } + _, err := vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-client", authPath), params) + require.NoError(t, err) + + params = map[string]interface{}{ + "bound_service_account_names": consulServerServiceAccountName, + "bound_service_account_namespaces": ns, + "policies": fmt.Sprintf("consul-gossip,connect-ca,consul-server-%s", datacenter), + "ttl": "24h", + } + _, err = vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-server", authPath), params) + require.NoError(t, err) + + // Create the CA role that all components will use to fetch the Server CA certs. + params = map[string]interface{}{ + "bound_service_account_names": "*", + "bound_service_account_namespaces": ns, + "policies": "consul-ca", + "ttl": "24h", + } + _, err = vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-ca", authPath), params) + require.NoError(t, err) +} + +// configurePKICA generates a CA in Vault. +func configurePKICA(t *testing.T, vaultClient *vapi.Client) { + // Create root CA to issue Consul server certificates and the `consul-server` PKI role. + // See https://learn.hashicorp.com/tutorials/consul/vault-pki-consul-secure-tls. + // Generate the root CA. + params := map[string]interface{}{ + "common_name": "Consul CA", + "ttl": "24h", + } + _, err := vaultClient.Logical().Write("pki/root/generate/internal", params) + require.NoError(t, err) + + err = vaultClient.Sys().PutPolicy("consul-ca", caPolicy) + require.NoError(t, err) +} + +// configurePKICertificates configures roles so that Consul server TLS certificates +// can be issued by Vault. +func configurePKICertificates(t *testing.T, vaultClient *vapi.Client, consulReleaseName, ns, datacenter string) string { + // Create the Vault PKI Role. + consulServerDNSName := consulReleaseName + "-consul-server" + allowedDomains := fmt.Sprintf("%s.consul,%s,%s.%s,%s.%s.svc", datacenter, consulServerDNSName, consulServerDNSName, ns, consulServerDNSName, ns) + params := map[string]interface{}{ + "allowed_domains": allowedDomains, + "allow_bare_domains": "true", + "allow_localhost": "true", + "allow_subdomains": "true", + "generate_lease": "true", + "max_ttl": "1h", + } + + pkiRoleName := fmt.Sprintf("consul-server-%s", datacenter) + + _, err := vaultClient.Logical().Write(fmt.Sprintf("pki/roles/%s", pkiRoleName), params) + require.NoError(t, err) + + certificateIssuePath := fmt.Sprintf("pki/issue/%s", pkiRoleName) + serverTLSPolicy := fmt.Sprintf(` +path %q { + capabilities = ["create", "update"] +}`, certificateIssuePath) + + // Create the server policy. + err = vaultClient.Sys().PutPolicy(pkiRoleName, serverTLSPolicy) + require.NoError(t, err) + + return certificateIssuePath +} diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index e19e196c84..0521ab0f23 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -1,9 +1,6 @@ package vault import ( - "crypto/rand" - "encoding/base64" - "fmt" "testing" "github.com/hashicorp/consul-k8s/acceptance/framework/consul" @@ -14,45 +11,6 @@ import ( "github.com/stretchr/testify/require" ) -const ( - gossipPolicy = ` -path "consul/data/secret/gossip" { - capabilities = ["read"] -}` - - // connectCAPolicy allows Consul to bootstrap all certificates for the service mesh in Vault. - // Adapted from https://www.consul.io/docs/connect/ca/vault#consul-managed-pki-paths. - connectCAPolicy = ` -path "/sys/mounts" { - capabilities = [ "read" ] -} - -path "/sys/mounts/connect_root" { - capabilities = [ "create", "read", "update", "delete", "list" ] -} - -path "/sys/mounts/connect_inter" { - capabilities = [ "create", "read", "update", "delete", "list" ] -} - -path "/connect_root/*" { - capabilities = [ "create", "read", "update", "delete", "list" ] -} - -path "/connect_inter/*" { - capabilities = [ "create", "read", "update", "delete", "list" ] -} -` - serverTLSPolicy = ` -path "pki/issue/consul-server" { - capabilities = ["create", "update"] -}` - caPolicy = ` -path "pki/cert/ca" { - capabilities = ["read"] -}` -) - // TestVault installs Vault, bootstraps it with secrets, policies, and Kube Auth Method. // It then configures Consul to use vault as the backend and checks that it works. func TestVault(t *testing.T) { @@ -62,116 +20,31 @@ func TestVault(t *testing.T) { consulReleaseName := helpers.RandomName() vaultReleaseName := helpers.RandomName() - consulClientServiceAccountName := fmt.Sprintf("%s-consul-client", consulReleaseName) - consulServerServiceAccountName := fmt.Sprintf("%s-consul-server", consulReleaseName) - vaultCluster := vault.NewVaultCluster(t, ctx, cfg, vaultReleaseName) + vaultCluster := vault.NewVaultCluster(t, ctx, cfg, vaultReleaseName, nil) vaultCluster.Create(t, ctx) // Vault is now installed in the cluster. // Now fetch the Vault client so we can create the policies and secrets. vaultClient := vaultCluster.VaultClient(t) - // Create the Vault Policy for the gossip key. - logger.Log(t, "Creating policies") - err := vaultClient.Sys().PutPolicy("consul-gossip", gossipPolicy) - require.NoError(t, err) + gossipKey := configureGossipVaultSecret(t, vaultClient) // Create the Vault Policy for the connect-ca. - err = vaultClient.Sys().PutPolicy("connect-ca", connectCAPolicy) - require.NoError(t, err) - - // Create the Auth Roles for consul-server and consul-client. - // Auth roles bind policies to Kubernetes service accounts, which - // then enables the Vault agent init container to call 'vault login' - // with the Kubernetes auth method to obtain a Vault token. - // Please see https://www.vaultproject.io/docs/auth/kubernetes#configuration - // for more details. - logger.Log(t, "Creating the consul-server and consul-client roles") - params := map[string]interface{}{ - "bound_service_account_names": consulClientServiceAccountName, - "bound_service_account_namespaces": ns, - "policies": "consul-gossip", - "ttl": "24h", - } - _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-client", params) + err := vaultClient.Sys().PutPolicy("connect-ca", connectCAPolicy) require.NoError(t, err) - params = map[string]interface{}{ - "bound_service_account_names": consulServerServiceAccountName, - "bound_service_account_namespaces": ns, - "policies": "consul-gossip,connect-ca,consul-server", - "ttl": "24h", - } - _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-server", params) - require.NoError(t, err) + configureKubernetesAuthRoles(t, vaultClient, consulReleaseName, ns, "kubernetes", "dc1") - // Create the CA role that all components will use to fetch the Server CA certs. - params = map[string]interface{}{ - "bound_service_account_names": "*", - "bound_service_account_namespaces": ns, - "policies": "consul-ca", - "ttl": "24h", - } - _, err = vaultClient.Logical().Write("auth/kubernetes/role/consul-ca", params) - require.NoError(t, err) - - // Generate the gossip secret. - gossipKey, err := generateGossipSecret() - require.NoError(t, err) - - // Create the gossip secret. - logger.Log(t, "Creating the gossip secret") - params = map[string]interface{}{ - "data": map[string]interface{}{ - "gossip": gossipKey, - }, - } - _, err = vaultClient.Logical().Write("consul/data/secret/gossip", params) - require.NoError(t, err) + configurePKICA(t, vaultClient) + certPath := configurePKICertificates(t, vaultClient, consulReleaseName, ns, "dc1") vaultCASecret := vault.CASecretName(vaultReleaseName) - // Bootstrap TLS by creating the CA infrastructure required for Consul server TLS and also create the `consul-server` PKI role. - // Using https://learn.hashicorp.com/tutorials/consul/vault-pki-consul-secure-tls. - // Generate the root CA. - params = map[string]interface{}{ - "common_name": "dc1.consul", - "ttl": "24h", - } - _, err = vaultClient.Logical().Write("pki/root/generate/internal", params) - require.NoError(t, err) - - // Create the Vault PKI Role. - name := consulReleaseName + "-consul" - allowedDomains := fmt.Sprintf("dc1.consul,%s-server,%s-server.%s,%s-server.%s.svc", name, name, ns, name, ns) - params = map[string]interface{}{ - "allowed_domains": allowedDomains, - "allow_bare_domains": "true", - "allow_localhost": "true", - "allow_subdomains": "true", - "generate_lease": "true", - "max_ttl": "1h", - } - _, err = vaultClient.Logical().Write("pki/roles/consul-server", params) - require.NoError(t, err) - - // Create the server and ca policies - err = vaultClient.Sys().PutPolicy("consul-server", serverTLSPolicy) - require.NoError(t, err) - err = vaultClient.Sys().PutPolicy("consul-ca", caPolicy) - require.NoError(t, err) - consulHelmValues := map[string]string{ - // TODO: Update the global image once 1.11 is GA. - "global.image": "docker.mirror.hashicorp.services/hashicorpdev/consul:latest", - - "server.enabled": "true", - "server.replicas": "1", "server.extraVolumes[0].type": "secret", "server.extraVolumes[0].name": vaultCASecret, "server.extraVolumes[0].load": "false", - "global.datacenter": "dc1", "connectInject.enabled": "true", "connectInject.replicas": "1", @@ -199,9 +72,8 @@ func TestVault(t *testing.T) { "terminatingGateways.enabled": "true", "terminatingGateways.defaults.replicas": "1", - "server.serverCert.secretName": "pki/issue/consul-server", + "server.serverCert.secretName": certPath, "global.tls.caCert.secretName": "pki/cert/ca", - "global.tls.httpsOnly": "false", "global.tls.enableAutoEncrypt": "true", // For sync catalog, it is sufficient to check that the deployment is running and ready @@ -250,20 +122,3 @@ func TestVault(t *testing.T) { k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://localhost:1234") } } - -// generateGossipSecret generates a random 32 byte secret returned as a base64 encoded string. -func generateGossipSecret() (string, error) { - // This code was copied from Consul's Keygen command: - // https://github.com/hashicorp/consul/blob/d652cc86e3d0322102c2b5e9026c6a60f36c17a5/command/keygen/keygen.go - - key := make([]byte, 32) - n, err := rand.Reader.Read(key) - if err != nil { - return "", fmt.Errorf("error reading random data: %s", err) - } - if n != 32 { - return "", fmt.Errorf("couldn't read enough entropy") - } - - return base64.StdEncoding.EncodeToString(key), nil -} diff --git a/acceptance/tests/vault/vault_wan_fed_test.go b/acceptance/tests/vault/vault_wan_fed_test.go new file mode 100644 index 0000000000..77689ef40a --- /dev/null +++ b/acceptance/tests/vault/vault_wan_fed_test.go @@ -0,0 +1,267 @@ +package vault + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/consul-k8s/acceptance/framework/config" + "github.com/hashicorp/consul-k8s/acceptance/framework/consul" + "github.com/hashicorp/consul-k8s/acceptance/framework/environment" + "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" + "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" + "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/consul-k8s/acceptance/framework/vault" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Test that WAN federation via Mesh gateways works with Vault +// as the secrets backend, testing all possible credentials that can be used for WAN federation. +// This test deploys a Vault cluster with a server in the primary k8s cluster and exposes it to the +// secondary cluster via a Kubernetes service. We then only need to deploy Vault agent injector +// in the secondary that will treat the Vault server in the primary as an external server. +func TestVault_WANFederationViaGateways(t *testing.T) { + cfg := suite.Config() + if !cfg.EnableMultiCluster { + t.Skipf("skipping this test because -enable-multi-cluster is not set") + } + primaryCtx := suite.Environment().DefaultContext(t) + secondaryCtx := suite.Environment().Context(t, environment.SecondaryContextName) + + ns := primaryCtx.KubectlOptions(t).Namespace + + vaultReleaseName := helpers.RandomName() + consulReleaseName := helpers.RandomName() + + // In the primary cluster, we will expose Vault server as a Load balancer + // or a NodePort service so that the secondary can connect to it. + primaryVaultHelmValues := map[string]string{ + "server.service.type": "LoadBalancer", + } + if cfg.UseKind { + primaryVaultHelmValues["server.service.type"] = "NodePort" + primaryVaultHelmValues["server.service.nodePort"] = "31000" + } + + primaryVaultCluster := vault.NewVaultCluster(t, primaryCtx, cfg, vaultReleaseName, primaryVaultHelmValues) + primaryVaultCluster.Create(t, primaryCtx) + + externalVaultAddress := vaultAddress(t, cfg, primaryCtx, vaultReleaseName) + + // In the secondary cluster, we will only deploy the agent injector and provide + // it with the primary's Vault address. We also want to configure the injector with + // a different k8s auth method path since the secondary cluster will need its own auth method. + secondaryVaultHelmValues := map[string]string{ + "server.enabled": "false", + "injector.externalVaultAddr": externalVaultAddress, + "injector.authPath": "auth/kubernetes-dc2", + } + + secondaryVaultCluster := vault.NewVaultCluster(t, secondaryCtx, cfg, vaultReleaseName, secondaryVaultHelmValues) + secondaryVaultCluster.Create(t, secondaryCtx) + + vaultClient := primaryVaultCluster.VaultClient(t) + + configureGossipVaultSecret(t, vaultClient) + + configureKubernetesAuthRoles(t, vaultClient, consulReleaseName, ns, "kubernetes", "dc1") + + // Configure Vault Kubernetes auth method for the secondary datacenter. + { + // Create auth method service account and ClusterRoleBinding. The Vault server + // in the primary cluster will use this service account token to talk to the secondary + // Kubernetes cluster. + // This ClusterRoleBinding is adapted from the Vault server's role: + // https://github.com/hashicorp/vault-helm/blob/b0528fce49c529f2c37953ea3a14f30ed651e0d6/templates/server-clusterrolebinding.yaml + + // Use a single name for all RBAC objects. + authMethodRBACName := fmt.Sprintf("%s-vault-auth-method", vaultReleaseName) + _, err := secondaryCtx.KubernetesClient(t).RbacV1().ClusterRoleBindings().Create(context.Background(), &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: authMethodRBACName, + }, + Subjects: []rbacv1.Subject{{Kind: rbacv1.ServiceAccountKind, Name: authMethodRBACName, Namespace: ns}}, + RoleRef: rbacv1.RoleRef{APIGroup: "rbac.authorization.k8s.io", Name: "system:auth-delegator", Kind: "ClusterRole"}, + }, metav1.CreateOptions{}) + require.NoError(t, err) + + // Create service account for the auth method in the secondary cluster. + _, err = secondaryCtx.KubernetesClient(t).CoreV1().ServiceAccounts(ns).Create(context.Background(), &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: authMethodRBACName, + }, + }, metav1.CreateOptions{}) + require.NoError(t, err) + t.Cleanup(func() { + secondaryCtx.KubernetesClient(t).RbacV1().ClusterRoleBindings().Delete(context.Background(), authMethodRBACName, metav1.DeleteOptions{}) + secondaryCtx.KubernetesClient(t).CoreV1().ServiceAccounts(ns).Delete(context.Background(), authMethodRBACName, metav1.DeleteOptions{}) + }) + + // Figure out the host for the Kubernetes API. This needs to be reachable from the Vault server + // in the primary cluster. + k8sAuthMethodHost := k8s.KubernetesAPIServerHost(t, cfg, secondaryCtx) + + // Now, configure the auth method in Vault. + secondaryVaultCluster.ConfigureAuthMethod(t, vaultClient, "kubernetes-dc2", k8sAuthMethodHost, authMethodRBACName, ns) + } + + configureKubernetesAuthRoles(t, vaultClient, consulReleaseName, ns, "kubernetes-dc2", "dc2") + + // Generate a CA and create PKI roles for the primary and secondary Consul servers. + configurePKICA(t, vaultClient) + primaryCertPath := configurePKICertificates(t, vaultClient, consulReleaseName, ns, "dc1") + secondaryCertPath := configurePKICertificates(t, vaultClient, consulReleaseName, ns, "dc2") + + // Move Vault CA secret from primary to secondary so that we can mount it to pods in the + // secondary cluster. + vaultCASecretName := vault.CASecretName(vaultReleaseName) + logger.Logf(t, "retrieving Vault CA secret %s from the primary cluster and applying to the secondary", vaultCASecretName) + vaultCASecret, err := primaryCtx.KubernetesClient(t).CoreV1().Secrets(primaryCtx.KubectlOptions(t).Namespace).Get(context.Background(), vaultCASecretName, metav1.GetOptions{}) + vaultCASecret.ResourceVersion = "" + require.NoError(t, err) + _, err = secondaryCtx.KubernetesClient(t).CoreV1().Secrets(secondaryCtx.KubectlOptions(t).Namespace).Create(context.Background(), vaultCASecret, metav1.CreateOptions{}) + require.NoError(t, err) + t.Cleanup(func() { + secondaryCtx.KubernetesClient(t).CoreV1().Secrets(ns).Delete(context.Background(), vaultCASecretName, metav1.DeleteOptions{}) + }) + + primaryConsulHelmValues := map[string]string{ + "global.datacenter": "dc1", + + "global.federation.enabled": "true", + + // TLS config. + "global.tls.enabled": "true", + "global.tls.httpsOnly": "false", + "global.tls.enableAutoEncrypt": "true", + "global.tls.caCert.secretName": "pki/cert/ca", + "server.serverCert.secretName": primaryCertPath, + + // Gossip config. + "global.gossipEncryption.secretName": "consul/data/secret/gossip", + "global.gossipEncryption.secretKey": "gossip", + + // Mesh config. + "connectInject.enabled": "true", + "controller.enabled": "true", + "meshGateway.enabled": "true", + "meshGateway.replicas": "1", + + // Server config. + "server.extraVolumes[0].type": "secret", + "server.extraVolumes[0].name": vaultCASecretName, + "server.extraVolumes[0].load": "false", + + // Vault config. + "global.secretsBackend.vault.enabled": "true", + "global.secretsBackend.vault.consulServerRole": "consul-server", + "global.secretsBackend.vault.consulClientRole": "consul-client", + "global.secretsBackend.vault.consulCARole": "consul-ca", + "global.secretsBackend.vault.ca.secretName": vaultCASecretName, + "global.secretsBackend.vault.ca.secretKey": "tls.crt", + } + + if cfg.UseKind { + primaryConsulHelmValues["meshGateway.service.type"] = "NodePort" + primaryConsulHelmValues["meshGateway.service.nodePort"] = "30000" + } + + primaryConsulCluster := consul.NewHelmCluster(t, primaryConsulHelmValues, primaryCtx, cfg, consulReleaseName) + primaryConsulCluster.Create(t) + + // Get the address of the mesh gateway. + primaryMeshGWAddress := meshGatewayAddress(t, cfg, primaryCtx, consulReleaseName) + serverExtraConfig := fmt.Sprintf(`"{\"primary_gateways\":[\"%s\"]\,\"primary_datacenter\":\"dc1\"}"`, primaryMeshGWAddress) + secondaryConsulHelmValues := map[string]string{ + "global.datacenter": "dc2", + + "global.federation.enabled": "true", + + // TLS config. + "global.tls.enabled": "true", + "global.tls.httpsOnly": "false", + "global.tls.enableAutoEncrypt": "true", + "global.tls.caCert.secretName": "pki/cert/ca", + "server.serverCert.secretName": secondaryCertPath, + + // Gossip config. + "global.gossipEncryption.secretName": "consul/data/secret/gossip", + "global.gossipEncryption.secretKey": "gossip", + + // Mesh config. + "connectInject.enabled": "true", + "meshGateway.enabled": "true", + "meshGateway.replicas": "1", + + // Server config. + "server.extraVolumes[0].type": "secret", + "server.extraVolumes[0].name": vaultCASecretName, + "server.extraVolumes[0].load": "false", + "server.extraConfig": serverExtraConfig, + + // Vault config. + "global.secretsBackend.vault.enabled": "true", + "global.secretsBackend.vault.consulServerRole": "consul-server", + "global.secretsBackend.vault.consulClientRole": "consul-client", + "global.secretsBackend.vault.consulCARole": "consul-ca", + "global.secretsBackend.vault.ca.secretName": vaultCASecretName, + "global.secretsBackend.vault.ca.secretKey": "tls.crt", + "global.secretsBackend.vault.agentAnnotations": fmt.Sprintf("vault.hashicorp.com/tls-server-name: %s-vault", vaultReleaseName), + } + + if cfg.UseKind { + secondaryConsulHelmValues["meshGateway.service.type"] = "NodePort" + secondaryConsulHelmValues["meshGateway.service.nodePort"] = "30000" + } + + // Install the secondary consul cluster in the secondary kubernetes context. + secondaryConsulCluster := consul.NewHelmCluster(t, secondaryConsulHelmValues, secondaryCtx, cfg, consulReleaseName) + secondaryConsulCluster.Create(t) + + // Verify federation between servers. + logger.Log(t, "verifying federation was successful") + primaryClient := primaryConsulCluster.SetupConsulClient(t, false) + secondaryClient := secondaryConsulCluster.SetupConsulClient(t, false) + helpers.VerifyFederation(t, primaryClient, secondaryClient, consulReleaseName, false) + + // Create a ProxyDefaults resource to configure services to use the mesh + // gateways. + logger.Log(t, "creating proxy-defaults config") + kustomizeDir := "../fixtures/bases/mesh-gateway" + k8s.KubectlApplyK(t, primaryCtx.KubectlOptions(t), kustomizeDir) + helpers.Cleanup(t, cfg.NoCleanupOnFailure, func() { + k8s.KubectlDeleteK(t, primaryCtx.KubectlOptions(t), kustomizeDir) + }) + + // Check that we can connect services over the mesh gateways. + logger.Log(t, "creating static-server in dc2") + k8s.DeployKustomize(t, secondaryCtx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + + logger.Log(t, "creating static-client in dc1") + k8s.DeployKustomize(t, primaryCtx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-multi-dc") + + logger.Log(t, "checking that connection is successful") + k8s.CheckStaticServerConnectionSuccessful(t, primaryCtx.KubectlOptions(t), "http://localhost:1234") +} + +// vaultAddress returns Vault's server URL depending on test configuration. +func vaultAddress(t *testing.T, cfg *config.TestConfig, ctx environment.TestContext, vaultReleaseName string) string { + vaultHost := k8s.ServiceHost(t, cfg, ctx, fmt.Sprintf("%s-vault", vaultReleaseName)) + if cfg.UseKind { + return fmt.Sprintf("https://%s:31000", vaultHost) + } + return fmt.Sprintf("https://%s:8200", vaultHost) +} + +// meshGatewayAddress returns a full address of the mesh gateway depending on configuration. +func meshGatewayAddress(t *testing.T, cfg *config.TestConfig, ctx environment.TestContext, consulReleaseName string) string { + primaryMeshGWHost := k8s.ServiceHost(t, cfg, ctx, fmt.Sprintf("%s-consul-mesh-gateway", consulReleaseName)) + if cfg.UseKind { + return fmt.Sprintf("%s:%d", primaryMeshGWHost, 30000) + } else { + return fmt.Sprintf("%s:%d", primaryMeshGWHost, 443) + } +} diff --git a/charts/consul/templates/mesh-gateway-deployment.yaml b/charts/consul/templates/mesh-gateway-deployment.yaml index a66242e2c8..8a0a05caba 100644 --- a/charts/consul/templates/mesh-gateway-deployment.yaml +++ b/charts/consul/templates/mesh-gateway-deployment.yaml @@ -36,6 +36,20 @@ spec: component: mesh-gateway annotations: "consul.hashicorp.com/connect-inject": "false" + {{- if (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) }} + "vault.hashicorp.com/agent-init-first": "true" + "vault.hashicorp.com/agent-inject": "true" + "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} + "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} + "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} + {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} + "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" + "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" + {{- end }} + {{- if .Values.global.secretsBackend.vault.agentAnnotations }} + {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} + {{- end }} + {{- end }} {{- if (and .Values.global.metrics.enabled .Values.global.metrics.enableGatewayMetrics) }} "prometheus.io/scrape": "true" "prometheus.io/path": "/metrics" diff --git a/charts/consul/test/unit/mesh-gateway-deployment.bats b/charts/consul/test/unit/mesh-gateway-deployment.bats index f796f4bb46..c434fce1c5 100755 --- a/charts/consul/test/unit/mesh-gateway-deployment.bats +++ b/charts/consul/test/unit/mesh-gateway-deployment.bats @@ -1531,3 +1531,175 @@ EOF [ "$status" -eq 1 ] [[ "$output" =~ "global.enableConsulNamespaces must be true if global.adminPartitions.enabled=true" ]] } + +#-------------------------------------------------------------------- +# Vault + +@test "meshGateway/Deployment: vault CA is not configured by default" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "meshGateway/Deployment: vault CA is not configured when secretName is set but secretKey is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "meshGateway/Deployment: vault CA is not configured when secretKey is set but secretName is not" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/agent-extra-secret")') + [ "${actual}" = "false" ] + local actual=$(echo $object | yq -r '.metadata.annotations | has("vault.hashicorp.com/ca-cert")') + [ "${actual}" = "false" ] +} + +@test "meshGateway/Deployment: vault CA is configured when both secretName and secretKey are set" { + cd `chart_dir` + local object=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.secretsBackend.vault.ca.secretName=ca' \ + --set 'global.secretsBackend.vault.ca.secretKey=tls.crt' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-extra-secret"') + [ "${actual}" = "ca" ] + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/ca-cert"') + [ "${actual}" = "/vault/custom/tls.crt" ] +} + +@test "meshGateway/Deployment: vault tls annotations are set when tls is enabled" { + cd `chart_dir` + local cmd=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=bar' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'server.serverCert.secretName=pki_int/issue/test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-serverca.crt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"pki_int/cert/ca\" -}}\n{{- .Data.certificate -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-serverca.crt"]' | tee /dev/stderr)" + [ "${actual}" = "pki_int/cert/ca" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-init-first"]' | tee /dev/stderr)" + [ "${actual}" = "true" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/agent-inject"]' | tee /dev/stderr)" + [ "${actual}" = "true" ] + + local actual="$(echo $cmd | + yq -r '.annotations["vault.hashicorp.com/role"]' | tee /dev/stderr)" + [ "${actual}" = "test" ] +} + +#-------------------------------------------------------------------- +# Vault agent annotations + +@test "meshGateway/Deployment: no vault agent annotations defined by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations | del(."consul.hashicorp.com/connect-inject") | del(."vault.hashicorp.com/agent-inject") | del(."vault.hashicorp.com/role")' | tee /dev/stderr) + [ "${actual}" = "{}" ] +} + +@test "meshGateway/Deployment: vault agent annotations can be set" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/mesh-gateway-deployment.yaml \ + --set 'connectInject.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.agentAnnotations=foo: bar' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) + [ "${actual}" = "bar" ] +} From b4756c3490f884be3d2709c725c2133f5aec3250 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Thu, 17 Feb 2022 12:08:14 -0700 Subject: [PATCH 270/418] vault: add support for wan federation with Vault when ACLs are enabled (#1025) - Add support for storing ACL replication token in Vault --- .github/workflows/golangci-lint-cli.yml | 2 +- acceptance/framework/consul/cli_cluster.go | 2 +- acceptance/framework/consul/consul_cluster.go | 40 +++--- .../framework/consul/consul_cluster_test.go | 2 +- acceptance/tests/vault/helpers.go | 46 ++++++- acceptance/tests/vault/vault_wan_fed_test.go | 64 +++++++--- charts/consul/templates/_helpers.tpl | 14 +++ .../consul/templates/server-acl-init-job.yaml | 28 +++-- .../consul/templates/server-statefulset.yaml | 10 +- .../consul/test/unit/server-acl-init-job.bats | 116 ++++++++++++------ .../test/unit/server-config-configmap.bats | 22 ---- .../consul/test/unit/server-statefulset.bats | 34 +++++ charts/consul/values.yaml | 23 +++- .../subcommand/server-acl-init/command.go | 8 +- .../server-acl-init/command_test.go | 66 ++++++++++ .../server-acl-init/create_or_update.go | 85 ++++++++----- 16 files changed, 420 insertions(+), 142 deletions(-) diff --git a/.github/workflows/golangci-lint-cli.yml b/.github/workflows/golangci-lint-cli.yml index f4c395b23c..50860bbabb 100644 --- a/.github/workflows/golangci-lint-cli.yml +++ b/.github/workflows/golangci-lint-cli.yml @@ -1,4 +1,4 @@ -name: golangci-lint-acceptance +name: golangci-lint-cli on: push: tags: diff --git a/acceptance/framework/consul/cli_cluster.go b/acceptance/framework/consul/cli_cluster.go index 5493533909..71662b88d8 100644 --- a/acceptance/framework/consul/cli_cluster.go +++ b/acceptance/framework/consul/cli_cluster.go @@ -51,7 +51,7 @@ func NewCLICluster( ctx environment.TestContext, cfg *config.TestConfig, releaseName string, -) Cluster { +) *CLICluster { // Create the namespace so the PSPs, SCCs, and enterprise secret can be created in the right namespace. createOrUpdateNamespace(t, ctx.KubernetesClient(t), consulNS) diff --git a/acceptance/framework/consul/consul_cluster.go b/acceptance/framework/consul/consul_cluster.go index cda22d9322..f2586b5c5b 100644 --- a/acceptance/framework/consul/consul_cluster.go +++ b/acceptance/framework/consul/consul_cluster.go @@ -40,6 +40,11 @@ type Cluster interface { // HelmCluster implements Cluster and uses Helm // to create, destroy, and upgrade consul type HelmCluster struct { + // ACLToken is an optional ACL token that will be used to create + // a Consul API client. If not provided, we will attempt to read + // a bootstrap token from a Kubernetes secret stored in the cluster. + ACLToken string + ctx environment.TestContext helmOptions *helm.Options releaseName string @@ -55,7 +60,7 @@ func NewHelmCluster( ctx environment.TestContext, cfg *config.TestConfig, releaseName string, -) Cluster { +) *HelmCluster { if cfg.EnablePodSecurityPolicies { configurePodSecurityPolicies(t, ctx.KubernetesClient(t), cfg, ctx.KubectlOptions(t).Namespace) @@ -234,21 +239,26 @@ func (h *HelmCluster) SetupConsulClient(t *testing.T, secure bool) *api.Client { config.TLSConfig.InsecureSkipVerify = true config.Scheme = "https" - // Get the ACL token. First, attempt to read it from the bootstrap token (this will be true in primary Consul servers). - // If the bootstrap token doesn't exist, it means we are running against a secondary cluster - // and will try to read the replication token from the federation secret. - // In secondary servers, we don't create a bootstrap token since ACLs are only bootstrapped in the primary. - // Instead, we provide a replication token that serves the role of the bootstrap token. - aclSecret, err := h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), h.releaseName+"-consul-bootstrap-acl-token", metav1.GetOptions{}) - if err != nil && errors.IsNotFound(err) { - federationSecret := fmt.Sprintf("%s-consul-federation", h.releaseName) - aclSecret, err = h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), federationSecret, metav1.GetOptions{}) - require.NoError(t, err) - config.Token = string(aclSecret.Data["replicationToken"]) - } else if err == nil { - config.Token = string(aclSecret.Data["token"]) + // If an ACL token is provided, we'll use that instead of trying to find it. + if h.ACLToken != "" { + config.Token = h.ACLToken } else { - require.NoError(t, err) + // Get the ACL token. First, attempt to read it from the bootstrap token (this will be true in primary Consul servers). + // If the bootstrap token doesn't exist, it means we are running against a secondary cluster + // and will try to read the replication token from the federation secret. + // In secondary servers, we don't create a bootstrap token since ACLs are only bootstrapped in the primary. + // Instead, we provide a replication token that serves the role of the bootstrap token. + aclSecret, err := h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), h.releaseName+"-consul-bootstrap-acl-token", metav1.GetOptions{}) + if err != nil && errors.IsNotFound(err) { + federationSecret := fmt.Sprintf("%s-consul-federation", h.releaseName) + aclSecret, err = h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), federationSecret, metav1.GetOptions{}) + require.NoError(t, err) + config.Token = string(aclSecret.Data["replicationToken"]) + } else if err == nil { + config.Token = string(aclSecret.Data["token"]) + } else { + require.NoError(t, err) + } } } diff --git a/acceptance/framework/consul/consul_cluster_test.go b/acceptance/framework/consul/consul_cluster_test.go index 1a9ac604db..3fb6710c8b 100644 --- a/acceptance/framework/consul/consul_cluster_test.go +++ b/acceptance/framework/consul/consul_cluster_test.go @@ -65,7 +65,7 @@ func TestNewHelmCluster(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cluster := NewHelmCluster(t, tt.helmValues, &ctx{}, &config.TestConfig{ConsulImage: "test-config-image"}, "test") - require.Equal(t, cluster.(*HelmCluster).helmOptions.SetValues, tt.want) + require.Equal(t, cluster.helmOptions.SetValues, tt.want) }) } } diff --git a/acceptance/tests/vault/helpers.go b/acceptance/tests/vault/helpers.go index d1439ee32e..7a690ec67a 100644 --- a/acceptance/tests/vault/helpers.go +++ b/acceptance/tests/vault/helpers.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/go-uuid" vapi "github.com/hashicorp/vault/api" "github.com/stretchr/testify/require" ) @@ -16,6 +17,10 @@ const ( path "consul/data/secret/gossip" { capabilities = ["read"] }` + replicationTokenPolicy = ` +path "consul/data/secret/replication" { + capabilities = ["read", "update"] +}` // connectCAPolicy allows Consul to bootstrap all certificates for the service mesh in Vault. // Adapted from https://www.consul.io/docs/connect/ca/vault#consul-managed-pki-paths. @@ -113,7 +118,7 @@ func configureKubernetesAuthRoles(t *testing.T, vaultClient *vapi.Client, consul params = map[string]interface{}{ "bound_service_account_names": consulServerServiceAccountName, "bound_service_account_namespaces": ns, - "policies": fmt.Sprintf("consul-gossip,connect-ca,consul-server-%s", datacenter), + "policies": fmt.Sprintf("consul-gossip,connect-ca,consul-server-%s,consul-replication-token", datacenter), "ttl": "24h", } _, err = vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-server", authPath), params) @@ -178,3 +183,42 @@ path %q { return certificateIssuePath } + +// configureReplicationTokenVaultSecret generates a replication token secret ID, +// stores it in vault as a secret and configures a policy to access it. +func configureReplicationTokenVaultSecret(t *testing.T, vaultClient *vapi.Client, consulReleaseName, ns string, authMethodPaths ...string) string { + // Create the Vault Policy for the replication token. + logger.Log(t, "Creating replication token policy") + err := vaultClient.Sys().PutPolicy("consul-replication-token", replicationTokenPolicy) + require.NoError(t, err) + + // Generate the token secret. + token, err := uuid.GenerateUUID() + require.NoError(t, err) + + // Create the replication token secret. + logger.Log(t, "Creating the replication token secret") + params := map[string]interface{}{ + "data": map[string]interface{}{ + "replication": token, + }, + } + _, err = vaultClient.Logical().Write("consul/data/secret/replication", params) + require.NoError(t, err) + + logger.Log(t, "Creating kubernetes auth role for the server-acl-init job") + serverACLInitSAName := fmt.Sprintf("%s-consul-server-acl-init", consulReleaseName) + params = map[string]interface{}{ + "bound_service_account_names": serverACLInitSAName, + "bound_service_account_namespaces": ns, + "policies": "consul-replication-token", + "ttl": "24h", + } + + for _, authMethodPath := range authMethodPaths { + _, err := vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/server-acl-init", authMethodPath), params) + require.NoError(t, err) + } + + return token +} diff --git a/acceptance/tests/vault/vault_wan_fed_test.go b/acceptance/tests/vault/vault_wan_fed_test.go index 77689ef40a..ed25f7bfea 100644 --- a/acceptance/tests/vault/vault_wan_fed_test.go +++ b/acceptance/tests/vault/vault_wan_fed_test.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/vault" + "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -115,6 +116,8 @@ func TestVault_WANFederationViaGateways(t *testing.T) { primaryCertPath := configurePKICertificates(t, vaultClient, consulReleaseName, ns, "dc1") secondaryCertPath := configurePKICertificates(t, vaultClient, consulReleaseName, ns, "dc2") + replicationToken := configureReplicationTokenVaultSecret(t, vaultClient, consulReleaseName, ns, "kubernetes", "kubernetes-dc2") + // Move Vault CA secret from primary to secondary so that we can mount it to pods in the // secondary cluster. vaultCASecretName := vault.CASecretName(vaultReleaseName) @@ -135,7 +138,6 @@ func TestVault_WANFederationViaGateways(t *testing.T) { // TLS config. "global.tls.enabled": "true", - "global.tls.httpsOnly": "false", "global.tls.enableAutoEncrypt": "true", "global.tls.caCert.secretName": "pki/cert/ca", "server.serverCert.secretName": primaryCertPath, @@ -144,6 +146,12 @@ func TestVault_WANFederationViaGateways(t *testing.T) { "global.gossipEncryption.secretName": "consul/data/secret/gossip", "global.gossipEncryption.secretKey": "gossip", + // ACL config. + "global.acls.manageSystemACLs": "true", + "global.acls.createReplicationToken": "true", + "global.acls.replicationToken.secretName": "consul/data/secret/replication", + "global.acls.replicationToken.secretKey": "replication", + // Mesh config. "connectInject.enabled": "true", "controller.enabled": "true", @@ -156,12 +164,13 @@ func TestVault_WANFederationViaGateways(t *testing.T) { "server.extraVolumes[0].load": "false", // Vault config. - "global.secretsBackend.vault.enabled": "true", - "global.secretsBackend.vault.consulServerRole": "consul-server", - "global.secretsBackend.vault.consulClientRole": "consul-client", - "global.secretsBackend.vault.consulCARole": "consul-ca", - "global.secretsBackend.vault.ca.secretName": vaultCASecretName, - "global.secretsBackend.vault.ca.secretKey": "tls.crt", + "global.secretsBackend.vault.enabled": "true", + "global.secretsBackend.vault.consulServerRole": "consul-server", + "global.secretsBackend.vault.consulClientRole": "consul-client", + "global.secretsBackend.vault.consulCARole": "consul-ca", + "global.secretsBackend.vault.manageSystemACLsRole": "server-acl-init", + "global.secretsBackend.vault.ca.secretName": vaultCASecretName, + "global.secretsBackend.vault.ca.secretKey": "tls.crt", } if cfg.UseKind { @@ -182,7 +191,6 @@ func TestVault_WANFederationViaGateways(t *testing.T) { // TLS config. "global.tls.enabled": "true", - "global.tls.httpsOnly": "false", "global.tls.enableAutoEncrypt": "true", "global.tls.caCert.secretName": "pki/cert/ca", "server.serverCert.secretName": secondaryCertPath, @@ -191,6 +199,11 @@ func TestVault_WANFederationViaGateways(t *testing.T) { "global.gossipEncryption.secretName": "consul/data/secret/gossip", "global.gossipEncryption.secretKey": "gossip", + // ACL config. + "global.acls.manageSystemACLs": "true", + "global.acls.replicationToken.secretName": "consul/data/secret/replication", + "global.acls.replicationToken.secretKey": "replication", + // Mesh config. "connectInject.enabled": "true", "meshGateway.enabled": "true", @@ -203,13 +216,14 @@ func TestVault_WANFederationViaGateways(t *testing.T) { "server.extraConfig": serverExtraConfig, // Vault config. - "global.secretsBackend.vault.enabled": "true", - "global.secretsBackend.vault.consulServerRole": "consul-server", - "global.secretsBackend.vault.consulClientRole": "consul-client", - "global.secretsBackend.vault.consulCARole": "consul-ca", - "global.secretsBackend.vault.ca.secretName": vaultCASecretName, - "global.secretsBackend.vault.ca.secretKey": "tls.crt", - "global.secretsBackend.vault.agentAnnotations": fmt.Sprintf("vault.hashicorp.com/tls-server-name: %s-vault", vaultReleaseName), + "global.secretsBackend.vault.enabled": "true", + "global.secretsBackend.vault.consulServerRole": "consul-server", + "global.secretsBackend.vault.consulClientRole": "consul-client", + "global.secretsBackend.vault.consulCARole": "consul-ca", + "global.secretsBackend.vault.manageSystemACLsRole": "server-acl-init", + "global.secretsBackend.vault.ca.secretName": vaultCASecretName, + "global.secretsBackend.vault.ca.secretKey": "tls.crt", + "global.secretsBackend.vault.agentAnnotations": fmt.Sprintf("vault.hashicorp.com/tls-server-name: %s-vault", vaultReleaseName), } if cfg.UseKind { @@ -223,9 +237,10 @@ func TestVault_WANFederationViaGateways(t *testing.T) { // Verify federation between servers. logger.Log(t, "verifying federation was successful") - primaryClient := primaryConsulCluster.SetupConsulClient(t, false) - secondaryClient := secondaryConsulCluster.SetupConsulClient(t, false) - helpers.VerifyFederation(t, primaryClient, secondaryClient, consulReleaseName, false) + primaryClient := primaryConsulCluster.SetupConsulClient(t, true) + secondaryConsulCluster.ACLToken = replicationToken + secondaryClient := secondaryConsulCluster.SetupConsulClient(t, true) + helpers.VerifyFederation(t, primaryClient, secondaryClient, consulReleaseName, true) // Create a ProxyDefaults resource to configure services to use the mesh // gateways. @@ -243,6 +258,19 @@ func TestVault_WANFederationViaGateways(t *testing.T) { logger.Log(t, "creating static-client in dc1") k8s.DeployKustomize(t, primaryCtx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-multi-dc") + logger.Log(t, "creating intention") + _, _, err = primaryClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: "static-server", + Sources: []*api.SourceIntention{ + { + Name: "static-client", + Action: api.IntentionActionAllow, + }, + }, + }, nil) + require.NoError(t, err) + logger.Log(t, "checking that connection is successful") k8s.CheckStaticServerConnectionSuccessful(t, primaryCtx.KubectlOptions(t), "http://localhost:1234") } diff --git a/charts/consul/templates/_helpers.tpl b/charts/consul/templates/_helpers.tpl index 277f744d08..28a3fdf0ed 100644 --- a/charts/consul/templates/_helpers.tpl +++ b/charts/consul/templates/_helpers.tpl @@ -59,6 +59,20 @@ as well as the global.name setting. {{- if .Values.global.tls -}}{{- if .Values.global.tls.serverAdditionalIPSANs -}}{{- range $ipsan := .Values.global.tls.serverAdditionalIPSANs }},{{ $ipsan }} {{- end -}}{{- end -}}{{- end -}} {{- end -}} +{{- define "consul.vaultReplicationTokenTemplate" -}} +| + {{ "{{" }}- with secret "{{ .Values.global.acls.replicationToken.secretName }}" -{{ "}}" }} + {{ "{{" }}- {{ printf ".Data.data.%s" .Values.global.acls.replicationToken.secretKey }} -{{ "}}" }} + {{ "{{" }}- end -{{ "}}" }} +{{- end -}} + +{{- define "consul.vaultReplicationTokenConfigTemplate" -}} +| + {{ "{{" }}- with secret "{{ .Values.global.acls.replicationToken.secretName }}" -{{ "}}" }} + acl { tokens { agent = "{{ "{{" }}- {{ printf ".Data.data.%s" .Values.global.acls.replicationToken.secretKey }} -{{ "}}" }}", replication = "{{ "{{" }}- {{ printf ".Data.data.%s" .Values.global.acls.replicationToken.secretKey }} -{{ "}}" }}" }} + {{ "{{" }}- end -{{ "}}" }} +{{- end -}} + {{/* Sets up the extra-from-values config file passed to consul and then uses sed to do any necessary substitution for HOST_IP/POD_IP/HOSTNAME. Useful for dogstats telemetry. The output file diff --git a/charts/consul/templates/server-acl-init-job.yaml b/charts/consul/templates/server-acl-init-job.yaml index 5195e7975e..27bc8c1bf0 100644 --- a/charts/consul/templates/server-acl-init-job.yaml +++ b/charts/consul/templates/server-acl-init-job.yaml @@ -4,7 +4,9 @@ {{- if and .Values.global.acls.createReplicationToken (not .Values.global.acls.manageSystemACLs) }}{{ fail "if global.acls.createReplicationToken is true, global.acls.manageSystemACLs must be true" }}{{ end -}} {{- if .Values.global.bootstrapACLs }}{{ fail "global.bootstrapACLs was removed, use global.acls.manageSystemACLs instead" }}{{ end -}} {{- if .Values.global.acls.manageSystemACLs }} -{{- /* We don't render this job when server.updatePartition > 0 because that +{{- if and .Values.global.secretsBackend.vault.enabled .Values.global.acls.replicationToken.secretName (not .Values.global.secretsBackend.vault.manageSystemACLsRole) }}{{ fail "global.secretsBackend.vault.manageSystemACLsRole must be set if global.secretsBackend.vault.enabled is true and global.acls.replicationToken is provided" }}{{ end -}} +{{- if or (and .Values.global.acls.replicationToken.secretName (not .Values.global.acls.replicationToken.secretKey)) (and .Values.global.acls.replicationToken.secretKey (not .Values.global.acls.replicationToken.secretName))}}{{ fail "both global.acls.replicationToken.secretKey and global.acls.replicationToken.secretName must be set if one of them is provided" }}{{ end -}} + {{- /* We don't render this job when server.updatePartition > 0 because that means a server rollout is in progress and this job won't complete unless the rollout is finished (which won't happen until the partition is 0). If we ran it in this case, then the job would not complete which would cause @@ -37,13 +39,21 @@ spec: {{- if (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) }} "vault.hashicorp.com/agent-pre-populate-only": "true" "vault.hashicorp.com/agent-inject": "true" - "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ template "consul.serverTLSCATemplate" . }} + {{- if .Values.global.secretsBackend.vault.manageSystemACLsRole }} + "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.manageSystemACLsRole }} + {{- else if .Values.global.tls.enabled }} + "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} + {{- end }} {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} "vault.hashicorp.com/agent-extra-secret": "{{ .Values.global.secretsBackend.vault.ca.secretName }}" "vault.hashicorp.com/ca-cert": "/vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }}" {{- end }} + {{- if .Values.global.acls.replicationToken.secretName }} + "vault.hashicorp.com/agent-inject-secret-replication-token": "{{ .Values.global.acls.replicationToken.secretName }}" + "vault.hashicorp.com/agent-inject-template-replication-token": {{ template "consul.vaultReplicationTokenTemplate" . }} + {{- end }} {{- if .Values.global.secretsBackend.vault.agentAnnotations }} {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} {{- end }} @@ -51,7 +61,7 @@ spec: spec: restartPolicy: Never serviceAccountName: {{ template "consul.fullname" . }}-server-acl-init - {{- if (or .Values.global.tls.enabled (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey)) }} + {{- if (or .Values.global.tls.enabled .Values.global.acls.replicationToken.secretName (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey)) }} volumes: {{- if and .Values.global.tls.enabled (not .Values.global.secretsBackend.vault.enabled) }} - name: consul-ca-cert @@ -72,7 +82,7 @@ spec: items: - key: {{ .Values.global.acls.bootstrapToken.secretKey }} path: bootstrap-token - {{- else if (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) }} + {{- else if and .Values.global.acls.replicationToken.secretName (not .Values.global.secretsBackend.vault.enabled) }} - name: acl-replication-token secret: secretName: {{ .Values.global.acls.replicationToken.secretName }} @@ -89,7 +99,7 @@ spec: valueFrom: fieldRef: fieldPath: metadata.namespace - {{- if (or .Values.global.tls.enabled (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey)) }} + {{- if (or .Values.global.tls.enabled .Values.global.acls.replicationToken.secretName (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey)) }} volumeMounts: {{- if and .Values.global.tls.enabled (not .Values.global.secretsBackend.vault.enabled) }} - name: consul-ca-cert @@ -100,7 +110,7 @@ spec: - name: bootstrap-token mountPath: /consul/acl/tokens readOnly: true - {{- else if (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) }} + {{- else if and .Values.global.acls.replicationToken.secretName (not .Values.global.secretsBackend.vault.enabled) }} - name: acl-replication-token mountPath: /consul/acl/tokens readOnly: true @@ -232,9 +242,13 @@ spec: {{- if (and .Values.global.acls.bootstrapToken.secretName .Values.global.acls.bootstrapToken.secretKey) }} -bootstrap-token-file=/consul/acl/tokens/bootstrap-token \ - {{- else if (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) }} + {{- else if .Values.global.acls.replicationToken.secretName }} + {{- if .Values.global.secretsBackend.vault.enabled }} + -acl-replication-token-file=/vault/secrets/replication-token \ + {{- else }} -acl-replication-token-file=/consul/acl/tokens/acl-replication-token \ {{- end }} + {{- end }} {{- if .Values.controller.enabled }} -create-controller-token=true \ diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 0a6c16778b..74e1b4f63c 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -75,6 +75,10 @@ spec: "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ include "consul.serverTLSCATemplate" . }} {{- end }} + {{- if (and .Values.global.acls.replicationToken.secretName (not .Values.global.acls.createReplicationToken)) }} + "vault.hashicorp.com/agent-inject-secret-replication-token-config.hcl": "{{ .Values.global.acls.replicationToken.secretName }}" + "vault.hashicorp.com/agent-inject-template-replication-token-config.hcl": {{ template "consul.vaultReplicationTokenConfigTemplate" . }} + {{- end }} {{- if .Values.global.secretsBackend.vault.agentAnnotations }} {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} {{- end }} @@ -217,7 +221,7 @@ spec: - name: CONSUL_LICENSE_PATH value: /consul/license/{{ .Values.global.enterpriseLicense.secretKey }} {{- end }} - {{- if (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) }} + {{- if (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey (not .Values.global.secretsBackend.vault.enabled)) }} - name: ACL_REPLICATION_TOKEN valueFrom: secretKeyRef: @@ -294,8 +298,12 @@ spec: -hcl="connect { enable_mesh_gateway_wan_federation = true }" \ {{- end }} {{- if (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) }} + {{- if (and .Values.global.secretsBackend.vault.enabled (not .Values.global.acls.createReplicationToken)) }} + -config-file=/vault/secrets/replication-token-config.hcl \ + {{- else }} -hcl="acl { tokens { agent = \"${ACL_REPLICATION_TOKEN}\", replication = \"${ACL_REPLICATION_TOKEN}\" } }" \ {{- end }} + {{- end }} {{- if .Values.ui.enabled }} -ui \ {{- if .Values.ui.dashboardURLTemplates.service }} diff --git a/charts/consul/test/unit/server-acl-init-job.bats b/charts/consul/test/unit/server-acl-init-job.bats index 1b84b5860b..a096a8aeb8 100644 --- a/charts/consul/test/unit/server-acl-init-job.bats +++ b/charts/consul/test/unit/server-acl-init-job.bats @@ -726,6 +726,72 @@ load _helpers [ "${actual}" = "/vault/custom/tls.crt" ] } +#-------------------------------------------------------------------- +# Replication token in Vault + +@test "serverACLInit/Job: vault replication token can be provided" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' \ + --set 'global.secretsBackend.vault.manageSystemACLsRole=acl-role' \ + --set 'global.acls.replicationToken.secretName=/vault/secret' \ + --set 'global.acls.replicationToken.secretKey=token' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check that the role is set. + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/role"') + [ "${actual}" = "acl-role" ] + + # Check Vault secret annotations. + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-inject-secret-replication-token"') + [ "${actual}" = "/vault/secret" ] + + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-inject-template-replication-token"') + local expected=$'{{- with secret \"/vault/secret\" -}}\n{{- .Data.data.token -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + # Check that replication token Kubernetes secret volumes and volumeMounts are not attached. + local actual=$(echo $object | yq -r '.metadata.annotations."vault.hashicorp.com/agent-inject-secret-replication-token"') + [ "${actual}" = "/vault/secret" ] + + local actual=$(echo $object | jq -r '.spec.volumes') + [ "${actual}" = "null" ] + + local actual=$(echo $object | jq -r '.spec.containers[] | select(.name="post-install-job").volumeMounts') + [ "${actual}" = "null" ] + + # Check that the replication token flag is set to the path of the Vault secret. + local actual=$(echo $object | jq -r '.spec.containers[] | select(.name="post-install-job").command | any(contains("-acl-replication-token-file=/vault/secrets/replication-token"))') + [ "${actual}" = "true" ] +} + +@test "serverACLInit/Job: manageSystemACLsRole is required when Vault is enabled and replication token is set" { + cd `chart_dir` + run helm template \ + -s templates/server-acl-init-job.yaml \ + --set 'global.acls.manageSystemACLs=true' \ + --set 'global.acls.replicationToken.secretName=/vault/secret' \ + --set 'global.acls.replicationToken.secretKey=foo' \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.tls.caCert.secretName=foo' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=carole' . + [ "$status" -eq 1 ] + [[ "$output" =~ "global.secretsBackend.vault.manageSystemACLsRole must be set if global.secretsBackend.vault.enabled is true and global.acls.replicationToken is provided" ]] +} + #-------------------------------------------------------------------- # Vault agent annotations @@ -1230,59 +1296,31 @@ load _helpers #-------------------------------------------------------------------- # global.acls.replicationToken -@test "serverACLInit/Job: -acl-replication-token-file is not set by default" { +@test "serverACLInit/Job: replicationToken.secretKey is required when replicationToken.secretName is set" { cd `chart_dir` - local object=$(helm template \ + run helm template \ -s templates/server-acl-init-job.yaml \ --set 'global.acls.manageSystemACLs=true' \ - . | tee /dev/stderr) - - # Test the flag is not set. - local actual=$(echo "$object" | - yq '.spec.template.spec.containers[0].command | any(contains("-acl-replication-token-file"))' | tee /dev/stderr) - [ "${actual}" = "false" ] - - # Test the volume doesn't exist - local actual=$(echo "$object" | - yq '.spec.template.spec.volumes | length == 0' | tee /dev/stderr) - [ "${actual}" = "true" ] - - # Test the volume mount doesn't exist - local actual=$(echo "$object" | - yq '.spec.template.spec.containers[0].volumeMounts | length == 0' | tee /dev/stderr) - [ "${actual}" = "true" ] + --set 'global.acls.replicationToken.secretName=name' \ . + [ "$status" -eq 1 ] + [[ "$output" =~ "both global.acls.replicationToken.secretKey and global.acls.replicationToken.secretName must be set if one of them is provided" ]] } -@test "serverACLInit/Job: -acl-replication-token-file is not set when acls.replicationToken.secretName is set but secretKey is not" { +@test "serverACLInit/Job: replicationToken.secretName is required when replicationToken.secretKey is set" { cd `chart_dir` - local object=$(helm template \ + run helm template \ -s templates/server-acl-init-job.yaml \ --set 'global.acls.manageSystemACLs=true' \ - --set 'global.acls.replicationToken.secretName=name' \ - . | tee /dev/stderr) - - # Test the flag is not set. - local actual=$(echo "$object" | - yq '.spec.template.spec.containers[0].command | any(contains("-acl-replication-token-file"))' | tee /dev/stderr) - [ "${actual}" = "false" ] - - # Test the volume doesn't exist - local actual=$(echo "$object" | - yq '.spec.template.spec.volumes | length == 0' | tee /dev/stderr) - [ "${actual}" = "true" ] - - # Test the volume mount doesn't exist - local actual=$(echo "$object" | - yq '.spec.template.spec.containers[0].volumeMounts | length == 0' | tee /dev/stderr) - [ "${actual}" = "true" ] + --set 'global.acls.replicationToken.secretKey=key' \ . + [ "$status" -eq 1 ] + [[ "$output" =~ "both global.acls.replicationToken.secretKey and global.acls.replicationToken.secretName must be set if one of them is provided" ]] } -@test "serverACLInit/Job: -acl-replication-token-file is not set when acls.replicationToken.secretKey is set but secretName is not" { +@test "serverACLInit/Job: -acl-replication-token-file is not set by default" { cd `chart_dir` local object=$(helm template \ -s templates/server-acl-init-job.yaml \ --set 'global.acls.manageSystemACLs=true' \ - --set 'global.acls.replicationToken.secretKey=key' \ . | tee /dev/stderr) # Test the flag is not set. diff --git a/charts/consul/test/unit/server-config-configmap.bats b/charts/consul/test/unit/server-config-configmap.bats index cea3ef7eff..ecb96599e8 100755 --- a/charts/consul/test/unit/server-config-configmap.bats +++ b/charts/consul/test/unit/server-config-configmap.bats @@ -168,28 +168,6 @@ load _helpers [ "${actual}" = "null" ] } -@test "server/ConfigMap: enable_token_replication is not set when acls.replicationToken.secretName is set but secretKey is not" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-config-configmap.yaml \ - --set 'global.acls.manageSystemACLs=true' \ - --set 'global.acls.replicationToken.secretName=name' \ - . | tee /dev/stderr | - yq -r '.data["acl-config.json"]' | yq -r '.acl.enable_token_replication' | tee /dev/stderr) - [ "${actual}" = "null" ] -} - -@test "server/ConfigMap: enable_token_replication is not set when acls.replicationToken.secretKey is set but secretName is not" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-config-configmap.yaml \ - --set 'global.acls.manageSystemACLs=true' \ - --set 'global.acls.replicationToken.secretKey=key' \ - . | tee /dev/stderr | - yq -r '.data["acl-config.json"]' | yq -r '.acl.enable_token_replication' | tee /dev/stderr) - [ "${actual}" = "null" ] -} - @test "server/ConfigMap: enable_token_replication is set when acls.replicationToken.secretKey and secretName are set" { cd `chart_dir` local actual=$(helm template \ diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 65e3abe511..7c49a7a001 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -1872,6 +1872,40 @@ load _helpers [ "${actual}" = "bar" ] } +#-------------------------------------------------------------------- +# Vault replication token + +@test "server/StatefulSet: vault replication token is configured when secret provided and createReplicationToken is false" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=test' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.acls.replicationToken.secretName=vault/replication-token' \ + --set 'global.acls.replicationToken.secretKey=token' \ + . | tee /dev/stderr | + yq -r '.spec.template' | tee /dev/stderr) + + # Check that Vault annotations are set. + local actual="$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-secret-replication-token-config.hcl"]' | tee /dev/stderr)" + [ "${actual}" = "vault/replication-token" ] + + local actual="$(echo $object | + yq -r '.metadata.annotations["vault.hashicorp.com/agent-inject-template-replication-token-config.hcl"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"vault/replication-token\" -}}\nacl { tokens { agent = \"{{- .Data.data.token -}}\", replication = \"{{- .Data.data.token -}}\" }}\n{{- end -}}' + [ "${actual}" = "${expected}" ] + + # Check that ACL_REPLICATION_TOKEN env var is not provided. + local actual="$(echo $object | yq -r '.spec.containers[] | select(.name=="consul").env[] | select(.name=="ACL_REPLICATION_TOKEN")' | tee /dev/stderr)" + [ "${actual}" = "" ] + + # Check that path to Vault secret config is provided to the command. + local actual="$(echo $object | yq -r '.spec.containers[] | select(.name=="consul").command | any(contains("-config-file=/vault/secrets/replication-token-config.hcl"))' | tee /dev/stderr)" + [ "${actual}" = "true" ] +} + #-------------------------------------------------------------------- # ui.dashboardURLTemplates.service diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index fac5b836be..3f2e36cc38 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -138,7 +138,10 @@ global: # The Vault role for the Consul server. # The role must be connected to the Consul server's service account and # have a policy with read capabilities for the following secrets: - # - gossip encryption key defined by `global.gossipEncryption.secretName`. + # - gossip encryption key defined by `global.gossipEncryption.secretName` + # - certificate issue path defined by `server.serverCert.secretName` + # - CA certificate defined by `global.tls.caCert.secretName` + # - replication token defined by `global.acls.replicationToken.secretName` if `global.federation.enabled` is `true` # To discover the service account name of the Consul server, run # ```shell-session # $ helm template --show-only templates/server-serviceaccount.yaml hashicorp/consul @@ -150,13 +153,23 @@ global: # The role must be connected to the Consul client's service account and # have a policy with read capabilities for the following secrets: # - gossip encryption key defined by `global.gossipEncryption.secretName`. - # To discover the service account name of the Consul server, run + # To discover the service account name of the Consul client, run # ```shell-session - # $ helm template --show-only templates/client-daemonset.yaml charts/consul + # $ helm template --show-only templates/client-serviceaccount.yaml charts/consul # ``` # and check the name of `metadata.name`. consulClientRole: "" + # A Vault role to allow Kubernetes job that manages ACLs for this Helm chart (`server-acl-init`) + # to read and update Vault secrets for the Consul's bootstrap and replication tokens. + # This role must be bound the `server-acl-init`'s service account. + # To discover the service account name of the `server-acl-init` job, run + # ```shell-session + # $ helm template --show-only templates/server-acl-init-serviceaccount.yaml charts/consul + # ``` + # and check the name of `metadata.name`. + manageSystemACLsRole: "" + # This value defines additional annotations for # Vault agent on any pods where it'll be running. # This should be formatted as a multi-line string. @@ -376,9 +389,9 @@ global: # and create ACL tokens and policies. # This value is ignored if `bootstrapToken` is also set. replicationToken: - # The name of the Kubernetes secret. + # The name of the Kubernetes secret or the path of the secret in Vault. secretName: null - # The key of the Kubernetes secret. + # The key of the Kubernetes or Vault secret. secretKey: null # [Enterprise Only] This value refers to a Kubernetes secret that you have created diff --git a/control-plane/subcommand/server-acl-init/command.go b/control-plane/subcommand/server-acl-init/command.go index e665d1e3f0..64906d44ad 100644 --- a/control-plane/subcommand/server-acl-init/command.go +++ b/control-plane/subcommand/server-acl-init/command.go @@ -325,7 +325,7 @@ func (c *Command) Run(args []string) int { // the provided token to create policies and tokens for the rest of the components. c.log.Info("Bootstrap token is provided so skipping Consul server ACL bootstrapping") bootstrapToken = providedBootstrapToken - } else if c.flagACLReplicationTokenFile != "" { + } else if c.flagACLReplicationTokenFile != "" && !c.flagCreateACLReplicationToken { // If ACL replication is enabled, we don't need to ACL bootstrap the servers // since they will be performing replication. // We can use the replication token as our bootstrap token because it @@ -694,7 +694,11 @@ func (c *Command) Run(args []string) int { } // Policy must be global because it replicates from the primary DC // and so the primary DC needs to be able to accept the token. - err = c.createGlobalACL(common.ACLReplicationTokenName, rules, consulDC, isPrimary, consulClient) + if aclReplicationToken != "" { + err = c.createGlobalACLWithSecretID(common.ACLReplicationTokenName, rules, consulDC, isPrimary, consulClient, aclReplicationToken) + } else { + err = c.createGlobalACL(common.ACLReplicationTokenName, rules, consulDC, isPrimary, consulClient) + } if err != nil { c.log.Error(err.Error()) return 1 diff --git a/control-plane/subcommand/server-acl-init/command_test.go b/control-plane/subcommand/server-acl-init/command_test.go index da3cfc3de3..bbccfcc20d 100644 --- a/control-plane/subcommand/server-acl-init/command_test.go +++ b/control-plane/subcommand/server-acl-init/command_test.go @@ -10,6 +10,7 @@ import ( "net/http" "net/http/httptest" "net/url" + "os" "strconv" "strings" "testing" @@ -19,6 +20,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" @@ -325,6 +327,70 @@ func TestRun_TokensPrimaryDC(t *testing.T) { } } +func TestRun_ReplicationTokenPrimaryDC_WithProvidedSecretID(t *testing.T) { + t.Parallel() + + k8s, testSvr := completeSetup(t) + defer testSvr.Stop() + require := require.New(t) + + replicationToken := "123e4567-e89b-12d3-a456-426614174000" + replicationTokenFile, err := ioutil.TempFile("", "replicationtoken") + require.NoError(err) + defer os.Remove(replicationTokenFile.Name()) + + replicationTokenFile.WriteString(replicationToken) + // Run the command. + ui := cli.NewMockUi() + cmd := Command{ + UI: ui, + clientset: k8s, + } + cmd.init() + cmdArgs := []string{ + "-timeout=1m", + "-k8s-namespace=" + ns, + "-server-address", strings.Split(testSvr.HTTPAddr, ":")[0], + "-server-port", strings.Split(testSvr.HTTPAddr, ":")[1], + "-resource-prefix=" + resourcePrefix, + "-create-acl-replication-token", + "-acl-replication-token-file", replicationTokenFile.Name(), + } + + responseCode := cmd.Run(cmdArgs) + require.Equal(0, responseCode, ui.ErrorWriter.String()) + + // Check that this token is created. + consul, err := api.NewClient(&api.Config{ + Address: testSvr.HTTPAddr, + Token: replicationToken, + }) + require.NoError(err) + token, _, err := consul.ACL().TokenReadSelf(nil) + require.NoError(err) + + for _, policyLink := range token.Policies { + policy := policyExists(t, policyLink.Name, consul) + require.Nil(policy.Datacenters) + + // Test that the token was not created as a Kubernetes Secret. + _, err := k8s.CoreV1().Secrets(ns).Get(context.Background(), resourcePrefix+"-acl-replication-acl-token", metav1.GetOptions{}) + require.True(k8serrors.IsNotFound(err)) + } + + // Test that if the same command is run again, it doesn't error. + t.Run(t.Name()+"-retried", func(t *testing.T) { + ui = cli.NewMockUi() + cmd = Command{ + UI: ui, + clientset: k8s, + } + cmd.init() + responseCode = cmd.Run(cmdArgs) + require.Equal(0, responseCode, ui.ErrorWriter.String()) + }) +} + // Test creating each token type when replication is enabled. func TestRun_TokensReplicatedDC(t *testing.T) { t.Parallel() diff --git a/control-plane/subcommand/server-acl-init/create_or_update.go b/control-plane/subcommand/server-acl-init/create_or_update.go index a17d78c6e3..80dca054bf 100644 --- a/control-plane/subcommand/server-acl-init/create_or_update.go +++ b/control-plane/subcommand/server-acl-init/create_or_update.go @@ -13,26 +13,34 @@ import ( // createLocalACL creates a policy and acl token for this dc (datacenter), i.e. // the policy is only valid for this datacenter and the token is a local token. func (c *Command) createLocalACL(name, rules, dc string, isPrimary bool, consulClient *api.Client) error { - return c.createACL(name, rules, true, dc, isPrimary, consulClient) + return c.createACL(name, rules, true, dc, isPrimary, consulClient, "") } // createGlobalACL creates a global policy and acl token. The policy is valid // for all datacenters and the token is global. dc must be passed because the // policy name may have the datacenter name appended. func (c *Command) createGlobalACL(name, rules, dc string, isPrimary bool, consulClient *api.Client) error { - return c.createACL(name, rules, false, dc, isPrimary, consulClient) + return c.createACL(name, rules, false, dc, isPrimary, consulClient, "") +} + +// createGlobalACLWithSecretID creates a global policy and acl token with provided secret ID. +func (c *Command) createGlobalACLWithSecretID(name, rules, dc string, isPrimary bool, consulClient *api.Client, secretID string) error { + return c.createACL(name, rules, false, dc, isPrimary, consulClient, secretID) } // createACL creates a policy with rules and name. If localToken is true then // the token will be a local token and the policy will be scoped to only dc. // If localToken is false, the policy will be global. // The token will be written to a Kubernetes secret. -func (c *Command) createACL(name, rules string, localToken bool, dc string, isPrimary bool, consulClient *api.Client) error { +// When secretID is provided, we will use that value for the created token and +// will skip writing it to a Kubernetes secret (because in this case we assume that +// this value already exists in some secrets storage). +func (c *Command) createACL(name, rules string, localToken bool, dc string, isPrimary bool, consulClient *api.Client, secretID string) error { // Create policy with the given rules. policyName := fmt.Sprintf("%s-token", name) if c.flagFederation && !isPrimary { // If performing ACL replication, we must ensure policy names are - // globally unique so we append the datacenter name but only in secondary datacenters.. + // globally unique so we append the datacenter name but only in secondary datacenters. policyName += fmt.Sprintf("-%s", dc) } var datacenters []string @@ -53,21 +61,37 @@ func (c *Command) createACL(name, rules string, localToken bool, dc string, isPr return err } - // Check if the secret already exists, if so, we assume the ACL has already been - // created and return. - secretName := c.withPrefix(name + "-acl-token") - _, err = c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Get(c.ctx, secretName, metav1.GetOptions{}) - if err == nil { - c.log.Info(fmt.Sprintf("Secret %q already exists", secretName)) - return nil - } - // Create token for the policy if the secret did not exist previously. tokenTmpl := api.ACLToken{ Description: fmt.Sprintf("%s Token", policyTmpl.Name), Policies: []*api.ACLTokenPolicyLink{{Name: policyTmpl.Name}}, Local: localToken, } + + // Check if the replication token already exists in some form. + secretName := c.withPrefix(name + "-acl-token") + // When secretID is not provided, we assume that replication token should exist + // as a Kubernetes secret. + if secretID == "" { + // Check if the secret already exists, if so, we assume the ACL has already been + // created and return. + _, err = c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Get(c.ctx, secretName, metav1.GetOptions{}) + if err == nil { + c.log.Info(fmt.Sprintf("Secret %q already exists", secretName)) + return nil + } + } else { + // If secretID is provided, we check if the token with secretID already exists in Consul + // and exit if it does. Otherwise, set the secretID to the provided value. + _, _, err = consulClient.ACL().TokenReadSelf(&api.QueryOptions{Token: secretID}) + if err == nil { + c.log.Info("ACL replication token already exists; skipping creation") + return nil + } else { + tokenTmpl.SecretID = secretID + } + } + var token string err = c.untilSucceeds(fmt.Sprintf("creating token for policy %s", policyTmpl.Name), func() error { @@ -81,25 +105,28 @@ func (c *Command) createACL(name, rules string, localToken bool, dc string, isPr return err } - // Write token to a Kubernetes secret. - return c.untilSucceeds(fmt.Sprintf("writing Secret for token %s", policyTmpl.Name), - func() error { - secret := &apiv1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretName, - Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, - }, - Data: map[string][]byte{ - common.ACLTokenSecretKey: []byte(token), - }, - } - _, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Create(c.ctx, secret, metav1.CreateOptions{}) - return err - }) + if secretID == "" { + // Write token to a Kubernetes secret. + return c.untilSucceeds(fmt.Sprintf("writing Secret for token %s", policyTmpl.Name), + func() error { + secret := &apiv1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretName, + Labels: map[string]string{common.CLILabelKey: common.CLILabelValue}, + }, + Data: map[string][]byte{ + common.ACLTokenSecretKey: []byte(token), + }, + } + _, err := c.clientset.CoreV1().Secrets(c.flagK8sNamespace).Create(c.ctx, secret, metav1.CreateOptions{}) + return err + }) + } + return nil } func (c *Command) createOrUpdateACLPolicy(policy api.ACLPolicy, consulClient *api.Client) error { - // Attempt to create the ACL policy + // Attempt to create the ACL policy. _, _, err := consulClient.ACL().PolicyCreate(&policy, &api.WriteOptions{}) // With the introduction of Consul namespaces, if someone upgrades into a From bc6846685020bd5116edcc381085bf6d671fca47 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Thu, 17 Feb 2022 14:06:52 -0700 Subject: [PATCH 271/418] vault: allow providing auth method path to the connect CA configuration (#1029) --- acceptance/tests/vault/helpers.go | 18 +++++--- acceptance/tests/vault/vault_test.go | 6 +-- acceptance/tests/vault/vault_wan_fed_test.go | 42 ++++++++++++------- .../templates/server-config-configmap.yaml | 1 + .../test/unit/server-config-configmap.bats | 21 +++++++++- charts/consul/values.yaml | 3 ++ 6 files changed, 66 insertions(+), 25 deletions(-) diff --git a/acceptance/tests/vault/helpers.go b/acceptance/tests/vault/helpers.go index 7a690ec67a..8d27628328 100644 --- a/acceptance/tests/vault/helpers.go +++ b/acceptance/tests/vault/helpers.go @@ -22,9 +22,9 @@ path "consul/data/secret/replication" { capabilities = ["read", "update"] }` - // connectCAPolicy allows Consul to bootstrap all certificates for the service mesh in Vault. + // connectCAPolicyTemplate allows Consul to bootstrap all certificates for the service mesh in Vault. // Adapted from https://www.consul.io/docs/connect/ca/vault#consul-managed-pki-paths. - connectCAPolicy = ` + connectCAPolicyTemplate = ` path "/sys/mounts" { capabilities = [ "read" ] } @@ -33,7 +33,7 @@ path "/sys/mounts/connect_root" { capabilities = [ "create", "read", "update", "delete", "list" ] } -path "/sys/mounts/connect_inter" { +path "/sys/mounts/%s/connect_inter" { capabilities = [ "create", "read", "update", "delete", "list" ] } @@ -41,7 +41,7 @@ path "/connect_root/*" { capabilities = [ "create", "read", "update", "delete", "list" ] } -path "/connect_inter/*" { +path "/%s/connect_inter/*" { capabilities = [ "create", "read", "update", "delete", "list" ] } ` @@ -118,7 +118,7 @@ func configureKubernetesAuthRoles(t *testing.T, vaultClient *vapi.Client, consul params = map[string]interface{}{ "bound_service_account_names": consulServerServiceAccountName, "bound_service_account_namespaces": ns, - "policies": fmt.Sprintf("consul-gossip,connect-ca,consul-server-%s,consul-replication-token", datacenter), + "policies": fmt.Sprintf("consul-gossip,connect-ca-%s,consul-server-%s,consul-replication-token", datacenter, datacenter), "ttl": "24h", } _, err = vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-server", authPath), params) @@ -222,3 +222,11 @@ func configureReplicationTokenVaultSecret(t *testing.T, vaultClient *vapi.Client return token } + +// createConnectCAPolicy creates the Vault Policy for the connect-ca in a given datacenter. +func createConnectCAPolicy(t *testing.T, vaultClient *vapi.Client, datacenter string) { + err := vaultClient.Sys().PutPolicy( + fmt.Sprintf("connect-ca-%s", datacenter), + fmt.Sprintf(connectCAPolicyTemplate, datacenter, datacenter)) + require.NoError(t, err) +} diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 0521ab0f23..3d27bb002a 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -30,9 +30,7 @@ func TestVault(t *testing.T) { gossipKey := configureGossipVaultSecret(t, vaultClient) - // Create the Vault Policy for the connect-ca. - err := vaultClient.Sys().PutPolicy("connect-ca", connectCAPolicy) - require.NoError(t, err) + createConnectCAPolicy(t, vaultClient, "dc1") configureKubernetesAuthRoles(t, vaultClient, consulReleaseName, ns, "kubernetes", "dc1") @@ -60,7 +58,7 @@ func TestVault(t *testing.T) { "global.secretsBackend.vault.connectCA.address": vaultCluster.Address(), "global.secretsBackend.vault.connectCA.rootPKIPath": "connect_root", - "global.secretsBackend.vault.connectCA.intermediatePKIPath": "connect_inter", + "global.secretsBackend.vault.connectCA.intermediatePKIPath": "dc1/connect_inter", "global.acls.manageSystemACLs": "true", "global.tls.enabled": "true", diff --git a/acceptance/tests/vault/vault_wan_fed_test.go b/acceptance/tests/vault/vault_wan_fed_test.go index ed25f7bfea..e8779bd346 100644 --- a/acceptance/tests/vault/vault_wan_fed_test.go +++ b/acceptance/tests/vault/vault_wan_fed_test.go @@ -118,6 +118,10 @@ func TestVault_WANFederationViaGateways(t *testing.T) { replicationToken := configureReplicationTokenVaultSecret(t, vaultClient, consulReleaseName, ns, "kubernetes", "kubernetes-dc2") + // Create the Vault Policy for the Connect CA in both datacenters. + createConnectCAPolicy(t, vaultClient, "dc1") + createConnectCAPolicy(t, vaultClient, "dc2") + // Move Vault CA secret from primary to secondary so that we can mount it to pods in the // secondary cluster. vaultCASecretName := vault.CASecretName(vaultReleaseName) @@ -164,13 +168,16 @@ func TestVault_WANFederationViaGateways(t *testing.T) { "server.extraVolumes[0].load": "false", // Vault config. - "global.secretsBackend.vault.enabled": "true", - "global.secretsBackend.vault.consulServerRole": "consul-server", - "global.secretsBackend.vault.consulClientRole": "consul-client", - "global.secretsBackend.vault.consulCARole": "consul-ca", - "global.secretsBackend.vault.manageSystemACLsRole": "server-acl-init", - "global.secretsBackend.vault.ca.secretName": vaultCASecretName, - "global.secretsBackend.vault.ca.secretKey": "tls.crt", + "global.secretsBackend.vault.enabled": "true", + "global.secretsBackend.vault.consulServerRole": "consul-server", + "global.secretsBackend.vault.consulClientRole": "consul-client", + "global.secretsBackend.vault.consulCARole": "consul-ca", + "global.secretsBackend.vault.manageSystemACLsRole": "server-acl-init", + "global.secretsBackend.vault.ca.secretName": vaultCASecretName, + "global.secretsBackend.vault.ca.secretKey": "tls.crt", + "global.secretsBackend.vault.connectCA.address": primaryVaultCluster.Address(), + "global.secretsBackend.vault.connectCA.rootPKIPath": "connect_root", + "global.secretsBackend.vault.connectCA.intermediatePKIPath": "dc1/connect_inter", } if cfg.UseKind { @@ -216,14 +223,19 @@ func TestVault_WANFederationViaGateways(t *testing.T) { "server.extraConfig": serverExtraConfig, // Vault config. - "global.secretsBackend.vault.enabled": "true", - "global.secretsBackend.vault.consulServerRole": "consul-server", - "global.secretsBackend.vault.consulClientRole": "consul-client", - "global.secretsBackend.vault.consulCARole": "consul-ca", - "global.secretsBackend.vault.manageSystemACLsRole": "server-acl-init", - "global.secretsBackend.vault.ca.secretName": vaultCASecretName, - "global.secretsBackend.vault.ca.secretKey": "tls.crt", - "global.secretsBackend.vault.agentAnnotations": fmt.Sprintf("vault.hashicorp.com/tls-server-name: %s-vault", vaultReleaseName), + "global.secretsBackend.vault.enabled": "true", + "global.secretsBackend.vault.consulServerRole": "consul-server", + "global.secretsBackend.vault.consulClientRole": "consul-client", + "global.secretsBackend.vault.consulCARole": "consul-ca", + "global.secretsBackend.vault.manageSystemACLsRole": "server-acl-init", + "global.secretsBackend.vault.ca.secretName": vaultCASecretName, + "global.secretsBackend.vault.ca.secretKey": "tls.crt", + "global.secretsBackend.vault.agentAnnotations": fmt.Sprintf("vault.hashicorp.com/tls-server-name: %s-vault", vaultReleaseName), + "global.secretsBackend.vault.connectCA.address": externalVaultAddress, + "global.secretsBackend.vault.connectCA.authMethodPath": "kubernetes-dc2", + "global.secretsBackend.vault.connectCA.rootPKIPath": "connect_root", + "global.secretsBackend.vault.connectCA.intermediatePKIPath": "dc2/connect_inter", + "global.secretsBackend.vault.connectCA.additionalConfig": fmt.Sprintf(`"{"connect": [{"ca_config": [{"tls_server_name": "%s-vault"}]}]}"`, vaultReleaseName), } if cfg.UseKind { diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index f11177089a..dcaf372b20 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -29,6 +29,7 @@ data: "root_pki_path": "{{ .connectCA.rootPKIPath }}", "auth_method": { "type": "kubernetes", + "mount_path": "{{ .connectCA.authMethodPath }}", "params": { "role": "{{ .consulServerRole }}" } diff --git a/charts/consul/test/unit/server-config-configmap.bats b/charts/consul/test/unit/server-config-configmap.bats index ecb96599e8..5ab54081fe 100755 --- a/charts/consul/test/unit/server-config-configmap.bats +++ b/charts/consul/test/unit/server-config-configmap.bats @@ -375,7 +375,7 @@ load _helpers --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ . | tee /dev/stderr | yq '.data["connect-ca-config.json"]' | tee /dev/stderr) - [ "${actual}" = '"{\n \"connect\": [\n {\n \"ca_config\": [\n {\n \"address\": \"example.com\",\n \"intermediate_pki_path\": \"int\",\n \"root_pki_path\": \"root\",\n \"auth_method\": {\n \"type\": \"kubernetes\",\n \"params\": {\n \"role\": \"foo\"\n }\n }\n }\n ],\n \"ca_provider\": \"vault\"\n }\n ]\n}\n"' ] + [ "${actual}" = '"{\n \"connect\": [\n {\n \"ca_config\": [\n {\n \"address\": \"example.com\",\n \"intermediate_pki_path\": \"int\",\n \"root_pki_path\": \"root\",\n \"auth_method\": {\n \"type\": \"kubernetes\",\n \"mount_path\": \"kubernetes\",\n \"params\": {\n \"role\": \"foo\"\n }\n }\n }\n ],\n \"ca_provider\": \"vault\"\n }\n ]\n}\n"' ] local actual=$(helm template \ -s templates/server-config-configmap.yaml \ @@ -407,6 +407,25 @@ load _helpers [ "${actual}" = '"{\"hello\": \"world\"}\n"' ] } +@test "server/ConfigMap: can set auth method mount path" { + cd `chart_dir` + + local caConfig=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulServerRole=foo' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.connectCA.address=example.com' \ + --set 'global.secretsBackend.vault.connectCA.rootPKIPath=root' \ + --set 'global.secretsBackend.vault.connectCA.intermediatePKIPath=int' \ + --set 'global.secretsBackend.vault.connectCA.authMethodPath=kubernetes2' \ + . | tee /dev/stderr | + yq -r '.data["connect-ca-config.json"]' | tee /dev/stderr) + + local actual=$(echo $caConfig | jq -r .connect[0].ca_config[0].auth_method.mount_path) + [ "${actual}" = "kubernetes2" ] +} + @test "server/ConfigMap: doesn't set Vault CA cert in connect CA config by default" { cd `chart_dir` diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 3f2e36cc38..5dd6966cec 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -208,6 +208,9 @@ global: # The address of the Vault server. address: "" + # The mount path of the Kubernetes auth method in Vault. + authMethodPath: "kubernetes" + # The path to a PKI secrets engine for the root certificate. # Please see https://www.consul.io/docs/connect/ca/vault#rootpkipath. rootPKIPath: "" From 6a78947b46a383ce8e23a16f373191b9d9a31108 Mon Sep 17 00:00:00 2001 From: Andrew Stucki Date: Fri, 18 Feb 2022 14:39:44 -0500 Subject: [PATCH 272/418] Update cli flags based off of merged code --- .../consul/templates/api-gateway-controller-deployment.yaml | 4 ++-- .../consul/test/unit/api-gateway-controller-deployment.bats | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/consul/templates/api-gateway-controller-deployment.yaml b/charts/consul/templates/api-gateway-controller-deployment.yaml index c76cd9a29e..492d9f3302 100644 --- a/charts/consul/templates/api-gateway-controller-deployment.yaml +++ b/charts/consul/templates/api-gateway-controller-deployment.yaml @@ -84,9 +84,9 @@ spec: -consul-destination-namespace={{ .Values.apiGateway.consulNamespaces.consulDestinationNamespace }} \ {{- end }} {{- if .Values.apiGateway.consulNamespaces.mirroringK8S }} - -mirror-k8s-namespaces=true \ + -mirroring-k8s=true \ {{- if .Values.apiGateway.consulNamespaces.mirroringK8SPrefix }} - -mirror-k8s-namespace-prefix={{ .Values.apiGateway.consulNamespaces.mirroringK8SPrefix }} \ + -mirroring-k8s-prefix={{ .Values.apiGateway.consulNamespaces.mirroringK8SPrefix }} \ {{- end }} {{- end }} {{- end }} diff --git a/charts/consul/test/unit/api-gateway-controller-deployment.bats b/charts/consul/test/unit/api-gateway-controller-deployment.bats index bea24daad7..6810c5dde0 100755 --- a/charts/consul/test/unit/api-gateway-controller-deployment.bats +++ b/charts/consul/test/unit/api-gateway-controller-deployment.bats @@ -57,7 +57,7 @@ load _helpers --set 'global.enableConsulNamespaces=true' \ --set 'apiGateway.consulNamespaces.mirroringK8S=true' \ . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command | join(" ") | contains("-mirror-k8s-namespaces=true")' | tee /dev/stderr) + yq '.spec.template.spec.containers[0].command | join(" ") | contains("-mirroring-k8s=true")' | tee /dev/stderr) [ "${actual}" = "true" ] } @@ -71,7 +71,7 @@ load _helpers --set 'apiGateway.consulNamespaces.mirroringK8S=true' \ --set 'apiGateway.consulNamespaces.mirroringK8SPrefix=foo' \ . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command | join(" ") | contains("-mirror-k8s-namespace-prefix=foo")' | tee /dev/stderr) + yq '.spec.template.spec.containers[0].command | join(" ") | contains("-mirroring-k8s-prefix=foo")' | tee /dev/stderr) [ "${actual}" = "true" ] } From ae206c9009a1860391b3cb55dfaeea394654234c Mon Sep 17 00:00:00 2001 From: John Murret Date: Fri, 18 Feb 2022 12:58:09 -0700 Subject: [PATCH 273/418] Add support for Enterprise License to be configured in Vault (#1032) * Validate that users must set either both or neither enterpriseLicense.secretName and secretKey * Add ability to configure enterprise license tocome from vault * Add ability to configure enterprise license for client snapshot agent to come from vault * Add ability to configure enterprise license for client daemonset to come from vault * Updating the comments in help for enterprise license to mention it can also come from Vault. * Update Changelog for Enterprise License on Vault * Removing redundant tests in server-acl-init-job that test for existance of either both or neither enterprise license secretKey and secretName. * Do not mount volume or volume mounts for license when using vault * Removing redundant broken tests related to entperiseLicense not having either secretKey or secretName when the other is supplied * Adding test for that both global.enterpriseLicense.secretName and secretKey are provided when one of them is provided. * Adding acceptance test for Enterprise License on vault * Fixing acceptance test for Enterprise License on vault * Fixing ENTERPRISE_LICENSE setting enterprise-license-job for Enterprise License on vault * Fixing formatting * Fixing unit tests * Changing enterprise license logic in vault acceptance test to be conditional based on -enable-enterprise * Making helm values for ent license conditional in vault accpentance test. Adding failure logic to client-daemonset.yaml if secretName or secretKey is missing if one of them is already supplied. * checking on only enterpriseLicense.secretName (without secretKey) since chart will fail when both are not supplied. * Fixing broken test by allowing test suite config to be passed in so that we can conditionally add consul-enterprise licence policy to the Vault Auth Roles. * Adding license config in vault to TestVault_WANFederationViaGateways * Adding failure tests to client-statefulset when only one of global.enterpriseLicense.secretKey or secretName is supplied. --- CHANGELOG.md | 1 + acceptance/tests/vault/helpers.go | 35 +++++++- acceptance/tests/vault/vault_test.go | 19 +++- acceptance/tests/vault/vault_wan_fed_test.go | 18 +++- charts/consul/templates/_helpers.tpl | 2 +- charts/consul/templates/client-daemonset.yaml | 18 +++- .../client-snapshot-agent-deployment.yaml | 18 +++- .../templates/enterprise-license-job.yaml | 4 + .../consul/templates/server-statefulset.yaml | 20 ++++- charts/consul/test/unit/client-daemonset.bats | 90 +++++++++++++++++++ .../client-snapshot-agent-deployment.bats | 73 +++++++++++++++ .../test/unit/enterprise-license-job.bats | 18 ---- .../enterprise-license-podsecuritypolicy.bats | 18 ---- .../test/unit/enterprise-license-role.bats | 18 ---- .../unit/enterprise-license-rolebinding.bats | 18 ---- .../enterprise-license-serviceaccount.bats | 18 ---- .../consul/test/unit/server-acl-init-job.bats | 22 ----- .../consul/test/unit/server-statefulset.bats | 90 +++++++++++++++++++ charts/consul/values.yaml | 6 +- 19 files changed, 373 insertions(+), 133 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e24788482..aa4448ab95 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ IMPROVEMENTS: * Helm * Vault: Allow passing arbitrary annotations to the vault agent. [[GH-1015](https://github.com/hashicorp/consul-k8s/pull/1015)] * Vault: Add support for customized IP and DNS SANs for server cert in Vault. [[GH-1020](https://github.com/hashicorp/consul-k8s/pull/1020)] + * Vault: Add support for Enterprise License to be configured in Vault. [[GH-1032](https://github.com/hashicorp/consul-k8s/pull/1032)] BUG FIXES: * API Gateway diff --git a/acceptance/tests/vault/helpers.go b/acceptance/tests/vault/helpers.go index 8d27628328..e24f24b718 100644 --- a/acceptance/tests/vault/helpers.go +++ b/acceptance/tests/vault/helpers.go @@ -6,6 +6,7 @@ import ( "fmt" "testing" + "github.com/hashicorp/consul-k8s/acceptance/framework/config" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/go-uuid" vapi "github.com/hashicorp/vault/api" @@ -22,7 +23,12 @@ path "consul/data/secret/replication" { capabilities = ["read", "update"] }` - // connectCAPolicyTemplate allows Consul to bootstrap all certificates for the service mesh in Vault. + enterpriseLicensePolicy = ` +path "consul/data/secret/enterpriselicense" { + capabilities = ["read"] +}` + + // connectCAPolicy allows Consul to bootstrap all certificates for the service mesh in Vault. // Adapted from https://www.consul.io/docs/connect/ca/vault#consul-managed-pki-paths. connectCAPolicyTemplate = ` path "/sys/mounts" { @@ -93,11 +99,32 @@ func configureGossipVaultSecret(t *testing.T, vaultClient *vapi.Client) string { return gossipKey } +// configureEnterpriseLicenseVaultSecret stores it in vault as a secret and configures a policy to access it. +func configureEnterpriseLicenseVaultSecret(t *testing.T, vaultClient *vapi.Client, cfg *config.TestConfig) { + // Create the enterprise license secret. + logger.Log(t, "Creating the Enterprise License secret") + params := map[string]interface{}{ + "data": map[string]interface{}{ + "enterpriselicense": cfg.EnterpriseLicense, + }, + } + _, err := vaultClient.Logical().Write("consul/data/secret/enterpriselicense", params) + require.NoError(t, err) + + // Create the Vault Policy for the consul-enterpriselicense. + err = vaultClient.Sys().PutPolicy("consul-enterpriselicense", enterpriseLicensePolicy) + require.NoError(t, err) +} + // configureKubernetesAuthRoles configures roles for the Kubernetes auth method // that will be used by the test Helm chart installation. -func configureKubernetesAuthRoles(t *testing.T, vaultClient *vapi.Client, consulReleaseName, ns, authPath, datacenter string) { +func configureKubernetesAuthRoles(t *testing.T, vaultClient *vapi.Client, consulReleaseName, ns, authPath, datacenter string, cfg *config.TestConfig) { consulClientServiceAccountName := fmt.Sprintf("%s-consul-client", consulReleaseName) consulServerServiceAccountName := fmt.Sprintf("%s-consul-server", consulReleaseName) + sharedPolicies := "consul-gossip" + if cfg.EnableEnterprise { + sharedPolicies += ",consul-enterpriselicense" + } // Create the Auth Roles for consul-server and consul-client. // Auth roles bind policies to Kubernetes service accounts, which @@ -109,7 +136,7 @@ func configureKubernetesAuthRoles(t *testing.T, vaultClient *vapi.Client, consul params := map[string]interface{}{ "bound_service_account_names": consulClientServiceAccountName, "bound_service_account_namespaces": ns, - "policies": "consul-gossip", + "policies": sharedPolicies, "ttl": "24h", } _, err := vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-client", authPath), params) @@ -118,7 +145,7 @@ func configureKubernetesAuthRoles(t *testing.T, vaultClient *vapi.Client, consul params = map[string]interface{}{ "bound_service_account_names": consulServerServiceAccountName, "bound_service_account_namespaces": ns, - "policies": fmt.Sprintf("consul-gossip,connect-ca-%s,consul-server-%s,consul-replication-token", datacenter, datacenter), + "policies": fmt.Sprintf(sharedPolicies+",connect-ca-%s,consul-server-%s,consul-replication-token", datacenter, datacenter), "ttl": "24h", } _, err = vaultClient.Logical().Write(fmt.Sprintf("auth/%s/role/consul-server", authPath), params) diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 3d27bb002a..8025741c0b 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -31,8 +31,11 @@ func TestVault(t *testing.T) { gossipKey := configureGossipVaultSecret(t, vaultClient) createConnectCAPolicy(t, vaultClient, "dc1") + if cfg.EnableEnterprise { + configureEnterpriseLicenseVaultSecret(t, vaultClient, cfg) + } - configureKubernetesAuthRoles(t, vaultClient, consulReleaseName, ns, "kubernetes", "dc1") + configureKubernetesAuthRoles(t, vaultClient, consulReleaseName, ns, "kubernetes", "dc1", cfg) configurePKICA(t, vaultClient) certPath := configurePKICertificates(t, vaultClient, consulReleaseName, ns, "dc1") @@ -82,6 +85,12 @@ func TestVault(t *testing.T) { "syncCatalog.toConsul": "false", "syncCatalog.toK8S": "false", } + + if cfg.EnableEnterprise { + consulHelmValues["global.enterpriseLicense.secretName"] = "consul/data/secret/enterpriselicense" + consulHelmValues["global.enterpriseLicense.secretKey"] = "enterpriselicense" + } + logger.Log(t, "Installing Consul") consulCluster := consul.NewHelmCluster(t, consulHelmValues, ctx, cfg, consulReleaseName) consulCluster.Create(t) @@ -100,6 +109,14 @@ func TestVault(t *testing.T) { require.NoError(t, err) require.Equal(t, caConfig.Provider, "vault") + if cfg.EnableEnterprise { + // Validate that the enterprise license is set correctly. + logger.Log(t, "Validating the enterprise license has been set correctly.") + license, licenseErr := consulClient.Operator().LicenseGet(nil) + require.NoError(t, licenseErr) + require.True(t, license.Valid) + } + // Deploy two services and check that they can talk to each other. logger.Log(t, "creating static-server and static-client deployments") k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") diff --git a/acceptance/tests/vault/vault_wan_fed_test.go b/acceptance/tests/vault/vault_wan_fed_test.go index e8779bd346..23428e3d5a 100644 --- a/acceptance/tests/vault/vault_wan_fed_test.go +++ b/acceptance/tests/vault/vault_wan_fed_test.go @@ -68,7 +68,11 @@ func TestVault_WANFederationViaGateways(t *testing.T) { configureGossipVaultSecret(t, vaultClient) - configureKubernetesAuthRoles(t, vaultClient, consulReleaseName, ns, "kubernetes", "dc1") + if cfg.EnableEnterprise { + configureEnterpriseLicenseVaultSecret(t, vaultClient, cfg) + } + + configureKubernetesAuthRoles(t, vaultClient, consulReleaseName, ns, "kubernetes", "dc1", cfg) // Configure Vault Kubernetes auth method for the secondary datacenter. { @@ -109,7 +113,7 @@ func TestVault_WANFederationViaGateways(t *testing.T) { secondaryVaultCluster.ConfigureAuthMethod(t, vaultClient, "kubernetes-dc2", k8sAuthMethodHost, authMethodRBACName, ns) } - configureKubernetesAuthRoles(t, vaultClient, consulReleaseName, ns, "kubernetes-dc2", "dc2") + configureKubernetesAuthRoles(t, vaultClient, consulReleaseName, ns, "kubernetes-dc2", "dc2", cfg) // Generate a CA and create PKI roles for the primary and secondary Consul servers. configurePKICA(t, vaultClient) @@ -180,6 +184,11 @@ func TestVault_WANFederationViaGateways(t *testing.T) { "global.secretsBackend.vault.connectCA.intermediatePKIPath": "dc1/connect_inter", } + if cfg.EnableEnterprise { + primaryConsulHelmValues["global.enterpriseLicense.secretName"] = "consul/data/secret/enterpriselicense" + primaryConsulHelmValues["global.enterpriseLicense.secretKey"] = "enterpriselicense" + } + if cfg.UseKind { primaryConsulHelmValues["meshGateway.service.type"] = "NodePort" primaryConsulHelmValues["meshGateway.service.nodePort"] = "30000" @@ -238,6 +247,11 @@ func TestVault_WANFederationViaGateways(t *testing.T) { "global.secretsBackend.vault.connectCA.additionalConfig": fmt.Sprintf(`"{"connect": [{"ca_config": [{"tls_server_name": "%s-vault"}]}]}"`, vaultReleaseName), } + if cfg.EnableEnterprise { + secondaryConsulHelmValues["global.enterpriseLicense.secretName"] = "consul/data/secret/enterpriselicense" + secondaryConsulHelmValues["global.enterpriseLicense.secretKey"] = "enterpriselicense" + } + if cfg.UseKind { secondaryConsulHelmValues["meshGateway.service.type"] = "NodePort" secondaryConsulHelmValues["meshGateway.service.nodePort"] = "30000" diff --git a/charts/consul/templates/_helpers.tpl b/charts/consul/templates/_helpers.tpl index 28a3fdf0ed..b266907b4b 100644 --- a/charts/consul/templates/_helpers.tpl +++ b/charts/consul/templates/_helpers.tpl @@ -15,7 +15,7 @@ as well as the global.name setting. {{- end -}} {{- end -}} -{{- define "consul.vaultGossipTemplate" -}} +{{- define "consul.vaultSecretTemplate" -}} | {{ "{{" }}- with secret "{{ .secretName }}" -{{ "}}" }} {{ "{{" }}- {{ printf ".Data.data.%s" .secretKey }} -{{ "}}" }} diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index 9c7a8076d2..170aa9e4a7 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -7,6 +7,8 @@ {{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.tls.enableAutoEncrypt)) }}{{ fail "global.tls.enableAutoEncrypt must be true if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" }}{{ end -}} {{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.secretsBackend.vault.consulCARole)) }}{{ fail "global.secretsBackend.vault.consulCARole must be provided if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" }}{{ end -}} {{- if and .Values.global.federation.enabled .Values.global.adminPartitions.enabled }}{{ fail "If global.federation.enabled is true, global.adminPartitions.enabled must be false because they are mutually exclusive" }}{{ end }} +{{- if (and .Values.global.enterpriseLicense.secretName (not .Values.global.enterpriseLicense.secretKey)) }}{{fail "enterpriseLicense.secretKey and secretName must both be specified." }}{{ end -}} +{{- if (and (not .Values.global.enterpriseLicense.secretName) .Values.global.enterpriseLicense.secretKey) }}{{fail "enterpriseLicense.secretKey and secretName must both be specified." }}{{ end -}} # DaemonSet to run the Consul clients on every node. apiVersion: apps/v1 kind: DaemonSet @@ -53,7 +55,7 @@ spec: {{- if .Values.global.gossipEncryption.secretName }} {{- with .Values.global.gossipEncryption }} "vault.hashicorp.com/agent-inject-secret-gossip.txt": {{ .secretName }} - "vault.hashicorp.com/agent-inject-template-gossip.txt": {{ template "consul.vaultGossipTemplate" . }} + "vault.hashicorp.com/agent-inject-template-gossip.txt": {{ template "consul.vaultSecretTemplate" . }} {{- end }} {{- end }} {{- if .Values.global.tls.enabled }} @@ -63,6 +65,12 @@ spec: {{- if .Values.global.secretsBackend.vault.agentAnnotations }} {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} {{- end }} + {{- if .Values.global.enterpriseLicense.secretName }} + {{- with .Values.global.enterpriseLicense }} + "vault.hashicorp.com/agent-inject-secret-enterpriselicense.txt": "{{ .secretName }}" + "vault.hashicorp.com/agent-inject-template-enterpriselicense.txt": {{ template "consul.vaultSecretTemplate" . }} + {{- end }} + {{- end }} {{- end }} "consul.hashicorp.com/connect-inject": "false" "consul.hashicorp.com/config-checksum": {{ include (print $.Template.BasePath "/client-config-configmap.yaml") . | sha256sum }} @@ -159,7 +167,7 @@ spec: - name: aclconfig emptyDir: {} {{- else }} - {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-license secret: secretName: {{ .Values.global.enterpriseLicense.secretName }} @@ -213,7 +221,11 @@ spec: {{- end }} {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload (not .Values.global.acls.manageSystemACLs)) }} - name: CONSUL_LICENSE_PATH + {{- if .Values.global.secretsBackend.vault.enabled }} + value: /vault/secrets/enterpriselicense.txt + {{- else }} value: /consul/license/{{ .Values.global.enterpriseLicense.secretKey }} + {{- end }} {{- end }} {{- if .Values.global.tls.enabled }} - name: CONSUL_HTTP_ADDR @@ -348,7 +360,7 @@ spec: - name: aclconfig mountPath: /consul/aclconfig {{- else }} - {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-license mountPath: /consul/license readOnly: true diff --git a/charts/consul/templates/client-snapshot-agent-deployment.yaml b/charts/consul/templates/client-snapshot-agent-deployment.yaml index fd6266e803..7b7e953c98 100644 --- a/charts/consul/templates/client-snapshot-agent-deployment.yaml +++ b/charts/consul/templates/client-snapshot-agent-deployment.yaml @@ -28,7 +28,8 @@ spec: component: client-snapshot-agent annotations: "consul.hashicorp.com/connect-inject": "false" - {{- if (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) }} + {{- if .Values.global.secretsBackend.vault.enabled }} + {{- if .Values.global.tls.enabled }} "vault.hashicorp.com/agent-init-first": "true" "vault.hashicorp.com/agent-inject": "true" "vault.hashicorp.com/role": {{ .Values.global.secretsBackend.vault.consulCARole }} @@ -40,7 +41,14 @@ spec: {{- end }} {{- if .Values.global.secretsBackend.vault.agentAnnotations }} {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} + {{- end }} + {{- end }} + {{- if .Values.global.enterpriseLicense.secretName }} + {{- with .Values.global.enterpriseLicense }} + "vault.hashicorp.com/agent-inject-secret-enterpriselicense.txt": "{{ .secretName }}" + "vault.hashicorp.com/agent-inject-template-enterpriselicense.txt": {{ template "consul.vaultSecretTemplate" . }} {{- end }} + {{- end }} {{- end }} spec: {{- if .Values.client.tolerations }} @@ -66,7 +74,7 @@ spec: - name: aclconfig emptyDir: {} {{- else }} - {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-license secret: secretName: {{ .Values.global.enterpriseLicense.secretName }} @@ -118,7 +126,11 @@ spec: {{- else }} {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: CONSUL_LICENSE_PATH + {{- if .Values.global.secretsBackend.vault.enabled }} + value: /vault/secrets/enterpriselicense.txt + {{- else }} value: /consul/license/{{ .Values.global.enterpriseLicense.secretKey }} + {{- end }} {{- end }} {{- end}} command: @@ -148,7 +160,7 @@ spec: - name: aclconfig mountPath: /consul/aclconfig {{- else }} - {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-license mountPath: /consul/license readOnly: true diff --git a/charts/consul/templates/enterprise-license-job.yaml b/charts/consul/templates/enterprise-license-job.yaml index 287b30dcc4..08fda29484 100644 --- a/charts/consul/templates/enterprise-license-job.yaml +++ b/charts/consul/templates/enterprise-license-job.yaml @@ -54,10 +54,14 @@ spec: image: "{{ default .Values.global.image .Values.server.image }}" env: - name: ENTERPRISE_LICENSE + {{- if .Values.global.secretsBackend.vault.enabled }} + value: /vault/secrets/enterpriselicense.txt + {{- else }} valueFrom: secretKeyRef: name: {{ .Values.global.enterpriseLicense.secretName }} key: {{ .Values.global.enterpriseLicense.secretKey }} + {{- end }} - name: CONSUL_HTTP_ADDR {{- if .Values.global.tls.enabled }} value: https://{{ template "consul.fullname" . }}-server:8501 diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index 74e1b4f63c..e2eda87dc5 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -13,6 +13,8 @@ {{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.tls.caCert.secretName)) }}{{ fail "global.tls.caCert.secretName must be provided if global.tls.enabled=true and global.secretsBackend.vault.enabled=true." }}{{ end -}} {{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.tls.enableAutoEncrypt)) }}{{ fail "global.tls.enableAutoEncrypt must be true if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" }}{{ end -}} {{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.secretsBackend.vault.consulCARole)) }}{{ fail "global.secretsBackend.vault.consulCARole must be provided if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" }}{{ end -}} +{{- if (and .Values.global.enterpriseLicense.secretName (not .Values.global.enterpriseLicense.secretKey)) }}{{fail "enterpriseLicense.secretKey and secretName must both be specified." }}{{ end -}} +{{- if (and (not .Values.global.enterpriseLicense.secretName) .Values.global.enterpriseLicense.secretKey) }}{{fail "enterpriseLicense.secretKey and secretName must both be specified." }}{{ end -}} # StatefulSet to run the actual Consul server cluster. apiVersion: apps/v1 kind: StatefulSet @@ -64,7 +66,7 @@ spec: {{- if .Values.global.gossipEncryption.secretName }} {{- with .Values.global.gossipEncryption }} "vault.hashicorp.com/agent-inject-secret-gossip.txt": "{{ .secretName }}" - "vault.hashicorp.com/agent-inject-template-gossip.txt": {{ template "consul.vaultGossipTemplate" . }} + "vault.hashicorp.com/agent-inject-template-gossip.txt": {{ template "consul.vaultSecretTemplate" . }} {{- end }} {{- end }} {{- if .Values.server.serverCert.secretName }} @@ -82,6 +84,12 @@ spec: {{- if .Values.global.secretsBackend.vault.agentAnnotations }} {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} {{- end }} + {{- if .Values.global.enterpriseLicense.secretName }} + {{- with .Values.global.enterpriseLicense }} + "vault.hashicorp.com/agent-inject-secret-enterpriselicense.txt": "{{ .secretName }}" + "vault.hashicorp.com/agent-inject-template-enterpriselicense.txt": {{ template "consul.vaultSecretTemplate" . }} + {{- end }} + {{- end }} {{- end }} "consul.hashicorp.com/connect-inject": "false" "consul.hashicorp.com/config-checksum": {{ include (print $.Template.BasePath "/server-config-configmap.yaml") . | sha256sum }} @@ -135,7 +143,7 @@ spec: secretName: {{ template "consul.fullname" . }}-server-cert {{- end }} {{- end }} - {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.enableLicenseAutoload (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-license secret: secretName: {{ .Values.global.enterpriseLicense.secretName }} @@ -217,9 +225,13 @@ spec: - name: CONSUL_CACERT value: /consul/tls/ca/tls.crt {{- end }} - {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: CONSUL_LICENSE_PATH + {{- if .Values.global.secretsBackend.vault.enabled }} + value: /vault/secrets/enterpriselicense.txt + {{- else }} value: /consul/license/{{ .Values.global.enterpriseLicense.secretKey }} + {{- end }} {{- end }} {{- if (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey (not .Values.global.secretsBackend.vault.enabled)) }} - name: ACL_REPLICATION_TOKEN @@ -336,7 +348,7 @@ spec: mountPath: /consul/tls/server readOnly: true {{- end }} - {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.secretKey .Values.global.enterpriseLicense.enableLicenseAutoload) }} + {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.enableLicenseAutoload (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-license mountPath: /consul/license readOnly: true diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index 2da0d4d9a0..b596f857e0 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1414,6 +1414,27 @@ rollingUpdate: [ "${actual}" = "" ] } +@test "client/DaemonSet: when global.enterpriseLicense.secretKey!=null and global.enterpriseLicense.secretName=null, fail" { + cd `chart_dir` + run helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.enterpriseLicense.secretName=' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "enterpriseLicense.secretKey and secretName must both be specified." ]] +} + +@test "client/DaemonSet: when global.enterpriseLicense.secretName!=null and global.enterpriseLicense.secretKey=null, fail" { + cd `chart_dir` + run helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "enterpriseLicense.secretKey and secretName must both be specified." ]] +} #-------------------------------------------------------------------- # recursors @@ -1836,6 +1857,75 @@ rollingUpdate: [ "${actual}" = "true" ] } +@test "client/DaemonSet: vault enterprise license annotations are correct when enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=path/to/secret' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-enterpriselicense.txt"]' | tee /dev/stderr) + [ "${actual}" = "path/to/secret" ] + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-enterpriselicense.txt"]' | tee /dev/stderr) + local actual="$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-enterpriselicense.txt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"path/to/secret\" -}}\n{{- .Data.data.enterpriselicense -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] +} + +@test "client/DaemonSet: vault CONSUL_LICENSE_PATH is set to /vault/secrets/enterpriselicense.txt" { + cd `chart_dir` + local env=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=a/b/c/d' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env[]' | tee /dev/stderr) + + local actual + + local actual=$(echo $env | jq -r '. | select(.name == "CONSUL_LICENSE_PATH") | .value' | tee /dev/stderr) + [ "${actual}" = "/vault/secrets/enterpriselicense.txt" ] +} + +@test "client/DaemonSet: vault does not add volume for license secret" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=a/b/c/d' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.volumes[] | select(.name == "consul-license")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + +@test "client/DaemonSet: vault does not add volume mount for license secret" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=a/b/c/d' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-license")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + #-------------------------------------------------------------------- # Vault agent annotations diff --git a/charts/consul/test/unit/client-snapshot-agent-deployment.bats b/charts/consul/test/unit/client-snapshot-agent-deployment.bats index 4f3deb6bde..8e345189d7 100644 --- a/charts/consul/test/unit/client-snapshot-agent-deployment.bats +++ b/charts/consul/test/unit/client-snapshot-agent-deployment.bats @@ -583,6 +583,79 @@ exec /bin/consul snapshot agent \' [ "${actual}" = "/vault/custom/tls.crt" ] } +@test "client/SnapshotAgentDeployment: vault enterprise license annotations are correct when enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=path/to/secret' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-enterpriselicense.txt"]' | tee /dev/stderr) + [ "${actual}" = "path/to/secret" ] + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-enterpriselicense.txt"]' | tee /dev/stderr) + local actual="$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-enterpriselicense.txt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"path/to/secret\" -}}\n{{- .Data.data.enterpriselicense -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] +} + +@test "client/SnapshotAgentDeployment: vault CONSUL_LICENSE_PATH is set to /vault/secrets/enterpriselicense.txt" { + cd `chart_dir` + local env=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=a/b/c/d' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env[]' | tee /dev/stderr) + + local actual + + local actual=$(echo $env | jq -r '. | select(.name == "CONSUL_LICENSE_PATH") | .value' | tee /dev/stderr) + [ "${actual}" = "/vault/secrets/enterpriselicense.txt" ] +} + +@test "client/SnapshotAgentDeployment: vault does not add volume for license secret" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=a/b/c/d' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.volumes[] | select(.name == "consul-license")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + +@test "client/SnapshotAgentDeployment: vault does not add volume mount for license secret" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-snapshot-agent-deployment.yaml \ + --set 'client.snapshotAgent.enabled=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=a/b/c/d' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-license")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + #-------------------------------------------------------------------- # Vault agent annotations diff --git a/charts/consul/test/unit/enterprise-license-job.bats b/charts/consul/test/unit/enterprise-license-job.bats index 02bf995a20..cbdb913df6 100644 --- a/charts/consul/test/unit/enterprise-license-job.bats +++ b/charts/consul/test/unit/enterprise-license-job.bats @@ -29,24 +29,6 @@ load _helpers . } -@test "enterpriseLicense/Job: disabled when secretName is missing" { - cd `chart_dir` - assert_empty helm template \ - -s templates/enterprise-license-job.yaml \ - --set 'global.enterpriseLicense.secretKey=bar' \ - --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ - . -} - -@test "enterpriseLicense/Job: disabled when secretKey is missing" { - cd `chart_dir` - assert_empty helm template \ - -s templates/enterprise-license-job.yaml \ - --set 'global.enterpriseLicense.secretName=foo' \ - --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ - . -} - @test "enterpriseLicense/Job: enabled when secretName, secretKey is provided and autoload is disabled" { cd `chart_dir` local actual=$(helm template \ diff --git a/charts/consul/test/unit/enterprise-license-podsecuritypolicy.bats b/charts/consul/test/unit/enterprise-license-podsecuritypolicy.bats index a23134303d..90442ec902 100644 --- a/charts/consul/test/unit/enterprise-license-podsecuritypolicy.bats +++ b/charts/consul/test/unit/enterprise-license-podsecuritypolicy.bats @@ -30,24 +30,6 @@ load _helpers . } -@test "enterpriseLicense/PodSecurityPolicy: disabled when ent secretName missing" { - cd `chart_dir` - assert_empty helm template \ - -s templates/enterprise-license-podsecuritypolicy.yaml \ - --set 'global.enterpriseLicense.secretKey=bar' \ - --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ - . -} - -@test "enterpriseLicense/PodSecurityPolicy: disabled when ent secretKey missing" { - cd `chart_dir` - assert_empty helm template \ - -s templates/enterprise-license-podsecuritypolicy.yaml \ - --set 'global.enterpriseLicense.secretName=foo' \ - --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ - . -} - @test "enterpriseLicense/PodSecurityPolicy: disabled when enablePodSecurityPolicies=false" { cd `chart_dir` assert_empty helm template \ diff --git a/charts/consul/test/unit/enterprise-license-role.bats b/charts/consul/test/unit/enterprise-license-role.bats index 3ffd0ed5e8..e30d0cfd16 100644 --- a/charts/consul/test/unit/enterprise-license-role.bats +++ b/charts/consul/test/unit/enterprise-license-role.bats @@ -29,24 +29,6 @@ load _helpers . } -@test "enterpriseLicense/Role: disabled when ent secretName missing" { - cd `chart_dir` - assert_empty helm template \ - -s templates/enterprise-license-role.yaml \ - --set 'global.enterpriseLicense.secretKey=bar' \ - --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ - . -} - -@test "enterpriseLicense/Role: disabled when ent secretKey missing" { - cd `chart_dir` - assert_empty helm template \ - -s templates/enterprise-license-role.yaml \ - --set 'global.enterpriseLicense.secretName=foo' \ - --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ - . -} - @test "enterpriseLicense/Role: enabled when ent license defined" { cd `chart_dir` local actual=$(helm template \ diff --git a/charts/consul/test/unit/enterprise-license-rolebinding.bats b/charts/consul/test/unit/enterprise-license-rolebinding.bats index 0d03ee5b4e..d0052e1b68 100644 --- a/charts/consul/test/unit/enterprise-license-rolebinding.bats +++ b/charts/consul/test/unit/enterprise-license-rolebinding.bats @@ -29,24 +29,6 @@ load _helpers . } -@test "enterpriseLicense/RoleBinding: disabled when ent secretName missing" { - cd `chart_dir` - assert_empty helm template \ - -s templates/enterprise-license-rolebinding.yaml \ - --set 'global.enterpriseLicense.secretKey=bar' \ - --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ - . -} - -@test "enterpriseLicense/RoleBinding: disabled when ent secretKey missing" { - cd `chart_dir` - assert_empty helm template \ - -s templates/enterprise-license-rolebinding.yaml \ - --set 'global.enterpriseLicense.secretName=foo' \ - --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ - . -} - @test "enterpriseLicense/RoleBinding: enabled when ent license defined and autoload disabled" { cd `chart_dir` local actual=$(helm template \ diff --git a/charts/consul/test/unit/enterprise-license-serviceaccount.bats b/charts/consul/test/unit/enterprise-license-serviceaccount.bats index 5f83421657..98b5fd80af 100644 --- a/charts/consul/test/unit/enterprise-license-serviceaccount.bats +++ b/charts/consul/test/unit/enterprise-license-serviceaccount.bats @@ -29,24 +29,6 @@ load _helpers . } -@test "enterpriseLicense/ServiceAccount: disabled when ent secretName missing" { - cd `chart_dir` - assert_empty helm template \ - -s templates/enterprise-license-serviceaccount.yaml \ - --set 'global.enterpriseLicense.secretKey=bar' \ - --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ - . -} - -@test "enterpriseLicense/ServiceAccount: disabled when ent secretKey missing" { - cd `chart_dir` - assert_empty helm template \ - -s templates/enterprise-license-serviceaccount.yaml \ - --set 'global.enterpriseLicense.secretName=foo' \ - --set 'global.enterpriseLicense.enableLicenseAutoload=false' \ - . -} - @test "enterpriseLicense/ServiceAccount: enabled when ent license defined" { cd `chart_dir` local actual=$(helm template \ diff --git a/charts/consul/test/unit/server-acl-init-job.bats b/charts/consul/test/unit/server-acl-init-job.bats index a096a8aeb8..7eb37a2329 100644 --- a/charts/consul/test/unit/server-acl-init-job.bats +++ b/charts/consul/test/unit/server-acl-init-job.bats @@ -216,28 +216,6 @@ load _helpers [ "${actual}" = "true" ] } -@test "serverACLInit/Job: ent license acl option disabled missing global.enterpriseLicense.secretName" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-acl-init-job.yaml \ - --set 'global.acls.manageSystemACLs=true' \ - --set 'global.enterpriseLicense.secretKey=bar' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command | any(contains("-create-enterprise-license-token"))' | tee /dev/stderr) - [ "${actual}" = "false" ] -} - -@test "serverACLInit/Job: ent license acl option disabled missing global.enterpriseLicense.secretKey" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/server-acl-init-job.yaml \ - --set 'global.acls.manageSystemACLs=true' \ - --set 'global.enterpriseLicense.secretName=foo' \ - . | tee /dev/stderr | - yq '.spec.template.spec.containers[0].command | any(contains("-create-enterprise-license-token"))' | tee /dev/stderr) - [ "${actual}" = "false" ] -} - #-------------------------------------------------------------------- # client.snapshotAgent diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 7c49a7a001..45aa6ea443 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -1375,6 +1375,27 @@ load _helpers [ "${actual}" = "true" ] } +@test "server/StatefulSet: when global.enterpriseLicense.secretKey!=null and global.enterpriseLicense.secretName=null, fail" { + cd `chart_dir` + run helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.enterpriseLicense.secretName=' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "enterpriseLicense.secretKey and secretName must both be specified." ]] +} + +@test "server/StatefulSet: when global.enterpriseLicense.secretName!=null and global.enterpriseLicense.secretKey=null, fail" { + cd `chart_dir` + run helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.enterpriseLicense.secretName=foo' \ + --set 'global.enterpriseLicense.secretKey=' \ + . + [ "$status" -eq 1 ] + [[ "$output" =~ "enterpriseLicense.secretKey and secretName must both be specified." ]] +} #-------------------------------------------------------------------- # extraContainers @@ -1844,6 +1865,75 @@ load _helpers [ "${actual}" = "${expected}" ] } +@test "server/StatefulSet: vault enterprise license annotations are correct when enabled" { + cd `chart_dir` + local object=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=path/to/enterpriselicensesecret' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r '.spec.template.metadata' | tee /dev/stderr) + + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-secret-enterpriselicense.txt"]' | tee /dev/stderr) + [ "${actual}" = "path/to/enterpriselicensesecret" ] + local actual=$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-enterpriselicense.txt"]' | tee /dev/stderr) + local actual="$(echo $object | + yq -r '.annotations["vault.hashicorp.com/agent-inject-template-enterpriselicense.txt"]' | tee /dev/stderr)" + local expected=$'{{- with secret \"path/to/enterpriselicensesecret\" -}}\n{{- .Data.data.enterpriselicense -}}\n{{- end -}}' + [ "${actual}" = "${expected}" ] +} + +@test "server/StatefulSet: vault CONSUL_LICENSE_PATH is set to /vault/secrets/enterpriselicense.txt" { + cd `chart_dir` + local env=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=a/b/c/d' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env[]' | tee /dev/stderr) + + local actual + + local actual=$(echo $env | jq -r '. | select(.name == "CONSUL_LICENSE_PATH") | .value' | tee /dev/stderr) + [ "${actual}" = "/vault/secrets/enterpriselicense.txt" ] +} + +@test "server/StatefulSet: vault does not add volume for license secret" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=a/b/c/d' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.volumes[] | select(.name == "consul-license")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + +@test "server/StatefulSet: vault does not add volume mount for license secret" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.enterpriseLicense.secretName=a/b/c/d' \ + --set 'global.enterpriseLicense.secretKey=enterpriselicense' \ + . | tee /dev/stderr | + yq -r -c '.spec.template.spec.containers[0].volumeMounts[] | select(.name == "consul-license")' | tee /dev/stderr) + [ "${actual}" = "" ] +} + #-------------------------------------------------------------------- # Vault agent annotations diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 5dd6966cec..a53a769263 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -404,10 +404,10 @@ global: # introduce the license key via another route, then set these fields to null. # Note: the job to apply license runs on both Helm installs and upgrades. enterpriseLicense: - # The name of the Kubernetes secret that holds the enterprise license. - # The secret must be in the same namespace that Consul is installed into. + # secretName is the name of the Kubernetes secret or Vault secret path that holds the enterprise license. + # A Kubernetes secret must be in the same namespace that Consul is installed into. secretName: null - # The key within the Kubernetes secret that holds the enterprise license. + # secretKey is the key within the Kubernetes secret or Vault secret key that holds the enterprise license. secretKey: null # Manages license autoload. Required in Consul 1.10.0+, 1.9.7+ and 1.8.12+. enableLicenseAutoload: true From 6ad5bcdd1ebb712b841042fc4476acb04b241618 Mon Sep 17 00:00:00 2001 From: Andrew Stucki Date: Fri, 18 Feb 2022 15:18:59 -0500 Subject: [PATCH 274/418] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 074882f43c..1b4dc85536 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ IMPROVEMENTS: * Helm * Vault: Allow passing arbitrary annotations to the vault agent. [[GH-1015](https://github.com/hashicorp/consul-k8s/pull/1015)] + * API Gateway: Allow Kubernetes namespace to Consul enterprise namespace mapping for deployed gateways and mesh services. [[GH-1024](https://github.com/hashicorp/consul-k8s/pull/1024)] BUG FIXES: * API Gateway From 06ab05639f7774bcec78a9d244822889a9f92b79 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Tue, 22 Feb 2022 09:53:44 -0800 Subject: [PATCH 275/418] Multiport (#1012) Support a workaround for multi port pods by registering a Consul service per port, and by injecting init containers and envoy sidecars per port. Does not work for services with transparent proxy, metrics, or metrics merging. - Acceptance test for multiport - The multiport app is just http-echo listening on different ports in 2 containers - First, the test deploys `static-client` and `multiport`, with static-client having `multiport` and `multiport-admin` as upstreams. It checks that `static-client` can make connections to each service-- `multiport`, and `multiport-admin`. This is to test inbound connections for a multiport app. - Then the test deploys `static-server`, and checks that `multiport` can make a connection to `static-server`. This is to test outbound connections from a multiport app. Note that there is only 1 intention because all upstream connections are configured and go through the 1st service's envoy proxy. - Implementation for multiport - `handler` - uses the service name annotation to figure out if this is a multiport pod or not - inject a connect-init container and an envoy-sidecar container per port/service - mount all service account tokens not already on the pod. For any service whose service account is not already attached to the pod, this mounts a volume for that service account token. In container-init, these volumes are added as a container volumeMount so the service account token file can be passed to the connect-init command via `-bearer-token-file` - `container_init` -- update the template to pass in arguments specific to the multiport service - `envoy_sidecar` -- allow the bootstrap file path to have the service name in it for multiport services, and add `--base-id` since there could be multiple envoy sidecars. - `endpoints_controller`: the listener port should be 20000 for the first service, 20001 for the second, etc. Also only configures upstreams on first service port in a multiport pod. - `connect_init` command: when its a multiport app, add a filter to poll by service name, use the service specific bearertoken, acl-token-sink, and proxyid files --- acceptance/framework/k8s/deploy.go | 44 +- acceptance/tests/connect/connect_helper.go | 12 +- .../connect/connect_inject_namespaces_test.go | 12 +- .../tests/connect/connect_inject_test.go | 178 +++++++- .../multiport-app/anyuid-scc-rolebinding.yaml | 23 ++ .../bases/multiport-app/deployment.yaml | 78 ++++ .../bases/multiport-app/kustomization.yaml | 7 + .../privileged-scc-rolebinding.yaml | 23 ++ .../bases/multiport-app/psp-rolebinding.yaml | 23 ++ .../fixtures/bases/multiport-app/service.yaml | 23 ++ .../bases/multiport-app/serviceaccount.yaml | 9 + .../kustomization.yaml | 5 + .../static-client-inject-multiport/patch.yaml | 10 + .../ingress_gateway_namespaces_test.go | 8 +- .../ingress-gateway/ingress_gateway_test.go | 6 +- .../tests/mesh-gateway/mesh_gateway_test.go | 4 +- .../tests/partitions/partitions_test.go | 60 +-- .../terminating_gateway_namespaces_test.go | 4 +- .../terminating_gateway_test.go | 4 +- acceptance/tests/vault/vault_test.go | 6 +- acceptance/tests/vault/vault_wan_fed_test.go | 2 +- .../templates/connect-inject-clusterrole.yaml | 5 + .../connect-inject/container_init.go | 103 +++-- .../connect-inject/container_init_test.go | 189 ++++++++- .../connect-inject/endpoints_controller.go | 40 +- .../endpoints_controller_test.go | 388 +++++++++++++++++- control-plane/connect-inject/envoy_sidecar.go | 26 +- .../connect-inject/envoy_sidecar_test.go | 148 +++++-- control-plane/connect-inject/handler.go | 158 ++++++- control-plane/connect-inject/handler_test.go | 90 ++++ .../subcommand/connect-init/command.go | 36 +- .../connect-init/command_ent_test.go | 6 +- .../subcommand/connect-init/command_test.go | 111 ++++- 33 files changed, 1637 insertions(+), 204 deletions(-) create mode 100644 acceptance/tests/fixtures/bases/multiport-app/anyuid-scc-rolebinding.yaml create mode 100644 acceptance/tests/fixtures/bases/multiport-app/deployment.yaml create mode 100644 acceptance/tests/fixtures/bases/multiport-app/kustomization.yaml create mode 100644 acceptance/tests/fixtures/bases/multiport-app/privileged-scc-rolebinding.yaml create mode 100644 acceptance/tests/fixtures/bases/multiport-app/psp-rolebinding.yaml create mode 100644 acceptance/tests/fixtures/bases/multiport-app/service.yaml create mode 100644 acceptance/tests/fixtures/bases/multiport-app/serviceaccount.yaml create mode 100644 acceptance/tests/fixtures/cases/static-client-inject-multiport/kustomization.yaml create mode 100644 acceptance/tests/fixtures/cases/static-client-inject-multiport/patch.yaml diff --git a/acceptance/framework/k8s/deploy.go b/acceptance/framework/k8s/deploy.go index 2cf5e8876a..09272d5382 100644 --- a/acceptance/framework/k8s/deploy.go +++ b/acceptance/framework/k8s/deploy.go @@ -16,8 +16,6 @@ import ( "k8s.io/apimachinery/pkg/util/yaml" ) -const staticClientName = "static-client" - // Deploy creates a Kubernetes deployment by applying configuration stored at filepath, // sets up a cleanup function and waits for the deployment to become available. func Deploy(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailure bool, debugDirectory string, filepath string) { @@ -71,38 +69,43 @@ func DeployKustomize(t *testing.T, options *k8s.KubectlOptions, noCleanupOnFailu RunKubectl(t, options, "wait", "--for=condition=available", "--timeout=5m", fmt.Sprintf("deploy/%s", deployment.Name)) } -// CheckStaticServerConnection execs into a pod of the deployment given by deploymentName +// CheckStaticServerConnection execs into a pod of sourceApp // and runs a curl command with the provided curlArgs. // This function assumes that the connection is made to the static-server and expects the output -// to be "hello world" in a case of success. +// to be "hello world" by default, or expectedSuccessOutput in a case of success. // If expectSuccess is true, it will expect connection to succeed, // otherwise it will expect failure due to intentions. -func CheckStaticServerConnection(t *testing.T, options *k8s.KubectlOptions, expectSuccess bool, failureMessages []string, curlArgs ...string) { +func CheckStaticServerConnection(t *testing.T, options *k8s.KubectlOptions, sourceApp string, expectSuccess bool, failureMessages []string, expectedSuccessOutput string, curlArgs ...string) { t.Helper() - CheckStaticServerConnectionMultipleFailureMessages(t, options, expectSuccess, failureMessages, curlArgs...) + CheckStaticServerConnectionMultipleFailureMessages(t, options, sourceApp, expectSuccess, failureMessages, expectedSuccessOutput, curlArgs...) } -// CheckStaticServerConnectionMultipleFailureMessages execs into a pod of the deployment given by deploymentName +// CheckStaticServerConnectionMultipleFailureMessages execs into a pod of sourceApp // and runs a curl command with the provided curlArgs. // This function assumes that the connection is made to the static-server and expects the output -// to be "hello world" in a case of success. +// to be "hello world" by default, or expectedSuccessOutput in a case of success. // If expectSuccess is true, it will expect connection to succeed, // otherwise it will expect failure due to intentions. If multiple failureMessages are provided it will assert // on the existence of any of them. -func CheckStaticServerConnectionMultipleFailureMessages(t *testing.T, options *k8s.KubectlOptions, expectSuccess bool, failureMessages []string, curlArgs ...string) { +func CheckStaticServerConnectionMultipleFailureMessages(t *testing.T, options *k8s.KubectlOptions, sourceApp string, expectSuccess bool, failureMessages []string, expectedSuccessOutput string, curlArgs ...string) { t.Helper() + expectedOutput := "hello world" + if expectedSuccessOutput != "" { + expectedOutput = expectedSuccessOutput + } + retrier := &retry.Timer{Timeout: 80 * time.Second, Wait: 2 * time.Second} - args := []string{"exec", "deploy/" + staticClientName, "-c", staticClientName, "--", "curl", "-vvvsSf"} + args := []string{"exec", "deploy/" + sourceApp, "-c", sourceApp, "--", "curl", "-vvvsSf"} args = append(args, curlArgs...) retry.RunWith(retrier, t, func(r *retry.R) { output, err := RunKubectlAndGetOutputE(t, options, args...) if expectSuccess { require.NoError(r, err) - require.Contains(r, output, "hello world") + require.Contains(r, output, expectedOutput) } else { require.Error(r, err) require.Condition(r, func() bool { @@ -118,24 +121,33 @@ func CheckStaticServerConnectionMultipleFailureMessages(t *testing.T, options *k }) } +// CheckStaticServerConnectionSuccessfulWithMessage is just like CheckStaticServerConnectionSuccessful +// but it asserts on a non-default expected message. +func CheckStaticServerConnectionSuccessfulWithMessage(t *testing.T, options *k8s.KubectlOptions, sourceApp string, message string, curlArgs ...string) { + t.Helper() + start := time.Now() + CheckStaticServerConnectionMultipleFailureMessages(t, options, sourceApp, true, nil, message, curlArgs...) + logger.Logf(t, "Took %s to check if static server connection was successful", time.Since(start)) +} + // CheckStaticServerConnectionSuccessful is just like CheckStaticServerConnection // but it always expects a successful connection. -func CheckStaticServerConnectionSuccessful(t *testing.T, options *k8s.KubectlOptions, curlArgs ...string) { +func CheckStaticServerConnectionSuccessful(t *testing.T, options *k8s.KubectlOptions, sourceApp string, curlArgs ...string) { t.Helper() start := time.Now() - CheckStaticServerConnection(t, options, true, nil, curlArgs...) + CheckStaticServerConnection(t, options, sourceApp, true, nil, "", curlArgs...) logger.Logf(t, "Took %s to check if static server connection was successful", time.Since(start)) } // CheckStaticServerConnectionFailing is just like CheckStaticServerConnection // but it always expects a failing connection with various errors. -func CheckStaticServerConnectionFailing(t *testing.T, options *k8s.KubectlOptions, curlArgs ...string) { +func CheckStaticServerConnectionFailing(t *testing.T, options *k8s.KubectlOptions, sourceApp string, curlArgs ...string) { t.Helper() - CheckStaticServerConnection(t, options, false, []string{ + CheckStaticServerConnection(t, options, sourceApp, false, []string{ "curl: (52) Empty reply from server", "curl: (7) Failed to connect", "curl: (56) Recv failure: Connection reset by peer", - }, curlArgs...) + }, "", curlArgs...) } // labelMapToString takes a label map[string]string diff --git a/acceptance/tests/connect/connect_helper.go b/acceptance/tests/connect/connect_helper.go index f59864f900..cf7853c1b3 100644 --- a/acceptance/tests/connect/connect_helper.go +++ b/acceptance/tests/connect/connect_helper.go @@ -81,9 +81,9 @@ func ConnectInjectConnectivityCheck(t *testing.T, ctx environment.TestContext, c if secure { logger.Log(t, "checking that the connection is not successful because there's no intention") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), "http://static-server") + k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), staticClientName, "http://static-server") } else { - k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") } logger.Log(t, "creating intention") @@ -103,9 +103,9 @@ func ConnectInjectConnectivityCheck(t *testing.T, ctx environment.TestContext, c logger.Log(t, "checking that connection is successful") if cfg.EnableTransparentProxy { // todo: add an assertion that the traffic is going through the proxy - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://static-server") + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://static-server") } else { - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") } // Test that kubernetes readiness status is synced to Consul. @@ -120,8 +120,8 @@ func ConnectInjectConnectivityCheck(t *testing.T, ctx environment.TestContext, c // from server, which is the case when a connection is unsuccessful due to intentions in other tests. logger.Log(t, "checking that connection is unsuccessful") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server port 80: Connection refused"}, "http://static-server") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server port 80: Connection refused"}, "", "http://static-server") } else { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "", "http://localhost:1234") } } diff --git a/acceptance/tests/connect/connect_inject_namespaces_test.go b/acceptance/tests/connect/connect_inject_namespaces_test.go index c5dfa5604a..815b28dea4 100644 --- a/acceptance/tests/connect/connect_inject_namespaces_test.go +++ b/acceptance/tests/connect/connect_inject_namespaces_test.go @@ -177,9 +177,9 @@ func TestConnectInjectNamespaces(t *testing.T) { if c.secure { logger.Log(t, "checking that the connection is not successful because there's no intention") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionFailing(t, staticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionFailing(t, staticClientOpts, staticClientName, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) } else { - k8s.CheckStaticServerConnectionFailing(t, staticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, staticClientOpts, staticClientName, "http://localhost:1234") } intention := &api.ServiceIntentionsConfigEntry{ @@ -209,9 +209,9 @@ func TestConnectInjectNamespaces(t *testing.T) { logger.Log(t, "checking that connection is successful") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionSuccessful(t, staticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionSuccessful(t, staticClientOpts, staticClientName, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) } else { - k8s.CheckStaticServerConnectionSuccessful(t, staticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, staticClientOpts, staticClientName, "http://localhost:1234") } // Test that kubernetes readiness status is synced to Consul. @@ -226,9 +226,9 @@ func TestConnectInjectNamespaces(t *testing.T) { // from server, which is the case when a connection is unsuccessful due to intentions in other tests. logger.Log(t, "checking that connection is unsuccessful") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, staticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, staticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, "", fmt.Sprintf("http://static-server.%s", staticServerNamespace)) } else { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, staticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, staticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "", "http://localhost:1234") } }) } diff --git a/acceptance/tests/connect/connect_inject_test.go b/acceptance/tests/connect/connect_inject_test.go index ef3a95a6be..bf4d8a7047 100644 --- a/acceptance/tests/connect/connect_inject_test.go +++ b/acceptance/tests/connect/connect_inject_test.go @@ -6,11 +6,13 @@ import ( "strconv" "strings" "testing" + "time" "github.com/hashicorp/consul-k8s/acceptance/framework/consul" "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" + "github.com/hashicorp/consul/api" "github.com/hashicorp/consul/sdk/testutil/retry" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -137,9 +139,9 @@ func TestConnectInject_RestartConsulClients(t *testing.T) { logger.Log(t, "checking that connection is successful") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://static-server") + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://static-server") } else { - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") } logger.Log(t, "restarting Consul client daemonset") @@ -148,8 +150,176 @@ func TestConnectInject_RestartConsulClients(t *testing.T) { logger.Log(t, "checking that connection is still successful") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://static-server") + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://static-server") } else { - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") + } +} + +const multiport = "multiport" +const multiportAdmin = "multiport-admin" + +// Test that Connect works for an application with multiple ports. The multiport application is a Pod listening on +// two ports. This tests inbound connections to each port of the multiport app, and outbound connections from the +// multiport app to static-server. +func TestConnectInject_MultiportServices(t *testing.T) { + cases := []struct { + secure bool + autoEncrypt bool + }{ + {false, false}, + {true, false}, + {true, true}, + } + + for _, c := range cases { + name := fmt.Sprintf("secure: %t; auto-encrypt: %t", c.secure, c.autoEncrypt) + t.Run(name, func(t *testing.T) { + cfg := suite.Config() + ctx := suite.Environment().DefaultContext(t) + + // Multi port apps don't work with transparent proxy. + if cfg.EnableTransparentProxy { + t.Skipf("skipping this test because transparent proxy is enabled") + } + + helmValues := map[string]string{ + "connectInject.enabled": "true", + + "global.tls.enabled": strconv.FormatBool(c.secure), + "global.tls.enableAutoEncrypt": strconv.FormatBool(c.autoEncrypt), + "global.acls.manageSystemACLs": strconv.FormatBool(c.secure), + } + + releaseName := helpers.RandomName() + consulCluster := consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) + + consulCluster.Create(t) + + consulClient := consulCluster.SetupConsulClient(t, c.secure) + + // Check that the ACL token is deleted. + if c.secure { + // We need to register the cleanup function before we create the deployments + // because golang will execute them in reverse order i.e. the last registered + // cleanup function will be executed first. + t.Cleanup(func() { + retrier := &retry.Timer{Timeout: 5 * time.Minute, Wait: 1 * time.Second} + retry.RunWith(retrier, t, func(r *retry.R) { + tokens, _, err := consulClient.ACL().TokenList(nil) + require.NoError(r, err) + for _, token := range tokens { + require.NotContains(r, token.Description, multiport) + require.NotContains(r, token.Description, multiportAdmin) + require.NotContains(r, token.Description, staticClientName) + require.NotContains(r, token.Description, staticServerName) + } + }) + }) + } + + logger.Log(t, "creating multiport static-server and static-client deployments") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/bases/multiport-app") + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject-multiport") + + // Check that static-client has been injected and now has 2 containers. + podList, err := ctx.KubernetesClient(t).CoreV1().Pods(ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ + LabelSelector: "app=static-client", + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 2) + + // Check that multiport has been injected and now has 4 containers. + podList, err = ctx.KubernetesClient(t).CoreV1().Pods(ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ + LabelSelector: "app=multiport", + }) + require.NoError(t, err) + require.Len(t, podList.Items, 1) + require.Len(t, podList.Items[0].Spec.Containers, 4) + + if c.secure { + logger.Log(t, "checking that the connection is not successful because there's no intention") + k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:2234") + + logger.Log(t, fmt.Sprintf("creating intention for %s", multiport)) + _, _, err := consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: multiport, + Sources: []*api.SourceIntention{ + { + Name: staticClientName, + Action: api.IntentionActionAllow, + }, + }, + }, nil) + require.NoError(t, err) + logger.Log(t, fmt.Sprintf("creating intention for %s", multiportAdmin)) + _, _, err = consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: multiportAdmin, + Sources: []*api.SourceIntention{ + { + Name: staticClientName, + Action: api.IntentionActionAllow, + }, + }, + }, nil) + require.NoError(t, err) + } + + // Check connection from static-client to multiport. + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") + + // Check connection from static-client to multiport-admin. + k8s.CheckStaticServerConnectionSuccessfulWithMessage(t, ctx.KubectlOptions(t), staticClientName, "hello world from 9090 admin", "http://localhost:2234") + + // Now that we've checked inbound connections to a multi port pod, check outbound connection from multi port + // pod to static-server. + + // Deploy static-server. + k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + + // For outbound connections from the multi port pod, only intentions from the first service in the multiport + // pod need to be created, since all upstream connections are made through the first service's envoy proxy. + if c.secure { + logger.Log(t, "checking that the connection is not successful because there's no intention") + + k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), multiport, "http://localhost:3234") + + logger.Log(t, fmt.Sprintf("creating intention for %s", staticServerName)) + _, _, err := consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: staticServerName, + Sources: []*api.SourceIntention{ + { + Name: multiport, + Action: api.IntentionActionAllow, + }, + }, + }, nil) + require.NoError(t, err) + } + + // Check the connection from the multi port pod to static-server. + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), multiport, "http://localhost:3234") + + // Test that kubernetes readiness status is synced to Consul. This will make the multi port pods unhealthy + // and check inbound connections to the multi port pods' services. + // Create the files so that the readiness probes of the multi port pod fails. + logger.Log(t, "testing k8s -> consul health checks sync by making the multiport unhealthy") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+multiport, "--", "touch", "/tmp/unhealthy-multiport") + logger.Log(t, "testing k8s -> consul health checks sync by making the multiport-admin unhealthy") + k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+multiport, "--", "touch", "/tmp/unhealthy-multiport-admin") + + // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry + // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. + // We are expecting a "connection reset by peer" error because in a case of health checks, + // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply + // from server, which is the case when a connection is unsuccessful due to intentions in other tests. + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "", "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "", "http://localhost:2234") + }) } } diff --git a/acceptance/tests/fixtures/bases/multiport-app/anyuid-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/multiport-app/anyuid-scc-rolebinding.yaml new file mode 100644 index 0000000000..f80bd41d81 --- /dev/null +++ b/acceptance/tests/fixtures/bases/multiport-app/anyuid-scc-rolebinding.yaml @@ -0,0 +1,23 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: multiport-openshift-anyuid +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:openshift:scc:anyuid +subjects: + - kind: ServiceAccount + name: multiport +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: multiport-admin-openshift-anyuid +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:openshift:scc:anyuid +subjects: + - kind: ServiceAccount + name: multiport-admin diff --git a/acceptance/tests/fixtures/bases/multiport-app/deployment.yaml b/acceptance/tests/fixtures/bases/multiport-app/deployment.yaml new file mode 100644 index 0000000000..a99d415d80 --- /dev/null +++ b/acceptance/tests/fixtures/bases/multiport-app/deployment.yaml @@ -0,0 +1,78 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: multiport +spec: + replicas: 1 + selector: + matchLabels: + app: multiport + template: + metadata: + name: multiport + labels: + app: multiport + annotations: + "consul.hashicorp.com/connect-inject": "true" + 'consul.hashicorp.com/connect-service': 'multiport,multiport-admin' + 'consul.hashicorp.com/connect-service-upstreams': 'static-server:3234' + 'consul.hashicorp.com/connect-service-port': '8080,9090' + 'consul.hashicorp.com/transparent-proxy': 'false' + 'consul.hashicorp.com/enable-metrics': 'false' + 'consul.hashicorp.com/enable-metrics-merging': 'false' + spec: + containers: + - name: multiport + image: docker.mirror.hashicorp.services/hashicorp/http-echo:alpine + args: + - -text="hello world" + - -listen=:8080 + ports: + - containerPort: 8080 + name: http + livenessProbe: + httpGet: + port: 8080 + initialDelaySeconds: 1 + failureThreshold: 1 + periodSeconds: 1 + startupProbe: + httpGet: + port: 8080 + initialDelaySeconds: 1 + failureThreshold: 30 + periodSeconds: 1 + readinessProbe: + exec: + command: ['sh', '-c', 'test ! -f /tmp/unhealthy-multiport'] + initialDelaySeconds: 1 + failureThreshold: 1 + periodSeconds: 1 + - name: multiport-admin + image: docker.mirror.hashicorp.services/hashicorp/http-echo:alpine + args: + - -text="hello world from 9090 admin" + - -listen=:9090 + ports: + - containerPort: 9090 + name: http + livenessProbe: + httpGet: + port: 9090 + initialDelaySeconds: 1 + failureThreshold: 1 + periodSeconds: 1 + startupProbe: + httpGet: + port: 9090 + initialDelaySeconds: 1 + failureThreshold: 30 + periodSeconds: 1 + readinessProbe: + exec: + command: ['sh', '-c', 'test ! -f /tmp/unhealthy-multiport-admin'] + initialDelaySeconds: 1 + failureThreshold: 1 + periodSeconds: 1 + serviceAccountName: multiport + terminationGracePeriodSeconds: 0 # so deletion is quick diff --git a/acceptance/tests/fixtures/bases/multiport-app/kustomization.yaml b/acceptance/tests/fixtures/bases/multiport-app/kustomization.yaml new file mode 100644 index 0000000000..b9d8e11f73 --- /dev/null +++ b/acceptance/tests/fixtures/bases/multiport-app/kustomization.yaml @@ -0,0 +1,7 @@ +resources: + - deployment.yaml + - service.yaml + - serviceaccount.yaml + - psp-rolebinding.yaml + - anyuid-scc-rolebinding.yaml + - privileged-scc-rolebinding.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/bases/multiport-app/privileged-scc-rolebinding.yaml b/acceptance/tests/fixtures/bases/multiport-app/privileged-scc-rolebinding.yaml new file mode 100644 index 0000000000..f909785b36 --- /dev/null +++ b/acceptance/tests/fixtures/bases/multiport-app/privileged-scc-rolebinding.yaml @@ -0,0 +1,23 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: multiport-openshift-privileged +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:openshift:scc:privileged +subjects: + - kind: ServiceAccount + name: multiport +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: multiport-admin-openshift-privileged +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:openshift:scc:privileged +subjects: + - kind: ServiceAccount + name: multiport-admin diff --git a/acceptance/tests/fixtures/bases/multiport-app/psp-rolebinding.yaml b/acceptance/tests/fixtures/bases/multiport-app/psp-rolebinding.yaml new file mode 100644 index 0000000000..fce63f0076 --- /dev/null +++ b/acceptance/tests/fixtures/bases/multiport-app/psp-rolebinding.yaml @@ -0,0 +1,23 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: multiport +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: test-psp +subjects: + - kind: ServiceAccount + name: multiport +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: multiport-admin +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: test-psp +subjects: + - kind: ServiceAccount + name: multiport-admin diff --git a/acceptance/tests/fixtures/bases/multiport-app/service.yaml b/acceptance/tests/fixtures/bases/multiport-app/service.yaml new file mode 100644 index 0000000000..d18da258a3 --- /dev/null +++ b/acceptance/tests/fixtures/bases/multiport-app/service.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: Service +metadata: + name: multiport +spec: + selector: + app: multiport + ports: + - name: http + port: 80 + targetPort: 8080 +--- +apiVersion: v1 +kind: Service +metadata: + name: multiport-admin +spec: + selector: + app: multiport + ports: + - protocol: TCP + port: 80 + targetPort: 9090 diff --git a/acceptance/tests/fixtures/bases/multiport-app/serviceaccount.yaml b/acceptance/tests/fixtures/bases/multiport-app/serviceaccount.yaml new file mode 100644 index 0000000000..2293c2e173 --- /dev/null +++ b/acceptance/tests/fixtures/bases/multiport-app/serviceaccount.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: multiport +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: multiport-admin diff --git a/acceptance/tests/fixtures/cases/static-client-inject-multiport/kustomization.yaml b/acceptance/tests/fixtures/cases/static-client-inject-multiport/kustomization.yaml new file mode 100644 index 0000000000..9834f91903 --- /dev/null +++ b/acceptance/tests/fixtures/cases/static-client-inject-multiport/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - ../../bases/static-client + +patchesStrategicMerge: + - patch.yaml \ No newline at end of file diff --git a/acceptance/tests/fixtures/cases/static-client-inject-multiport/patch.yaml b/acceptance/tests/fixtures/cases/static-client-inject-multiport/patch.yaml new file mode 100644 index 0000000000..c38ce8e448 --- /dev/null +++ b/acceptance/tests/fixtures/cases/static-client-inject-multiport/patch.yaml @@ -0,0 +1,10 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: static-client +spec: + template: + metadata: + annotations: + "consul.hashicorp.com/connect-inject": "true" + "consul.hashicorp.com/connect-service-upstreams": "multiport:1234, multiport-admin:2234" \ No newline at end of file diff --git a/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go b/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go index f7ae5d13bc..f47f98d70f 100644 --- a/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go +++ b/acceptance/tests/ingress-gateway/ingress_gateway_namespaces_test.go @@ -128,7 +128,7 @@ func TestIngressGatewaySingleNamespace(t *testing.T) { // via the bounce pod. It should fail to connect with the // static-server pod because of intentions. logger.Log(t, "testing intentions prevent ingress") - k8s.CheckStaticServerConnectionFailing(t, nsK8SOptions, "-H", "Host: static-server.ingress.consul", ingressGatewayService) + k8s.CheckStaticServerConnectionFailing(t, nsK8SOptions, staticClientName, "-H", "Host: static-server.ingress.consul", ingressGatewayService) // Now we create the allow intention. logger.Log(t, "creating ingress-gateway => static-server intention") @@ -150,7 +150,7 @@ func TestIngressGatewaySingleNamespace(t *testing.T) { // Test that we can make a call to the ingress gateway // via the static-client pod. It should route to the static-server pod. logger.Log(t, "trying calls to ingress gateway") - k8s.CheckStaticServerConnectionSuccessful(t, nsK8SOptions, "-H", "Host: static-server.ingress.consul", ingressGatewayService) + k8s.CheckStaticServerConnectionSuccessful(t, nsK8SOptions, staticClientName, "-H", "Host: static-server.ingress.consul", ingressGatewayService) }) } } @@ -253,7 +253,7 @@ func TestIngressGatewayNamespaceMirroring(t *testing.T) { // via the bounce pod. It should fail to connect with the // static-server pod because of intentions. logger.Log(t, "testing intentions prevent ingress") - k8s.CheckStaticServerConnectionFailing(t, nsK8SOptions, "-H", "Host: static-server.ingress.consul", ingressGatewayService) + k8s.CheckStaticServerConnectionFailing(t, nsK8SOptions, staticClientName, "-H", "Host: static-server.ingress.consul", ingressGatewayService) // Now we create the allow intention. logger.Log(t, "creating ingress-gateway => static-server intention") @@ -275,7 +275,7 @@ func TestIngressGatewayNamespaceMirroring(t *testing.T) { // Test that we can make a call to the ingress gateway // via the static-client pod. It should route to the static-server pod. logger.Log(t, "trying calls to ingress gateway") - k8s.CheckStaticServerConnectionSuccessful(t, nsK8SOptions, "-H", "Host: static-server.ingress.consul", ingressGatewayService) + k8s.CheckStaticServerConnectionSuccessful(t, nsK8SOptions, staticClientName, "-H", "Host: static-server.ingress.consul", ingressGatewayService) }) } } diff --git a/acceptance/tests/ingress-gateway/ingress_gateway_test.go b/acceptance/tests/ingress-gateway/ingress_gateway_test.go index b727d4332a..359b917a73 100644 --- a/acceptance/tests/ingress-gateway/ingress_gateway_test.go +++ b/acceptance/tests/ingress-gateway/ingress_gateway_test.go @@ -13,6 +13,8 @@ import ( "github.com/stretchr/testify/require" ) +const staticClientName = "static-client" + // Test that ingress gateways work in a default installation and a secure installation. func TestIngressGateway(t *testing.T) { cases := []struct { @@ -92,7 +94,7 @@ func TestIngressGateway(t *testing.T) { // via the bounce pod. It should fail to connect with the // static-server pod because of intentions. logger.Log(t, "testing intentions prevent ingress") - k8s.CheckStaticServerConnectionFailing(t, k8sOptions, "-H", "Host: static-server.ingress.consul", fmt.Sprintf("http://%s-consul-ingress-gateway:8080/", releaseName)) + k8s.CheckStaticServerConnectionFailing(t, k8sOptions, staticClientName, "-H", "Host: static-server.ingress.consul", fmt.Sprintf("http://%s-consul-ingress-gateway:8080/", releaseName)) // Now we create the allow intention. logger.Log(t, "creating ingress-gateway => static-server intention") @@ -112,7 +114,7 @@ func TestIngressGateway(t *testing.T) { // Test that we can make a call to the ingress gateway // via the static-client pod. It should route to the static-server pod. logger.Log(t, "trying calls to ingress gateway") - k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, "-H", "Host: static-server.ingress.consul", fmt.Sprintf("http://%s-consul-ingress-gateway:8080/", releaseName)) + k8s.CheckStaticServerConnectionSuccessful(t, k8sOptions, staticClientName, "-H", "Host: static-server.ingress.consul", fmt.Sprintf("http://%s-consul-ingress-gateway:8080/", releaseName)) }) } } diff --git a/acceptance/tests/mesh-gateway/mesh_gateway_test.go b/acceptance/tests/mesh-gateway/mesh_gateway_test.go index ed67252670..d6e4be90be 100644 --- a/acceptance/tests/mesh-gateway/mesh_gateway_test.go +++ b/acceptance/tests/mesh-gateway/mesh_gateway_test.go @@ -125,7 +125,7 @@ func TestMeshGatewayDefault(t *testing.T) { k8s.DeployKustomize(t, primaryContext.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-multi-dc") logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, primaryContext.KubectlOptions(t), "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, primaryContext.KubectlOptions(t), staticClientName, "http://localhost:1234") } // Test that Connect and wan federation over mesh gateways work in a secure installation, @@ -274,7 +274,7 @@ func TestMeshGatewaySecure(t *testing.T) { require.NoError(t, err) logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, primaryContext.KubectlOptions(t), "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, primaryContext.KubectlOptions(t), staticClientName, "http://localhost:1234") }) } } diff --git a/acceptance/tests/partitions/partitions_test.go b/acceptance/tests/partitions/partitions_test.go index a4a95e7078..d3c732f071 100644 --- a/acceptance/tests/partitions/partitions_test.go +++ b/acceptance/tests/partitions/partitions_test.go @@ -379,11 +379,11 @@ func TestPartitions(t *testing.T) { if c.ACLsAndAutoEncryptEnabled { logger.Log(t, "checking that the connection is not successful because there's no intention") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) - k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) } else { - k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, staticClientName, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, staticClientName, "http://localhost:1234") } intention := &api.ServiceIntentionsConfigEntry{ @@ -421,11 +421,11 @@ func TestPartitions(t *testing.T) { logger.Log(t, "checking that connection is successful") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) - k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) } else { - k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, staticClientName, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, staticClientName, "http://localhost:1234") } // Test that kubernetes readiness status is synced to Consul. @@ -441,11 +441,11 @@ func TestPartitions(t *testing.T) { // from server, which is the case when a connection is unsuccessful due to intentions in other tests. logger.Log(t, "checking that connection is unsuccessful") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, "", fmt.Sprintf("http://static-server.%s", staticServerNamespace)) + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, "", fmt.Sprintf("http://static-server.%s", staticServerNamespace)) } else { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "", "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "", "http://localhost:1234") } }) // This section of the tests runs the cross-partition networking tests. @@ -541,15 +541,15 @@ func TestPartitions(t *testing.T) { logger.Log(t, "checking that the connection is not successful because there's no intention") if cfg.EnableTransparentProxy { if !c.mirrorK8S { - k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, secondaryPartition)) - k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, defaultPartition)) + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, defaultPartition)) } else { - k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, secondaryPartition)) - k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, defaultPartition)) + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, defaultPartition)) } } else { - k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, serverClusterStaticClientOpts, staticClientName, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, clientClusterStaticClientOpts, staticClientName, "http://localhost:1234") } intention := &api.ServiceIntentionsConfigEntry{ @@ -590,15 +590,15 @@ func TestPartitions(t *testing.T) { logger.Log(t, "checking that connection is successful") if cfg.EnableTransparentProxy { if !c.mirrorK8S { - k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, secondaryPartition)) - k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, defaultPartition)) + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, defaultPartition)) } else { - k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, secondaryPartition)) - k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, defaultPartition)) + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, staticClientName, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, defaultPartition)) } } else { - k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, "http://localhost:1234") - k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, serverClusterStaticClientOpts, staticClientName, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, clientClusterStaticClientOpts, staticClientName, "http://localhost:1234") } // Test that kubernetes readiness status is synced to Consul. @@ -615,15 +615,15 @@ func TestPartitions(t *testing.T) { logger.Log(t, "checking that connection is unsuccessful") if cfg.EnableTransparentProxy { if !c.mirrorK8S { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, secondaryPartition)) - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, defaultPartition)) + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, "", fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, "", fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", c.destinationNamespace, defaultPartition)) } else { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, secondaryPartition)) - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, defaultPartition)) + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, "", fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, secondaryPartition)) + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server.ns1 port 80: Connection refused"}, "", fmt.Sprintf("http://static-server.virtual.%s.ns.%s.ap.dc1.dc.consul", staticServerNamespace, defaultPartition)) } } else { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, serverClusterStaticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "", "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, clientClusterStaticClientOpts, staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "", "http://localhost:1234") } }) }) diff --git a/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go b/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go index 061d85e662..76510b9a76 100644 --- a/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go +++ b/acceptance/tests/terminating-gateway/terminating_gateway_namespaces_test.go @@ -121,7 +121,7 @@ func TestTerminatingGatewaySingleNamespace(t *testing.T) { // Test that we can make a call to the terminating gateway. logger.Log(t, "trying calls to terminating gateway") - k8s.CheckStaticServerConnectionSuccessful(t, nsK8SOptions, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, nsK8SOptions, staticClientName, "http://localhost:1234") }) } } @@ -229,7 +229,7 @@ func TestTerminatingGatewayNamespaceMirroring(t *testing.T) { // Test that we can make a call to the terminating gateway logger.Log(t, "trying calls to terminating gateway") - k8s.CheckStaticServerConnectionSuccessful(t, ns2K8SOptions, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, ns2K8SOptions, staticClientName, "http://localhost:1234") }) } } diff --git a/acceptance/tests/terminating-gateway/terminating_gateway_test.go b/acceptance/tests/terminating-gateway/terminating_gateway_test.go index 690e231e2b..cb362d4445 100644 --- a/acceptance/tests/terminating-gateway/terminating_gateway_test.go +++ b/acceptance/tests/terminating-gateway/terminating_gateway_test.go @@ -93,7 +93,7 @@ func TestTerminatingGateway(t *testing.T) { // Test that we can make a call to the terminating gateway. logger.Log(t, "trying calls to terminating gateway") - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") }) } } @@ -191,7 +191,7 @@ func assertNoConnectionAndAddIntention(t *testing.T, consulClient *api.Client, k t.Helper() logger.Log(t, "testing intentions prevent connections through the terminating gateway") - k8s.CheckStaticServerConnectionFailing(t, k8sOptions, "http://localhost:1234") + k8s.CheckStaticServerConnectionFailing(t, k8sOptions, staticClientName, "http://localhost:1234") logger.Log(t, "creating static-client => static-server intention") _, _, err := consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index 8025741c0b..ed4410999b 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -11,6 +11,8 @@ import ( "github.com/stretchr/testify/require" ) +const staticClientName = "static-client" + // TestVault installs Vault, bootstraps it with secrets, policies, and Kube Auth Method. // It then configures Consul to use vault as the backend and checks that it works. func TestVault(t *testing.T) { @@ -132,8 +134,8 @@ func TestVault(t *testing.T) { logger.Log(t, "checking that connection is successful") if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://static-server") + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://static-server") } else { - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") } } diff --git a/acceptance/tests/vault/vault_wan_fed_test.go b/acceptance/tests/vault/vault_wan_fed_test.go index 23428e3d5a..16d9163cfb 100644 --- a/acceptance/tests/vault/vault_wan_fed_test.go +++ b/acceptance/tests/vault/vault_wan_fed_test.go @@ -298,7 +298,7 @@ func TestVault_WANFederationViaGateways(t *testing.T) { require.NoError(t, err) logger.Log(t, "checking that connection is successful") - k8s.CheckStaticServerConnectionSuccessful(t, primaryCtx.KubectlOptions(t), "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, primaryCtx.KubectlOptions(t), staticClientName, "http://localhost:1234") } // vaultAddress returns Vault's server URL depending on test configuration. diff --git a/charts/consul/templates/connect-inject-clusterrole.yaml b/charts/consul/templates/connect-inject-clusterrole.yaml index 892ef8f406..9d01420363 100644 --- a/charts/consul/templates/connect-inject-clusterrole.yaml +++ b/charts/consul/templates/connect-inject-clusterrole.yaml @@ -49,5 +49,10 @@ rules: - {{ template "consul.fullname" . }}-connect-inject-acl-token verbs: - get +- apiGroups: [""] + resources: + - serviceaccounts + verbs: + - get {{- end }} {{- end }} diff --git a/control-plane/connect-inject/container_init.go b/control-plane/connect-inject/container_init.go index c258203c9a..526e473bfc 100644 --- a/control-plane/connect-inject/container_init.go +++ b/control-plane/connect-inject/container_init.go @@ -72,6 +72,18 @@ type initContainerCommandData struct { // ConsulDNSClusterIP is the IP of the Consul DNS Service. ConsulDNSClusterIP string + + // MultiPort determines whether this is a multi port Pod, which configures the init container to be specific to one + // of the services on the multi port Pod. + MultiPort bool + + // EnvoyAdminPort configures the admin port of the Envoy sidecar. This will be unique per service in a multi port + // Pod. + EnvoyAdminPort int + + // BearerTokenFile configures where the service account token can be found. This will be unique per service in a + // multi port Pod. + BearerTokenFile string } // initCopyContainer returns the init container spec for the copy container which places @@ -104,9 +116,9 @@ func (h *Handler) initCopyContainer() corev1.Container { return container } -// containerInit returns the init container spec for that polls for the service and the connect proxy service to be registered -// so that it can save theproxy service id to the shared volume and boostrap Envoy with the proxy-id -func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod) (corev1.Container, error) { +// containerInit returns the init container spec for connect-init that polls for the service and the connect proxy service to be registered +// so that it can save the proxy service id to the shared volume and boostrap Envoy with the proxy-id. +func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod, mpi multiPortInfo) (corev1.Container, error) { // Check if tproxy is enabled on this pod. tproxyEnabled, err := transparentProxyEnabled(namespace, pod, h.EnableTransparentProxy) if err != nil { @@ -129,6 +141,8 @@ func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod) (cor } } + multiPort := mpi.serviceName != "" + data := initContainerCommandData{ AuthMethod: h.AuthMethod, ConsulPartition: h.ConsulPartition, @@ -142,12 +156,41 @@ func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod) (cor TProxyExcludeUIDs: splitCommaSeparatedItemsFromAnnotation(annotationTProxyExcludeUIDs, pod), ConsulDNSClusterIP: consulDNSClusterIP, EnvoyUID: envoyUserAndGroupID, + MultiPort: multiPort, + EnvoyAdminPort: 19000 + mpi.serviceIndex, } - if data.AuthMethod != "" { - data.ServiceAccountName = pod.Spec.ServiceAccountName + // Create expected volume mounts + volMounts := []corev1.VolumeMount{ + { + Name: volumeName, + MountPath: "/consul/connect-inject", + }, + } + + if multiPort { + data.ServiceName = mpi.serviceName + } else { data.ServiceName = pod.Annotations[annotationService] } + if h.AuthMethod != "" { + if multiPort { + // If multi port then we require that the service account name + // matches the service name. + data.ServiceAccountName = mpi.serviceName + } else { + data.ServiceAccountName = pod.Spec.ServiceAccountName + } + // Extract the service account token's volume mount + saTokenVolumeMount, bearerTokenFile, err := findServiceAccountVolumeMount(pod, multiPort, mpi.serviceName) + if err != nil { + return corev1.Container{}, err + } + data.BearerTokenFile = bearerTokenFile + + // Append to volume mounts + volMounts = append(volMounts, saTokenVolumeMount) + } // This determines how to configure the consul connect envoy command: what // metrics backend to use and what path to expose on the @@ -166,25 +209,6 @@ func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod) (cor data.PrometheusBackendPort = mergedMetricsPort } - // Create expected volume mounts - volMounts := []corev1.VolumeMount{ - { - Name: volumeName, - MountPath: "/consul/connect-inject", - }, - } - - if h.AuthMethod != "" { - // Extract the service account token's volume mount - saTokenVolumeMount, err := findServiceAccountVolumeMount(pod) - if err != nil { - return corev1.Container{}, err - } - - // Append to volume mounts - volMounts = append(volMounts, saTokenVolumeMount) - } - // Render the command var buf bytes.Buffer tpl := template.Must(template.New("root").Parse(strings.TrimSpace( @@ -194,8 +218,12 @@ func (h *Handler) containerInit(namespace corev1.Namespace, pod corev1.Pod) (cor return corev1.Container{}, err } + initContainerName := InjectInitContainerName + if multiPort { + initContainerName = fmt.Sprintf("%s-%s", InjectInitContainerName, mpi.serviceName) + } container := corev1.Container{ - Name: InjectInitContainerName, + Name: initContainerName, Image: h.ImageConsulK8S, Env: []corev1.EnvVar{ { @@ -327,6 +355,10 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -acl-auth-method="{{ .AuthMethod }}" \ -service-account-name="{{ .ServiceAccountName }}" \ -service-name="{{ .ServiceName }}" \ + -bearer-token-file={{ .BearerTokenFile }} \ + {{- if .MultiPort }} + -acl-token-sink=/consul/connect-inject/acl-token-{{ .ServiceName }} \ + {{- end }} {{- if .ConsulNamespace }} {{- if .NamespaceMirroringEnabled }} {{- /* If namespace mirroring is enabled, the auth method is @@ -337,6 +369,13 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD {{- end }} {{- end }} {{- end }} + {{- if .MultiPort }} + -multiport=true \ + -proxy-id-file=/consul/connect-inject/proxyid-{{ .ServiceName }} \ + {{- if not .AuthMethod }} + -service-name="{{ .ServiceName }}" \ + {{- end }} + {{- end }} {{- if .ConsulPartition }} -partition="{{ .ConsulPartition }}" \ {{- end }} @@ -346,7 +385,11 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD # Generate the envoy bootstrap code /consul/connect-inject/consul connect envoy \ + {{- if .MultiPort }} + -proxy-id="$(cat /consul/connect-inject/proxyid-{{.ServiceName}})" \ + {{- else }} -proxy-id="$(cat /consul/connect-inject/proxyid)" \ + {{- end }} {{- if .PrometheusScrapePath }} -prometheus-scrape-path="{{ .PrometheusScrapePath }}" \ {{- end }} @@ -354,15 +397,23 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -prometheus-backend-port="{{ .PrometheusBackendPort }}" \ {{- end }} {{- if .AuthMethod }} + {{- if .MultiPort }} + -token-file="/consul/connect-inject/acl-token-{{ .ServiceName }}" \ + {{- else }} -token-file="/consul/connect-inject/acl-token" \ {{- end }} + {{- end }} {{- if .ConsulPartition }} -partition="{{ .ConsulPartition }}" \ {{- end }} {{- if .ConsulNamespace }} -namespace="{{ .ConsulNamespace }}" \ {{- end }} - -bootstrap > /consul/connect-inject/envoy-bootstrap.yaml + {{- if .MultiPort }} + -admin-bind=127.0.0.1:{{ .EnvoyAdminPort }} \ + {{- end }} + -bootstrap > {{ if .MultiPort }}/consul/connect-inject/envoy-bootstrap-{{.ServiceName}}.yaml{{ else }}/consul/connect-inject/envoy-bootstrap.yaml{{ end }} + {{- if .EnableTransparentProxy }} {{- /* The newline below is intentional to allow extra space diff --git a/control-plane/connect-inject/container_init_test.go b/control-plane/connect-inject/container_init_test.go index 58cfe95d73..f536ba68f0 100644 --- a/control-plane/connect-inject/container_init_test.go +++ b/control-plane/connect-inject/container_init_test.go @@ -131,7 +131,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD h := tt.Handler pod := *tt.Pod(minimal()) - container, err := h.containerInit(testNS, pod) + container, err := h.containerInit(testNS, pod, multiPortInfo{}) require.NoError(err) actual := strings.Join(container.Command, " ") require.Contains(actual, tt.Cmd) @@ -296,7 +296,7 @@ func TestHandlerContainerInit_transparentProxy(t *testing.T) { } ns := testNS ns.Labels = c.namespaceLabel - container, err := h.containerInit(ns, *pod) + container, err := h.containerInit(ns, *pod, multiPortInfo{}) require.NoError(t, err) actualCmd := strings.Join(container.Command, " ") @@ -384,7 +384,7 @@ func TestHandlerContainerInit_consulDNS(t *testing.T) { ns := testNS ns.Labels = c.namespaceLabel - container, err := h.containerInit(ns, *pod) + container, err := h.containerInit(ns, *pod, multiPortInfo{}) require.NoError(t, err) actualCmd := strings.Join(container.Command, " ") @@ -573,6 +573,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -acl-auth-method="auth-method" \ -service-account-name="web" \ -service-name="" \ + -bearer-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token \ -auth-method-namespace="non-default" \ -partition="default" \ -consul-service-namespace="non-default" \ @@ -605,6 +606,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -acl-auth-method="auth-method" \ -service-account-name="web" \ -service-name="" \ + -bearer-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token \ -auth-method-namespace="default" \ -partition="non-default" \ -consul-service-namespace="k8snamespace" \ @@ -702,6 +704,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD -acl-auth-method="auth-method" \ -service-account-name="web" \ -service-name="web" \ + -bearer-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token \ -auth-method-namespace="default" \ -partition="non-default" \ -consul-service-namespace="k8snamespace" \ @@ -729,7 +732,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD require := require.New(t) h := tt.Handler - container, err := h.containerInit(testNS, *tt.Pod(minimal())) + container, err := h.containerInit(testNS, *tt.Pod(minimal()), multiPortInfo{}) require.NoError(err) actual := strings.Join(container.Command, " ") require.Equal(tt.Cmd, actual) @@ -737,6 +740,178 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD } } +func TestHandlerContainerInit_Multiport(t *testing.T) { + minimal := func() *corev1.Pod { + return &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + annotationService: "web,web-admin", + }, + }, + + Spec: corev1.PodSpec{ + Volumes: []corev1.Volume{ + { + Name: "web-admin-service-account", + }, + }, + Containers: []corev1.Container{ + { + Name: "web", + }, + { + Name: "web-side", + }, + { + Name: "web-admin", + }, + { + Name: "web-admin-side", + }, + { + Name: "auth-method-secret", + VolumeMounts: []corev1.VolumeMount{ + { + Name: "service-account-secret", + MountPath: "/var/run/secrets/kubernetes.io/serviceaccount", + }, + }, + }, + }, + ServiceAccountName: "web", + }, + } + } + + cases := []struct { + Name string + Pod func(*corev1.Pod) *corev1.Pod + Handler Handler + NumInitContainers int + MultiPortInfos []multiPortInfo + Cmd []string // Strings.Contains test + }{ + { + "Whole template, multiport", + func(pod *corev1.Pod) *corev1.Pod { + return pod + }, + Handler{}, + 2, + []multiPortInfo{ + { + serviceIndex: 0, + serviceName: "web", + }, + { + serviceIndex: 1, + serviceName: "web-admin", + }, + }, + []string{`/bin/sh -ec +export CONSUL_HTTP_ADDR="${HOST_IP}:8500" +export CONSUL_GRPC_ADDR="${HOST_IP}:8502" +consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD_NAMESPACE} \ + -multiport=true \ + -proxy-id-file=/consul/connect-inject/proxyid-web \ + -service-name="web" \ + +# Generate the envoy bootstrap code +/consul/connect-inject/consul connect envoy \ + -proxy-id="$(cat /consul/connect-inject/proxyid-web)" \ + -admin-bind=127.0.0.1:19000 \ + -bootstrap > /consul/connect-inject/envoy-bootstrap-web.yaml`, + + `/bin/sh -ec +export CONSUL_HTTP_ADDR="${HOST_IP}:8500" +export CONSUL_GRPC_ADDR="${HOST_IP}:8502" +consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD_NAMESPACE} \ + -multiport=true \ + -proxy-id-file=/consul/connect-inject/proxyid-web-admin \ + -service-name="web-admin" \ + +# Generate the envoy bootstrap code +/consul/connect-inject/consul connect envoy \ + -proxy-id="$(cat /consul/connect-inject/proxyid-web-admin)" \ + -admin-bind=127.0.0.1:19001 \ + -bootstrap > /consul/connect-inject/envoy-bootstrap-web-admin.yaml`, + }, + }, + { + "Whole template, multiport, auth method", + func(pod *corev1.Pod) *corev1.Pod { + return pod + }, + Handler{ + AuthMethod: "auth-method", + }, + 2, + []multiPortInfo{ + { + serviceIndex: 0, + serviceName: "web", + }, + { + serviceIndex: 1, + serviceName: "web-admin", + }, + }, + []string{`/bin/sh -ec +export CONSUL_HTTP_ADDR="${HOST_IP}:8500" +export CONSUL_GRPC_ADDR="${HOST_IP}:8502" +consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD_NAMESPACE} \ + -acl-auth-method="auth-method" \ + -service-account-name="web" \ + -service-name="web" \ + -bearer-token-file=/var/run/secrets/kubernetes.io/serviceaccount/token \ + -acl-token-sink=/consul/connect-inject/acl-token-web \ + -multiport=true \ + -proxy-id-file=/consul/connect-inject/proxyid-web \ + +# Generate the envoy bootstrap code +/consul/connect-inject/consul connect envoy \ + -proxy-id="$(cat /consul/connect-inject/proxyid-web)" \ + -token-file="/consul/connect-inject/acl-token-web" \ + -admin-bind=127.0.0.1:19000 \ + -bootstrap > /consul/connect-inject/envoy-bootstrap-web.yaml`, + + `/bin/sh -ec +export CONSUL_HTTP_ADDR="${HOST_IP}:8500" +export CONSUL_GRPC_ADDR="${HOST_IP}:8502" +consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD_NAMESPACE} \ + -acl-auth-method="auth-method" \ + -service-account-name="web-admin" \ + -service-name="web-admin" \ + -bearer-token-file=/consul/serviceaccount-web-admin/token \ + -acl-token-sink=/consul/connect-inject/acl-token-web-admin \ + -multiport=true \ + -proxy-id-file=/consul/connect-inject/proxyid-web-admin \ + +# Generate the envoy bootstrap code +/consul/connect-inject/consul connect envoy \ + -proxy-id="$(cat /consul/connect-inject/proxyid-web-admin)" \ + -token-file="/consul/connect-inject/acl-token-web-admin" \ + -admin-bind=127.0.0.1:19001 \ + -bootstrap > /consul/connect-inject/envoy-bootstrap-web-admin.yaml`, + }, + }, + } + + for _, tt := range cases { + t.Run(tt.Name, func(t *testing.T) { + require := require.New(t) + + h := tt.Handler + for i := 0; i < tt.NumInitContainers; i++ { + container, err := h.containerInit(testNS, *tt.Pod(minimal()), tt.MultiPortInfos[i]) + require.NoError(err) + actual := strings.Join(container.Command, " ") + require.Equal(tt.Cmd[i], actual) + } + }) + } +} + func TestHandlerContainerInit_authMethod(t *testing.T) { require := require.New(t) h := Handler{ @@ -765,7 +940,7 @@ func TestHandlerContainerInit_authMethod(t *testing.T) { ServiceAccountName: "foo", }, } - container, err := h.containerInit(testNS, *pod) + container, err := h.containerInit(testNS, *pod, multiPortInfo{}) require.NoError(err) actual := strings.Join(container.Command, " ") require.Contains(actual, ` @@ -802,7 +977,7 @@ func TestHandlerContainerInit_WithTLS(t *testing.T) { }, }, } - container, err := h.containerInit(testNS, *pod) + container, err := h.containerInit(testNS, *pod, multiPortInfo{}) require.NoError(err) actual := strings.Join(container.Command, " ") require.Contains(actual, ` @@ -846,7 +1021,7 @@ func TestHandlerContainerInit_Resources(t *testing.T) { }, }, } - container, err := h.containerInit(testNS, *pod) + container, err := h.containerInit(testNS, *pod, multiPortInfo{}) require.NoError(err) require.Equal(corev1.ResourceRequirements{ Limits: corev1.ResourceList{ diff --git a/control-plane/connect-inject/endpoints_controller.go b/control-plane/connect-inject/endpoints_controller.go index 7dcca14091..8213fa2278 100644 --- a/control-plane/connect-inject/endpoints_controller.go +++ b/control-plane/connect-inject/endpoints_controller.go @@ -367,9 +367,14 @@ func (r *EndpointsController) upsertHealthCheck(pod corev1.Pod, client *api.Clie return nil } +// getServiceName computes the service name to register with Consul from the pod and endpoints object. In a single port +// service, it defaults to the endpoints name, but can be overridden by a pod annotation. In a multi port service, the +// endpoints name is always used since the pod annotation will have multiple service names listed (one per port). +// Changing the Consul service name via annotations is not supported for multi port services. func getServiceName(pod corev1.Pod, serviceEndpoints corev1.Endpoints) string { serviceName := serviceEndpoints.Name - if serviceNameFromAnnotation, ok := pod.Annotations[annotationService]; ok && serviceNameFromAnnotation != "" { + // If the annotation has a comma, it is a multi port Pod. In that case we always use the name of the endpoint. + if serviceNameFromAnnotation, ok := pod.Annotations[annotationService]; ok && serviceNameFromAnnotation != "" && !strings.Contains(serviceNameFromAnnotation, ",") { serviceName = serviceNameFromAnnotation } return serviceName @@ -397,6 +402,11 @@ func (r *EndpointsController) createServiceRegistrations(pod corev1.Pod, service // The handler will always set the port annotation if one is not provided on the pod. var consulServicePort int if raw, ok := pod.Annotations[annotationPort]; ok && raw != "" { + if multiPort := strings.Split(raw, ","); len(multiPort) > 1 { + // Figure out which index of the ports annotation to use by + // finding the index of the service names annotation. + raw = multiPort[getMultiPortIdx(pod, serviceEndpoints)] + } if port, err := portValue(pod, raw); port > 0 { if err != nil { return nil, nil, err @@ -471,17 +481,21 @@ func (r *EndpointsController) createServiceRegistrations(pod corev1.Pod, service proxyConfig.LocalServicePort = consulServicePort } - upstreams, err := r.processUpstreams(pod) + upstreams, err := r.processUpstreams(pod, serviceEndpoints) if err != nil { return nil, nil, err } proxyConfig.Upstreams = upstreams + proxyPort := 20000 + if idx := getMultiPortIdx(pod, serviceEndpoints); idx >= 0 { + proxyPort += idx + } proxyService := &api.AgentServiceRegistration{ Kind: api.ServiceKindConnectProxy, ID: proxyServiceID, Name: proxyServiceName, - Port: 20000, + Port: proxyPort, Address: pod.Status.PodIP, Meta: meta, Namespace: r.consulNamespace(pod.Namespace), @@ -489,7 +503,7 @@ func (r *EndpointsController) createServiceRegistrations(pod corev1.Pod, service Checks: api.AgentServiceChecks{ { Name: "Proxy Public Listener", - TCP: fmt.Sprintf("%s:20000", pod.Status.PodIP), + TCP: fmt.Sprintf("%s:%d", pod.Status.PodIP, proxyPort), Interval: "10s", DeregisterCriticalServiceAfter: "10m", }, @@ -816,7 +830,14 @@ func serviceInstancesForK8SServiceNameAndNamespace(k8sServiceName, k8sServiceNam // processUpstreams reads the list of upstreams from the Pod annotation and converts them into a list of api.Upstream // objects. -func (r *EndpointsController) processUpstreams(pod corev1.Pod) ([]api.Upstream, error) { +func (r *EndpointsController) processUpstreams(pod corev1.Pod, endpoints corev1.Endpoints) ([]api.Upstream, error) { + // In a multiport pod, only the first service's proxy should have upstreams configured. This skips configuring + // upstreams on additional services on the pod. + mpIdx := getMultiPortIdx(pod, endpoints) + if mpIdx > 0 { + return []api.Upstream{}, nil + } + var upstreams []api.Upstream if raw, ok := pod.Annotations[annotationUpstreams]; ok && raw != "" { for _, raw := range strings.Split(raw, ",") { @@ -1072,3 +1093,12 @@ func consulTags(pod corev1.Pod) []string { return interpolatedTags } + +func getMultiPortIdx(pod corev1.Pod, serviceEndpoints corev1.Endpoints) int { + for i, name := range strings.Split(pod.Annotations[annotationService], ",") { + if name == getServiceName(pod, serviceEndpoints) { + return i + } + } + return -1 +} diff --git a/control-plane/connect-inject/endpoints_controller_test.go b/control-plane/connect-inject/endpoints_controller_test.go index 98351c3f39..9b25c149b0 100644 --- a/control-plane/connect-inject/endpoints_controller_test.go +++ b/control-plane/connect-inject/endpoints_controller_test.go @@ -171,7 +171,14 @@ func TestProcessUpstreamsTLSandACLs(t *testing.T) { pod := createPod("pod1", "1.2.3.4", true, true) pod.Annotations[annotationUpstreams] = "upstream1:1234:dc1" - upstreams, err := ep.processUpstreams(*pod) + upstreams, err := ep.processUpstreams(*pod, corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "svcname", + Namespace: "default", + Labels: map[string]string{}, + Annotations: map[string]string{}, + }, + }) require.NoError(t, err) expected := []api.Upstream{ @@ -527,7 +534,14 @@ func TestProcessUpstreams(t *testing.T) { EnableConsulPartitions: tt.consulPartitionsEnabled, } - upstreams, err := ep.processUpstreams(*tt.pod()) + upstreams, err := ep.processUpstreams(*tt.pod(), corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "svcname", + Namespace: "default", + Labels: map[string]string{}, + Annotations: map[string]string{}, + }, + }) if tt.expErr != "" { require.EqualError(t, err, tt.expErr) } else { @@ -538,6 +552,376 @@ func TestProcessUpstreams(t *testing.T) { } } +func TestGetServiceName(t *testing.T) { + t.Parallel() + cases := []struct { + name string + pod func() *corev1.Pod + endpoint *corev1.Endpoints + expSvcName string + }{ + { + name: "single port, with annotation", + pod: func() *corev1.Pod { + pod1 := createPod("pod1", "1.2.3.4", true, true) + pod1.Annotations[annotationService] = "web" + return pod1 + }, + endpoint: &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "not-web", + Namespace: "default", + }, + }, + expSvcName: "web", + }, + { + name: "single port, without annotation", + pod: func() *corev1.Pod { + pod1 := createPod("pod1", "1.2.3.4", true, true) + return pod1 + }, + endpoint: &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ep-name", + Namespace: "default", + }, + }, + expSvcName: "ep-name", + }, + { + name: "multi port, with annotation", + pod: func() *corev1.Pod { + pod1 := createPod("pod1", "1.2.3.4", true, true) + pod1.Annotations[annotationService] = "web,web-admin" + return pod1 + }, + endpoint: &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "ep-name-multiport", + Namespace: "default", + }, + }, + expSvcName: "ep-name-multiport", + }, + } + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + + svcName := getServiceName(*tt.pod(), *tt.endpoint) + require.Equal(t, tt.expSvcName, svcName) + + }) + } +} + +func TestReconcileCreateEndpoint_MultiportService(t *testing.T) { + t.Parallel() + nodeName := "test-node" + cases := []struct { + name string + consulSvcName string + k8sObjects func() []runtime.Object + initialConsulSvcs []*api.AgentServiceRegistration + expectedNumSvcInstances int + expectedConsulSvcInstancesMap map[string][]*api.CatalogService + expectedProxySvcInstancesMap map[string][]*api.CatalogService + expectedAgentHealthChecks []*api.AgentCheck + }{ + { + name: "Multiport service", + consulSvcName: "web,web-admin", + k8sObjects: func() []runtime.Object { + pod1 := createPod("pod1", "1.2.3.4", true, true) + pod1.Annotations[annotationPort] = "8080,9090" + pod1.Annotations[annotationService] = "web,web-admin" + pod1.Annotations[annotationUpstreams] = "upstream1:1234" + endpoint1 := &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "web", + Namespace: "default", + }, + Subsets: []corev1.EndpointSubset{ + { + Addresses: []corev1.EndpointAddress{ + { + IP: "1.2.3.4", + NodeName: &nodeName, + TargetRef: &corev1.ObjectReference{ + Kind: "Pod", + Name: "pod1", + Namespace: "default", + }, + }, + }, + }, + }, + } + endpoint2 := &corev1.Endpoints{ + ObjectMeta: metav1.ObjectMeta{ + Name: "web-admin", + Namespace: "default", + }, + Subsets: []corev1.EndpointSubset{ + { + Addresses: []corev1.EndpointAddress{ + { + IP: "1.2.3.4", + NodeName: &nodeName, + TargetRef: &corev1.ObjectReference{ + Kind: "Pod", + Name: "pod1", + Namespace: "default", + }, + }, + }, + }, + }, + } + return []runtime.Object{pod1, endpoint1, endpoint2} + }, + initialConsulSvcs: []*api.AgentServiceRegistration{}, + expectedNumSvcInstances: 1, + expectedConsulSvcInstancesMap: map[string][]*api.CatalogService{ + "web": { + { + ServiceID: "pod1-web", + ServiceName: "web", + ServiceAddress: "1.2.3.4", + ServicePort: 8080, + ServiceMeta: map[string]string{ + MetaKeyPodName: "pod1", + MetaKeyKubeServiceName: "web", + MetaKeyKubeNS: "default", + MetaKeyManagedBy: managedByValue, + }, + ServiceTags: []string{}, + }, + }, + "web-admin": { + { + ServiceID: "pod1-web-admin", + ServiceName: "web-admin", + ServiceAddress: "1.2.3.4", + ServicePort: 9090, + ServiceMeta: map[string]string{ + MetaKeyPodName: "pod1", + MetaKeyKubeServiceName: "web-admin", + MetaKeyKubeNS: "default", + MetaKeyManagedBy: managedByValue, + }, + ServiceTags: []string{}, + }, + }, + }, + expectedProxySvcInstancesMap: map[string][]*api.CatalogService{ + "web": { + { + ServiceID: "pod1-web-sidecar-proxy", + ServiceName: "web-sidecar-proxy", + ServiceAddress: "1.2.3.4", + ServicePort: 20000, + ServiceProxy: &api.AgentServiceConnectProxyConfig{ + DestinationServiceName: "web", + DestinationServiceID: "pod1-web", + LocalServiceAddress: "127.0.0.1", + LocalServicePort: 8080, + Upstreams: []api.Upstream{ + { + DestinationType: api.UpstreamDestTypeService, + DestinationName: "upstream1", + LocalBindPort: 1234, + }, + }, + }, + ServiceMeta: map[string]string{ + MetaKeyPodName: "pod1", + MetaKeyKubeServiceName: "web", + MetaKeyKubeNS: "default", + MetaKeyManagedBy: managedByValue, + }, + ServiceTags: []string{}, + }, + }, + "web-admin": { + { + ServiceID: "pod1-web-admin-sidecar-proxy", + ServiceName: "web-admin-sidecar-proxy", + ServiceAddress: "1.2.3.4", + ServicePort: 20001, + ServiceProxy: &api.AgentServiceConnectProxyConfig{ + DestinationServiceName: "web-admin", + DestinationServiceID: "pod1-web-admin", + LocalServiceAddress: "127.0.0.1", + LocalServicePort: 9090, + }, + ServiceMeta: map[string]string{ + MetaKeyPodName: "pod1", + MetaKeyKubeServiceName: "web-admin", + MetaKeyKubeNS: "default", + MetaKeyManagedBy: managedByValue, + }, + ServiceTags: []string{}, + }, + }, + }, + expectedAgentHealthChecks: []*api.AgentCheck{ + { + CheckID: "default/pod1-web/kubernetes-health-check", + ServiceName: "web", + ServiceID: "pod1-web", + Name: "Kubernetes Health Check", + Status: api.HealthPassing, + Output: kubernetesSuccessReasonMsg, + Type: ttl, + }, + { + CheckID: "default/pod1-web-admin/kubernetes-health-check", + ServiceName: "web-admin", + ServiceID: "pod1-web-admin", + Name: "Kubernetes Health Check", + Status: api.HealthPassing, + Output: kubernetesSuccessReasonMsg, + Type: ttl, + }, + }, + }, + } + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + // The agent pod needs to have the address 127.0.0.1 so when the + // code gets the agent pods via the label component=client, and + // makes requests against the agent API, it will actually hit the + // test server we have on localhost. + fakeClientPod := createPod("fake-consul-client", "127.0.0.1", false, true) + fakeClientPod.Labels = map[string]string{"component": "client", "app": "consul", "release": "consul"} + + // Add the default namespace. + ns := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "default"}} + // Create fake k8s client + k8sObjects := append(tt.k8sObjects(), fakeClientPod, &ns) + + fakeClient := fake.NewClientBuilder().WithRuntimeObjects(k8sObjects...).Build() + + // Create test consul server + consul, err := testutil.NewTestServerConfigT(t, func(c *testutil.TestServerConfig) { + c.NodeName = nodeName + }) + require.NoError(t, err) + defer consul.Stop() + consul.WaitForServiceIntentions(t) + + cfg := &api.Config{ + Address: consul.HTTPAddr, + } + consulClient, err := api.NewClient(cfg) + require.NoError(t, err) + addr := strings.Split(consul.HTTPAddr, ":") + consulPort := addr[1] + + // Register service and proxy in consul. + for _, svc := range tt.initialConsulSvcs { + err = consulClient.Agent().ServiceRegister(svc) + require.NoError(t, err) + } + + // Create the endpoints controller + ep := &EndpointsController{ + Client: fakeClient, + Log: logrtest.TestLogger{T: t}, + ConsulClient: consulClient, + ConsulPort: consulPort, + ConsulScheme: "http", + AllowK8sNamespacesSet: mapset.NewSetWith("*"), + DenyK8sNamespacesSet: mapset.NewSetWith(), + ReleaseName: "consul", + ReleaseNamespace: "default", + ConsulClientCfg: cfg, + } + namespacedName := types.NamespacedName{ + Namespace: "default", + Name: "web", + } + namespacedName2 := types.NamespacedName{ + Namespace: "default", + Name: "web-admin", + } + + resp, err := ep.Reconcile(context.Background(), ctrl.Request{ + NamespacedName: namespacedName, + }) + require.NoError(t, err) + require.False(t, resp.Requeue) + resp, err = ep.Reconcile(context.Background(), ctrl.Request{ + NamespacedName: namespacedName2, + }) + require.NoError(t, err) + require.False(t, resp.Requeue) + + // After reconciliation, Consul should have the service with the correct number of instances + svcs := strings.Split(tt.consulSvcName, ",") + for _, service := range svcs { + serviceInstances, _, err := consulClient.Catalog().Service(service, "", nil) + require.NoError(t, err) + require.Len(t, serviceInstances, tt.expectedNumSvcInstances) + for i, instance := range serviceInstances { + require.Equal(t, tt.expectedConsulSvcInstancesMap[service][i].ServiceID, instance.ServiceID) + require.Equal(t, tt.expectedConsulSvcInstancesMap[service][i].ServiceName, instance.ServiceName) + require.Equal(t, tt.expectedConsulSvcInstancesMap[service][i].ServiceAddress, instance.ServiceAddress) + require.Equal(t, tt.expectedConsulSvcInstancesMap[service][i].ServicePort, instance.ServicePort) + require.Equal(t, tt.expectedConsulSvcInstancesMap[service][i].ServiceMeta, instance.ServiceMeta) + require.Equal(t, tt.expectedConsulSvcInstancesMap[service][i].ServiceTags, instance.ServiceTags) + } + proxyServiceInstances, _, err := consulClient.Catalog().Service(fmt.Sprintf("%s-sidecar-proxy", service), "", nil) + require.NoError(t, err) + require.Len(t, proxyServiceInstances, tt.expectedNumSvcInstances) + for i, instance := range proxyServiceInstances { + require.Equal(t, tt.expectedProxySvcInstancesMap[service][i].ServiceID, instance.ServiceID) + require.Equal(t, tt.expectedProxySvcInstancesMap[service][i].ServiceName, instance.ServiceName) + require.Equal(t, tt.expectedProxySvcInstancesMap[service][i].ServiceAddress, instance.ServiceAddress) + require.Equal(t, tt.expectedProxySvcInstancesMap[service][i].ServicePort, instance.ServicePort) + require.Equal(t, tt.expectedProxySvcInstancesMap[service][i].ServiceMeta, instance.ServiceMeta) + require.Equal(t, tt.expectedProxySvcInstancesMap[service][i].ServiceTags, instance.ServiceTags) + + // When comparing the ServiceProxy field we ignore the DestinationNamespace + // field within that struct because on Consul OSS it's set to "" but on Consul Enterprise + // it's set to "default" and we want to re-use this test for both OSS and Ent. + // This does mean that we don't test that field but that's okay because + // it's not getting set specifically in this test. + // To do the comparison that ignores that field we use go-cmp instead + // of the regular require.Equal call since it supports ignoring certain + // fields. + diff := cmp.Diff(tt.expectedProxySvcInstancesMap[service][i].ServiceProxy, instance.ServiceProxy, + cmpopts.IgnoreFields(api.Upstream{}, "DestinationNamespace", "DestinationPartition")) + require.Empty(t, diff, "expected objects to be equal") + } + _, checkInfos, err := consulClient.Agent().AgentHealthServiceByName(fmt.Sprintf("%s-sidecar-proxy", service)) + expectedChecks := []string{"Proxy Public Listener", "Destination Alias"} + require.NoError(t, err) + require.Len(t, checkInfos, tt.expectedNumSvcInstances) + for _, checkInfo := range checkInfos { + checks := checkInfo.Checks + require.Contains(t, expectedChecks, checks[0].Name) + require.Contains(t, expectedChecks, checks[1].Name) + } + } + + // Check that the Consul health check was created for the k8s pod. + if tt.expectedAgentHealthChecks != nil { + for i := range tt.expectedAgentHealthChecks { + filter := fmt.Sprintf("CheckID == `%s`", tt.expectedAgentHealthChecks[i].CheckID) + check, err := consulClient.Agent().ChecksWithFilter(filter) + require.NoError(t, err) + require.EqualValues(t, len(check), 1) + // Ignoring Namespace because the response from ENT includes it and OSS does not. + var ignoredFields = []string{"Node", "Definition", "Namespace", "Partition"} + require.True(t, cmp.Equal(check[tt.expectedAgentHealthChecks[i].CheckID], tt.expectedAgentHealthChecks[i], cmpopts.IgnoreFields(api.AgentCheck{}, ignoredFields...))) + } + } + }) + } +} + // TestReconcileCreateEndpoint tests the logic to create service instances in Consul from the addresses in the Endpoints // object. The cases test an empty endpoints object, a basic endpoints object with one address, a basic endpoints object // with two addresses, and an endpoints object with every possible customization. diff --git a/control-plane/connect-inject/envoy_sidecar.go b/control-plane/connect-inject/envoy_sidecar.go index b521297c54..02d3869556 100644 --- a/control-plane/connect-inject/envoy_sidecar.go +++ b/control-plane/connect-inject/envoy_sidecar.go @@ -10,19 +10,25 @@ import ( "k8s.io/apimachinery/pkg/api/resource" ) -func (h *Handler) envoySidecar(namespace corev1.Namespace, pod corev1.Pod) (corev1.Container, error) { +func (h *Handler) envoySidecar(namespace corev1.Namespace, pod corev1.Pod, mpi multiPortInfo) (corev1.Container, error) { resources, err := h.envoySidecarResources(pod) if err != nil { return corev1.Container{}, err } - cmd, err := h.getContainerSidecarCommand(pod) + multiPort := mpi.serviceName != "" + cmd, err := h.getContainerSidecarCommand(pod, mpi.serviceName, mpi.serviceIndex) if err != nil { return corev1.Container{}, err } + containerName := envoySidecarContainer + if multiPort { + containerName = fmt.Sprintf("%s-%s", envoySidecarContainer, mpi.serviceName) + } + container := corev1.Container{ - Name: envoySidecarContainer, + Name: containerName, Image: h.ImageEnvoy, Env: []corev1.EnvVar{ { @@ -62,7 +68,7 @@ func (h *Handler) envoySidecar(namespace corev1.Namespace, pod corev1.Pod) (core // has only injected init containers so all containers defined in pod.Spec.Containers are from the user. for _, c := range pod.Spec.Containers { // User container and Envoy container cannot have the same UID. - if c.SecurityContext != nil && c.SecurityContext.RunAsUser != nil && *c.SecurityContext.RunAsUser == envoyUserAndGroupID { + if c.SecurityContext != nil && c.SecurityContext.RunAsUser != nil && *c.SecurityContext.RunAsUser == envoyUserAndGroupID && c.Image != h.ImageEnvoy { return corev1.Container{}, fmt.Errorf("container %q has runAsUser set to the same uid %q as envoy which is not allowed", c.Name, envoyUserAndGroupID) } } @@ -76,10 +82,18 @@ func (h *Handler) envoySidecar(namespace corev1.Namespace, pod corev1.Pod) (core return container, nil } -func (h *Handler) getContainerSidecarCommand(pod corev1.Pod) ([]string, error) { +func (h *Handler) getContainerSidecarCommand(pod corev1.Pod, multiPortSvcName string, multiPortSvcIdx int) ([]string, error) { + bootstrapFile := "/consul/connect-inject/envoy-bootstrap.yaml" + if multiPortSvcName != "" { + bootstrapFile = fmt.Sprintf("/consul/connect-inject/envoy-bootstrap-%s.yaml", multiPortSvcName) + } cmd := []string{ "envoy", - "--config-path", "/consul/connect-inject/envoy-bootstrap.yaml", + "--config-path", bootstrapFile, + } + if multiPortSvcName != "" { + // --base-id is needed so multiple Envoy proxies can run on the same host. + cmd = append(cmd, "--base-id", fmt.Sprintf("%d", multiPortSvcIdx)) } extraArgs, annotationSet := pod.Annotations[annotationEnvoyExtraArgs] diff --git a/control-plane/connect-inject/envoy_sidecar_test.go b/control-plane/connect-inject/envoy_sidecar_test.go index 269581c4b8..56af91ab3e 100644 --- a/control-plane/connect-inject/envoy_sidecar_test.go +++ b/control-plane/connect-inject/envoy_sidecar_test.go @@ -28,7 +28,7 @@ func TestHandlerEnvoySidecar(t *testing.T) { }, }, } - container, err := h.envoySidecar(testNS, pod) + container, err := h.envoySidecar(testNS, pod, multiPortInfo{}) require.NoError(err) require.Equal(container.Command, []string{ "envoy", @@ -43,6 +43,55 @@ func TestHandlerEnvoySidecar(t *testing.T) { }) } +func TestHandlerEnvoySidecar_Multiport(t *testing.T) { + require := require.New(t) + h := Handler{} + pod := corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + annotationService: "web,web-admin", + }, + }, + + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "web", + }, + { + Name: "web-admin", + }, + }, + }, + } + multiPortInfos := []multiPortInfo{ + { + serviceIndex: 0, + serviceName: "web", + }, + { + serviceIndex: 1, + serviceName: "web-admin", + }, + } + expCommand := map[int][]string{ + 0: {"envoy", "--config-path", "/consul/connect-inject/envoy-bootstrap-web.yaml", "--base-id", "0"}, + 1: {"envoy", "--config-path", "/consul/connect-inject/envoy-bootstrap-web-admin.yaml", "--base-id", "1"}, + } + for i := 0; i < 2; i++ { + container, err := h.envoySidecar(testNS, pod, multiPortInfos[i]) + require.NoError(err) + require.Equal(expCommand[i], container.Command) + + require.Equal(container.VolumeMounts, []corev1.VolumeMount{ + { + Name: volumeName, + MountPath: "/consul/connect-inject", + }, + }) + } +} + func TestHandlerEnvoySidecar_withSecurityContext(t *testing.T) { cases := map[string]struct { tproxyEnabled bool @@ -106,7 +155,7 @@ func TestHandlerEnvoySidecar_withSecurityContext(t *testing.T) { }, }, } - ec, err := h.envoySidecar(testNS, pod) + ec, err := h.envoySidecar(testNS, pod, multiPortInfo{}) require.NoError(t, err) require.Equal(t, c.expSecurityContext, ec.SecurityContext) }) @@ -130,37 +179,88 @@ func TestHandlerEnvoySidecar_FailsWithDuplicatePodSecurityContextUID(t *testing. }, }, } - _, err := h.envoySidecar(testNS, pod) + _, err := h.envoySidecar(testNS, pod, multiPortInfo{}) require.Error(err, fmt.Sprintf("pod security context cannot have the same uid as envoy: %v", envoyUserAndGroupID)) } -// Test that if the user specifies a container with security context with the same uid as `envoyUserAndGroupID` -// that we return an error to the handler. +// Test that if the user specifies a container with security context with the same uid as `envoyUserAndGroupID` that we +// return an error to the handler. If a container using the envoy image has the same uid, we don't return an error +// because in multiport pod there can be multiple envoy sidecars. func TestHandlerEnvoySidecar_FailsWithDuplicateContainerSecurityContextUID(t *testing.T) { - require := require.New(t) - h := Handler{} - pod := corev1.Pod{ - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: "web", - // Setting RunAsUser: 1 should succeed. - SecurityContext: &corev1.SecurityContext{ - RunAsUser: pointerToInt64(1), + cases := []struct { + name string + pod corev1.Pod + handler Handler + expErr bool + expErrMessage error + }{ + { + name: "fails with non envoy image", + pod: corev1.Pod{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "web", + // Setting RunAsUser: 1 should succeed. + SecurityContext: &corev1.SecurityContext{ + RunAsUser: pointerToInt64(1), + }, + }, + { + Name: "app", + // Setting RunAsUser: 5995 should fail. + SecurityContext: &corev1.SecurityContext{ + RunAsUser: pointerToInt64(envoyUserAndGroupID), + }, + Image: "not-envoy", + }, }, }, - { - Name: "app", - // Setting RunAsUser: 5995 should fail. - SecurityContext: &corev1.SecurityContext{ - RunAsUser: pointerToInt64(envoyUserAndGroupID), + }, + handler: Handler{}, + expErr: true, + expErrMessage: fmt.Errorf("container app has runAsUser set to the same uid %q as envoy which is not allowed", envoyUserAndGroupID), + }, + { + name: "doesn't fail with envoy image", + pod: corev1.Pod{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "web", + // Setting RunAsUser: 1 should succeed. + SecurityContext: &corev1.SecurityContext{ + RunAsUser: pointerToInt64(1), + }, + }, + { + Name: "sidecar", + // Setting RunAsUser: 5995 should succeed if the image matches h.ImageEnvoy. + SecurityContext: &corev1.SecurityContext{ + RunAsUser: pointerToInt64(envoyUserAndGroupID), + }, + Image: "envoy", + }, }, }, }, + handler: Handler{ + ImageEnvoy: "envoy", + }, + expErr: false, }, } - _, err := h.envoySidecar(testNS, pod) - require.Error(err, fmt.Sprintf("container %q has runAsUser set to the same uid %q as envoy which is not allowed", pod.Spec.Containers[1].Name, envoyUserAndGroupID)) + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + _, err := tc.handler.envoySidecar(testNS, tc.pod, multiPortInfo{}) + if tc.expErr { + require.Error(t, err, tc.expErrMessage) + } else { + require.NoError(t, err) + } + }) + } } // Test that we can pass extra args to envoy via the extraEnvoyArgs flag @@ -247,7 +347,7 @@ func TestHandlerEnvoySidecar_EnvoyExtraArgs(t *testing.T) { EnvoyExtraArgs: tc.envoyExtraArgs, } - c, err := h.envoySidecar(testNS, *tc.pod) + c, err := h.envoySidecar(testNS, *tc.pod, multiPortInfo{}) require.NoError(t, err) require.Equal(t, tc.expectedContainerCommand, c.Command) }) @@ -421,7 +521,7 @@ func TestHandlerEnvoySidecar_Resources(t *testing.T) { }, }, } - container, err := c.handler.envoySidecar(testNS, pod) + container, err := c.handler.envoySidecar(testNS, pod, multiPortInfo{}) if c.expErr != "" { require.NotNil(err) require.Contains(err.Error(), c.expErr) diff --git a/control-plane/connect-inject/handler.go b/control-plane/connect-inject/handler.go index 8e7eb48a63..6e454557c0 100644 --- a/control-plane/connect-inject/handler.go +++ b/control-plane/connect-inject/handler.go @@ -6,7 +6,9 @@ import ( "errors" "fmt" "net/http" + "path/filepath" "strconv" + "strings" mapset "github.com/deckarep/golang-set" "github.com/go-logr/logr" @@ -155,6 +157,10 @@ type Handler struct { decoder *admission.Decoder } +type multiPortInfo struct { + serviceIndex int + serviceName string +} // Handle is the admission.Handler implementation that actually handles the // webhook request for admission control. This should be registered or @@ -225,21 +231,91 @@ func (h *Handler) Handle(ctx context.Context, req admission.Request) admission.R return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error getting namespace metadata for container: %s", err)) } - // Add the init container that listens for the service and proxy service and sets up the Envoy configuration. - initContainer, err := h.containerInit(*ns, pod) - if err != nil { - h.Log.Error(err, "error configuring injection init container", "request name", req.Name) - return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error configuring injection init container: %s", err)) - } - pod.Spec.InitContainers = append(pod.Spec.InitContainers, initContainer) + // Get service names from the annotation. If theres 0-1 service names, it's a single port pod, otherwise it's multi + // port. + annotatedSvcNames := h.annotatedServiceNames(pod) + multiPort := len(annotatedSvcNames) > 1 - // Add the Envoy sidecar. - envoySidecar, err := h.envoySidecar(*ns, pod) - if err != nil { - h.Log.Error(err, "error configuring injection sidecar container", "request name", req.Name) - return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error configuring injection sidecar container: %s", err)) + // For single port pods, add the single init container and envoy sidecar. + if !multiPort { + // Add the init container that registers the service and sets up the Envoy configuration. + initContainer, err := h.containerInit(*ns, pod, multiPortInfo{}) + if err != nil { + h.Log.Error(err, "error configuring injection init container", "request name", req.Name) + return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error configuring injection init container: %s", err)) + } + pod.Spec.InitContainers = append(pod.Spec.InitContainers, initContainer) + + // Add the Envoy sidecar. + envoySidecar, err := h.envoySidecar(*ns, pod, multiPortInfo{}) + if err != nil { + h.Log.Error(err, "error configuring injection sidecar container", "request name", req.Name) + return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error configuring injection sidecar container: %s", err)) + } + pod.Spec.Containers = append(pod.Spec.Containers, envoySidecar) + } else { + // For multi port pods, check for unsupported cases, mount all relevant service account tokens, and mount an init + // container and envoy sidecar per port. Tproxy, metrics, and metrics merging are not supported for multi port pods. + // In a single port pod, the service account specified in the pod is sufficient for mounting the service account + // token to the pod. In a multi port pod, where multiple services are registered with Consul, we also require a + // service account per service. So, this will look for service accounts whose name matches the service and mount + // those tokens if not already specified via the pod's serviceAccountName. + + h.Log.Info("processing multiport pod") + err := h.checkUnsupportedMultiPortCases(*ns, pod) + if err != nil { + h.Log.Error(err, "checking unsupported cases for multi port pods") + return admission.Errored(http.StatusInternalServerError, err) + } + for i, svc := range annotatedSvcNames { + h.Log.Info(fmt.Sprintf("service: %s", svc)) + if h.AuthMethod != "" { + if svc != "" && pod.Spec.ServiceAccountName != svc { + sa, err := h.Clientset.CoreV1().ServiceAccounts(req.Namespace).Get(ctx, svc, metav1.GetOptions{}) + if err != nil { + h.Log.Error(err, "couldn't get service accounts") + return admission.Errored(http.StatusInternalServerError, err) + } + if len(sa.Secrets) == 0 { + h.Log.Info(fmt.Sprintf("service account %s has zero secrets exp at least 1", svc)) + return admission.Errored(http.StatusInternalServerError, fmt.Errorf("service account %s has zero secrets, expected at least one", svc)) + } + saSecret := sa.Secrets[0].Name + h.Log.Info("found service account, mounting service account secret to Pod", "serviceAccountName", sa.Name) + pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{ + Name: fmt.Sprintf("%s-service-account", svc), + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: saSecret, + }, + }, + }) + } + } + + // This will get passed to the init and sidecar containers so they are configured correctly. + mpi := multiPortInfo{ + serviceIndex: i, + serviceName: svc, + } + + // Add the init container that registers the service and sets up the Envoy configuration. + initContainer, err := h.containerInit(*ns, pod, mpi) + if err != nil { + h.Log.Error(err, "error configuring injection init container", "request name", req.Name) + return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error configuring injection init container: %s", err)) + } + pod.Spec.InitContainers = append(pod.Spec.InitContainers, initContainer) + + // Add the Envoy sidecar. + envoySidecar, err := h.envoySidecar(*ns, pod, mpi) + if err != nil { + h.Log.Error(err, "error configuring injection sidecar container", "request name", req.Name) + return admission.Errored(http.StatusInternalServerError, fmt.Errorf("error configuring injection sidecar container: %s", err)) + } + pod.Spec.Containers = append(pod.Spec.Containers, envoySidecar) + } } - pod.Spec.Containers = append(pod.Spec.Containers, envoySidecar) // Now that the consul-sidecar no longer needs to re-register services periodically // (that functionality lives in the endpoints-controller), @@ -460,6 +536,7 @@ func (h *Handler) validatePod(pod corev1.Pod) error { } func portValue(pod corev1.Pod, value string) (int32, error) { + value = strings.Split(value, ",")[0] // First search for the named port. for _, c := range pod.Spec.Containers { for _, p := range c.Ports { @@ -474,7 +551,23 @@ func portValue(pod corev1.Pod, value string) (int32, error) { return int32(raw), err } -func findServiceAccountVolumeMount(pod corev1.Pod) (corev1.VolumeMount, error) { +func findServiceAccountVolumeMount(pod corev1.Pod, multiPort bool, multiPortSvcName string) (corev1.VolumeMount, string, error) { + // In the case of a multiPort pod, there may be another service account + // token mounted as a different volume. Its name must be -serviceaccount. + // If not we'll fall back to the service account for the pod. + if multiPort { + for _, v := range pod.Spec.Volumes { + if v.Name == fmt.Sprintf("%s-service-account", multiPortSvcName) { + mountPath := fmt.Sprintf("/consul/serviceaccount-%s", multiPortSvcName) + return corev1.VolumeMount{ + Name: v.Name, + ReadOnly: true, + MountPath: mountPath, + }, filepath.Join(mountPath, "token"), nil + } + } + } + // Find the volume mount that is mounted at the known // service account token location var volumeMount corev1.VolumeMount @@ -489,10 +582,43 @@ func findServiceAccountVolumeMount(pod corev1.Pod) (corev1.VolumeMount, error) { // Return an error if volumeMount is still empty if (corev1.VolumeMount{}) == volumeMount { - return volumeMount, errors.New("unable to find service account token volumeMount") + return volumeMount, "", errors.New("unable to find service account token volumeMount") + } + + return volumeMount, "/var/run/secrets/kubernetes.io/serviceaccount/token", nil +} + +func (h *Handler) annotatedServiceNames(pod corev1.Pod) []string { + var annotatedSvcNames []string + if anno, ok := pod.Annotations[annotationService]; ok { + annotatedSvcNames = strings.Split(anno, ",") } + return annotatedSvcNames +} - return volumeMount, nil +func (h *Handler) checkUnsupportedMultiPortCases(ns corev1.Namespace, pod corev1.Pod) error { + tproxyEnabled, err := transparentProxyEnabled(ns, pod, h.EnableTransparentProxy) + if err != nil { + return fmt.Errorf("couldn't check if tproxy is enabled: %s", err) + } + metricsEnabled, err := h.MetricsConfig.enableMetrics(pod) + if err != nil { + return fmt.Errorf("couldn't check if metrics is enabled: %s", err) + } + metricsMergingEnabled, err := h.MetricsConfig.enableMetricsMerging(pod) + if err != nil { + return fmt.Errorf("couldn't check if metrics merging is enabled: %s", err) + } + if tproxyEnabled { + return fmt.Errorf("multi port services are not compatible with transparent proxy") + } + if metricsEnabled { + return fmt.Errorf("multi port services are not compatible with metrics") + } + if metricsMergingEnabled { + return fmt.Errorf("multi port services are not compatible with metrics merging") + } + return nil } func (h *Handler) InjectDecoder(d *admission.Decoder) error { diff --git a/control-plane/connect-inject/handler_test.go b/control-plane/connect-inject/handler_test.go index 8f34ecea71..cd77de66f4 100644 --- a/control-plane/connect-inject/handler_test.go +++ b/control-plane/connect-inject/handler_test.go @@ -525,6 +525,60 @@ func TestHandlerHandle(t *testing.T) { }, }, }, + { + "multi port pod", + Handler{ + Log: logrtest.TestLogger{T: t}, + AllowK8sNamespacesSet: mapset.NewSetWith("*"), + DenyK8sNamespacesSet: mapset.NewSet(), + decoder: decoder, + Clientset: defaultTestClientWithNamespace(), + }, + admission.Request{ + AdmissionRequest: admissionv1.AdmissionRequest{ + Namespace: namespaces.DefaultNamespace, + Object: encodeRaw(t, &corev1.Pod{ + Spec: basicSpec, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + annotationService: "web, web-admin", + }, + }, + }), + }, + }, + "", + []jsonpatch.Operation{ + { + Operation: "add", + Path: "/spec/volumes", + }, + { + Operation: "add", + Path: "/spec/initContainers", + }, + { + Operation: "add", + Path: "/spec/containers/1", + }, + { + Operation: "add", + Path: "/spec/containers/2", + }, + { + Operation: "add", + Path: "/metadata/annotations/" + escapeJSONPointer(keyInjectStatus), + }, + { + Operation: "add", + Path: "/metadata/annotations/" + escapeJSONPointer(annotationOriginalPod), + }, + { + Operation: "add", + Path: "/metadata/labels", + }, + }, + }, } for _, tt := range cases { @@ -1612,6 +1666,42 @@ func TestOverwriteProbes(t *testing.T) { } } +func TestHandler_checkUnsupportedMultiPortCases(t *testing.T) { + cases := []struct { + name string + annotations map[string]string + expErr string + }{ + { + name: "tproxy", + annotations: map[string]string{keyTransparentProxy: "true"}, + expErr: "multi port services are not compatible with transparent proxy", + }, + { + name: "metrics", + annotations: map[string]string{annotationEnableMetrics: "true"}, + expErr: "multi port services are not compatible with metrics", + }, + { + name: "metrics merging", + annotations: map[string]string{annotationEnableMetricsMerging: "true"}, + expErr: "multi port services are not compatible with metrics merging", + }, + } + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + h := Handler{} + pod := minimal() + pod.Annotations = tt.annotations + err := h.checkUnsupportedMultiPortCases(corev1.Namespace{}, *pod) + require.Error(t, err) + require.Equal(t, tt.expErr, err.Error()) + }) + + } + +} + // encodeRaw is a helper to encode some data into a RawExtension. func encodeRaw(t *testing.T, input interface{}) runtime.RawExtension { data, err := json.Marshal(input) diff --git a/control-plane/subcommand/connect-init/command.go b/control-plane/subcommand/connect-init/command.go index 3d30710107..01a23e9c2c 100644 --- a/control-plane/subcommand/connect-init/command.go +++ b/control-plane/subcommand/connect-init/command.go @@ -44,9 +44,10 @@ type Command struct { flagLogLevel string flagLogJSON bool - bearerTokenFile string // Location of the bearer token. Default is /var/run/secrets/kubernetes.io/serviceaccount/token. - tokenSinkFile string // Location to write the output token. Default is defaultTokenSinkFile. - proxyIDFile string // Location to write the output proxyID. Default is defaultProxyIDFile. + flagBearerTokenFile string // Location of the bearer token. Default is /var/run/secrets/kubernetes.io/serviceaccount/token. + flagACLTokenSink string // Location to write the output token. Default is defaultTokenSinkFile. + flagProxyIDFile string // Location to write the output proxyID. Default is defaultProxyIDFile. + flagMultiPort bool serviceRegistrationPollingAttempts uint64 // Number of times to poll for this service to be registered. flagSet *flag.FlagSet @@ -66,21 +67,16 @@ func (c *Command) init() { c.flagSet.StringVar(&c.flagConsulServiceNamespace, "consul-service-namespace", "", "Consul destination namespace of the service.") c.flagSet.StringVar(&c.flagServiceAccountName, "service-account-name", "", "Service account name on the pod.") c.flagSet.StringVar(&c.flagServiceName, "service-name", "", "Service name as specified via the pod annotation.") + c.flagSet.StringVar(&c.flagBearerTokenFile, "bearer-token-file", defaultBearerTokenFile, "Path to service account token file.") + c.flagSet.StringVar(&c.flagACLTokenSink, "acl-token-sink", defaultTokenSinkFile, "File name where where ACL token should be saved.") + c.flagSet.StringVar(&c.flagProxyIDFile, "proxy-id-file", defaultProxyIDFile, "File name where proxy's Consul service ID should be saved.") + c.flagSet.BoolVar(&c.flagMultiPort, "multiport", false, "If the pod is a multi port pod.") c.flagSet.StringVar(&c.flagLogLevel, "log-level", "info", "Log verbosity level. Supported values (in order of detail) are \"trace\", "+ "\"debug\", \"info\", \"warn\", and \"error\".") c.flagSet.BoolVar(&c.flagLogJSON, "log-json", false, "Enable or disable JSON output format for logging.") - if c.bearerTokenFile == "" { - c.bearerTokenFile = defaultBearerTokenFile - } - if c.tokenSinkFile == "" { - c.tokenSinkFile = defaultTokenSinkFile - } - if c.proxyIDFile == "" { - c.proxyIDFile = defaultProxyIDFile - } if c.serviceRegistrationPollingAttempts == 0 { c.serviceRegistrationPollingAttempts = defaultServicePollingRetries } @@ -134,7 +130,7 @@ func (c *Command) Run(args []string) int { // loginMeta is the default metadata that we pass to the consul login API. loginMeta := map[string]string{"pod": fmt.Sprintf("%s/%s", c.flagPodNamespace, c.flagPodName)} err = backoff.Retry(func() error { - err := common.ConsulLogin(consulClient, c.bearerTokenFile, c.flagACLAuthMethod, c.tokenSinkFile, c.flagAuthMethodNamespace, loginMeta) + err := common.ConsulLogin(consulClient, c.flagBearerTokenFile, c.flagACLAuthMethod, c.flagACLTokenSink, c.flagAuthMethodNamespace, loginMeta) if err != nil { c.logger.Error("Consul login failed; retrying", "error", err) } @@ -151,7 +147,7 @@ func (c *Command) Run(args []string) int { return 1 } // Now update the client so that it will read the ACL token we just fetched. - cfg.TokenFile = c.tokenSinkFile + cfg.TokenFile = c.flagACLTokenSink consulClient, err = consul.NewClient(cfg) if err != nil { c.logger.Error("Unable to update client connection", "error", err) @@ -210,7 +206,13 @@ func (c *Command) Run(args []string) int { var errServiceNameMismatch error err = backoff.Retry(func() error { registrationRetryCount++ - filter := fmt.Sprintf("Meta[%q] == %q and Meta[%q] == %q", connectinject.MetaKeyPodName, c.flagPodName, connectinject.MetaKeyKubeNS, c.flagPodNamespace) + filter := fmt.Sprintf("Meta[%q] == %q and Meta[%q] == %q ", + connectinject.MetaKeyPodName, c.flagPodName, connectinject.MetaKeyKubeNS, c.flagPodNamespace) + if c.flagMultiPort && c.flagServiceName != "" { + // If the service name is set and this is a multi-port pod there may be multiple services registered for + // this one Pod. If so, we want to ensure the service and proxy matching our expected name is registered. + filter += fmt.Sprintf(` and (Service == %q or Service == "%s-sidecar-proxy")`, c.flagServiceName, c.flagServiceName) + } serviceList, err := consulClient.Agent().ServicesWithFilter(filter) if err != nil { c.logger.Error("Unable to get Agent services", "error", err) @@ -231,7 +233,7 @@ func (c *Command) Run(args []string) int { " `consul.hashicorp.com/service-ignore: \"true\"` to all services except the one used by Consul for handling requests.") } - return fmt.Errorf("did not find correct number of services: %d", len(serviceList)) + return fmt.Errorf("did not find correct number of services, found: %d, services: %+v", len(serviceList), serviceList) } for _, svc := range serviceList { c.logger.Info("Registered service has been detected", "service", svc.Service) @@ -271,7 +273,7 @@ func (c *Command) Run(args []string) int { return 1 } // Write the proxy ID to the shared volume so `consul connect envoy` can use it for bootstrapping. - err = common.WriteFileWithPerms(c.proxyIDFile, proxyID, os.FileMode(0444)) + err = common.WriteFileWithPerms(c.flagProxyIDFile, proxyID, os.FileMode(0444)) if err != nil { c.logger.Error("Unable to write proxy ID to file", "error", err) return 1 diff --git a/control-plane/subcommand/connect-init/command_ent_test.go b/control-plane/subcommand/connect-init/command_ent_test.go index f043542d83..891ee2ed32 100644 --- a/control-plane/subcommand/connect-init/command_ent_test.go +++ b/control-plane/subcommand/connect-init/command_ent_test.go @@ -184,9 +184,6 @@ func TestRun_ServicePollingWithACLsAndTLSWithNamespaces(t *testing.T) { ui := cli.NewMockUi() cmd := Command{ UI: ui, - bearerTokenFile: bearerFile, - tokenSinkFile: tokenFile, - proxyIDFile: proxyFile, serviceRegistrationPollingAttempts: 5, } // We build the http-addr because normally it's defined by the init container setting @@ -196,6 +193,9 @@ func TestRun_ServicePollingWithACLsAndTLSWithNamespaces(t *testing.T) { "-service-account-name", testServiceAccountName, "-http-addr", fmt.Sprintf("%s://%s", cfg.Scheme, cfg.Address), "-consul-service-namespace", c.consulServiceNamespace, + "-acl-token-sink", tokenFile, + "-bearer-token-file", bearerFile, + "-proxy-id-file", proxyFile, } if c.acls { flags = append(flags, "-acl-auth-method", test.AuthMethod, "-auth-method-namespace", c.authMethodNamespace) diff --git a/control-plane/subcommand/connect-init/command_test.go b/control-plane/subcommand/connect-init/command_test.go index 40136b9fd8..7965a5ea30 100644 --- a/control-plane/subcommand/connect-init/command_test.go +++ b/control-plane/subcommand/connect-init/command_test.go @@ -8,6 +8,7 @@ import ( "net/http/httptest" "net/url" "os" + "strconv" "testing" "time" @@ -68,6 +69,7 @@ func TestRun_ServicePollingWithACLsAndTLS(t *testing.T) { includeServiceAccountName bool serviceAccountNameMismatch bool expFail bool + multiport bool }{ { name: "ACLs enabled, no tls", @@ -91,6 +93,13 @@ func TestRun_ServicePollingWithACLsAndTLS(t *testing.T) { serviceAccountName: "web", serviceName: "web", }, + { + name: "ACLs enabled, multiport service", + tls: false, + serviceAccountName: "counting-admin", + serviceName: "counting-admin", + multiport: true, + }, { name: "ACLs enabled, service name annotation doesn't match service account name", tls: false, @@ -152,6 +161,9 @@ func TestRun_ServicePollingWithACLsAndTLS(t *testing.T) { // Register Consul services. testConsulServices := []api.AgentServiceRegistration{consulCountingSvc, consulCountingSvcSidecar} + if tt.multiport { + testConsulServices = append(testConsulServices, consulCountingSvcMultiport, consulCountingSvcSidecarMultiport) + } for _, svc := range testConsulServices { require.NoError(t, consulClient.Agent().ServiceRegister(&svc)) } @@ -159,9 +171,6 @@ func TestRun_ServicePollingWithACLsAndTLS(t *testing.T) { ui := cli.NewMockUi() cmd := Command{ UI: ui, - bearerTokenFile: bearerFile, - tokenSinkFile: tokenFile, - proxyIDFile: proxyFile, serviceRegistrationPollingAttempts: 3, } @@ -173,6 +182,10 @@ func TestRun_ServicePollingWithACLsAndTLS(t *testing.T) { "-service-account-name", tt.serviceAccountName, "-service-name", tt.serviceName, "-http-addr", fmt.Sprintf("%s://%s", cfg.Scheme, cfg.Address), + "-bearer-token-file", bearerFile, + "-acl-token-sink", tokenFile, + "-proxy-id-file", proxyFile, + "-multiport=" + strconv.FormatBool(tt.multiport), } // Add the CA File if necessary since we're not setting CONSUL_CACERT in tt ENV. if tt.tls { @@ -201,7 +214,11 @@ func TestRun_ServicePollingWithACLsAndTLS(t *testing.T) { // Validate contents of proxyFile. data, err := ioutil.ReadFile(proxyFile) require.NoError(t, err) - require.Contains(t, string(data), "counting-counting-sidecar-proxy") + if tt.multiport { + require.Contains(t, string(data), "counting-admin-sidecar-proxy-id") + } else { + require.Contains(t, string(data), "counting-counting-sidecar-proxy") + } }) } } @@ -210,8 +227,10 @@ func TestRun_ServicePollingWithACLsAndTLS(t *testing.T) { func TestRun_ServicePollingOnly(t *testing.T) { t.Parallel() cases := []struct { - name string - tls bool + name string + tls bool + serviceName string + multiport bool }{ { name: "ACLs disabled, no tls", @@ -221,6 +240,12 @@ func TestRun_ServicePollingOnly(t *testing.T) { name: "ACLs disabled, tls", tls: true, }, + { + name: "Multiport, ACLs disabled, no tls", + tls: false, + serviceName: "counting-admin", + multiport: true, + }, } for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { @@ -260,6 +285,9 @@ func TestRun_ServicePollingOnly(t *testing.T) { // Register Consul services. testConsulServices := []api.AgentServiceRegistration{consulCountingSvc, consulCountingSvcSidecar} + if tt.multiport { + testConsulServices = append(testConsulServices, consulCountingSvcMultiport, consulCountingSvcSidecarMultiport) + } for _, svc := range testConsulServices { require.NoError(t, consulClient.Agent().ServiceRegister(&svc)) } @@ -267,7 +295,6 @@ func TestRun_ServicePollingOnly(t *testing.T) { ui := cli.NewMockUi() cmd := Command{ UI: ui, - proxyIDFile: proxyFile, serviceRegistrationPollingAttempts: 3, } // We build the http-addr because normally it's defined by the init container setting @@ -275,7 +302,15 @@ func TestRun_ServicePollingOnly(t *testing.T) { flags := []string{ "-pod-name", testPodName, "-pod-namespace", testPodNamespace, + "-proxy-id-file", proxyFile, + "-multiport=" + strconv.FormatBool(tt.multiport), "-http-addr", fmt.Sprintf("%s://%s", cfg.Scheme, cfg.Address)} + + // In a multiport case, the service name will be passed in to the test. + if tt.serviceName != "" { + flags = append(flags, "-service-name", tt.serviceName) + } + // Add the CA File if necessary since we're not setting CONSUL_CACERT in tt ENV. if tt.tls { flags = append(flags, "-ca-file", caFile) @@ -288,7 +323,11 @@ func TestRun_ServicePollingOnly(t *testing.T) { // Validate contents of proxyFile. data, err := ioutil.ReadFile(proxyFile) require.NoError(t, err) - require.Contains(t, string(data), "counting-counting-sidecar-proxy") + if tt.multiport { + require.Contains(t, string(data), "counting-admin-sidecar-proxy-id") + } else { + require.Contains(t, string(data), "counting-counting-sidecar-proxy") + } }) } @@ -460,13 +499,13 @@ func TestRun_ServicePollingErrors(t *testing.T) { ui := cli.NewMockUi() cmd := Command{ UI: ui, - proxyIDFile: proxyFile, serviceRegistrationPollingAttempts: 1, } flags := []string{ "-http-addr", server.HTTPAddr, "-pod-name", testPodName, "-pod-namespace", testPodNamespace, + "-proxy-id-file", proxyFile, } code := cmd.Run(flags) @@ -504,13 +543,13 @@ func TestRun_RetryServicePolling(t *testing.T) { ui := cli.NewMockUi() cmd := Command{ UI: ui, - proxyIDFile: proxyFile, serviceRegistrationPollingAttempts: 10, } flags := []string{ "-pod-name", testPodName, "-pod-namespace", testPodNamespace, "-http-addr", server.HTTPAddr, + "-proxy-id-file", proxyFile, } code := cmd.Run(flags) require.Equal(t, 0, code) @@ -544,13 +583,13 @@ func TestRun_InvalidProxyFile(t *testing.T) { ui := cli.NewMockUi() cmd := Command{ UI: ui, - proxyIDFile: randFileName, serviceRegistrationPollingAttempts: 3, } flags := []string{ "-pod-name", testPodName, "-pod-namespace", testPodNamespace, "-http-addr", server.HTTPAddr, + "-proxy-id-file", randFileName, } code := cmd.Run(flags) require.Equal(t, 1, code) @@ -608,8 +647,8 @@ func TestRun_FailsWithBadServerResponses(t *testing.T) { ui := cli.NewMockUi() cmd := Command{ UI: ui, - bearerTokenFile: bearerFile, - tokenSinkFile: tokenFile, + flagBearerTokenFile: bearerFile, + flagACLTokenSink: tokenFile, serviceRegistrationPollingAttempts: uint64(servicesGetRetries), } @@ -619,6 +658,8 @@ func TestRun_FailsWithBadServerResponses(t *testing.T) { "-pod-name", testPodName, "-pod-namespace", testPodNamespace, "-acl-auth-method", test.AuthMethod, "-service-account-name", testServiceAccountName, + "-bearer-token-file", bearerFile, + "-acl-token-sink", tokenFile, "-http-addr", serverURL.String()} code := cmd.Run(flags) require.Equal(t, 1, code) @@ -683,16 +724,16 @@ func TestRun_LoginWithRetries(t *testing.T) { ui := cli.NewMockUi() cmd := Command{ - UI: ui, - tokenSinkFile: tokenFile, - bearerTokenFile: bearerFile, - proxyIDFile: proxyFile, + UI: ui, } code := cmd.Run([]string{ "-pod-name", testPodName, "-pod-namespace", testPodNamespace, "-acl-auth-method", test.AuthMethod, "-service-account-name", testServiceAccountName, + "-acl-token-sink", tokenFile, + "-bearer-token-file", bearerFile, + "-proxy-id-file", proxyFile, "-http-addr", serverURL.String()}) fmt.Println(ui.ErrorWriter.String()) require.Equal(t, c.ExpCode, code) @@ -762,16 +803,16 @@ func TestRun_EnsureTokenExists(t *testing.T) { ui := cli.NewMockUi() cmd := Command{ - UI: ui, - tokenSinkFile: tokenFile, - bearerTokenFile: bearerFile, - proxyIDFile: proxyFile, + UI: ui, } code := cmd.Run([]string{ "-pod-name", testPodName, "-pod-namespace", testPodNamespace, "-acl-auth-method", test.AuthMethod, "-service-account-name", testServiceAccountName, + "-acl-token-sink", tokenFile, + "-bearer-token-file", bearerFile, + "-proxy-id-file", proxyFile, "-http-addr", serverURL.String()}) if c.neverSucceed { require.Equal(t, 1, code) @@ -937,4 +978,32 @@ var ( metaKeyKubeServiceName: "counting", }, } + consulCountingSvcMultiport = api.AgentServiceRegistration{ + ID: "counting-admin-id", + Name: "counting-admin", + Address: "127.0.0.1", + Meta: map[string]string{ + metaKeyPodName: "counting-pod", + metaKeyKubeNS: "default-ns", + metaKeyKubeServiceName: "counting-admin", + }, + } + consulCountingSvcSidecarMultiport = api.AgentServiceRegistration{ + ID: "counting-admin-sidecar-proxy-id", + Name: "counting-admin-sidecar-proxy", + Kind: "connect-proxy", + Proxy: &api.AgentServiceConnectProxyConfig{ + DestinationServiceName: "counting-admin", + DestinationServiceID: "counting-admin-id", + Config: nil, + Upstreams: nil, + }, + Port: 9999, + Address: "127.0.0.1", + Meta: map[string]string{ + metaKeyPodName: "counting-pod", + metaKeyKubeNS: "default-ns", + metaKeyKubeServiceName: "counting-admin", + }, + } ) From ba330553bff5b33d159a036166535b49ee735664 Mon Sep 17 00:00:00 2001 From: Jeff-Apple <79924108+Jeff-Apple@users.noreply.github.com> Date: Tue, 22 Feb 2022 09:55:13 -0800 Subject: [PATCH 276/418] Update charts/consul/values.yaml Co-authored-by: Iryna Shustava --- charts/consul/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 986676fe5b..3e849b6ef9 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -2552,7 +2552,7 @@ apiGateway: # @type: string service: null - # [Enterprise Only] These settings manage the api gateway's interaction with + # [Enterprise Only] These settings manage the API Gateway's interaction with # Consul namespaces (requires consul-ent v1.7+). # Also, `global.enableConsulNamespaces` must be true. consulNamespaces: From dcac9ab20dce49d6944fd2c7b56e8c12624e1f65 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 22 Feb 2022 11:35:48 -0700 Subject: [PATCH 277/418] Allow configuring primary DC and gateways via designated Helm values (#1038) --- acceptance/framework/config/config.go | 8 ++-- acceptance/framework/config/config_test.go | 5 ++- acceptance/tests/vault/vault_wan_fed_test.go | 6 +-- .../templates/server-config-configmap.yaml | 7 ++++ .../test/unit/server-config-configmap.bats | 38 +++++++++++++++++++ charts/consul/values.yaml | 8 ++++ 6 files changed, 64 insertions(+), 8 deletions(-) diff --git a/acceptance/framework/config/config.go b/acceptance/framework/config/config.go index 7834b1adb7..c89947aa9b 100644 --- a/acceptance/framework/config/config.go +++ b/acceptance/framework/config/config.go @@ -63,11 +63,11 @@ func (t *TestConfig) HelmValuesFromConfig() (map[string]string, error) { return nil, err } setIfNotEmpty(helmValues, "global.image", entImage) - } - if t.EnterpriseLicense != "" { - setIfNotEmpty(helmValues, "global.enterpriseLicense.secretName", LicenseSecretName) - setIfNotEmpty(helmValues, "global.enterpriseLicense.secretKey", LicenseSecretKey) + if t.EnterpriseLicense != "" { + setIfNotEmpty(helmValues, "global.enterpriseLicense.secretName", LicenseSecretName) + setIfNotEmpty(helmValues, "global.enterpriseLicense.secretKey", LicenseSecretKey) + } } if t.EnableOpenshift { diff --git a/acceptance/framework/config/config_test.go b/acceptance/framework/config/config_test.go index f628c8afc9..feb82ceb38 100644 --- a/acceptance/framework/config/config_test.go +++ b/acceptance/framework/config/config_test.go @@ -58,12 +58,15 @@ func TestConfig_HelmValuesFromConfig(t *testing.T) { { "sets ent license secret", TestConfig{ + EnableEnterprise: true, EnterpriseLicense: "ent-license", + ConsulImage: "consul:test-version", }, map[string]string{ "global.enterpriseLicense.secretName": "license", "global.enterpriseLicense.secretKey": "key", "connectInject.transparentProxy.defaultEnabled": "false", + "global.image": "consul:test-version", }, }, { @@ -109,7 +112,7 @@ func TestConfig_HelmValuesFromConfig(t *testing.T) { t.Run(tt.name, func(t *testing.T) { values, err := tt.testConfig.HelmValuesFromConfig() require.NoError(t, err) - require.Equal(t, values, tt.want) + require.Equal(t, tt.want, values) }) } } diff --git a/acceptance/tests/vault/vault_wan_fed_test.go b/acceptance/tests/vault/vault_wan_fed_test.go index 16d9163cfb..e8ac60cf73 100644 --- a/acceptance/tests/vault/vault_wan_fed_test.go +++ b/acceptance/tests/vault/vault_wan_fed_test.go @@ -199,11 +199,12 @@ func TestVault_WANFederationViaGateways(t *testing.T) { // Get the address of the mesh gateway. primaryMeshGWAddress := meshGatewayAddress(t, cfg, primaryCtx, consulReleaseName) - serverExtraConfig := fmt.Sprintf(`"{\"primary_gateways\":[\"%s\"]\,\"primary_datacenter\":\"dc1\"}"`, primaryMeshGWAddress) secondaryConsulHelmValues := map[string]string{ "global.datacenter": "dc2", - "global.federation.enabled": "true", + "global.federation.enabled": "true", + "global.federation.primaryDatacenter": "dc1", + "global.federation.primaryGateways[0]": primaryMeshGWAddress, // TLS config. "global.tls.enabled": "true", @@ -229,7 +230,6 @@ func TestVault_WANFederationViaGateways(t *testing.T) { "server.extraVolumes[0].type": "secret", "server.extraVolumes[0].name": vaultCASecretName, "server.extraVolumes[0].load": "false", - "server.extraConfig": serverExtraConfig, // Vault config. "global.secretsBackend.vault.enabled": "true", diff --git a/charts/consul/templates/server-config-configmap.yaml b/charts/consul/templates/server-config-configmap.yaml index dcaf372b20..3ac7a29fd4 100644 --- a/charts/consul/templates/server-config-configmap.yaml +++ b/charts/consul/templates/server-config-configmap.yaml @@ -78,4 +78,11 @@ data: { "enable_central_service_config": true } + {{- if .Values.global.federation.enabled }} + federation-config.json: |- + { + "primary_datacenter": "{{ .Values.global.federation.primaryDatacenter }}", + "primary_gateways": {{ .Values.global.federation.primaryGateways | toJson }} + } + {{- end }} {{- end }} diff --git a/charts/consul/test/unit/server-config-configmap.bats b/charts/consul/test/unit/server-config-configmap.bats index 5ab54081fe..6fddfe7be2 100755 --- a/charts/consul/test/unit/server-config-configmap.bats +++ b/charts/consul/test/unit/server-config-configmap.bats @@ -492,4 +492,42 @@ load _helpers . | tee /dev/stderr | yq '.data["connect-ca-config.json"] | contains("\"ca_file\": \"/consul/vault-ca/tls.crt\"")' | tee /dev/stderr) [ "${actual}" = "true" ] +} + +@test "server/ConfigMap: doesn't add federation config by default" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + . | tee /dev/stderr | + yq '.data["federation-config.json"] | length > 0' | tee /dev/stderr) + [ "${actual}" = "false" ] +} + +@test "server/ConfigMap: adds empty federation config when global.federation.enabled is true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.federation.enabled=true' \ + --set 'global.tls.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq '.data["federation-config.json"]' | tee /dev/stderr) + [ "${actual}" = '"{\n \"primary_datacenter\": \"\",\n \"primary_gateways\": []\n}"' ] +} + +@test "server/ConfigMap: can set primary dc and gateways when global.federation.enabled is true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/server-config-configmap.yaml \ + --set 'global.federation.enabled=true' \ + --set 'global.federation.primaryDatacenter=dc1' \ + --set 'global.federation.primaryGateways[0]=1.1.1.1:443' \ + --set 'global.federation.primaryGateways[1]=2.2.2.2:443' \ + --set 'global.tls.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + . | tee /dev/stderr | + yq '.data["federation-config.json"]' | tee /dev/stderr) + [ "${actual}" = '"{\n \"primary_datacenter\": \"dc1\",\n \"primary_gateways\": [\"1.1.1.1:443\",\"2.2.2.2:443\"]\n}"' ] } \ No newline at end of file diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 3e849b6ef9..78db68860f 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -430,6 +430,14 @@ global: # `-consul-federation`. createFederationSecret: false + # The name of the primary datacenter. + primaryDatacenter: "" + + # A list of addresses of the primary mesh gateways in the form :. + # (e.g. ["1.1.1.1:443", "2.3.4.5:443"] + # @type: array + primaryGateways: [] + # Configures metrics for Consul service mesh metrics: # Configures the Helm chart’s components From d60fbd63e301bc6afe54b370857358fe989828a1 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 22 Feb 2022 11:36:07 -0700 Subject: [PATCH 278/418] Update changelog (#1039) --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85c8eba1c8..676cf4268d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,12 @@ ## UNRELEASED + +FEATURES: +* Support WAN federation via Mesh Gateways with Vault as the secrets backend. [[GH-1016](https://github.com/hashicorp/consul-k8s/pull/1016),[GH-1025](https://github.com/hashicorp/consul-k8s/pull/1025),[GH-1029](https://github.com/hashicorp/consul-k8s/pull/1029),[GH-1038](https://github.com/hashicorp/consul-k8s/pull/1038)] + **Note**: To use WAN federation with ACLs and Vault, you will need to create a KV secret in Vault that will serve as the replication token with + a random UUID: `vault kv put secret/consul/replication key="$(uuidgen)"`. You will need to then provide this secret to both the primary + and the secondary datacenters with `global.acls.replicationToken` values and allow the `global.secretsBackend.vault.manageSystemACLsRole` Vault role to read it. + In the primary datacenter, the Helm chart will create the replication token in Consul using the UUID as the secret ID of the token. + IMPROVEMENTS: * Helm * Vault: Allow passing arbitrary annotations to the vault agent. [[GH-1015](https://github.com/hashicorp/consul-k8s/pull/1015)] From ed2db851d41782edded5f60aefb88611fcde9fe0 Mon Sep 17 00:00:00 2001 From: Nitya Dhanushkodi Date: Tue, 22 Feb 2022 11:31:11 -0800 Subject: [PATCH 279/418] Update changelog for multiport (#1041) --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 676cf4268d..29c5a0a9f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ FEATURES: a random UUID: `vault kv put secret/consul/replication key="$(uuidgen)"`. You will need to then provide this secret to both the primary and the secondary datacenters with `global.acls.replicationToken` values and allow the `global.secretsBackend.vault.manageSystemACLsRole` Vault role to read it. In the primary datacenter, the Helm chart will create the replication token in Consul using the UUID as the secret ID of the token. +* Connect: Support workaround for pods with multiple ports, by registering a Consul service and injecting an Envoy sidecar and init container per port. [[GH-1012](https://github.com/hashicorp/consul-k8s/pull/1012)] + * Transparent proxying, metrics, and metrics merging are not supported for multi-port pods. + * Multi-port pods should specify annotations in the format, such that the service names and port names correspond with each other in the specified order, i.e. `web` service is listening on `8080`, `web-admin` service is listening on `9090`. + * `consul.hashicorp.com/connect-service': 'web,web-admin` + * `consul.hashicorp.com/connect-service-port': '8080,9090` IMPROVEMENTS: * Helm From 842452602717097c930e6fe6978f2c0416e31183 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 22 Feb 2022 12:59:38 -0700 Subject: [PATCH 280/418] Add godot linter and fix issues (#1042) Also, add makefile targets for linters --- .golangci.yml | 1 + Makefile | 20 +++++++++++ acceptance/framework/consul/cli_cluster.go | 2 +- acceptance/framework/consul/consul_cluster.go | 4 +-- .../framework/environment/environment.go | 2 +- .../tests/mesh-gateway/mesh_gateway_test.go | 2 +- cli/common/flag/flag_bool.go | 2 +- cli/common/flag/flag_enum.go | 2 +- cli/common/flag/flag_enum_single.go | 2 +- cli/common/flag/flag_float.go | 2 +- cli/common/flag/flag_int.go | 8 ++--- cli/common/flag/flag_string.go | 2 +- cli/common/flag/flag_string_map.go | 2 +- cli/common/flag/flag_string_slice.go | 2 +- cli/common/flag/flag_time.go | 2 +- cli/common/flag/flag_var.go | 2 +- cli/common/terminal/basic.go | 12 +++---- cli/common/terminal/table.go | 2 +- cli/common/terminal/ui.go | 4 +-- .../api/v1alpha1/exportedservices_types.go | 4 +-- .../api/v1alpha1/groupversion_info.go | 4 +-- .../api/v1alpha1/ingressgateway_types.go | 4 +-- control-plane/api/v1alpha1/mesh_types.go | 4 +-- .../api/v1alpha1/proxydefaults_types.go | 4 +-- .../api/v1alpha1/servicedefaults_types.go | 4 +-- .../api/v1alpha1/serviceintentions_types.go | 4 +-- .../api/v1alpha1/serviceresolver_types.go | 4 +-- .../api/v1alpha1/servicerouter_types.go | 4 +-- .../api/v1alpha1/servicesplitter_types.go | 4 +-- control-plane/api/v1alpha1/shared_types.go | 2 +- control-plane/api/v1alpha1/status.go | 8 ++--- .../api/v1alpha1/terminatinggateway_types.go | 6 ++-- control-plane/catalog/to-consul/resource.go | 12 +++---- .../catalog/to-consul/resource_test.go | 34 +++++++++---------- control-plane/catalog/to-consul/syncer.go | 4 +-- control-plane/catalog/to-consul/testing.go | 2 +- control-plane/catalog/to-k8s/sink.go | 2 +- control-plane/catalog/to-k8s/sink_test.go | 6 ++-- control-plane/catalog/to-k8s/source_test.go | 6 ++-- control-plane/connect-inject/annotations.go | 6 ++-- .../connect-inject/container_init_test.go | 2 +- control-plane/connect-inject/handler_test.go | 4 +-- .../controller/configentry_controller_test.go | 4 +-- .../controller/exportedservices_controller.go | 2 +- control-plane/controller/mesh_controller.go | 2 +- .../controller/proxydefaults_controller.go | 2 +- .../serviceintentions_controller.go | 2 +- .../controller/servicesplitter_controller.go | 2 +- control-plane/helper/cert/source_gen.go | 2 +- control-plane/helper/cert/source_gen_test.go | 4 +-- .../helper/coalesce/coalesce_test.go | 6 ++-- control-plane/helper/controller/controller.go | 4 +-- .../helper/controller/controller_test.go | 4 +-- .../subcommand/common/common_test.go | 2 +- .../subcommand/consul-sidecar/command.go | 2 +- .../subcommand/consul-sidecar/command_test.go | 2 +- .../subcommand/flags/flag_map_value.go | 2 +- .../get-consul-client-ca/command_test.go | 4 +-- .../subcommand/server-acl-init/rules.go | 2 +- .../subcommand/sync-catalog/command.go | 2 +- .../subcommand/sync-catalog/command_test.go | 14 ++++---- .../webhook-cert-manager/command.go | 2 +- 62 files changed, 148 insertions(+), 127 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index d6f534e8be..99e8b2ee8c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -2,6 +2,7 @@ linters: # enables all defaults + the below, `golangci-lint linters` to see the list of active linters. enable: - gofmt + - godot # TODO: re-enable things as we have main cleaned up vs the defaults #- stylecheck #- goconst diff --git a/Makefile b/Makefile index 49b8822d1b..1cd32824cb 100644 --- a/Makefile +++ b/Makefile @@ -39,17 +39,37 @@ control-plane-clean: ## Delete bin and pkg dirs. $(CURDIR)/control-plane/bin \ $(CURDIR)/control-plane/pkg +control-plane-lint: ## Run linter in the control-plane directory. + cd control-plane; golangci-lint run -c ../.golangci.yml + ctrl-generate: get-controller-gen ## Run CRD code generation. cd control-plane; $(CONTROLLER_GEN) object:headerFile="build-support/controller/boilerplate.go.txt" paths="./..." +# ===========> CLI Targets + +cli-lint: ## Run linter in the control-plane directory. + cd cli; golangci-lint run -c ../.golangci.yml + + + + +# ===========> Acceptance Tests Targets + +acceptance-lint: ## Run linter in the control-plane directory. + cd acceptance; golangci-lint run -c ../.golangci.yml + + # ===========> Shared Targets help: ## Show targets and their descriptions. @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' +lint: ## Run linter in the control-plane, cli, and acceptance directories. + for p in control-plane cli acceptance; do cd $$p; golangci-lint run --path-prefix $$p -c ../.golangci.yml; cd ..; done + ctrl-manifests: get-controller-gen ## Generate CRD manifests. cd control-plane; $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases make copy-crds-to-chart diff --git a/acceptance/framework/consul/cli_cluster.go b/acceptance/framework/consul/cli_cluster.go index 71662b88d8..27191b7fa3 100644 --- a/acceptance/framework/consul/cli_cluster.go +++ b/acceptance/framework/consul/cli_cluster.go @@ -29,7 +29,7 @@ const ( CLIReleaseName = "consul" ) -// CLICluster +// CLICluster. type CLICluster struct { ctx environment.TestContext namespace string diff --git a/acceptance/framework/consul/consul_cluster.go b/acceptance/framework/consul/consul_cluster.go index f2586b5c5b..3842809660 100644 --- a/acceptance/framework/consul/consul_cluster.go +++ b/acceptance/framework/consul/consul_cluster.go @@ -26,7 +26,7 @@ import ( "k8s.io/client-go/kubernetes" ) -// Cluster represents a consul cluster object +// Cluster represents a consul cluster object. type Cluster interface { Create(t *testing.T) Destroy(t *testing.T) @@ -38,7 +38,7 @@ type Cluster interface { } // HelmCluster implements Cluster and uses Helm -// to create, destroy, and upgrade consul +// to create, destroy, and upgrade consul. type HelmCluster struct { // ACLToken is an optional ACL token that will be used to create // a Consul API client. If not provided, we will attempt to read diff --git a/acceptance/framework/environment/environment.go b/acceptance/framework/environment/environment.go index 7c8a89e15b..15121b97e3 100644 --- a/acceptance/framework/environment/environment.go +++ b/acceptance/framework/environment/environment.go @@ -17,7 +17,7 @@ const ( ) // TestEnvironment represents the infrastructure environment of the test, -// such as the kubernetes cluster(s) the test is running against +// such as the kubernetes cluster(s) the test is running against. type TestEnvironment interface { DefaultContext(t *testing.T) TestContext Context(t *testing.T, name string) TestContext diff --git a/acceptance/tests/mesh-gateway/mesh_gateway_test.go b/acceptance/tests/mesh-gateway/mesh_gateway_test.go index d6e4be90be..230f5b01f4 100644 --- a/acceptance/tests/mesh-gateway/mesh_gateway_test.go +++ b/acceptance/tests/mesh-gateway/mesh_gateway_test.go @@ -18,7 +18,7 @@ import ( const staticClientName = "static-client" // Test that Connect and wan federation over mesh gateways work in a default installation -// i.e. without ACLs because TLS is required for WAN federation over mesh gateways +// i.e. without ACLs because TLS is required for WAN federation over mesh gateways. func TestMeshGatewayDefault(t *testing.T) { env := suite.Environment() cfg := suite.Config() diff --git a/cli/common/flag/flag_bool.go b/cli/common/flag/flag_bool.go index 6240cf2a63..2862c2fe40 100644 --- a/cli/common/flag/flag_bool.go +++ b/cli/common/flag/flag_bool.go @@ -7,7 +7,7 @@ import ( "github.com/posener/complete" ) -// -- BoolVar and boolValue +// -- BoolVar and boolValue. type BoolVar struct { Name string Aliases []string diff --git a/cli/common/flag/flag_enum.go b/cli/common/flag/flag_enum.go index 90e33069fa..ac9ecaedc1 100644 --- a/cli/common/flag/flag_enum.go +++ b/cli/common/flag/flag_enum.go @@ -8,7 +8,7 @@ import ( "github.com/posener/complete" ) -// -- EnumVar and enumValue +// -- EnumVar and enumValue. type EnumVar struct { Name string Aliases []string diff --git a/cli/common/flag/flag_enum_single.go b/cli/common/flag/flag_enum_single.go index 667f7707bd..ddef52796b 100644 --- a/cli/common/flag/flag_enum_single.go +++ b/cli/common/flag/flag_enum_single.go @@ -8,7 +8,7 @@ import ( "github.com/posener/complete" ) -// -- EnumVar and enumValue +// -- EnumVar and enumValue. type EnumSingleVar struct { Name string Aliases []string diff --git a/cli/common/flag/flag_float.go b/cli/common/flag/flag_float.go index 0a2f5c994e..1f7fcfad67 100644 --- a/cli/common/flag/flag_float.go +++ b/cli/common/flag/flag_float.go @@ -7,7 +7,7 @@ import ( "github.com/posener/complete" ) -// -- Float64Var and float64Value +// -- Float64Var and float64Value. type Float64Var struct { Name string Aliases []string diff --git a/cli/common/flag/flag_int.go b/cli/common/flag/flag_int.go index 12e87bef9c..419dabaa0e 100644 --- a/cli/common/flag/flag_int.go +++ b/cli/common/flag/flag_int.go @@ -7,7 +7,7 @@ import ( "github.com/posener/complete" ) -// -- IntVar and intValue +// -- IntVar and intValue. type IntVar struct { Name string Aliases []string @@ -79,7 +79,7 @@ func (i *intValue) String() string { return strconv.Itoa(int(*i.target)) } func (i *intValue) Example() string { return "int" } func (i *intValue) Hidden() bool { return i.hidden } -// -- Int64Var and int64Value +// -- Int64Var and int64Value. type Int64Var struct { Name string Aliases []string @@ -151,7 +151,7 @@ func (i *int64Value) String() string { return strconv.FormatInt(int64(*i.targe func (i *int64Value) Example() string { return "int" } func (i *int64Value) Hidden() bool { return i.hidden } -// -- UintVar && uintValue +// -- UintVar && uintValue. type UintVar struct { Name string Aliases []string @@ -223,7 +223,7 @@ func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i.targ func (i *uintValue) Example() string { return "uint" } func (i *uintValue) Hidden() bool { return i.hidden } -// -- Uint64Var and uint64Value +// -- Uint64Var and uint64Value. type Uint64Var struct { Name string Aliases []string diff --git a/cli/common/flag/flag_string.go b/cli/common/flag/flag_string.go index ee17a2916d..b16a1be16d 100644 --- a/cli/common/flag/flag_string.go +++ b/cli/common/flag/flag_string.go @@ -6,7 +6,7 @@ import ( "github.com/posener/complete" ) -// -- StringVar and stringValue +// -- StringVar and stringValue. type StringVar struct { Name string Aliases []string diff --git a/cli/common/flag/flag_string_map.go b/cli/common/flag/flag_string_map.go index 009b1d7761..5314a66655 100644 --- a/cli/common/flag/flag_string_map.go +++ b/cli/common/flag/flag_string_map.go @@ -8,7 +8,7 @@ import ( "github.com/posener/complete" ) -// -- StringMapVar and stringMapValue +// -- StringMapVar and stringMapValue. type StringMapVar struct { Name string Aliases []string diff --git a/cli/common/flag/flag_string_slice.go b/cli/common/flag/flag_string_slice.go index 7f27c245a4..b567c64936 100644 --- a/cli/common/flag/flag_string_slice.go +++ b/cli/common/flag/flag_string_slice.go @@ -7,7 +7,7 @@ import ( "github.com/posener/complete" ) -// -- StringSliceVar and stringSliceValue +// -- StringSliceVar and stringSliceValue. type StringSliceVar struct { Name string Aliases []string diff --git a/cli/common/flag/flag_time.go b/cli/common/flag/flag_time.go index 39562b765d..45dc297f3d 100644 --- a/cli/common/flag/flag_time.go +++ b/cli/common/flag/flag_time.go @@ -8,7 +8,7 @@ import ( "github.com/posener/complete" ) -// -- DurationVar and durationValue +// -- DurationVar and durationValue. type DurationVar struct { Name string Aliases []string diff --git a/cli/common/flag/flag_var.go b/cli/common/flag/flag_var.go index 7546c517f4..1b4114f16f 100644 --- a/cli/common/flag/flag_var.go +++ b/cli/common/flag/flag_var.go @@ -8,7 +8,7 @@ import ( "github.com/posener/complete" ) -// -- VarFlag +// -- VarFlag. type VarFlag struct { Name string Aliases []string diff --git a/cli/common/terminal/basic.go b/cli/common/terminal/basic.go index 2425b2d53c..d06815b8f5 100644 --- a/cli/common/terminal/basic.go +++ b/cli/common/terminal/basic.go @@ -15,7 +15,7 @@ import ( "github.com/mattn/go-isatty" ) -// basicUI +// basicUI. type basicUI struct { ctx context.Context } @@ -26,7 +26,7 @@ func NewBasicUI(ctx context.Context) *basicUI { } } -// Input implements UI +// Input implements UI. func (ui *basicUI) Input(input *Input) (string, error) { var buf bytes.Buffer @@ -67,12 +67,12 @@ func (ui *basicUI) Input(input *Input) (string, error) { } } -// Interactive implements UI +// Interactive implements UI. func (ui *basicUI) Interactive() bool { return isatty.IsTerminal(os.Stdin.Fd()) } -// Output implements UI +// Output implements UI. func (ui *basicUI) Output(msg string, raw ...interface{}) { msg, style, w := Interpret(msg, raw...) @@ -112,7 +112,7 @@ func (ui *basicUI) Output(msg string, raw ...interface{}) { fmt.Fprintln(w, msg) } -// NamedValues implements UI +// NamedValues implements UI. func (ui *basicUI) NamedValues(rows []NamedValue, opts ...Option) { cfg := &config{Writer: color.Output} for _, opt := range opts { @@ -143,7 +143,7 @@ func (ui *basicUI) NamedValues(rows []NamedValue, opts ...Option) { _, _ = colorInfo.Fprintln(cfg.Writer, buf.String()) } -// OutputWriters implements UI +// OutputWriters implements UI. func (ui *basicUI) OutputWriters() (io.Writer, io.Writer, error) { return os.Stdout, os.Stderr, nil } diff --git a/cli/common/terminal/table.go b/cli/common/terminal/table.go index 4d55e0006e..c8e8c2c67b 100644 --- a/cli/common/terminal/table.go +++ b/cli/common/terminal/table.go @@ -39,7 +39,7 @@ func (t *Table) Rich(cols []string, colors []string) { t.Rows = append(t.Rows, row) } -// Table implements UI +// Table implements UI. func (u *basicUI) Table(tbl *Table, opts ...Option) { // Build our config and set our options cfg := &config{Writer: color.Output} diff --git a/cli/common/terminal/ui.go b/cli/common/terminal/ui.go index e7d938a408..a9baa7aa87 100644 --- a/cli/common/terminal/ui.go +++ b/cli/common/terminal/ui.go @@ -11,7 +11,7 @@ import ( // ErrNonInteractive is returned when Input is called on a non-Interactive UI. var ErrNonInteractive = errors.New("noninteractive UI doesn't support this operation") -// Passed to UI.NamedValues to provide a nicely formatted key: value output +// Passed to UI.NamedValues to provide a nicely formatted key: value output. type NamedValue struct { Name string Value interface{} @@ -66,7 +66,7 @@ type Input struct { Secret bool } -// Interpret decomposes the msg and arguments into the message, style, and writer +// Interpret decomposes the msg and arguments into the message, style, and writer. func Interpret(msg string, raw ...interface{}) (string, string, io.Writer) { // Build our args and options var args []interface{} diff --git a/control-plane/api/v1alpha1/exportedservices_types.go b/control-plane/api/v1alpha1/exportedservices_types.go index 7d744c055d..01c54dbe17 100644 --- a/control-plane/api/v1alpha1/exportedservices_types.go +++ b/control-plane/api/v1alpha1/exportedservices_types.go @@ -40,14 +40,14 @@ type ExportedServices struct { //+kubebuilder:object:root=true -// ExportedServicesList contains a list of ExportedServices +// ExportedServicesList contains a list of ExportedServices. type ExportedServicesList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []ExportedServices `json:"items"` } -// ExportedServicesSpec defines the desired state of ExportedServices +// ExportedServicesSpec defines the desired state of ExportedServices. type ExportedServicesSpec struct { // Services is a list of services to be exported and the list of partitions // to expose them to. diff --git a/control-plane/api/v1alpha1/groupversion_info.go b/control-plane/api/v1alpha1/groupversion_info.go index b6054efb6f..cdbe085af4 100644 --- a/control-plane/api/v1alpha1/groupversion_info.go +++ b/control-plane/api/v1alpha1/groupversion_info.go @@ -11,10 +11,10 @@ import ( const ConsulHashicorpGroup string = "consul.hashicorp.com" var ( - // GroupVersion is group version used to register these objects + // GroupVersion is group version used to register these objects. GroupVersion = schema.GroupVersion{Group: "consul.hashicorp.com", Version: "v1alpha1"} - // SchemeBuilder is used to add go types to the GroupVersionKind scheme + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} // AddToScheme adds the types in this group-version to the given scheme. diff --git a/control-plane/api/v1alpha1/ingressgateway_types.go b/control-plane/api/v1alpha1/ingressgateway_types.go index ca32e72dd0..aef9917b49 100644 --- a/control-plane/api/v1alpha1/ingressgateway_types.go +++ b/control-plane/api/v1alpha1/ingressgateway_types.go @@ -43,14 +43,14 @@ type IngressGateway struct { // +kubebuilder:object:root=true -// IngressGatewayList contains a list of IngressGateway +// IngressGatewayList contains a list of IngressGateway. type IngressGatewayList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []IngressGateway `json:"items"` } -// IngressGatewaySpec defines the desired state of IngressGateway +// IngressGatewaySpec defines the desired state of IngressGateway. type IngressGatewaySpec struct { // TLS holds the TLS configuration for this gateway. TLS GatewayTLSConfig `json:"tls,omitempty"` diff --git a/control-plane/api/v1alpha1/mesh_types.go b/control-plane/api/v1alpha1/mesh_types.go index c62a684f65..057ba9f071 100644 --- a/control-plane/api/v1alpha1/mesh_types.go +++ b/control-plane/api/v1alpha1/mesh_types.go @@ -34,14 +34,14 @@ type Mesh struct { //+kubebuilder:object:root=true -// MeshList contains a list of Mesh +// MeshList contains a list of Mesh. type MeshList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []Mesh `json:"items"` } -// MeshSpec defines the desired state of Mesh +// MeshSpec defines the desired state of Mesh. type MeshSpec struct { TransparentProxy TransparentProxyMeshConfig `json:"transparentProxy,omitempty"` } diff --git a/control-plane/api/v1alpha1/proxydefaults_types.go b/control-plane/api/v1alpha1/proxydefaults_types.go index 1e38842d4b..22f498cf8e 100644 --- a/control-plane/api/v1alpha1/proxydefaults_types.go +++ b/control-plane/api/v1alpha1/proxydefaults_types.go @@ -41,7 +41,7 @@ type ProxyDefaults struct { // +kubebuilder:object:root=true -// ProxyDefaultsList contains a list of ProxyDefaults +// ProxyDefaultsList contains a list of ProxyDefaults. type ProxyDefaultsList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` @@ -50,7 +50,7 @@ type ProxyDefaultsList struct { // RawMessage for Config based on recommendation here: https://github.com/kubernetes-sigs/controller-tools/issues/294#issuecomment-518380816 -// ProxyDefaultsSpec defines the desired state of ProxyDefaults +// ProxyDefaultsSpec defines the desired state of ProxyDefaults. type ProxyDefaultsSpec struct { // Config is an arbitrary map of configuration values used by Connect proxies. // Any values that your proxy allows can be configured globally here. diff --git a/control-plane/api/v1alpha1/servicedefaults_types.go b/control-plane/api/v1alpha1/servicedefaults_types.go index f5b0160397..fe4b85c755 100644 --- a/control-plane/api/v1alpha1/servicedefaults_types.go +++ b/control-plane/api/v1alpha1/servicedefaults_types.go @@ -39,14 +39,14 @@ type ServiceDefaults struct { // +kubebuilder:object:root=true -// ServiceDefaultsList contains a list of ServiceDefaults +// ServiceDefaultsList contains a list of ServiceDefaults. type ServiceDefaultsList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []ServiceDefaults `json:"items"` } -// ServiceDefaultsSpec defines the desired state of ServiceDefaults +// ServiceDefaultsSpec defines the desired state of ServiceDefaults. type ServiceDefaultsSpec struct { // Protocol sets the protocol of the service. This is used by Connect proxies for // things like observability features and to unlock usage of the diff --git a/control-plane/api/v1alpha1/serviceintentions_types.go b/control-plane/api/v1alpha1/serviceintentions_types.go index 2a776e8209..0bab3adc74 100644 --- a/control-plane/api/v1alpha1/serviceintentions_types.go +++ b/control-plane/api/v1alpha1/serviceintentions_types.go @@ -40,14 +40,14 @@ type ServiceIntentions struct { // +kubebuilder:object:root=true -// ServiceIntentionsList contains a list of ServiceIntentions +// ServiceIntentionsList contains a list of ServiceIntentions. type ServiceIntentionsList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []ServiceIntentions `json:"items"` } -// ServiceIntentionsSpec defines the desired state of ServiceIntentions +// ServiceIntentionsSpec defines the desired state of ServiceIntentions. type ServiceIntentionsSpec struct { // Destination is the intention destination that will have the authorization granted to. Destination Destination `json:"destination,omitempty"` diff --git a/control-plane/api/v1alpha1/serviceresolver_types.go b/control-plane/api/v1alpha1/serviceresolver_types.go index 7ce67cb370..2d5fc1e8c8 100644 --- a/control-plane/api/v1alpha1/serviceresolver_types.go +++ b/control-plane/api/v1alpha1/serviceresolver_types.go @@ -37,14 +37,14 @@ type ServiceResolver struct { // +kubebuilder:object:root=true -// ServiceResolverList contains a list of ServiceResolver +// ServiceResolverList contains a list of ServiceResolver. type ServiceResolverList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []ServiceResolver `json:"items"` } -// ServiceResolverSpec defines the desired state of ServiceResolver +// ServiceResolverSpec defines the desired state of ServiceResolver. type ServiceResolverSpec struct { // DefaultSubset is the subset to use when no explicit subset is requested. // If empty the unnamed subset is used. diff --git a/control-plane/api/v1alpha1/servicerouter_types.go b/control-plane/api/v1alpha1/servicerouter_types.go index cc455a0853..9f8f7fc3fd 100644 --- a/control-plane/api/v1alpha1/servicerouter_types.go +++ b/control-plane/api/v1alpha1/servicerouter_types.go @@ -41,14 +41,14 @@ type ServiceRouter struct { // +kubebuilder:object:root=true -// ServiceRouterList contains a list of ServiceRouter +// ServiceRouterList contains a list of ServiceRouter. type ServiceRouterList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []ServiceRouter `json:"items"` } -// ServiceRouterSpec defines the desired state of ServiceRouter +// ServiceRouterSpec defines the desired state of ServiceRouter. type ServiceRouterSpec struct { // Routes are the list of routes to consider when processing L7 requests. // The first route to match in the list is terminal and stops further diff --git a/control-plane/api/v1alpha1/servicesplitter_types.go b/control-plane/api/v1alpha1/servicesplitter_types.go index fb5ba74d7f..b61b1a320b 100644 --- a/control-plane/api/v1alpha1/servicesplitter_types.go +++ b/control-plane/api/v1alpha1/servicesplitter_types.go @@ -37,7 +37,7 @@ type ServiceSplitter struct { // +kubebuilder:object:root=true -// ServiceSplitterList contains a list of ServiceSplitter +// ServiceSplitterList contains a list of ServiceSplitter. type ServiceSplitterList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` @@ -46,7 +46,7 @@ type ServiceSplitterList struct { type ServiceSplits []ServiceSplit -// ServiceSplitterSpec defines the desired state of ServiceSplitter +// ServiceSplitterSpec defines the desired state of ServiceSplitter. type ServiceSplitterSpec struct { // Splits defines how much traffic to send to which set of service instances during a traffic split. // The sum of weights across all splits must add up to 100. diff --git a/control-plane/api/v1alpha1/shared_types.go b/control-plane/api/v1alpha1/shared_types.go index 1191614698..9b884cf476 100644 --- a/control-plane/api/v1alpha1/shared_types.go +++ b/control-plane/api/v1alpha1/shared_types.go @@ -52,7 +52,7 @@ type TransparentProxy struct { } // MeshGateway controls how Mesh Gateways are used for upstream Connect -// services +// services. type MeshGateway struct { // Mode is the mode that should be used for the upstream connection. // One of none, local, or remote. diff --git a/control-plane/api/v1alpha1/status.go b/control-plane/api/v1alpha1/status.go index 1dd19241f2..d7cd0e0b78 100644 --- a/control-plane/api/v1alpha1/status.go +++ b/control-plane/api/v1alpha1/status.go @@ -5,7 +5,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// Conditions is the schema for the conditions portion of the payload +// Conditions is the schema for the conditions portion of the payload. type Conditions []Condition // ConditionType is a camel-cased condition type. @@ -42,7 +42,7 @@ type Condition struct { Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"` } -// IsTrue is true if the condition is True +// IsTrue is true if the condition is True. func (c *Condition) IsTrue() bool { if c == nil { return false @@ -50,7 +50,7 @@ func (c *Condition) IsTrue() bool { return c.Status == corev1.ConditionTrue } -// IsFalse is true if the condition is False +// IsFalse is true if the condition is False. func (c *Condition) IsFalse() bool { if c == nil { return false @@ -58,7 +58,7 @@ func (c *Condition) IsFalse() bool { return c.Status == corev1.ConditionFalse } -// IsUnknown is true if the condition is Unknown +// IsUnknown is true if the condition is Unknown. func (c *Condition) IsUnknown() bool { if c == nil { return true diff --git a/control-plane/api/v1alpha1/terminatinggateway_types.go b/control-plane/api/v1alpha1/terminatinggateway_types.go index 1236307b99..6e708b5d44 100644 --- a/control-plane/api/v1alpha1/terminatinggateway_types.go +++ b/control-plane/api/v1alpha1/terminatinggateway_types.go @@ -41,20 +41,20 @@ type TerminatingGateway struct { // +kubebuilder:object:root=true -// TerminatingGatewayList contains a list of TerminatingGateway +// TerminatingGatewayList contains a list of TerminatingGateway. type TerminatingGatewayList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` Items []TerminatingGateway `json:"items"` } -// TerminatingGatewaySpec defines the desired state of TerminatingGateway +// TerminatingGatewaySpec defines the desired state of TerminatingGateway. type TerminatingGatewaySpec struct { // Services is a list of service names represented by the terminating gateway. Services []LinkedService `json:"services,omitempty"` } -// A LinkedService is a service represented by a terminating gateway +// A LinkedService is a service represented by a terminating gateway. type LinkedService struct { // The namespace the service is registered in. Namespace string `json:"namespace,omitempty"` diff --git a/control-plane/catalog/to-consul/resource.go b/control-plane/catalog/to-consul/resource.go index 5188f2ccb5..4444f14b18 100644 --- a/control-plane/catalog/to-consul/resource.go +++ b/control-plane/catalog/to-consul/resource.go @@ -35,14 +35,14 @@ type NodePortSyncType string const ( // Only sync NodePort services with a node's ExternalIP address. - // Doesn't sync if an ExternalIP doesn't exist + // Doesn't sync if an ExternalIP doesn't exist. ExternalOnly NodePortSyncType = "ExternalOnly" // Sync with an ExternalIP first, if it doesn't exist, use the - // node's InternalIP address instead + // node's InternalIP address instead. ExternalFirst NodePortSyncType = "ExternalFirst" - // Sync NodePort services using + // Sync NodePort services using. InternalOnly NodePortSyncType = "InternalOnly" ) @@ -226,7 +226,7 @@ func (t *ServiceResource) Delete(key string, _ interface{}) error { // doDelete is a helper function for deletion. // -// Precondition: assumes t.serviceLock is held +// Precondition: assumes t.serviceLock is held. func (t *ServiceResource) doDelete(key string) { delete(t.serviceMap, key) t.Log.Debug("[doDelete] deleting service from serviceMap", "key", key) @@ -292,7 +292,7 @@ func (t *ServiceResource) shouldSync(svc *apiv1.Service) bool { // shouldTrackEndpoints returns true if the endpoints for the given key // should be tracked. // -// Precondition: this requires the lock to be held +// Precondition: this requires the lock to be held. func (t *ServiceResource) shouldTrackEndpoints(key string) bool { // The service must be one we care about for us to watch the endpoints. // We care about a service that exists in our service map (is enabled @@ -664,7 +664,7 @@ func (t *ServiceResource) registerServiceInstance( // sync calls the Syncer.Sync function from the generated registrations. // -// Precondition: lock must be held +// Precondition: lock must be held. func (t *ServiceResource) sync() { // NOTE(mitchellh): This isn't the most efficient way to do this and // the times that sync are called are also not the most efficient. All diff --git a/control-plane/catalog/to-consul/resource_test.go b/control-plane/catalog/to-consul/resource_test.go index 6bc99eb5f7..9fc5ced094 100644 --- a/control-plane/catalog/to-consul/resource_test.go +++ b/control-plane/catalog/to-consul/resource_test.go @@ -102,7 +102,7 @@ func TestServiceResource_defaultEnableDisable(t *testing.T) { }) } -// Test that we can default disable +// Test that we can default disable. func TestServiceResource_defaultDisable(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -128,7 +128,7 @@ func TestServiceResource_defaultDisable(t *testing.T) { }) } -// Test that we can default disable but override +// Test that we can default disable but override. func TestServiceResource_defaultDisableEnable(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -196,7 +196,7 @@ func TestServiceResource_changeSyncToFalse(t *testing.T) { } // Test that the k8s namespace is appended with a '-' -// when AddK8SNamespaceSuffix is true +// when AddK8SNamespaceSuffix is true. func TestServiceResource_addK8SNamespace(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -224,7 +224,7 @@ func TestServiceResource_addK8SNamespace(t *testing.T) { } // Test k8s namespace suffix is appended -// when the consul prefix is provided +// when the consul prefix is provided. func TestServiceResource_addK8SNamespaceWithPrefix(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -281,7 +281,7 @@ func TestServiceResource_ConsulNodeName(t *testing.T) { } // Test k8s namespace suffix is not appended -// when the service name annotation is provided +// when the service name annotation is provided. func TestServiceResource_addK8SNamespaceWithNameAnnotation(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -339,7 +339,7 @@ func TestServiceResource_externalIP(t *testing.T) { }) } -// Test externalIP with Prefix +// Test externalIP with Prefix. func TestServiceResource_externalIPPrefix(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -397,7 +397,7 @@ func TestServiceResource_lb(t *testing.T) { }) } -// Test that the proper registrations are generated for a LoadBalancer with a prefix +// Test that the proper registrations are generated for a LoadBalancer with a prefix. func TestServiceResource_lbPrefix(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -460,7 +460,7 @@ func TestServiceResource_lbMultiEndpoint(t *testing.T) { }) } -// Test explicit name annotation +// Test explicit name annotation. func TestServiceResource_lbAnnotatedName(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -487,7 +487,7 @@ func TestServiceResource_lbAnnotatedName(t *testing.T) { }) } -// Test default port and additional ports in the meta +// Test default port and additional ports in the meta. func TestServiceResource_lbPort(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -519,7 +519,7 @@ func TestServiceResource_lbPort(t *testing.T) { }) } -// Test default port works with override annotation +// Test default port works with override annotation. func TestServiceResource_lbAnnotatedPort(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -552,7 +552,7 @@ func TestServiceResource_lbAnnotatedPort(t *testing.T) { }) } -// Test annotated tags +// Test annotated tags. func TestServiceResource_lbAnnotatedTags(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -580,7 +580,7 @@ func TestServiceResource_lbAnnotatedTags(t *testing.T) { }) } -// Test annotated service meta +// Test annotated service meta. func TestServiceResource_lbAnnotatedMeta(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -607,7 +607,7 @@ func TestServiceResource_lbAnnotatedMeta(t *testing.T) { }) } -// Test that with LoadBalancerEndpointsSync set to true we track the IP of the endpoints not the LB IP/name +// Test that with LoadBalancerEndpointsSync set to true we track the IP of the endpoints not the LB IP/name. func TestServiceResource_lbRegisterEndpoints(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -701,7 +701,7 @@ func TestServiceResource_nodePort(t *testing.T) { }) } -// Test node port works with prefix +// Test node port works with prefix. func TestServiceResource_nodePortPrefix(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -922,7 +922,7 @@ func TestServiceResource_nodePort_internalOnlySync(t *testing.T) { } // Test that the proper registrations are generated for a NodePort type -// when preferring to sync external Node IPs over internal IPs +// when preferring to sync external Node IPs over internal IPs. func TestServiceResource_nodePort_externalFirstSync(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -1005,7 +1005,7 @@ func TestServiceResource_clusterIP(t *testing.T) { }) } -// Test clusterIP with prefix +// Test clusterIP with prefix. func TestServiceResource_clusterIPPrefix(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -1188,7 +1188,7 @@ func TestServiceResource_clusterIPSyncDisabled(t *testing.T) { }) } -// Test that the ClusterIP services are synced when watching all namespaces +// Test that the ClusterIP services are synced when watching all namespaces. func TestServiceResource_clusterIPAllNamespaces(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() diff --git a/control-plane/catalog/to-consul/syncer.go b/control-plane/catalog/to-consul/syncer.go index 557e51bf0d..2e2edad61a 100644 --- a/control-plane/catalog/to-consul/syncer.go +++ b/control-plane/catalog/to-consul/syncer.go @@ -98,7 +98,7 @@ type ConsulSyncer struct { watchers map[string]map[string]context.CancelFunc } -// Sync implements Syncer +// Sync implements Syncer. func (s *ConsulSyncer) Sync(rs []*api.CatalogRegistration) { // Grab the lock so we can replace the sync state s.lock.Lock() @@ -317,7 +317,7 @@ func (s *ConsulSyncer) watchService(ctx context.Context, name, namespace string) // scheduleReapService finds all the instances of the service with the given // name that have the k8s tag and schedules them for removal. // -// Precondition: lock must be held +// Precondition: lock must be held. func (s *ConsulSyncer) scheduleReapServiceLocked(name, namespace string) error { // Set up query options opts := api.QueryOptions{AllowStale: true} diff --git a/control-plane/catalog/to-consul/testing.go b/control-plane/catalog/to-consul/testing.go index 89813ac5d6..e6541c6ba1 100644 --- a/control-plane/catalog/to-consul/testing.go +++ b/control-plane/catalog/to-consul/testing.go @@ -17,7 +17,7 @@ type testSyncer struct { Registrations []*api.CatalogRegistration } -// Sync implements Syncer +// Sync implements Syncer. func (s *testSyncer) Sync(rs []*api.CatalogRegistration) { s.Lock() defer s.Unlock() diff --git a/control-plane/catalog/to-k8s/sink.go b/control-plane/catalog/to-k8s/sink.go index e3bfed7789..fa8821989e 100644 --- a/control-plane/catalog/to-k8s/sink.go +++ b/control-plane/catalog/to-k8s/sink.go @@ -82,7 +82,7 @@ type K8SSink struct { triggerCh chan struct{} } -// SetServices implements Sink +// SetServices implements Sink. func (s *K8SSink) SetServices(svcs map[string]string) { s.lock.Lock() defer s.lock.Unlock() diff --git a/control-plane/catalog/to-k8s/sink_test.go b/control-plane/catalog/to-k8s/sink_test.go index 2883b1f9f3..fbce7bbaaf 100644 --- a/control-plane/catalog/to-k8s/sink_test.go +++ b/control-plane/catalog/to-k8s/sink_test.go @@ -221,7 +221,7 @@ func TestK8SSink_updateReconcile(t *testing.T) { }) } -// Test that if the service is updated locally, it is reconciled +// Test that if the service is updated locally, it is reconciled. func TestK8SSink_updateService(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -284,7 +284,7 @@ func TestK8SSink_updateService(t *testing.T) { }) } -// Test that if the service is deleted remotely, it is recreated +// Test that if the service is deleted remotely, it is recreated. func TestK8SSink_deleteReconcileRemote(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() @@ -347,7 +347,7 @@ func TestK8SSink_deleteReconcileRemote(t *testing.T) { }) } -// Test that if the service is deleted locally, it is recreated +// Test that if the service is deleted locally, it is recreated. func TestK8SSink_deleteReconcileLocal(t *testing.T) { t.Parallel() client := fake.NewSimpleClientset() diff --git a/control-plane/catalog/to-k8s/source_test.go b/control-plane/catalog/to-k8s/source_test.go index f7e97fe19f..d3ed4a8a26 100644 --- a/control-plane/catalog/to-k8s/source_test.go +++ b/control-plane/catalog/to-k8s/source_test.go @@ -259,7 +259,7 @@ func TestSource_deleteServiceInstance(t *testing.T) { }) } -// testRegistration creates a Consul test registration +// testRegistration creates a Consul test registration. func testRegistration(node, service string, tags []string) *api.CatalogRegistration { return &api.CatalogRegistration{ Node: node, @@ -271,13 +271,13 @@ func testRegistration(node, service string, tags []string) *api.CatalogRegistrat } } -// testSource creates a Source and Sink for testing +// testSource creates a Source and Sink for testing. func testSource(client *api.Client) (*Source, *TestSink, func()) { return testSourceWithConfig(client, func(source *Source) {}) } // testSourceWithConfig starts a Source that can be configured -// prior to starting via the configurator method +// prior to starting via the configurator method. func testSourceWithConfig(client *api.Client, configurator func(*Source)) (*Source, *TestSink, func()) { sink := &TestSink{} s := &Source{ diff --git a/control-plane/connect-inject/annotations.go b/control-plane/connect-inject/annotations.go index 8e9730d41a..ec723d80fd 100644 --- a/control-plane/connect-inject/annotations.go +++ b/control-plane/connect-inject/annotations.go @@ -13,7 +13,7 @@ const ( // annotationInject is the key of the annotation that controls whether // injection is explicitly enabled or disabled for a pod. This should - // be set to a truthy or falsy value, as parseable by strconv.ParseBool + // be set to a truthy or falsy value, as parseable by strconv.ParseBool. annotationInject = "consul.hashicorp.com/connect-inject" // annotationService is the name of the service to proxy. This defaults @@ -39,7 +39,7 @@ const ( annotationUpstreams = "consul.hashicorp.com/connect-service-upstreams" // annotationTags is a list of tags to register with the service - // this is specified as a comma separated list e.g. abc,123 + // this is specified as a comma separated list e.g. abc,123. annotationTags = "consul.hashicorp.com/service-tags" // annotationConnectTags is a list of tags to register with the service @@ -53,7 +53,7 @@ const ( // annotationMeta is a list of metadata key/value pairs to add to the service // registration. This is specified in the format `:` - // e.g. consul.hashicorp.com/service-meta-foo:bar + // e.g. consul.hashicorp.com/service-meta-foo:bar. annotationMeta = "consul.hashicorp.com/service-meta-" // annotationSyncPeriod controls the -sync-period flag passed to the diff --git a/control-plane/connect-inject/container_init_test.go b/control-plane/connect-inject/container_init_test.go index f536ba68f0..2b8927f258 100644 --- a/control-plane/connect-inject/container_init_test.go +++ b/control-plane/connect-inject/container_init_test.go @@ -956,7 +956,7 @@ consul-k8s-control-plane connect-init -pod-name=${POD_NAME} -pod-namespace=${POD // If Consul CA cert is set, // Consul addresses should use HTTPS -// and CA cert should be set as env variable +// and CA cert should be set as env variable. func TestHandlerContainerInit_WithTLS(t *testing.T) { require := require.New(t) h := Handler{ diff --git a/control-plane/connect-inject/handler_test.go b/control-plane/connect-inject/handler_test.go index cd77de66f4..0ae01fd93c 100644 --- a/control-plane/connect-inject/handler_test.go +++ b/control-plane/connect-inject/handler_test.go @@ -863,7 +863,7 @@ func TestHandlerPrometheusAnnotations(t *testing.T) { } } -// Test portValue function +// Test portValue function. func TestHandlerPortValue(t *testing.T) { cases := []struct { Name string @@ -950,7 +950,7 @@ func TestHandlerPortValue(t *testing.T) { } } -// Test consulNamespace function +// Test consulNamespace function. func TestConsulNamespace(t *testing.T) { cases := []struct { Name string diff --git a/control-plane/controller/configentry_controller_test.go b/control-plane/controller/configentry_controller_test.go index 9ed1c324ac..74787beb12 100644 --- a/control-plane/controller/configentry_controller_test.go +++ b/control-plane/controller/configentry_controller_test.go @@ -1468,7 +1468,7 @@ func TestConfigEntryControllers_setsSyncedToTrue(t *testing.T) { } // Test that if the config entry exists in Consul but is not managed by the -// controller, creating/updating the resource fails +// controller, creating/updating the resource fails. func TestConfigEntryControllers_doesNotCreateUnownedConfigEntry(t *testing.T) { t.Parallel() kubeNS := "default" @@ -1566,7 +1566,7 @@ func TestConfigEntryControllers_doesNotCreateUnownedConfigEntry(t *testing.T) { } // Test that if the config entry exists in Consul but is not managed by the -// controller, deleting the resource does not delete the Consul config entry +// controller, deleting the resource does not delete the Consul config entry. func TestConfigEntryControllers_doesNotDeleteUnownedConfig(t *testing.T) { t.Parallel() kubeNS := "default" diff --git a/control-plane/controller/exportedservices_controller.go b/control-plane/controller/exportedservices_controller.go index be0445f4a1..84e767d6dc 100644 --- a/control-plane/controller/exportedservices_controller.go +++ b/control-plane/controller/exportedservices_controller.go @@ -12,7 +12,7 @@ import ( consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" ) -// ExportedServicesController reconciles a ExportedServices object +// ExportedServicesController reconciles a ExportedServices object. type ExportedServicesController struct { client.Client Log logr.Logger diff --git a/control-plane/controller/mesh_controller.go b/control-plane/controller/mesh_controller.go index 61652d23fe..e15f49fca0 100644 --- a/control-plane/controller/mesh_controller.go +++ b/control-plane/controller/mesh_controller.go @@ -12,7 +12,7 @@ import ( consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" ) -// MeshController reconciles a Mesh object +// MeshController reconciles a Mesh object. type MeshController struct { client.Client Log logr.Logger diff --git a/control-plane/controller/proxydefaults_controller.go b/control-plane/controller/proxydefaults_controller.go index 658806d340..a63e121522 100644 --- a/control-plane/controller/proxydefaults_controller.go +++ b/control-plane/controller/proxydefaults_controller.go @@ -12,7 +12,7 @@ import ( consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" ) -// ProxyDefaultsController reconciles a ProxyDefaults object +// ProxyDefaultsController reconciles a ProxyDefaults object. type ProxyDefaultsController struct { client.Client Log logr.Logger diff --git a/control-plane/controller/serviceintentions_controller.go b/control-plane/controller/serviceintentions_controller.go index 1ee1db037c..3b70447517 100644 --- a/control-plane/controller/serviceintentions_controller.go +++ b/control-plane/controller/serviceintentions_controller.go @@ -12,7 +12,7 @@ import ( consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" ) -// ServiceIntentionsController reconciles a ServiceIntentions object +// ServiceIntentionsController reconciles a ServiceIntentions object. type ServiceIntentionsController struct { client.Client Log logr.Logger diff --git a/control-plane/controller/servicesplitter_controller.go b/control-plane/controller/servicesplitter_controller.go index a8b6267c70..9d07845dbb 100644 --- a/control-plane/controller/servicesplitter_controller.go +++ b/control-plane/controller/servicesplitter_controller.go @@ -12,7 +12,7 @@ import ( consulv1alpha1 "github.com/hashicorp/consul-k8s/control-plane/api/v1alpha1" ) -// ServiceSplitterReconciler reconciles a ServiceSplitter object +// ServiceSplitterReconciler reconciles a ServiceSplitter object. type ServiceSplitterController struct { client.Client Log logr.Logger diff --git a/control-plane/helper/cert/source_gen.go b/control-plane/helper/cert/source_gen.go index 8226e9ce72..e9c79ed390 100644 --- a/control-plane/helper/cert/source_gen.go +++ b/control-plane/helper/cert/source_gen.go @@ -34,7 +34,7 @@ type GenSource struct { caSigner crypto.Signer } -// Certificate implements Source +// Certificate implements Source. func (s *GenSource) Certificate(ctx context.Context, last *Bundle) (Bundle, error) { s.mu.Lock() defer s.mu.Unlock() diff --git a/control-plane/helper/cert/source_gen_test.go b/control-plane/helper/cert/source_gen_test.go index b654f10d0f..8926e89174 100644 --- a/control-plane/helper/cert/source_gen_test.go +++ b/control-plane/helper/cert/source_gen_test.go @@ -20,7 +20,7 @@ func init() { hasOpenSSL = err == nil } -// Test that valid certificates are generated +// Test that valid certificates are generated. func TestGenSource_valid(t *testing.T) { t.Parallel() @@ -36,7 +36,7 @@ func TestGenSource_valid(t *testing.T) { testBundleVerify(t, &bundle) } -// Test that certs are regenerated near expiry +// Test that certs are regenerated near expiry. func TestGenSource_expiry(t *testing.T) { t.Parallel() diff --git a/control-plane/helper/coalesce/coalesce_test.go b/control-plane/helper/coalesce/coalesce_test.go index 2cfe7bd65c..8489fed8b4 100644 --- a/control-plane/helper/coalesce/coalesce_test.go +++ b/control-plane/helper/coalesce/coalesce_test.go @@ -46,11 +46,11 @@ func TestCoalesce_max(t *testing.T) { testSummer(&total, deltaCh)) duration := time.Since(start) if total < 4 || total > 6 { - // 4 to 6 to account for CI weirdness + // 4 to 6 to account for CI weirdness. t.Fatalf("total should be 4 to 6: %d", total) } - // We should complete in the max period + // We should complete in the max period. if duration < 500*time.Millisecond { t.Fatalf("duration should be greater than max: %s", duration) } @@ -58,7 +58,7 @@ func TestCoalesce_max(t *testing.T) { // Test that if the cancel function is called, Coalesce exits. // We test this via having a function that just sleeps and then calling -// cancel on it. We expect that Coalesce exits +// cancel on it. We expect that Coalesce exits. func TestCoalesce_cancel(t *testing.T) { total := 0 deltaCh := make(chan int, 10) diff --git a/control-plane/helper/controller/controller.go b/control-plane/helper/controller/controller.go index 66a1d3b005..6edfb9d89c 100644 --- a/control-plane/helper/controller/controller.go +++ b/control-plane/helper/controller/controller.go @@ -134,7 +134,7 @@ func (c *Controller) Run(stopCh <-chan struct{}) { }, time.Second, stopCh) } -// HasSynced implements cache.Controller +// HasSynced implements cache.Controller. func (c *Controller) HasSynced() bool { if c.informer == nil { return false @@ -143,7 +143,7 @@ func (c *Controller) HasSynced() bool { return c.informer.HasSynced() } -// LastSyncResourceVersion implements cache.Controller +// LastSyncResourceVersion implements cache.Controller. func (c *Controller) LastSyncResourceVersion() string { if c.informer == nil { return "" diff --git a/control-plane/helper/controller/controller_test.go b/control-plane/helper/controller/controller_test.go index 2f83bc5705..43fe677280 100644 --- a/control-plane/helper/controller/controller_test.go +++ b/control-plane/helper/controller/controller_test.go @@ -22,7 +22,7 @@ func TestController_impl(t *testing.T) { var _ cache.Controller = &Controller{} } -// Test that data that exists before is synced +// Test that data that exists before is synced. func TestController_initialData(t *testing.T) { t.Parallel() require := require.New(t) @@ -46,7 +46,7 @@ func TestController_initialData(t *testing.T) { require.Len(deleted, 0) } -// Test that created data after starting is loaded +// Test that created data after starting is loaded. func TestController_create(t *testing.T) { t.Parallel() require := require.New(t) diff --git a/control-plane/subcommand/common/common_test.go b/control-plane/subcommand/common/common_test.go index d5ac9a11b1..179d10a114 100644 --- a/control-plane/subcommand/common/common_test.go +++ b/control-plane/subcommand/common/common_test.go @@ -29,7 +29,7 @@ func TestZapLogger_InvalidLogLevel(t *testing.T) { require.EqualError(t, err, "unknown log level \"invalid\": unrecognized level: \"invalid\"") } -// ZapLogger should convert "trace" log level to "debug" +// ZapLogger should convert "trace" log level to "debug". func TestZapLogger_TraceLogLevel(t *testing.T) { _, err := ZapLogger("trace", false) require.NoError(t, err) diff --git a/control-plane/subcommand/consul-sidecar/command.go b/control-plane/subcommand/consul-sidecar/command.go index b6ff0d9d39..509696378d 100644 --- a/control-plane/subcommand/consul-sidecar/command.go +++ b/control-plane/subcommand/consul-sidecar/command.go @@ -398,7 +398,7 @@ func (c *Command) parseConsulFlags() []string { } // interrupt sends os.Interrupt signal to the command -// so it can exit gracefully. This function is needed for tests +// so it can exit gracefully. This function is needed for tests. func (c *Command) interrupt() { c.sendSignal(syscall.SIGINT) } diff --git a/control-plane/subcommand/consul-sidecar/command_test.go b/control-plane/subcommand/consul-sidecar/command_test.go index 53008ffab9..f9b7c77625 100644 --- a/control-plane/subcommand/consul-sidecar/command_test.go +++ b/control-plane/subcommand/consul-sidecar/command_test.go @@ -225,7 +225,7 @@ func (em *mockEnvoyMetricsGetter) Get(_ string) (resp *http.Response, err error) return response, nil } -// mockServiceMetricsGetter +// mockServiceMetricsGetter. type mockServiceMetricsGetter struct { // reqURL is the last URL that was passed to Get(url) reqURL string diff --git a/control-plane/subcommand/flags/flag_map_value.go b/control-plane/subcommand/flags/flag_map_value.go index cb10c8ecc4..9ddb4dad08 100644 --- a/control-plane/subcommand/flags/flag_map_value.go +++ b/control-plane/subcommand/flags/flag_map_value.go @@ -9,7 +9,7 @@ import ( // Taken from https://github.com/hashicorp/consul/blob/35daee45bc3bf9fdce5845f2219576e861b23f40/command/flags/flag_map_value.go // This was done so we don't depend on internal Consul implementation. -// Ensure implements +// Ensure implements. var _ flag.Value = (*FlagMapValue)(nil) // FlagMapValue is a flag implementation used to provide key=value semantics diff --git a/control-plane/subcommand/get-consul-client-ca/command_test.go b/control-plane/subcommand/get-consul-client-ca/command_test.go index 8655465771..4250e6d81f 100644 --- a/control-plane/subcommand/get-consul-client-ca/command_test.go +++ b/control-plane/subcommand/get-consul-client-ca/command_test.go @@ -64,7 +64,7 @@ func TestRun_FlagsValidation(t *testing.T) { // Test that in the happy case scenario // we retrieve the CA from Consul and -// write it to a file +// write it to a file. func TestRun(t *testing.T) { t.Parallel() outputFile, err := ioutil.TempFile("", "ca") @@ -293,7 +293,7 @@ func TestRun_GetsOnlyActiveRoot(t *testing.T) { } // Test that when using cloud auto-join -// it uses the provider to get the address of the server +// it uses the provider to get the address of the server. func TestRun_WithProvider(t *testing.T) { t.Parallel() outputFile, err := ioutil.TempFile("", "ca") diff --git a/control-plane/subcommand/server-acl-init/rules.go b/control-plane/subcommand/server-acl-init/rules.go index 83d836cd6d..a634e9473d 100644 --- a/control-plane/subcommand/server-acl-init/rules.go +++ b/control-plane/subcommand/server-acl-init/rules.go @@ -233,7 +233,7 @@ partition "{{ .PartitionName }}" { // Creating a separate terminating gateway rule function because // eventually this may need to be created with permissions for // all of the services it represents, though that is not part -// of the initial implementation +// of the initial implementation. func (c *Command) terminatingGatewayRules(name, namespace string) (string, error) { terminatingGatewayRulesTpl := ` {{- if .EnablePartitions }} diff --git a/control-plane/subcommand/sync-catalog/command.go b/control-plane/subcommand/sync-catalog/command.go index fa478412c2..105ce6619c 100644 --- a/control-plane/subcommand/sync-catalog/command.go +++ b/control-plane/subcommand/sync-catalog/command.go @@ -382,7 +382,7 @@ func (c *Command) Help() string { } // interrupt sends os.Interrupt signal to the command -// so it can exit gracefully. This function is needed for tests +// so it can exit gracefully. This function is needed for tests. func (c *Command) interrupt() { c.sendSignal(syscall.SIGINT) } diff --git a/control-plane/subcommand/sync-catalog/command_test.go b/control-plane/subcommand/sync-catalog/command_test.go index 3956b24f2d..6cc629336e 100644 --- a/control-plane/subcommand/sync-catalog/command_test.go +++ b/control-plane/subcommand/sync-catalog/command_test.go @@ -18,7 +18,7 @@ import ( "k8s.io/client-go/kubernetes/fake" ) -// Test flag validation +// Test flag validation. func TestRun_FlagValidation(t *testing.T) { t.Parallel() @@ -51,7 +51,7 @@ func TestRun_FlagValidation(t *testing.T) { } } -// Test that the default consul service is synced to k8s +// Test that the default consul service is synced to k8s. func TestRun_Defaults_SyncsConsulServiceToK8s(t *testing.T) { t.Parallel() @@ -83,7 +83,7 @@ func TestRun_Defaults_SyncsConsulServiceToK8s(t *testing.T) { }) } -// Test that the command exits cleanly on signals +// Test that the command exits cleanly on signals. func TestRun_ExitCleanlyOnSignals(t *testing.T) { t.Run("SIGINT", testSignalHandling(syscall.SIGINT)) t.Run("SIGTERM", testSignalHandling(syscall.SIGTERM)) @@ -126,7 +126,7 @@ func testSignalHandling(sig os.Signal) func(*testing.T) { } // Test that when -add-k8s-namespace-suffix flag is used -// k8s namespaces are appended to the service names synced to Consul +// k8s namespaces are appended to the service names synced to Consul. func TestRun_ToConsulWithAddK8SNamespaceSuffix(t *testing.T) { t.Parallel() @@ -171,7 +171,7 @@ func TestRun_ToConsulWithAddK8SNamespaceSuffix(t *testing.T) { } // Test that switching AddK8SNamespaceSuffix from false to true -// results in re-registering services in Consul with namespaced names +// results in re-registering services in Consul with namespaced names. func TestCommand_Run_ToConsulChangeAddK8SNamespaceSuffixToTrue(t *testing.T) { t.Parallel() @@ -231,7 +231,7 @@ func TestCommand_Run_ToConsulChangeAddK8SNamespaceSuffixToTrue(t *testing.T) { // Test that services with same name but in different namespaces // get registered as different services in consul -// when using -add-k8s-namespace-suffix +// when using -add-k8s-namespace-suffix. func TestCommand_Run_ToConsulTwoServicesSameNameDifferentNamespace(t *testing.T) { t.Parallel() @@ -574,7 +574,7 @@ func TestRun_ToConsulChangingFlags(t *testing.T) { } } -// Set up test consul agent and fake kubernetes cluster client +// Set up test consul agent and fake kubernetes cluster client. func completeSetup(t *testing.T) (*fake.Clientset, *testutil.TestServer) { k8s := fake.NewSimpleClientset() diff --git a/control-plane/subcommand/webhook-cert-manager/command.go b/control-plane/subcommand/webhook-cert-manager/command.go index 2f69889975..570a432ad9 100644 --- a/control-plane/subcommand/webhook-cert-manager/command.go +++ b/control-plane/subcommand/webhook-cert-manager/command.go @@ -412,7 +412,7 @@ func (c *Command) Synopsis() string { } // interrupt sends os.Interrupt signal to the command -// so it can exit gracefully. This function is needed for tests +// so it can exit gracefully. This function is needed for tests. func (c *Command) interrupt() { c.sendSignal(syscall.SIGINT) } From 6ad9e1a1e8cedbea828320e9131de4aa4c7bf6c0 Mon Sep 17 00:00:00 2001 From: David Yu Date: Tue, 22 Feb 2022 14:35:28 -0800 Subject: [PATCH 281/418] CHANGELOG: formatting consul k8s wanted vault (#1045) --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29c5a0a9f7..cbc6aaada2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,9 @@ FEATURES: * Support WAN federation via Mesh Gateways with Vault as the secrets backend. [[GH-1016](https://github.com/hashicorp/consul-k8s/pull/1016),[GH-1025](https://github.com/hashicorp/consul-k8s/pull/1025),[GH-1029](https://github.com/hashicorp/consul-k8s/pull/1029),[GH-1038](https://github.com/hashicorp/consul-k8s/pull/1038)] - **Note**: To use WAN federation with ACLs and Vault, you will need to create a KV secret in Vault that will serve as the replication token with - a random UUID: `vault kv put secret/consul/replication key="$(uuidgen)"`. You will need to then provide this secret to both the primary + * **Note**: To use WAN federation with ACLs and Vault, you will need to create a KV secret in Vault that will serve as the replication token with + a random UUID: `vault kv put secret/consul/replication key="$(uuidgen)"`. + * You will need to then provide this secret to both the primary and the secondary datacenters with `global.acls.replicationToken` values and allow the `global.secretsBackend.vault.manageSystemACLsRole` Vault role to read it. In the primary datacenter, the Helm chart will create the replication token in Consul using the UUID as the secret ID of the token. * Connect: Support workaround for pods with multiple ports, by registering a Consul service and injecting an Envoy sidecar and init container per port. [[GH-1012](https://github.com/hashicorp/consul-k8s/pull/1012)] From 16aaf2d564728d7c1a927ebbcfc173a03cdfe189 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Wed, 23 Feb 2022 13:19:47 -0600 Subject: [PATCH 282/418] update chart for release 0.41.0 (#1048) * update chart for release 0.41.0 * update values.yaml --- charts/consul/Chart.yaml | 8 ++++---- charts/consul/values.yaml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index d5c1f18444..dc57082d06 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: consul -version: 0.40.0 -appVersion: 1.11.2 +version: 0.41.0 +appVersion: 1.11.3 kubeVersion: ">=1.18.0-0" description: Official HashiCorp Consul Chart home: https://www.consul.io @@ -13,9 +13,9 @@ annotations: artifacthub.io/prerelease: false artifacthub.io/images: | - name: consul - image: hashicorp/consul:1.11.2 + image: hashicorp/consul:1.11.3 - name: consul-k8s-control-plane - image: hashicorp/consul-k8s-control-plane:0.40.0 + image: hashicorp/consul-k8s-control-plane:0.41.0 - name: envoy image: envoyproxy/envoy-alpine:v1.20.1 artifacthub.io/license: MPL-2.0 diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 78db68860f..45423a6586 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -85,7 +85,7 @@ global: # image: "hashicorp/consul-enterprise:1.10.0-ent" # ``` # @default: hashicorp/consul: - image: "hashicorp/consul:1.11.2" + image: "hashicorp/consul:1.11.3" # Array of objects containing image pull secret names that will be applied to each service account. # This can be used to reference image pull secrets if using a custom consul or consul-k8s-control-plane Docker image. @@ -105,7 +105,7 @@ global: # image that is used for functionality such as catalog sync. # This can be overridden per component. # @default: hashicorp/consul-k8s-control-plane: - imageK8S: "hashicorp/consul-k8s-control-plane:0.40.0" + imageK8S: "hashicorp/consul-k8s-control-plane:0.41.0" # The name of the datacenter that the agents should # register as. This can't be changed once the Consul cluster is up and running From 74854902b387225535dd072a032ed60d1cb7f19c Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Wed, 23 Feb 2022 19:29:40 +0000 Subject: [PATCH 283/418] Release v0.41.0 --- CHANGELOG.md | 2 +- cli/version/version.go | 4 ++-- control-plane/version/version.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cbc6aaada2..4387d9507f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.41.0 (February 23, 2022) FEATURES: * Support WAN federation via Mesh Gateways with Vault as the secrets backend. [[GH-1016](https://github.com/hashicorp/consul-k8s/pull/1016),[GH-1025](https://github.com/hashicorp/consul-k8s/pull/1025),[GH-1029](https://github.com/hashicorp/consul-k8s/pull/1029),[GH-1038](https://github.com/hashicorp/consul-k8s/pull/1038)] diff --git a/cli/version/version.go b/cli/version/version.go index 1c0fec12d8..c348c81623 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.40.0" + Version = "0.41.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 1c0fec12d8..c348c81623 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.40.0" + Version = "0.41.0" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From f50dce36ce7dea745157dbb047bfcdd23d4bfe2d Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Wed, 23 Feb 2022 19:54:59 +0000 Subject: [PATCH 284/418] Putting source back into Dev Mode --- CHANGELOG.md | 2 ++ cli/version/version.go | 2 +- control-plane/version/version.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4387d9507f..2cc5e91da3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## UNRELEASED + ## 0.41.0 (February 23, 2022) FEATURES: diff --git a/cli/version/version.go b/cli/version/version.go index c348c81623..b8e5766d15 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index c348c81623..b8e5766d15 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable From cd11d478e44534e4b46726f35f9d71a94d7f07ac Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 23 Feb 2022 17:42:00 -0500 Subject: [PATCH 285/418] Create an Issue Context Bot (#1047) --- .github/workflows/issue-context-bot.yml | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/issue-context-bot.yml diff --git a/.github/workflows/issue-context-bot.yml b/.github/workflows/issue-context-bot.yml new file mode 100644 index 0000000000..89522136c2 --- /dev/null +++ b/.github/workflows/issue-context-bot.yml @@ -0,0 +1,28 @@ +name: Issue Context Bot + +on: + issues: + types: transferred + +jobs: + add-context: + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - uses: wow-actions/auto-comment@v1.0.7 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + issuesTransferred: | + "Hi @{{ author }}, + + It looks like your issue has been transferred to the Consul on Kubernetes repository. + If your issue is a question or bug report, there is some additional context that will + help us solve your issue. Please reply with the following information if it is not + included in your original issue: + + - the [Helm values](https://www.consul.io/docs/k8s/helm) you used to install Consul + on Kubernetes + - the version of Consul on Kubernetes used + - the version of Kubernetes you are using + - if you installed Consul on Kubernetes using Helm or the Consul-K8s CLI" From 199d2f1f5a80930ec6784283847f9ba8a9d5bee1 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 23 Feb 2022 21:30:50 -0500 Subject: [PATCH 286/418] Fix an issue with the issue-context-bot trigger. (#1052) --- .github/workflows/issue-context-bot.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/issue-context-bot.yml b/.github/workflows/issue-context-bot.yml index 89522136c2..51f37f7ee9 100644 --- a/.github/workflows/issue-context-bot.yml +++ b/.github/workflows/issue-context-bot.yml @@ -1,14 +1,10 @@ name: Issue Context Bot -on: - issues: - types: transferred +on: [issues] jobs: add-context: runs-on: ubuntu-latest - permissions: - issues: write steps: - uses: wow-actions/auto-comment@v1.0.7 with: From 3914721e375a0c6d3cea50d715948028d78eeb79 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Thu, 24 Feb 2022 10:01:30 -0700 Subject: [PATCH 287/418] Bump envoy version (#1051) --- CHANGELOG.md | 4 ++++ charts/consul/Chart.yaml | 2 +- charts/consul/test/unit/ingress-gateways-deployment.bats | 2 +- charts/consul/test/unit/mesh-gateway-deployment.bats | 2 +- charts/consul/test/unit/terminating-gateways-deployment.bats | 2 +- charts/consul/values.yaml | 2 +- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cc5e91da3..9dfb33b600 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## UNRELEASED +BUG FIXES: +* Helm + * Support Envoy 1.20.2. [[GH-1051](https://github.com/hashicorp/consul-k8s/pull/1051)] + ## 0.41.0 (February 23, 2022) FEATURES: diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index dc57082d06..e57d11ae26 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -17,7 +17,7 @@ annotations: - name: consul-k8s-control-plane image: hashicorp/consul-k8s-control-plane:0.41.0 - name: envoy - image: envoyproxy/envoy-alpine:v1.20.1 + image: envoyproxy/envoy-alpine:v1.20.2 artifacthub.io/license: MPL-2.0 artifacthub.io/links: | - name: Documentation diff --git a/charts/consul/test/unit/ingress-gateways-deployment.bats b/charts/consul/test/unit/ingress-gateways-deployment.bats index d2c02d1dda..76b20dd501 100644 --- a/charts/consul/test/unit/ingress-gateways-deployment.bats +++ b/charts/consul/test/unit/ingress-gateways-deployment.bats @@ -83,7 +83,7 @@ load _helpers --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -s -r '.[0].spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.1" ] + [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.2" ] } @test "ingressGateways/Deployment: envoy image can be set using the global value" { diff --git a/charts/consul/test/unit/mesh-gateway-deployment.bats b/charts/consul/test/unit/mesh-gateway-deployment.bats index c434fce1c5..e8a2b1eeec 100755 --- a/charts/consul/test/unit/mesh-gateway-deployment.bats +++ b/charts/consul/test/unit/mesh-gateway-deployment.bats @@ -335,7 +335,7 @@ key2: value2' \ --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -r '.spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.1" ] + [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.2" ] } @test "meshGateway/Deployment: setting meshGateway.imageEnvoy fails" { diff --git a/charts/consul/test/unit/terminating-gateways-deployment.bats b/charts/consul/test/unit/terminating-gateways-deployment.bats index 1cc2fbdd16..4a23a232ba 100644 --- a/charts/consul/test/unit/terminating-gateways-deployment.bats +++ b/charts/consul/test/unit/terminating-gateways-deployment.bats @@ -83,7 +83,7 @@ load _helpers --set 'connectInject.enabled=true' \ . | tee /dev/stderr | yq -s -r '.[0].spec.template.spec.containers[0].image' | tee /dev/stderr) - [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.1" ] + [ "${actual}" = "envoyproxy/envoy-alpine:v1.20.2" ] } @test "terminatingGateways/Deployment: envoy image can be set using the global value" { diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index 45423a6586..a37946b2b6 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -490,7 +490,7 @@ global: # connect-injected sidecar proxies and mesh, terminating, and ingress gateways. # See https://www.consul.io/docs/connect/proxies/envoy for full compatibility matrix between Consul and Envoy. # @default: envoyproxy/envoy-alpine: - imageEnvoy: "envoyproxy/envoy-alpine:v1.20.1" + imageEnvoy: "envoyproxy/envoy-alpine:v1.20.2" # Configuration for running this Helm chart on the Red Hat OpenShift platform. # This Helm chart currently supports OpenShift v4.x+. From d90a213045815ba64a0cb48d9c9c3498a5790053 Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Thu, 24 Feb 2022 11:09:08 -0600 Subject: [PATCH 288/418] release 0.41.1 (#1056) --- charts/consul/Chart.yaml | 4 ++-- charts/consul/values.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index e57d11ae26..5c3c613157 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: consul -version: 0.41.0 +version: 0.41.1 appVersion: 1.11.3 kubeVersion: ">=1.18.0-0" description: Official HashiCorp Consul Chart @@ -15,7 +15,7 @@ annotations: - name: consul image: hashicorp/consul:1.11.3 - name: consul-k8s-control-plane - image: hashicorp/consul-k8s-control-plane:0.41.0 + image: hashicorp/consul-k8s-control-plane:0.41.1 - name: envoy image: envoyproxy/envoy-alpine:v1.20.2 artifacthub.io/license: MPL-2.0 diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index a37946b2b6..f22d7059d0 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -105,7 +105,7 @@ global: # image that is used for functionality such as catalog sync. # This can be overridden per component. # @default: hashicorp/consul-k8s-control-plane: - imageK8S: "hashicorp/consul-k8s-control-plane:0.41.0" + imageK8S: "hashicorp/consul-k8s-control-plane:0.41.1" # The name of the datacenter that the agents should # register as. This can't be changed once the Consul cluster is up and running From c4faf134d7163fb45834e014148554427a094045 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Thu, 24 Feb 2022 17:11:20 +0000 Subject: [PATCH 289/418] Release v0.41.1 --- CHANGELOG.md | 2 +- cli/version/version.go | 4 ++-- control-plane/version/version.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9dfb33b600..fd6a82aa4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## UNRELEASED +## 0.41.1 (February 24, 2022) BUG FIXES: * Helm diff --git a/cli/version/version.go b/cli/version/version.go index b8e5766d15..573ee49086 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.41.0" + Version = "0.41.1" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index b8e5766d15..573ee49086 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -14,12 +14,12 @@ var ( // // Version must conform to the format expected by // github.com/hashicorp/go-version for tests to work. - Version = "0.41.0" + Version = "0.41.1" // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "dev" + VersionPrerelease = "" ) // GetHumanVersion composes the parts of the version in a way that's suitable From 918485ce8a319c729958021025227debb2179e75 Mon Sep 17 00:00:00 2001 From: hc-github-team-consul-ecosystem <82990057+hc-github-team-consul-ecosystem@users.noreply.github.com> Date: Thu, 24 Feb 2022 17:39:35 +0000 Subject: [PATCH 290/418] Putting source back into Dev Mode --- CHANGELOG.md | 2 ++ cli/version/version.go | 2 +- control-plane/version/version.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd6a82aa4b..0b55219d38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## UNRELEASED + ## 0.41.1 (February 24, 2022) BUG FIXES: diff --git a/cli/version/version.go b/cli/version/version.go index 573ee49086..b3a31b883f 100644 --- a/cli/version/version.go +++ b/cli/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable diff --git a/control-plane/version/version.go b/control-plane/version/version.go index 573ee49086..b3a31b883f 100644 --- a/control-plane/version/version.go +++ b/control-plane/version/version.go @@ -19,7 +19,7 @@ var ( // A pre-release marker for the version. If this is "" (empty string) // then it means that it is a final release. Otherwise, this is a pre-release // such as "dev" (in development), "beta", "rc1", etc. - VersionPrerelease = "" + VersionPrerelease = "dev" ) // GetHumanVersion composes the parts of the version in a way that's suitable From a5516c96ea982e1a2a7bc0f98663186f0231ad96 Mon Sep 17 00:00:00 2001 From: David Yu Date: Thu, 24 Feb 2022 10:35:37 -0800 Subject: [PATCH 291/418] chart: bump k8s requirement to 1.19 (#1049) * chart: bump k8s requirement to 1.19 will follow up with removal of bats test that are dependent on 1.18 * 1.19 * remove 1.19 tests for ui ingress * remove 1.19 flags since we default to 1.19+ * missed one --- charts/consul/Chart.yaml | 2 +- charts/consul/templates/ui-ingress.yaml | 2 - charts/consul/test/unit/ui-ingress.bats | 66 ++----------------------- 3 files changed, 5 insertions(+), 65 deletions(-) diff --git a/charts/consul/Chart.yaml b/charts/consul/Chart.yaml index 5c3c613157..ae895af58b 100644 --- a/charts/consul/Chart.yaml +++ b/charts/consul/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v2 name: consul version: 0.41.1 appVersion: 1.11.3 -kubeVersion: ">=1.18.0-0" +kubeVersion: ">=1.19.0-0" description: Official HashiCorp Consul Chart home: https://www.consul.io icon: https://raw.githubusercontent.com/hashicorp/consul-k8s/main/assets/icon.png diff --git a/charts/consul/templates/ui-ingress.yaml b/charts/consul/templates/ui-ingress.yaml index 473acd3469..0414a7cc2d 100644 --- a/charts/consul/templates/ui-ingress.yaml +++ b/charts/consul/templates/ui-ingress.yaml @@ -25,9 +25,7 @@ metadata: {{ tpl .Values.ui.ingress.annotations . | nindent 4 | trim }} {{- end }} spec: - {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "18" ) }} ingressClassName: {{ .Values.ui.ingress.ingressClassName }} - {{- end }} rules: {{ $global := .Values.global }} {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "19" ) }} diff --git a/charts/consul/test/unit/ui-ingress.bats b/charts/consul/test/unit/ui-ingress.bats index 005236be57..e351790aae 100755 --- a/charts/consul/test/unit/ui-ingress.bats +++ b/charts/consul/test/unit/ui-ingress.bats @@ -59,73 +59,31 @@ load _helpers [ "${actual}" = "foo.com" ] } -@test "ui/Ingress: exposes single port 80 when global.tls.enabled=false when Kube version < 1.19" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/ui-ingress.yaml \ - --set 'ui.ingress.enabled=true' \ - --set 'global.tls.enabled=false' \ - --set 'ui.ingress.hosts[0].host=foo.com' \ - --kube-version "1.18" \ - . | tee /dev/stderr | - yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) - [ "${actual}" = "80" ] -} - -@test "ui/Ingress: exposes single port 80 when global.tls.enabled=false when Kube version >= 1.19" { +@test "ui/Ingress: exposes single port 80 when global.tls.enabled=false" { cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ --set 'global.tls.enabled=false' \ --set 'ui.ingress.hosts[0].host=foo.com' \ - --kube-version "1.19" \ . | tee /dev/stderr | yq -r '.spec.rules[0].http.paths[0].backend.service.port.number' | tee /dev/stderr) [ "${actual}" = "80" ] } -@test "ui/Ingress: exposes single port 443 when global.tls.enabled=true and global.tls.httpsOnly=true when Kube version < 1.19" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/ui-ingress.yaml \ - --set 'ui.ingress.enabled=true' \ - --set 'global.tls.enabled=true' \ - --set 'ui.ingress.hosts[0].host=foo.com' \ - --kube-version "1.18" \ - . | tee /dev/stderr | - yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) - [ "${actual}" = "443" ] -} - -@test "ui/Ingress: exposes single port 443 when global.tls.enabled=true and global.tls.httpsOnly=true when Kube version >= 1.19" { +@test "ui/Ingress: exposes single port 443 when global.tls.enabled=true and global.tls.httpsOnly=true" { cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ --set 'ui.ingress.enabled=true' \ --set 'global.tls.enabled=true' \ --set 'ui.ingress.hosts[0].host=foo.com' \ - --kube-version "1.19" \ . | tee /dev/stderr | yq -r '.spec.rules[0].http.paths[0].backend.service.port.number' | tee /dev/stderr) [ "${actual}" = "443" ] } -@test "ui/Ingress: exposes the port 80 when global.tls.enabled=true and global.tls.httpsOnly=false when Kube version < 1.19" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/ui-ingress.yaml \ - --set 'ui.ingress.enabled=true' \ - --set 'global.tls.enabled=true' \ - --set 'global.tls.httpsOnly=false' \ - --set 'ui.ingress.hosts[0].host=foo.com' \ - --kube-version "1.18" \ - . | tee /dev/stderr | - yq -r '.spec.rules[0].http.paths[0].backend.servicePort' | tee /dev/stderr) - [ "${actual}" = "80" ] -} - -@test "ui/Ingress: exposes the port 80 when global.tls.enabled=true and global.tls.httpsOnly=false when Kube version >= 1.19" { +@test "ui/Ingress: exposes the port 80 when global.tls.enabled=true and global.tls.httpsOnly=false" { cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ @@ -133,27 +91,12 @@ load _helpers --set 'global.tls.enabled=true' \ --set 'global.tls.httpsOnly=false' \ --set 'ui.ingress.hosts[0].host=foo.com' \ - --kube-version "1.19" \ . | tee /dev/stderr | yq -r '.spec.rules[0].http.paths[0].backend.service.port.number' | tee /dev/stderr) [ "${actual}" = "80" ] } -@test "ui/Ingress: exposes the port 443 when global.tls.enabled=true and global.tls.httpsOnly=false when Kube version < 1.19" { - cd `chart_dir` - local actual=$(helm template \ - -s templates/ui-ingress.yaml \ - --set 'ui.ingress.enabled=true' \ - --set 'global.tls.enabled=true' \ - --set 'global.tls.httpsOnly=false' \ - --set 'ui.ingress.hosts[0].host=foo.com' \ - --kube-version "1.18" \ - . | tee /dev/stderr | - yq -r '.spec.rules[0].http.paths[1].backend.servicePort' | tee /dev/stderr) - [ "${actual}" = "443" ] -} - -@test "ui/Ingress: exposes the port 443 when global.tls.enabled=true and global.tls.httpsOnly=false when Kube version >= 1.19" { +@test "ui/Ingress: exposes the port 443 when global.tls.enabled=true and global.tls.httpsOnly=false" { cd `chart_dir` local actual=$(helm template \ -s templates/ui-ingress.yaml \ @@ -161,7 +104,6 @@ load _helpers --set 'global.tls.enabled=true' \ --set 'global.tls.httpsOnly=false' \ --set 'ui.ingress.hosts[0].host=foo.com' \ - --kube-version "1.19" \ . | tee /dev/stderr | yq -r '.spec.rules[0].http.paths[1].backend.service.port.number' | tee /dev/stderr) [ "${actual}" = "443" ] From cb5f283a56613988c533da1e5d20f4ad5c2a30e2 Mon Sep 17 00:00:00 2001 From: David Yu Date: Thu, 24 Feb 2022 11:49:19 -0800 Subject: [PATCH 292/418] CHANGELOG: bump to k8s 1.19+ (#1057) * CHANGELOG: bump to k8s 1.19+ * Update CHANGELOG.md Co-authored-by: Iryna Shustava Co-authored-by: Iryna Shustava --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b55219d38..a94aa36068 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## UNRELEASED +BREAKING CHANGES: +* Minimum Kubernetes version supported is 1.19 and now matches what is stated in the `README.md` file. [[GH-1049](https://github.com/hashicorp/consul-k8s/pull/1049)] + ## 0.41.1 (February 24, 2022) BUG FIXES: From 1a0d8d0cc073863d7c206126a3bfc6680b2efaa0 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 24 Feb 2022 17:02:34 -0500 Subject: [PATCH 293/418] give this resuable action a try --- .github/workflows/go-fmt-and-vet-helm-gen.yml | 10 ++++++ .github/workflows/reusable/go-fmt-and-vet.yml | 34 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 .github/workflows/go-fmt-and-vet-helm-gen.yml create mode 100644 .github/workflows/reusable/go-fmt-and-vet.yml diff --git a/.github/workflows/go-fmt-and-vet-helm-gen.yml b/.github/workflows/go-fmt-and-vet-helm-gen.yml new file mode 100644 index 0000000000..8dd057c2ac --- /dev/null +++ b/.github/workflows/go-fmt-and-vet-helm-gen.yml @@ -0,0 +1,10 @@ +name: go-fmt-and-vet-helm-gen + +on: + workflow_dispatch: + +jobs: + go-fmt-and-vet-helm-gen: + uses: hashicorp/consul-k8s/.github/workflows/reusable/go-fmt-and-vet.yml@crt-build-and-tests + with: + directory: hack/helm-reference-gen diff --git a/.github/workflows/reusable/go-fmt-and-vet.yml b/.github/workflows/reusable/go-fmt-and-vet.yml new file mode 100644 index 0000000000..4eb1f7c7b8 --- /dev/null +++ b/.github/workflows/reusable/go-fmt-and-vet.yml @@ -0,0 +1,34 @@ +name: go-fmt-and-vet + +on: + workflow_call: + inputs: + directory: + required: true + type: string + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: go mod download + working-directory: ${{inputs.directory}} + run: go mod download + + - name: check go fmt + working-directory: ${{inputs.directory}} + run: | + files=$(go fmt ./...) + if [ -n "$files" ]; then + echo "The following file(s) do not conform to go fmt:" + echo "$files" + exit 1 + fi + + - name: go vet + working-directory: ${{inputs.directory}} + run: go vet ./... From 2611ccc29be6adf445d8f13a2b23c8c699aa1236 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 24 Feb 2022 17:07:35 -0500 Subject: [PATCH 294/418] subdirectories are not supported --- .github/workflows/go-fmt-and-vet-helm-gen.yml | 2 +- .../go-fmt-and-vet.yml => reusable-go-fmt-and-vet.yml} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{reusable/go-fmt-and-vet.yml => reusable-go-fmt-and-vet.yml} (100%) diff --git a/.github/workflows/go-fmt-and-vet-helm-gen.yml b/.github/workflows/go-fmt-and-vet-helm-gen.yml index 8dd057c2ac..50cfb5567f 100644 --- a/.github/workflows/go-fmt-and-vet-helm-gen.yml +++ b/.github/workflows/go-fmt-and-vet-helm-gen.yml @@ -5,6 +5,6 @@ on: jobs: go-fmt-and-vet-helm-gen: - uses: hashicorp/consul-k8s/.github/workflows/reusable/go-fmt-and-vet.yml@crt-build-and-tests + uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests with: directory: hack/helm-reference-gen diff --git a/.github/workflows/reusable/go-fmt-and-vet.yml b/.github/workflows/reusable-go-fmt-and-vet.yml similarity index 100% rename from .github/workflows/reusable/go-fmt-and-vet.yml rename to .github/workflows/reusable-go-fmt-and-vet.yml From b7e92f4f97f21609b9b81343673a441d25eeb8c0 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 24 Feb 2022 17:25:58 -0500 Subject: [PATCH 295/418] run on push and comment out CircleCI config --- .circleci/config.yml | 1994 ++++++++--------- .github/workflows/go-fmt-and-vet-helm-gen.yml | 8 +- 2 files changed, 1003 insertions(+), 999 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2bf464fc1a..d34bb55cda 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,997 +1,997 @@ -# Originally from consul-k8s -version: 2.1 -orbs: - slack: circleci/slack@3.4.2 -# reusable 'executor' object for jobs -executors: - go: - docker: - - image: docker.mirror.hashicorp.services/cimg/go:1.17.5 - environment: - TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests - -control-plane-path : &control-plane-path control-plane -cli-path : &cli-path cli -acceptance-mod-path: &acceptance-mod-path acceptance -acceptance-test-path: &acceptance-test-path acceptance/tests -acceptance-framework-path: &acceptance-framework-path acceptance/framework -charts-consul-path: &charts-consul-path charts/consul -helm-gen-path: &helm-gen-path hack/helm-reference-gen -gke-terraform-path: &gke-terraform-path charts/consul/test/terraform/gke -eks-terraform-path: &eks-terraform-path charts/consul/test/terraform/eks -aks-terraform-path: &aks-terraform-path charts/consul/test/terraform/aks -openshift-terraform-path: &openshift-terraform-path charts/consul/test/terraform/openshift - -commands: - install-prereqs: - steps: - - run: - name: Install gotestsum, kind, kubectl, and helm - command: | - wget https://golang.org/dl/go1.17.5.linux-amd64.tar.gz - sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.5.linux-amd64.tar.gz - rm go1.17.5.linux-amd64.tar.gz - echo 'export PATH=$PATH:/usr/local/go/bin' >> $BASH_ENV - - wget https://github.com/gotestyourself/gotestsum/releases/download/v1.6.4/gotestsum_1.6.4_linux_amd64.tar.gz - sudo tar -C /usr/local/bin -xzf gotestsum_1.6.4_linux_amd64.tar.gz - rm gotestsum_1.6.4_linux_amd64.tar.gz - - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.0/kind-linux-amd64 - chmod +x ./kind - sudo mv ./kind /usr/local/bin/kind - - curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" - chmod +x ./kubectl - sudo mv ./kubectl /usr/local/bin/kubectl - - wget https://get.helm.sh/helm-v3.7.0-linux-amd64.tar.gz - tar -zxvf helm-v3.7.0-linux-amd64.tar.gz - sudo mv linux-amd64/helm /usr/local/bin/helm - - create-kind-clusters: - parameters: - version: - type: string - steps: - - run: - name: Create kind clusters - command: | - kind create cluster --name dc1 --image kindest/node:<< parameters.version >> - kind create cluster --name dc2 --image kindest/node:<< parameters.version >> - run-acceptance-tests: - parameters: - failfast: - type: boolean - default: false - additional-flags: - type: string - consul-k8s-image: - type: string - default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" - go-path: - type: string - default: "/home/circleci/.go_workspace" - steps: - - when: - condition: << parameters.failfast >> - steps: - - run: - name: Run acceptance tests - working_directory: *acceptance-test-path - no_output_timeout: 2h - command: | - # Enterprise tests can't run on fork PRs because they require - # a secret. - if [ -z "$CIRCLE_PR_NUMBER" ]; then - ENABLE_ENTERPRISE=true - fi - - # We have to run the tests for each package separately so that we can - # exit early if any test fails (-failfast only works within a single - # package). - exit_code=0 - pkgs=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname) - echo "Running $(echo $pkgs | wc -w) packages:" - echo $pkgs - for pkg in $pkgs - do - if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ - << parameters.additional-flags >> \ - ${ENABLE_ENTERPRISE:+-enable-enterprise} \ - -enable-multi-cluster \ - -debug-directory="$TEST_RESULTS/debug" \ - -consul-k8s-image=<< parameters.consul-k8s-image >> - then - echo "Tests in ${pkg} failed, aborting early" - exit_code=1 - break - fi - done - gotestsum --raw-command --junitfile "$TEST_RESULTS/gotestsum-report.xml" -- cat jsonfile* - exit $exit_code - - - unless: - condition: << parameters.failfast >> - steps: - - run: - name: Run acceptance tests - working_directory: *acceptance-test-path - no_output_timeout: 2h - command: | - # Enterprise tests can't run on fork PRs because they require - # a secret. - if [ -z "$CIRCLE_PR_NUMBER" ]; then - ENABLE_ENTERPRISE=true - fi - - pkgs=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname) - echo "Running $pkgs" - gotestsum --junitfile "$TEST_RESULTS/gotestsum-report.xml" -- $pkgs -p 1 -timeout 2h -failfast \ - << parameters.additional-flags >> \ - -enable-multi-cluster \ - ${ENABLE_ENTERPRISE:+-enable-enterprise} \ - -debug-directory="$TEST_RESULTS/debug" \ - -consul-k8s-image=<< parameters.consul-k8s-image >> - -jobs: - go-fmt-and-vet-control-plane: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} - - - run: - name: go mod download - working_directory: *control-plane-path - command: go mod download - - # Save go module cache if the go.mod file has changed - - save_cache: - key: consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} - paths: - - "/home/circleci/go/pkg/mod" - - # check go fmt output because it does not report non-zero when there are fmt changes - - run: - name: check go fmt - working_directory: *control-plane-path - command: | - files=$(go fmt ./...) - if [ -n "$files" ]; then - echo "The following file(s) do not conform to go fmt:" - echo "$files" - exit 1 - fi - - run: cd control-plane && go vet ./... - - lint-control-plane: - executor: go - steps: - - checkout - - run: go get -u github.com/hashicorp/lint-consul-retry && lint-consul-retry - - run: - name: run lint - working_directory: *control-plane-path - command: go run hack/lint-api-new-client/main.go - - test-control-plane: - executor: go - environment: - TEST_RESULTS: /tmp/test-results - parallelism: 1 - steps: - - checkout - - run: mkdir -p $TEST_RESULTS - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} - - # run go tests with gotestsum - - run: - name: run go tests - working_directory: *control-plane-path - command: | - # download and install the consul binary - wget https://releases.hashicorp.com/consul/"${CONSUL_VERSION}"/consul_"${CONSUL_VERSION}"_linux_amd64.zip && \ - unzip consul_"${CONSUL_VERSION}"_linux_amd64.zip -d /home/circleci/bin && - rm consul_"${CONSUL_VERSION}"_linux_amd64.zip - PACKAGE_NAMES=$(go list ./...) - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - test-enterprise-control-plane: - executor: go - environment: - TEST_RESULTS: /tmp/test-results - parallelism: 1 - steps: - - checkout - - run: mkdir -p $TEST_RESULTS - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} - - # run go tests with gotestsum - - run: - name: run enterprise go tests - working_directory: *control-plane-path - command: | - # download and install the consul binary - wget https://releases.hashicorp.com/consul/"${CONSUL_ENT_VERSION}"/consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip && \ - unzip consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip -d /home/circleci/bin && - rm consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip - PACKAGE_NAMES=$(go list ./...) - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - build-distro: # defines a parameterized job - description: A job that will build the os/arch distro set by XC_OS and XC_ARCH - parameters: - OS: - description: What OSes to build - default: "" - type: string - ARCH: - description: What architectures to build - default: "" - type: string - executor: go - environment: - GOXPARALLEL: 2 # CircleCI containers are 2 CPU x 4GB RAM - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} - - run: - name: build local - working_directory: *control-plane-path - command: XC_OS="<< parameters.OS >>" XC_ARCH="<< parameters.ARCH >>" ./build-support/scripts/build-local.sh - # persist to downstream job - - persist_to_workspace: - root: . - paths: - - control-plane/pkg/bin - # save dev build to CircleCI - - store_artifacts: - path: ./control-plane/pkg/bin - - # upload dev docker image - dev-upload-docker: - executor: go - steps: - - checkout - # get consul-k8s binary - - attach_workspace: - at: . - - setup_remote_docker - - run: - name: make ci.dev-docker - working_directory: *control-plane-path - command: make ci.dev-docker - - unit-cli: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-k8s-cli-modcache-v2-{{ checksum "cli/go.mod" }} - - - run: - name: go mod download - working_directory: *cli-path - command: go mod download - - # Save go module cache if the go.mod file has changed - - save_cache: - key: consul-k8s-cli-modcache-v2-{{ checksum "cli/go.mod" }} - paths: - - "/home/circleci/go/pkg/mod" - - - run: mkdir -p $TEST_RESULTS - - - run: - name: Run tests - working_directory: *cli-path - command: | - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - go-fmt-and-vet-acceptance: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - - - run: - name: go mod download - working_directory: *acceptance-mod-path - command: go mod download - - # Save go module cache if the go.mod file has changed - - save_cache: - key: consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - paths: - - "/home/circleci/go/pkg/mod" - - # check go fmt output because it does not report non-zero when there are fmt changes - - run: - name: check go fmt - working_directory: *acceptance-mod-path - command: | - files=$(go fmt ./...) - if [ -n "$files" ]; then - echo "The following file(s) do not conform to go fmt:" - echo "$files" - exit 1 - fi - - - run: - name: go vet - working_directory: *acceptance-mod-path - command: go vet ./... - - go-fmt-and-vet-helm-gen: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} - - - run: - name: go mod download - working_directory: *helm-gen-path - command: go mod download - - # Save go module cache if the go.mod file has changed - - save_cache: - key: consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} - paths: - - "/home/circleci/go/pkg/mod" - - # check go fmt output because it does not report non-zero when there are fmt changes - - run: - name: check go fmt - working_directory: *helm-gen-path - command: | - files=$(go fmt ./...) - if [ -n "$files" ]; then - echo "The following file(s) do not conform to go fmt:" - echo "$files" - exit 1 - fi - - - run: - name: go vet - working_directory: *helm-gen-path - command: go vet ./... - - unit-acceptance-framework: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run: - name: Run tests - working_directory: *acceptance-framework-path - command: | - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - unit-helm-gen: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run: - name: Run tests - working_directory: *helm-gen-path - command: | - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - validate-helm-gen: - executor: go - steps: - - checkout - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run: - name: Validate helm gen - working_directory: *helm-gen-path - command: | - go run ./... -validate - - unit-test-helm-templates: - docker: - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - - steps: - - checkout - - - run: - name: Run Unit Tests - working_directory: charts/consul - command: bats --jobs 4 ./test/unit - - acceptance: - environment: - - TEST_RESULTS: /tmp/test-results - machine: - image: ubuntu-2004:202010-01 - resource_class: xlarge - parallelism: 6 - steps: - - checkout - - install-prereqs - - create-kind-clusters: - version: "v1.22.4" - - restore_cache: - keys: - - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} - - run: - name: go mod download - working_directory: *acceptance-mod-path - command: go mod download - - save_cache: - key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} - paths: - - ~/.go_workspace/pkg/mod - - run: mkdir -p $TEST_RESULTS - - run-acceptance-tests: - failfast: true - additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - acceptance-tproxy: - environment: - - TEST_RESULTS: /tmp/test-results - machine: - image: ubuntu-2004:202010-01 - resource_class: xlarge - parallelism: 6 - steps: - - checkout - - install-prereqs - - create-kind-clusters: - version: "v1.22.4" - - restore_cache: - keys: - - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} - - run: - name: go mod download - working_directory: *acceptance-mod-path - command: go mod download - - save_cache: - key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} - paths: - - ~/.go_workspace/pkg/mod - - run: mkdir -p $TEST_RESULTS - - run-acceptance-tests: - failfast: true - additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" -enable-transparent-proxy - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - ########################## - # CLEANUP CLOUD RESOURCES - ########################## - cleanup-gcp-resources: - docker: - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - steps: - - run: - name: cleanup leftover resources - command: | - echo "${GOOGLE_CREDENTIALS}" | gcloud auth activate-service-account --key-file=- - clusters=$(gcloud container clusters list --zone us-central1-a --project ${CLOUDSDK_CORE_PROJECT} --format json | jq -r '.[] | select(.name | test("^consul-k8s-\\d+$")) | .name') - for cluster in $clusters; do - echo "Deleting $cluster GKE cluster" - gcloud container clusters delete $cluster --zone us-central1-a --project ${CLOUDSDK_CORE_PROJECT} --quiet - done - - slack/status: - fail_only: true - failure_message: "GKE cleanup failed" - - cleanup-azure-resources: - docker: - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - steps: - - run: - name: cleanup leftover resources - command: | - az login --service-principal -u "$ARM_CLIENT_ID" -p "$ARM_CLIENT_SECRET" --tenant "$ARM_TENANT_ID" > /dev/null - resource_groups=$(az group list -o json | jq -r '.[] | select(.name | test("^consul-k8s-\\d+$")) | .name') - for group in $resource_groups; do - echo "Deleting $group resource group" - az group delete -n $group --yes - done - - slack/status: - fail_only: true - failure_message: "AKS cleanup failed" - - cleanup-eks-resources: - docker: - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - steps: - - checkout - - run: - name: cleanup eks resources - command: | - # Assume the role and set environment variables. - aws sts assume-role --role-arn "$AWS_ROLE_ARN" --role-session-name "consul-helm-$CIRCLE_BUILD_NUM" --duration-seconds 10800 > assume-role.json - export AWS_ACCESS_KEY_ID="$(jq -r .Credentials.AccessKeyId assume-role.json)" - export AWS_SECRET_ACCESS_KEY="$(jq -r .Credentials.SecretAccessKey assume-role.json)" - export AWS_SESSION_TOKEN="$(jq -r .Credentials.SessionToken assume-role.json)" - - make ci.aws-acceptance-test-cleanup - - slack/status: - fail_only: true - failure_message: "EKS cleanup failed" - - ######################## - # ACCEPTANCE TESTS - ######################## - acceptance-gke-1-20: - environment: - - TEST_RESULTS: /tmp/test-results - docker: - # This image is built from test/docker/Test.dockerfile - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - - steps: - - run: - name: Exit if forked PR - command: | - if [ -n "$CIRCLE_PR_NUMBER" ]; then - echo "Skipping acceptance tests for forked PRs; marking step successful." - circleci step halt - fi - - - checkout - - - run: - name: terraform init & apply - working_directory: *gke-terraform-path - command: | - terraform init - echo "${GOOGLE_CREDENTIALS}" | gcloud auth activate-service-account --key-file=- - - # On GKE, we're setting the build number instead of build URL because label values - # cannot contain '/'. - terraform apply \ - -var project=${CLOUDSDK_CORE_PROJECT} \ - -var init_cli=true \ - -var cluster_count=2 \ - -var labels="{\"build_number\": \"$CIRCLE_BUILD_NUM\"}" \ - -auto-approve - - primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) - secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) - - echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV - echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run-acceptance-tests: - additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-pod-security-policies -enable-transparent-proxy - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - - run: - name: terraform destroy - working_directory: *gke-terraform-path - command: | - terraform destroy -var project=${CLOUDSDK_CORE_PROJECT} -auto-approve - when: always - - - slack/status: - fail_only: true - failure_message: "GKE acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - - acceptance-aks-1-21: - environment: - - TEST_RESULTS: /tmp/test-results - docker: - # This image is built from test/docker/Test.dockerfile - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - - steps: - - checkout - - - run: - name: terraform init & apply - working_directory: *aks-terraform-path - command: | - terraform init - - terraform apply \ - -var client_id="$ARM_CLIENT_ID" \ - -var client_secret="$ARM_CLIENT_SECRET" \ - -var cluster_count=2 \ - -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" \ - -auto-approve - - primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) - secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) - - echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV - echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run-acceptance-tests: - additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-transparent-proxy - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - - run: - name: terraform destroy - working_directory: *aks-terraform-path - command: | - terraform destroy -auto-approve - when: always - - - slack/status: - fail_only: true - failure_message: "AKS acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - - acceptance-eks-1-19: - environment: - - TEST_RESULTS: /tmp/test-results - docker: - # This image is built from test/docker/Test.dockerfile - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - - steps: - - checkout - - - run: - name: configure aws - command: | - aws configure --profile helm_user set aws_access_key_id "$AWS_ACCESS_KEY_ID" - aws configure --profile helm_user set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" - aws configure set role_arn "$AWS_ROLE_ARN" - aws configure set source_profile helm_user - - echo "unset AWS_ACCESS_KEY_ID" >> $BASH_ENV - echo "unset AWS_SECRET_ACCESS_KEY" >> $BASH_ENV - - - run: - name: terraform init & apply - working_directory: *eks-terraform-path - command: | - terraform init - - terraform apply -var cluster_count=2 -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" -auto-approve - - primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) - secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) - - echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV - echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run-acceptance-tests: - additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-transparent-proxy - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - - run: - name: terraform destroy - working_directory: *eks-terraform-path - command: | - terraform destroy -var cluster_count=2 -auto-approve - when: always - - - slack/status: - fail_only: true - failure_message: "EKS acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - - acceptance-openshift: - environment: - TEST_RESULTS: /tmp/test-results - parallelism: 1 - docker: - # This image is built from test/docker/Test.dockerfile - - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - - steps: - - checkout - - run: - name: terraform init & apply - working_directory: *openshift-terraform-path - command: | - terraform init - az login --service-principal -u "$ARM_CLIENT_ID" -p "$ARM_CLIENT_SECRET" --tenant "$ARM_TENANT_ID" > /dev/null - terraform apply \ - -var cluster_count=2 \ - -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" \ - -auto-approve - - primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) - secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) - - echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV - echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV - - # Restore go module cache if there is one - - restore_cache: - keys: - - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} - - - run: mkdir -p $TEST_RESULTS - - - run-acceptance-tests: - additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-openshift -enable-transparent-proxy - - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - - run: - name: terraform destroy - working_directory: *openshift-terraform-path - command: | - terraform destroy -auto-approve - when: always - - - slack/status: - fail_only: true - failure_message: "OpenShift acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" - - acceptance-kind-1-23: - environment: - - TEST_RESULTS: /tmp/test-results - machine: - image: ubuntu-2004:202010-01 - resource_class: xlarge - steps: - - checkout - - install-prereqs - - create-kind-clusters: - version: "v1.23.0" - - restore_cache: - keys: - - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} - - run: - name: go mod download - working_directory: *acceptance-mod-path - command: go mod download - - save_cache: - key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} - paths: - - ~/.go_workspace/pkg/mod - - run: mkdir -p $TEST_RESULTS - - run-acceptance-tests: - additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" -enable-transparent-proxy - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - - slack/status: - fail_only: true - failure_message: "Acceptance tests against Kind with Kubernetes v1.22 failed. Check the logs at: ${CIRCLE_BUILD_URL}" - - update-helm-charts-index: - docker: - - image: docker.mirror.hashicorp.services/circleci/golang:latest - steps: - - checkout - - run: - name: verify chart version matches tag version - working_directory: *charts-consul-path - command: | - GO111MODULE=on go get github.com/mikefarah/yq/v2 - git_tag=$(echo "${CIRCLE_TAG#v}") - chart_tag=$(yq r Chart.yaml version) - if [ "${git_tag}" != "${chart_tag}" ]; then - echo "chart version (${chart_tag}) did not match git version (${git_tag})" - exit 1 - fi - - run: - name: update helm-charts index - command: | - curl --show-error --silent --fail --user "${CIRCLE_TOKEN}:" \ - -X POST \ - -H 'Content-Type: application/json' \ - -H 'Accept: application/json' \ - -d "{\"branch\": \"master\",\"parameters\":{\"SOURCE_REPO\": \"${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}\",\"SOURCE_TAG\": \"${CIRCLE_TAG}\"}}" \ - "${CIRCLE_ENDPOINT}/${CIRCLE_PROJECT}/pipeline" - - slack/status: - fail_only: true - failure_message: "Failed to trigger an update to the helm charts index. Check the logs at: ${CIRCLE_BUILD_URL}" - -workflows: - version: 2 - test-and-build: - jobs: - # Fmt, vet, lint control plane and helm code - - go-fmt-and-vet-control-plane - - lint-control-plane - - go-fmt-and-vet-acceptance - - go-fmt-and-vet-helm-gen - # Unit test control plane - - test-control-plane: - requires: - - go-fmt-and-vet-control-plane - - lint-control-plane - - test-enterprise-control-plane: - filters: - branches: - # Forked pull requests have CIRCLE_BRANCH set to pull/XXX. - ignore: /pull\/[0-9]+/ - requires: - - go-fmt-and-vet-control-plane - - lint-control-plane - # Unit test CLI - - unit-cli - # Unit tests for go modules in helm and bats tests for templates - - unit-acceptance-framework: - requires: - - go-fmt-and-vet-acceptance - - unit-helm-gen: - requires: - - go-fmt-and-vet-helm-gen - - validate-helm-gen - - unit-test-helm-templates - # Build control plane binaries - - build-distro: - OS: "freebsd linux windows" - ARCH: "386" - name: build-distros-386 - requires: - - test-control-plane - - test-enterprise-control-plane - - build-distro: - OS: "darwin freebsd linux solaris windows" - ARCH: "amd64" - name: build-distros-amd64 - requires: - - test-control-plane - - test-enterprise-control-plane - - build-distro: - OS: "linux" - ARCH: "arm arm64" - name: build-distros-arm-arm64 - requires: - - test-control-plane - - test-enterprise-control-plane - - dev-upload-docker: - context: consul-ci - requires: - - build-distros-amd64 - # Run acceptance tests using the docker image built for the control plane - - acceptance: - requires: - - dev-upload-docker - - unit-test-helm-templates - - unit-acceptance-framework - - unit-cli - - acceptance-tproxy: - requires: - - dev-upload-docker - - unit-test-helm-templates - - unit-acceptance-framework - - unit-cli - nightly-acceptance-tests: - triggers: - - schedule: - cron: "0 0 * * *" - filters: - branches: - only: - - main - jobs: - - cleanup-gcp-resources - - cleanup-azure-resources - - cleanup-eks-resources -# Disable until we can use UBI images. -# - acceptance-openshift: -# requires: -# - cleanup-azure-resources - - acceptance-gke-1-20: - requires: - - cleanup-gcp-resources - - acceptance-eks-1-19: - requires: - - cleanup-eks-resources - - acceptance-aks-1-21: - requires: - - cleanup-azure-resources - - acceptance-kind-1-23 +# # Originally from consul-k8s +# version: 2.1 +# orbs: +# slack: circleci/slack@3.4.2 +# # reusable 'executor' object for jobs +# executors: +# go: +# docker: +# - image: docker.mirror.hashicorp.services/cimg/go:1.17.5 +# environment: +# TEST_RESULTS: /tmp/test-results # path to where test results are saved +# CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests +# CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests + +# control-plane-path : &control-plane-path control-plane +# cli-path : &cli-path cli +# acceptance-mod-path: &acceptance-mod-path acceptance +# acceptance-test-path: &acceptance-test-path acceptance/tests +# acceptance-framework-path: &acceptance-framework-path acceptance/framework +# charts-consul-path: &charts-consul-path charts/consul +# helm-gen-path: &helm-gen-path hack/helm-reference-gen +# gke-terraform-path: &gke-terraform-path charts/consul/test/terraform/gke +# eks-terraform-path: &eks-terraform-path charts/consul/test/terraform/eks +# aks-terraform-path: &aks-terraform-path charts/consul/test/terraform/aks +# openshift-terraform-path: &openshift-terraform-path charts/consul/test/terraform/openshift + +# commands: +# install-prereqs: +# steps: +# - run: +# name: Install gotestsum, kind, kubectl, and helm +# command: | +# wget https://golang.org/dl/go1.17.5.linux-amd64.tar.gz +# sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.5.linux-amd64.tar.gz +# rm go1.17.5.linux-amd64.tar.gz +# echo 'export PATH=$PATH:/usr/local/go/bin' >> $BASH_ENV + +# wget https://github.com/gotestyourself/gotestsum/releases/download/v1.6.4/gotestsum_1.6.4_linux_amd64.tar.gz +# sudo tar -C /usr/local/bin -xzf gotestsum_1.6.4_linux_amd64.tar.gz +# rm gotestsum_1.6.4_linux_amd64.tar.gz + +# curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.0/kind-linux-amd64 +# chmod +x ./kind +# sudo mv ./kind /usr/local/bin/kind + +# curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" +# chmod +x ./kubectl +# sudo mv ./kubectl /usr/local/bin/kubectl + +# wget https://get.helm.sh/helm-v3.7.0-linux-amd64.tar.gz +# tar -zxvf helm-v3.7.0-linux-amd64.tar.gz +# sudo mv linux-amd64/helm /usr/local/bin/helm + +# create-kind-clusters: +# parameters: +# version: +# type: string +# steps: +# - run: +# name: Create kind clusters +# command: | +# kind create cluster --name dc1 --image kindest/node:<< parameters.version >> +# kind create cluster --name dc2 --image kindest/node:<< parameters.version >> +# run-acceptance-tests: +# parameters: +# failfast: +# type: boolean +# default: false +# additional-flags: +# type: string +# consul-k8s-image: +# type: string +# default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" +# go-path: +# type: string +# default: "/home/circleci/.go_workspace" +# steps: +# - when: +# condition: << parameters.failfast >> +# steps: +# - run: +# name: Run acceptance tests +# working_directory: *acceptance-test-path +# no_output_timeout: 2h +# command: | +# # Enterprise tests can't run on fork PRs because they require +# # a secret. +# if [ -z "$CIRCLE_PR_NUMBER" ]; then +# ENABLE_ENTERPRISE=true +# fi + +# # We have to run the tests for each package separately so that we can +# # exit early if any test fails (-failfast only works within a single +# # package). +# exit_code=0 +# pkgs=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname) +# echo "Running $(echo $pkgs | wc -w) packages:" +# echo $pkgs +# for pkg in $pkgs +# do +# if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ +# << parameters.additional-flags >> \ +# ${ENABLE_ENTERPRISE:+-enable-enterprise} \ +# -enable-multi-cluster \ +# -debug-directory="$TEST_RESULTS/debug" \ +# -consul-k8s-image=<< parameters.consul-k8s-image >> +# then +# echo "Tests in ${pkg} failed, aborting early" +# exit_code=1 +# break +# fi +# done +# gotestsum --raw-command --junitfile "$TEST_RESULTS/gotestsum-report.xml" -- cat jsonfile* +# exit $exit_code + +# - unless: +# condition: << parameters.failfast >> +# steps: +# - run: +# name: Run acceptance tests +# working_directory: *acceptance-test-path +# no_output_timeout: 2h +# command: | +# # Enterprise tests can't run on fork PRs because they require +# # a secret. +# if [ -z "$CIRCLE_PR_NUMBER" ]; then +# ENABLE_ENTERPRISE=true +# fi + +# pkgs=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname) +# echo "Running $pkgs" +# gotestsum --junitfile "$TEST_RESULTS/gotestsum-report.xml" -- $pkgs -p 1 -timeout 2h -failfast \ +# << parameters.additional-flags >> \ +# -enable-multi-cluster \ +# ${ENABLE_ENTERPRISE:+-enable-enterprise} \ +# -debug-directory="$TEST_RESULTS/debug" \ +# -consul-k8s-image=<< parameters.consul-k8s-image >> + +# jobs: +# go-fmt-and-vet-control-plane: +# executor: go +# steps: +# - checkout + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} + +# - run: +# name: go mod download +# working_directory: *control-plane-path +# command: go mod download + +# # Save go module cache if the go.mod file has changed +# - save_cache: +# key: consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} +# paths: +# - "/home/circleci/go/pkg/mod" + +# # check go fmt output because it does not report non-zero when there are fmt changes +# - run: +# name: check go fmt +# working_directory: *control-plane-path +# command: | +# files=$(go fmt ./...) +# if [ -n "$files" ]; then +# echo "The following file(s) do not conform to go fmt:" +# echo "$files" +# exit 1 +# fi +# - run: cd control-plane && go vet ./... + +# lint-control-plane: +# executor: go +# steps: +# - checkout +# - run: go get -u github.com/hashicorp/lint-consul-retry && lint-consul-retry +# - run: +# name: run lint +# working_directory: *control-plane-path +# command: go run hack/lint-api-new-client/main.go + +# test-control-plane: +# executor: go +# environment: +# TEST_RESULTS: /tmp/test-results +# parallelism: 1 +# steps: +# - checkout +# - run: mkdir -p $TEST_RESULTS + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} + +# # run go tests with gotestsum +# - run: +# name: run go tests +# working_directory: *control-plane-path +# command: | +# # download and install the consul binary +# wget https://releases.hashicorp.com/consul/"${CONSUL_VERSION}"/consul_"${CONSUL_VERSION}"_linux_amd64.zip && \ +# unzip consul_"${CONSUL_VERSION}"_linux_amd64.zip -d /home/circleci/bin && +# rm consul_"${CONSUL_VERSION}"_linux_amd64.zip +# PACKAGE_NAMES=$(go list ./...) +# gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES + +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# test-enterprise-control-plane: +# executor: go +# environment: +# TEST_RESULTS: /tmp/test-results +# parallelism: 1 +# steps: +# - checkout +# - run: mkdir -p $TEST_RESULTS + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} + +# # run go tests with gotestsum +# - run: +# name: run enterprise go tests +# working_directory: *control-plane-path +# command: | +# # download and install the consul binary +# wget https://releases.hashicorp.com/consul/"${CONSUL_ENT_VERSION}"/consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip && \ +# unzip consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip -d /home/circleci/bin && +# rm consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip +# PACKAGE_NAMES=$(go list ./...) +# gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES + +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# build-distro: # defines a parameterized job +# description: A job that will build the os/arch distro set by XC_OS and XC_ARCH +# parameters: +# OS: +# description: What OSes to build +# default: "" +# type: string +# ARCH: +# description: What architectures to build +# default: "" +# type: string +# executor: go +# environment: +# GOXPARALLEL: 2 # CircleCI containers are 2 CPU x 4GB RAM +# steps: +# - checkout + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} +# - run: +# name: build local +# working_directory: *control-plane-path +# command: XC_OS="<< parameters.OS >>" XC_ARCH="<< parameters.ARCH >>" ./build-support/scripts/build-local.sh +# # persist to downstream job +# - persist_to_workspace: +# root: . +# paths: +# - control-plane/pkg/bin +# # save dev build to CircleCI +# - store_artifacts: +# path: ./control-plane/pkg/bin + +# # upload dev docker image +# dev-upload-docker: +# executor: go +# steps: +# - checkout +# # get consul-k8s binary +# - attach_workspace: +# at: . +# - setup_remote_docker +# - run: +# name: make ci.dev-docker +# working_directory: *control-plane-path +# command: make ci.dev-docker + +# unit-cli: +# executor: go +# steps: +# - checkout + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-k8s-cli-modcache-v2-{{ checksum "cli/go.mod" }} + +# - run: +# name: go mod download +# working_directory: *cli-path +# command: go mod download + +# # Save go module cache if the go.mod file has changed +# - save_cache: +# key: consul-k8s-cli-modcache-v2-{{ checksum "cli/go.mod" }} +# paths: +# - "/home/circleci/go/pkg/mod" + +# - run: mkdir -p $TEST_RESULTS + +# - run: +# name: Run tests +# working_directory: *cli-path +# command: | +# gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 + +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# go-fmt-and-vet-acceptance: +# executor: go +# steps: +# - checkout + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + +# - run: +# name: go mod download +# working_directory: *acceptance-mod-path +# command: go mod download + +# # Save go module cache if the go.mod file has changed +# - save_cache: +# key: consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} +# paths: +# - "/home/circleci/go/pkg/mod" + +# # check go fmt output because it does not report non-zero when there are fmt changes +# - run: +# name: check go fmt +# working_directory: *acceptance-mod-path +# command: | +# files=$(go fmt ./...) +# if [ -n "$files" ]; then +# echo "The following file(s) do not conform to go fmt:" +# echo "$files" +# exit 1 +# fi + +# - run: +# name: go vet +# working_directory: *acceptance-mod-path +# command: go vet ./... + +# go-fmt-and-vet-helm-gen: +# executor: go +# steps: +# - checkout + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + +# - run: +# name: go mod download +# working_directory: *helm-gen-path +# command: go mod download + +# # Save go module cache if the go.mod file has changed +# - save_cache: +# key: consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} +# paths: +# - "/home/circleci/go/pkg/mod" + +# # check go fmt output because it does not report non-zero when there are fmt changes +# - run: +# name: check go fmt +# working_directory: *helm-gen-path +# command: | +# files=$(go fmt ./...) +# if [ -n "$files" ]; then +# echo "The following file(s) do not conform to go fmt:" +# echo "$files" +# exit 1 +# fi + +# - run: +# name: go vet +# working_directory: *helm-gen-path +# command: go vet ./... + +# unit-acceptance-framework: +# executor: go +# steps: +# - checkout + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + +# - run: mkdir -p $TEST_RESULTS + +# - run: +# name: Run tests +# working_directory: *acceptance-framework-path +# command: | +# gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 + +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# unit-helm-gen: +# executor: go +# steps: +# - checkout + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + +# - run: mkdir -p $TEST_RESULTS + +# - run: +# name: Run tests +# working_directory: *helm-gen-path +# command: | +# gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 + +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# validate-helm-gen: +# executor: go +# steps: +# - checkout + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + +# - run: mkdir -p $TEST_RESULTS + +# - run: +# name: Validate helm gen +# working_directory: *helm-gen-path +# command: | +# go run ./... -validate + +# unit-test-helm-templates: +# docker: +# - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + +# steps: +# - checkout + +# - run: +# name: Run Unit Tests +# working_directory: charts/consul +# command: bats --jobs 4 ./test/unit + +# acceptance: +# environment: +# - TEST_RESULTS: /tmp/test-results +# machine: +# image: ubuntu-2004:202010-01 +# resource_class: xlarge +# parallelism: 6 +# steps: +# - checkout +# - install-prereqs +# - create-kind-clusters: +# version: "v1.22.4" +# - restore_cache: +# keys: +# - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} +# - run: +# name: go mod download +# working_directory: *acceptance-mod-path +# command: go mod download +# - save_cache: +# key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} +# paths: +# - ~/.go_workspace/pkg/mod +# - run: mkdir -p $TEST_RESULTS +# - run-acceptance-tests: +# failfast: true +# additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# acceptance-tproxy: +# environment: +# - TEST_RESULTS: /tmp/test-results +# machine: +# image: ubuntu-2004:202010-01 +# resource_class: xlarge +# parallelism: 6 +# steps: +# - checkout +# - install-prereqs +# - create-kind-clusters: +# version: "v1.22.4" +# - restore_cache: +# keys: +# - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} +# - run: +# name: go mod download +# working_directory: *acceptance-mod-path +# command: go mod download +# - save_cache: +# key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} +# paths: +# - ~/.go_workspace/pkg/mod +# - run: mkdir -p $TEST_RESULTS +# - run-acceptance-tests: +# failfast: true +# additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" -enable-transparent-proxy +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# ########################## +# # CLEANUP CLOUD RESOURCES +# ########################## +# cleanup-gcp-resources: +# docker: +# - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 +# steps: +# - run: +# name: cleanup leftover resources +# command: | +# echo "${GOOGLE_CREDENTIALS}" | gcloud auth activate-service-account --key-file=- +# clusters=$(gcloud container clusters list --zone us-central1-a --project ${CLOUDSDK_CORE_PROJECT} --format json | jq -r '.[] | select(.name | test("^consul-k8s-\\d+$")) | .name') +# for cluster in $clusters; do +# echo "Deleting $cluster GKE cluster" +# gcloud container clusters delete $cluster --zone us-central1-a --project ${CLOUDSDK_CORE_PROJECT} --quiet +# done +# - slack/status: +# fail_only: true +# failure_message: "GKE cleanup failed" + +# cleanup-azure-resources: +# docker: +# - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 +# steps: +# - run: +# name: cleanup leftover resources +# command: | +# az login --service-principal -u "$ARM_CLIENT_ID" -p "$ARM_CLIENT_SECRET" --tenant "$ARM_TENANT_ID" > /dev/null +# resource_groups=$(az group list -o json | jq -r '.[] | select(.name | test("^consul-k8s-\\d+$")) | .name') +# for group in $resource_groups; do +# echo "Deleting $group resource group" +# az group delete -n $group --yes +# done +# - slack/status: +# fail_only: true +# failure_message: "AKS cleanup failed" + +# cleanup-eks-resources: +# docker: +# - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 +# steps: +# - checkout +# - run: +# name: cleanup eks resources +# command: | +# # Assume the role and set environment variables. +# aws sts assume-role --role-arn "$AWS_ROLE_ARN" --role-session-name "consul-helm-$CIRCLE_BUILD_NUM" --duration-seconds 10800 > assume-role.json +# export AWS_ACCESS_KEY_ID="$(jq -r .Credentials.AccessKeyId assume-role.json)" +# export AWS_SECRET_ACCESS_KEY="$(jq -r .Credentials.SecretAccessKey assume-role.json)" +# export AWS_SESSION_TOKEN="$(jq -r .Credentials.SessionToken assume-role.json)" + +# make ci.aws-acceptance-test-cleanup +# - slack/status: +# fail_only: true +# failure_message: "EKS cleanup failed" + +# ######################## +# # ACCEPTANCE TESTS +# ######################## +# acceptance-gke-1-20: +# environment: +# - TEST_RESULTS: /tmp/test-results +# docker: +# # This image is built from test/docker/Test.dockerfile +# - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + +# steps: +# - run: +# name: Exit if forked PR +# command: | +# if [ -n "$CIRCLE_PR_NUMBER" ]; then +# echo "Skipping acceptance tests for forked PRs; marking step successful." +# circleci step halt +# fi + +# - checkout + +# - run: +# name: terraform init & apply +# working_directory: *gke-terraform-path +# command: | +# terraform init +# echo "${GOOGLE_CREDENTIALS}" | gcloud auth activate-service-account --key-file=- + +# # On GKE, we're setting the build number instead of build URL because label values +# # cannot contain '/'. +# terraform apply \ +# -var project=${CLOUDSDK_CORE_PROJECT} \ +# -var init_cli=true \ +# -var cluster_count=2 \ +# -var labels="{\"build_number\": \"$CIRCLE_BUILD_NUM\"}" \ +# -auto-approve + +# primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) +# secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) + +# echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV +# echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + +# - run: mkdir -p $TEST_RESULTS + +# - run-acceptance-tests: +# additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-pod-security-policies -enable-transparent-proxy + +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# - run: +# name: terraform destroy +# working_directory: *gke-terraform-path +# command: | +# terraform destroy -var project=${CLOUDSDK_CORE_PROJECT} -auto-approve +# when: always + +# - slack/status: +# fail_only: true +# failure_message: "GKE acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" + +# acceptance-aks-1-21: +# environment: +# - TEST_RESULTS: /tmp/test-results +# docker: +# # This image is built from test/docker/Test.dockerfile +# - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + +# steps: +# - checkout + +# - run: +# name: terraform init & apply +# working_directory: *aks-terraform-path +# command: | +# terraform init + +# terraform apply \ +# -var client_id="$ARM_CLIENT_ID" \ +# -var client_secret="$ARM_CLIENT_SECRET" \ +# -var cluster_count=2 \ +# -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" \ +# -auto-approve + +# primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) +# secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) + +# echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV +# echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + +# - run: mkdir -p $TEST_RESULTS + +# - run-acceptance-tests: +# additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-transparent-proxy + +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# - run: +# name: terraform destroy +# working_directory: *aks-terraform-path +# command: | +# terraform destroy -auto-approve +# when: always + +# - slack/status: +# fail_only: true +# failure_message: "AKS acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" + +# acceptance-eks-1-19: +# environment: +# - TEST_RESULTS: /tmp/test-results +# docker: +# # This image is built from test/docker/Test.dockerfile +# - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + +# steps: +# - checkout + +# - run: +# name: configure aws +# command: | +# aws configure --profile helm_user set aws_access_key_id "$AWS_ACCESS_KEY_ID" +# aws configure --profile helm_user set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" +# aws configure set role_arn "$AWS_ROLE_ARN" +# aws configure set source_profile helm_user + +# echo "unset AWS_ACCESS_KEY_ID" >> $BASH_ENV +# echo "unset AWS_SECRET_ACCESS_KEY" >> $BASH_ENV + +# - run: +# name: terraform init & apply +# working_directory: *eks-terraform-path +# command: | +# terraform init + +# terraform apply -var cluster_count=2 -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" -auto-approve + +# primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) +# secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) + +# echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV +# echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + +# - run: mkdir -p $TEST_RESULTS + +# - run-acceptance-tests: +# additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-transparent-proxy + +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# - run: +# name: terraform destroy +# working_directory: *eks-terraform-path +# command: | +# terraform destroy -var cluster_count=2 -auto-approve +# when: always + +# - slack/status: +# fail_only: true +# failure_message: "EKS acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" + +# acceptance-openshift: +# environment: +# TEST_RESULTS: /tmp/test-results +# parallelism: 1 +# docker: +# # This image is built from test/docker/Test.dockerfile +# - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + +# steps: +# - checkout +# - run: +# name: terraform init & apply +# working_directory: *openshift-terraform-path +# command: | +# terraform init +# az login --service-principal -u "$ARM_CLIENT_ID" -p "$ARM_CLIENT_SECRET" --tenant "$ARM_TENANT_ID" > /dev/null +# terraform apply \ +# -var cluster_count=2 \ +# -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" \ +# -auto-approve + +# primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) +# secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) + +# echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV +# echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV + +# # Restore go module cache if there is one +# - restore_cache: +# keys: +# - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + +# - run: mkdir -p $TEST_RESULTS + +# - run-acceptance-tests: +# additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-openshift -enable-transparent-proxy + +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results + +# - run: +# name: terraform destroy +# working_directory: *openshift-terraform-path +# command: | +# terraform destroy -auto-approve +# when: always + +# - slack/status: +# fail_only: true +# failure_message: "OpenShift acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" + +# acceptance-kind-1-23: +# environment: +# - TEST_RESULTS: /tmp/test-results +# machine: +# image: ubuntu-2004:202010-01 +# resource_class: xlarge +# steps: +# - checkout +# - install-prereqs +# - create-kind-clusters: +# version: "v1.23.0" +# - restore_cache: +# keys: +# - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} +# - run: +# name: go mod download +# working_directory: *acceptance-mod-path +# command: go mod download +# - save_cache: +# key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} +# paths: +# - ~/.go_workspace/pkg/mod +# - run: mkdir -p $TEST_RESULTS +# - run-acceptance-tests: +# additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" -enable-transparent-proxy +# - store_test_results: +# path: /tmp/test-results +# - store_artifacts: +# path: /tmp/test-results +# - slack/status: +# fail_only: true +# failure_message: "Acceptance tests against Kind with Kubernetes v1.22 failed. Check the logs at: ${CIRCLE_BUILD_URL}" + +# update-helm-charts-index: +# docker: +# - image: docker.mirror.hashicorp.services/circleci/golang:latest +# steps: +# - checkout +# - run: +# name: verify chart version matches tag version +# working_directory: *charts-consul-path +# command: | +# GO111MODULE=on go get github.com/mikefarah/yq/v2 +# git_tag=$(echo "${CIRCLE_TAG#v}") +# chart_tag=$(yq r Chart.yaml version) +# if [ "${git_tag}" != "${chart_tag}" ]; then +# echo "chart version (${chart_tag}) did not match git version (${git_tag})" +# exit 1 +# fi +# - run: +# name: update helm-charts index +# command: | +# curl --show-error --silent --fail --user "${CIRCLE_TOKEN}:" \ +# -X POST \ +# -H 'Content-Type: application/json' \ +# -H 'Accept: application/json' \ +# -d "{\"branch\": \"master\",\"parameters\":{\"SOURCE_REPO\": \"${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}\",\"SOURCE_TAG\": \"${CIRCLE_TAG}\"}}" \ +# "${CIRCLE_ENDPOINT}/${CIRCLE_PROJECT}/pipeline" +# - slack/status: +# fail_only: true +# failure_message: "Failed to trigger an update to the helm charts index. Check the logs at: ${CIRCLE_BUILD_URL}" + +# workflows: +# version: 2 +# test-and-build: +# jobs: +# # Fmt, vet, lint control plane and helm code +# - go-fmt-and-vet-control-plane +# - lint-control-plane +# - go-fmt-and-vet-acceptance +# - go-fmt-and-vet-helm-gen +# # Unit test control plane +# - test-control-plane: +# requires: +# - go-fmt-and-vet-control-plane +# - lint-control-plane +# - test-enterprise-control-plane: +# filters: +# branches: +# # Forked pull requests have CIRCLE_BRANCH set to pull/XXX. +# ignore: /pull\/[0-9]+/ +# requires: +# - go-fmt-and-vet-control-plane +# - lint-control-plane +# # Unit test CLI +# - unit-cli +# # Unit tests for go modules in helm and bats tests for templates +# - unit-acceptance-framework: +# requires: +# - go-fmt-and-vet-acceptance +# - unit-helm-gen: +# requires: +# - go-fmt-and-vet-helm-gen +# - validate-helm-gen +# - unit-test-helm-templates +# # Build control plane binaries +# - build-distro: +# OS: "freebsd linux windows" +# ARCH: "386" +# name: build-distros-386 +# requires: +# - test-control-plane +# - test-enterprise-control-plane +# - build-distro: +# OS: "darwin freebsd linux solaris windows" +# ARCH: "amd64" +# name: build-distros-amd64 +# requires: +# - test-control-plane +# - test-enterprise-control-plane +# - build-distro: +# OS: "linux" +# ARCH: "arm arm64" +# name: build-distros-arm-arm64 +# requires: +# - test-control-plane +# - test-enterprise-control-plane +# - dev-upload-docker: +# context: consul-ci +# requires: +# - build-distros-amd64 +# # Run acceptance tests using the docker image built for the control plane +# - acceptance: +# requires: +# - dev-upload-docker +# - unit-test-helm-templates +# - unit-acceptance-framework +# - unit-cli +# - acceptance-tproxy: +# requires: +# - dev-upload-docker +# - unit-test-helm-templates +# - unit-acceptance-framework +# - unit-cli +# nightly-acceptance-tests: +# triggers: +# - schedule: +# cron: "0 0 * * *" +# filters: +# branches: +# only: +# - main +# jobs: +# - cleanup-gcp-resources +# - cleanup-azure-resources +# - cleanup-eks-resources +# # Disable until we can use UBI images. +# # - acceptance-openshift: +# # requires: +# # - cleanup-azure-resources +# - acceptance-gke-1-20: +# requires: +# - cleanup-gcp-resources +# - acceptance-eks-1-19: +# requires: +# - cleanup-eks-resources +# - acceptance-aks-1-21: +# requires: +# - cleanup-azure-resources +# - acceptance-kind-1-23 diff --git a/.github/workflows/go-fmt-and-vet-helm-gen.yml b/.github/workflows/go-fmt-and-vet-helm-gen.yml index 50cfb5567f..5ccf277b54 100644 --- a/.github/workflows/go-fmt-and-vet-helm-gen.yml +++ b/.github/workflows/go-fmt-and-vet-helm-gen.yml @@ -1,7 +1,11 @@ name: go-fmt-and-vet-helm-gen - on: - workflow_dispatch: + push: + tags: + - v* + branches: + - crt-build-and-tests + pull_request: jobs: go-fmt-and-vet-helm-gen: From 835b40a40a5923b9ce5de9bd5ff191af06f5ba0e Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 24 Feb 2022 17:33:19 -0500 Subject: [PATCH 296/418] fix job name and try go-fmt of control-plane --- .github/workflows/go-fmt-and-vet-control-plane.yml | 14 ++++++++++++++ .github/workflows/reusable-go-fmt-and-vet.yml | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/go-fmt-and-vet-control-plane.yml diff --git a/.github/workflows/go-fmt-and-vet-control-plane.yml b/.github/workflows/go-fmt-and-vet-control-plane.yml new file mode 100644 index 0000000000..4fc9e46ba4 --- /dev/null +++ b/.github/workflows/go-fmt-and-vet-control-plane.yml @@ -0,0 +1,14 @@ +name: go-fmt-and-vet-control-plane +on: + push: + tags: + - v* + branches: + - crt-build-and-tests + pull_request: + +jobs: + go-fmt-and-vet-helm-gen: + uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests + with: + directory: control-plane diff --git a/.github/workflows/reusable-go-fmt-and-vet.yml b/.github/workflows/reusable-go-fmt-and-vet.yml index 4eb1f7c7b8..8e34d40dd8 100644 --- a/.github/workflows/reusable-go-fmt-and-vet.yml +++ b/.github/workflows/reusable-go-fmt-and-vet.yml @@ -8,7 +8,7 @@ on: type: string jobs: - build: + execute: runs-on: ubuntu-latest steps: From 4bff1d4dea20d2c7bf8ee704a2666660f17c388d Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 24 Feb 2022 19:13:30 -0500 Subject: [PATCH 297/418] set the correct go version --- .github/workflows/reusable-go-fmt-and-vet.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/reusable-go-fmt-and-vet.yml b/.github/workflows/reusable-go-fmt-and-vet.yml index 8e34d40dd8..f8b62fff7a 100644 --- a/.github/workflows/reusable-go-fmt-and-vet.yml +++ b/.github/workflows/reusable-go-fmt-and-vet.yml @@ -15,6 +15,11 @@ jobs: - name: Checkout code uses: actions/checkout@v2 + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: 1.17.5 + - name: go mod download working-directory: ${{inputs.directory}} run: go mod download From 599c06203c1562b3a624fb93e142269a09c0919e Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 25 Feb 2022 11:56:24 -0500 Subject: [PATCH 298/418] place jobs into one test-and-build.yml file so that needs works --- .github/workflows/build-and-test.yml | 27 ++++++++++ .../go-fmt-and-vet-control-plane.yml | 14 ------ .github/workflows/go-fmt-and-vet-helm-gen.yml | 14 ------ .github/workflows/reusable-go-fmt-and-vet.yml | 11 ++++ .github/workflows/reusable-unit.yml | 50 +++++++++++++++++++ 5 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 .github/workflows/build-and-test.yml delete mode 100644 .github/workflows/go-fmt-and-vet-control-plane.yml delete mode 100644 .github/workflows/go-fmt-and-vet-helm-gen.yml create mode 100644 .github/workflows/reusable-unit.yml diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 0000000000..602a8d7524 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,27 @@ +name: test-and-build +on: + push: + tags: + - v* + branches: + - crt-build-and-tests + pull_request: + +jobs: + go-fmt-and-vet-helm-gen: + uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests + with: + directory: hack/helm-reference-gen + + unit-helm-gen: + uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests + with: + directory: hack/helm-reference-gen + needs: go-fmt-and-vet-helm-gen + + go-fmt-and-vet-control-plane: + uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests + with: + directory: control-plane + + diff --git a/.github/workflows/go-fmt-and-vet-control-plane.yml b/.github/workflows/go-fmt-and-vet-control-plane.yml deleted file mode 100644 index 4fc9e46ba4..0000000000 --- a/.github/workflows/go-fmt-and-vet-control-plane.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: go-fmt-and-vet-control-plane -on: - push: - tags: - - v* - branches: - - crt-build-and-tests - pull_request: - -jobs: - go-fmt-and-vet-helm-gen: - uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests - with: - directory: control-plane diff --git a/.github/workflows/go-fmt-and-vet-helm-gen.yml b/.github/workflows/go-fmt-and-vet-helm-gen.yml deleted file mode 100644 index 5ccf277b54..0000000000 --- a/.github/workflows/go-fmt-and-vet-helm-gen.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: go-fmt-and-vet-helm-gen -on: - push: - tags: - - v* - branches: - - crt-build-and-tests - pull_request: - -jobs: - go-fmt-and-vet-helm-gen: - uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests - with: - directory: hack/helm-reference-gen diff --git a/.github/workflows/reusable-go-fmt-and-vet.yml b/.github/workflows/reusable-go-fmt-and-vet.yml index f8b62fff7a..370a242e25 100644 --- a/.github/workflows/reusable-go-fmt-and-vet.yml +++ b/.github/workflows/reusable-go-fmt-and-vet.yml @@ -6,6 +6,7 @@ on: directory: required: true type: string + jobs: execute: @@ -20,6 +21,16 @@ jobs: with: go-version: 1.17.5 + - name: Setup go mod cache + uses: actions/cache@v2 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: go mod download working-directory: ${{inputs.directory}} run: go mod download diff --git a/.github/workflows/reusable-unit.yml b/.github/workflows/reusable-unit.yml new file mode 100644 index 0000000000..1a7108eeab --- /dev/null +++ b/.github/workflows/reusable-unit.yml @@ -0,0 +1,50 @@ +name: reusable-unit + +on: + workflow_call: + inputs: + directory: + required: true + type: string + + +jobs: + execute: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: 1.17.5 + + - name: Setup go mod cache + uses: actions/cache@v2 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Install gotestsum + run: | + wget https://github.com/gotestyourself/gotestsum/releases/download/v1.6.4/gotestsum_1.6.4_linux_amd64.tar.gz + sudo tar -C /usr/local/bin -xzf gotestsum_1.6.4_linux_amd64.tar.gz + rm gotestsum_1.6.4_linux_amd64.tar.gz + + - run: mkdir -p /tmp/test-results + + - name: go mod download + working-directory: ${{inputs.directory}} + run: go mod download + + - name: Run tests + working-directory: ${{inputs.directory}} + run: | + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 + From 7069a0976d6f3f2dd2d1bcef461cd95ed5408f7f Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 25 Feb 2022 11:58:14 -0500 Subject: [PATCH 299/418] place jobs into one test-and-build.yml file so that needs works --- .github/workflows/reusable-unit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-unit.yml b/.github/workflows/reusable-unit.yml index 1a7108eeab..dc2036c562 100644 --- a/.github/workflows/reusable-unit.yml +++ b/.github/workflows/reusable-unit.yml @@ -46,5 +46,5 @@ jobs: - name: Run tests working-directory: ${{inputs.directory}} run: | - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 + gotestsum --junitfile /tmp/test-results/gotestsum-report.xml ./... -- -p 4 From f186d8ae96a9eec064150df0d6ce56fff16003d5 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 25 Feb 2022 13:49:58 -0500 Subject: [PATCH 300/418] fill in matrix --- .github/workflows/build-and-test.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 602a8d7524..bd10acc39d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -8,7 +8,14 @@ on: pull_request: jobs: - go-fmt-and-vet-helm-gen: + validate-helm-gen: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + + go-fmt-vet-helm-gen: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests with: directory: hack/helm-reference-gen @@ -19,7 +26,7 @@ jobs: directory: hack/helm-reference-gen needs: go-fmt-and-vet-helm-gen - go-fmt-and-vet-control-plane: + go-fmt-vet-control-plane: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests with: directory: control-plane From 985fbfd7559b4590050425630496b0d3ab526577 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 25 Feb 2022 13:52:14 -0500 Subject: [PATCH 301/418] add filler control-plane tests --- .github/workflows/build-and-test.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index bd10acc39d..2a5e3a797b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -26,9 +26,34 @@ jobs: directory: hack/helm-reference-gen needs: go-fmt-and-vet-helm-gen + lint-control-plane: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + go-fmt-vet-control-plane: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests with: directory: control-plane + test-control-plane: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + needs: [lint-control-plane, go-fmt-vet-control-plane] + + test-enterprise-control-plane: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + needs: [lint-control-plane, go-fmt-vet-control-plane] + + + From feeec45e7fe321b96d836eb90476ec330a96cbb6 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 25 Feb 2022 13:54:02 -0500 Subject: [PATCH 302/418] add filler control-plane tests --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2a5e3a797b..5d7727b7cf 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -15,7 +15,7 @@ jobs: run: echo "Filler" - go-fmt-vet-helm-gen: + go-fmt-and-vet-helm-gen: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests with: directory: hack/helm-reference-gen From 3fd66a6f1403b0ce1bdc51647b1826ca54e5fd2b Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 25 Feb 2022 13:56:53 -0500 Subject: [PATCH 303/418] add distros filler --- .github/workflows/build-and-test.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 5d7727b7cf..690ff5a8c8 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -54,6 +54,30 @@ jobs: echo "Filler" needs: [lint-control-plane, go-fmt-vet-control-plane] + build-distros-amd64: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + needs: [test-control-plane, test-enterprise-control-plane] + + build-distros-arm-arm64: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + needs: [test-control-plane, test-enterprise-control-plane] + + build-distros-386: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + needs: [test-control-plane, test-enterprise-control-plane] + From dd85070b21910567a8dfb46e3978b00c3a03dd3d Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 25 Feb 2022 15:15:26 -0500 Subject: [PATCH 304/418] finish filling out the dependent jobs --- .github/workflows/build-and-test.yml | 67 +++++++++++++++++-- ...mt-and-vet.yml => reusable-go-fmt-vet.yml} | 0 2 files changed, 63 insertions(+), 4 deletions(-) rename .github/workflows/{reusable-go-fmt-and-vet.yml => reusable-go-fmt-vet.yml} (100%) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 690ff5a8c8..e65dc6a737 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -15,8 +15,8 @@ jobs: run: echo "Filler" - go-fmt-and-vet-helm-gen: - uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests + go-fmt-vet-helm-gen: + uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: directory: hack/helm-reference-gen @@ -24,7 +24,7 @@ jobs: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: hack/helm-reference-gen - needs: go-fmt-and-vet-helm-gen + needs: go-fmt-vet-helm-gen lint-control-plane: runs-on: ubuntu-latest @@ -34,7 +34,7 @@ jobs: echo "Filler" go-fmt-vet-control-plane: - uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-and-vet.yml@crt-build-and-tests + uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: directory: control-plane @@ -78,6 +78,65 @@ jobs: echo "Filler" needs: [test-control-plane, test-enterprise-control-plane] + go-fmt-vet-acceptance: + uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests + with: + directory: acceptance + + unit-acceptance: + uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests + with: + directory: acceptance + needs: go-fmt-vet-acceptance + + go-fmt-vet-cli: + uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests + with: + directory: cli + + unit-cli: + uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests + with: + directory: cli + needs: go-fmt-vet-cli + + unit-test-helm-template: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + + dev-upload-docker: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + needs: build-distros-amd64 + + acceptance-tproxy: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + needs: [unit-cli, dev-upload-docker, unit-acceptance, unit-test-helm-template] + + acceptance: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + needs: [unit-cli, dev-upload-docker, unit-acceptance, unit-test-helm-template] + + + + + + + diff --git a/.github/workflows/reusable-go-fmt-and-vet.yml b/.github/workflows/reusable-go-fmt-vet.yml similarity index 100% rename from .github/workflows/reusable-go-fmt-and-vet.yml rename to .github/workflows/reusable-go-fmt-vet.yml From d89ec2267953dc925496ad46eb8bef42ffebd32a Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 25 Feb 2022 15:26:35 -0500 Subject: [PATCH 305/418] unit test acceptance framework --- .github/workflows/build-and-test.yml | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index e65dc6a737..4d3da3498d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -24,7 +24,15 @@ jobs: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: hack/helm-reference-gen - needs: go-fmt-vet-helm-gen + needs: [go-fmt-vet-helm-gen, validate-helm-gen] + + unit-test-helm-template: + runs-on: ubuntu-latest + steps: + - name: TODO + run: + echo "Filler" + needs: [unit-helm-gen] lint-control-plane: runs-on: ubuntu-latest @@ -83,10 +91,10 @@ jobs: with: directory: acceptance - unit-acceptance: + unit-acceptance-framework: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: acceptance + directory: acceptance/framework needs: go-fmt-vet-acceptance go-fmt-vet-cli: @@ -100,13 +108,6 @@ jobs: directory: cli needs: go-fmt-vet-cli - unit-test-helm-template: - runs-on: ubuntu-latest - steps: - - name: TODO - run: - echo "Filler" - dev-upload-docker: runs-on: ubuntu-latest steps: @@ -121,7 +122,7 @@ jobs: - name: TODO run: echo "Filler" - needs: [unit-cli, dev-upload-docker, unit-acceptance, unit-test-helm-template] + needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-template] acceptance: runs-on: ubuntu-latest @@ -129,7 +130,7 @@ jobs: - name: TODO run: echo "Filler" - needs: [unit-cli, dev-upload-docker, unit-acceptance, unit-test-helm-template] + needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-template] From f8ae1ff109e99ad11322551fc63975183007781d Mon Sep 17 00:00:00 2001 From: David Yu Date: Fri, 25 Feb 2022 13:20:58 -0800 Subject: [PATCH 306/418] Dockerfile: bump to alpine 3.15 (#1058) * Dockerfile: bump to alpine 3.15 Bump control plane to 3.15 * changelog * Update CHANGELOG.md * Update CHANGELOG.md --- CHANGELOG.md | 7 ++++++- control-plane/build-support/docker/Release.dockerfile | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a94aa36068..0b93e0074d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,12 @@ ## UNRELEASED BREAKING CHANGES: -* Minimum Kubernetes version supported is 1.19 and now matches what is stated in the `README.md` file. [[GH-1049](https://github.com/hashicorp/consul-k8s/pull/1049)] +* Helm + * Minimum Kubernetes version supported is 1.19 and now matches what is stated in the `README.md` file. [[GH-1049](https://github.com/hashicorp/consul-k8s/pull/1049)] + +IMPROVEMENTS: +* Control Plane + * Upgrade Docker image Alpine version from 3.14 to 3.15. [[GH-1058](https://github.com/hashicorp/consul-k8s/pull/1058)] ## 0.41.1 (February 24, 2022) diff --git a/control-plane/build-support/docker/Release.dockerfile b/control-plane/build-support/docker/Release.dockerfile index fec607a7c1..b782bd579b 100644 --- a/control-plane/build-support/docker/Release.dockerfile +++ b/control-plane/build-support/docker/Release.dockerfile @@ -5,7 +5,7 @@ # We don't rebuild the software because we want the exact checksums and # binary signatures to match the software and our builds aren't fully # reproducible currently. -FROM alpine:3.14 +FROM alpine:3.15 # NAME and VERSION are the name of the software in releases.hashicorp.com # and the version to download. Example: NAME=consul VERSION=1.2.3. From 72e57077206d72472d4da66271240da87a3bccf5 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 11:33:15 -0500 Subject: [PATCH 307/418] use environment variables and pass in go version to reusable workflows --- .github/workflows/build-and-test.yml | 34 ++++++++++++++++++----- .github/workflows/reusable-go-fmt-vet.yml | 7 +++-- .github/workflows/reusable-unit.yml | 21 +++++++++----- 3 files changed, 46 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 4d3da3498d..33edfca801 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -7,6 +7,19 @@ on: - crt-build-and-tests pull_request: +env: + CONTROL_PLANE_PATH: control-plane + CLI_PATH: cli + ACCEPTANCE_MOD_PATH: acceptance + ACCEPTANCE_TEST_PATH: acceptance/tests + ACCEPTANCE_FRAMEWORK_PATH: acceptance/framework + CHARTS_CONSUL_PATH: charts/consul + HELM_GEN_PATH: hack/helm-reference-gen + TEST_RESULTS: /tmp/test-results # path to where test results are saved + CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests + GO_VERSION: 1.17.2 # Controls what golang version to use. Passed in as a variable to reusable workflows + jobs: validate-helm-gen: runs-on: ubuntu-latest @@ -18,12 +31,14 @@ jobs: go-fmt-vet-helm-gen: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: hack/helm-reference-gen + directory: $HELM_GEN_PATH + go-version: $GO_VERSION unit-helm-gen: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: hack/helm-reference-gen + directory: $HELM_GEN_PATH + go-version: $GO_VERSION needs: [go-fmt-vet-helm-gen, validate-helm-gen] unit-test-helm-template: @@ -44,7 +59,8 @@ jobs: go-fmt-vet-control-plane: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: control-plane + directory: $CONTROL_PLANE_PATH + go-version: $GO_VERSION test-control-plane: runs-on: ubuntu-latest @@ -89,23 +105,27 @@ jobs: go-fmt-vet-acceptance: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: acceptance + directory: $ACCEPTANCE_MOD_PATH + go-version: $GO_VERSION unit-acceptance-framework: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: acceptance/framework + directory: $ACCEPTANCE_FRAMEWORK_PATH + go-version: $GO_VERSION needs: go-fmt-vet-acceptance go-fmt-vet-cli: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: cli + directory: $CLI_PATH + go-version: $GO_VERSION unit-cli: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: cli + directory: $CLI_PATH + go-version: $GO_VERSION needs: go-fmt-vet-cli dev-upload-docker: diff --git a/.github/workflows/reusable-go-fmt-vet.yml b/.github/workflows/reusable-go-fmt-vet.yml index 370a242e25..718008d122 100644 --- a/.github/workflows/reusable-go-fmt-vet.yml +++ b/.github/workflows/reusable-go-fmt-vet.yml @@ -6,7 +6,10 @@ on: directory: required: true type: string - + go-version: + required: true + type: string + jobs: execute: @@ -19,7 +22,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: 1.17.5 + go-version: ${{inputs.go-version}} - name: Setup go mod cache uses: actions/cache@v2 diff --git a/.github/workflows/reusable-unit.yml b/.github/workflows/reusable-unit.yml index dc2036c562..d4ec6372d5 100644 --- a/.github/workflows/reusable-unit.yml +++ b/.github/workflows/reusable-unit.yml @@ -6,7 +6,14 @@ on: directory: required: true type: string - + go-version: + required: true + type: string + + +env: + TEST_RESULTS: /tmp/test-results # path to where test results are saved + GOTESTSUM_VERSION: 1.6.4 jobs: execute: @@ -19,7 +26,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: 1.17.5 + go-version: ${{inpusts.go-version}} - name: Setup go mod cache uses: actions/cache@v2 @@ -33,11 +40,11 @@ jobs: - name: Install gotestsum run: | - wget https://github.com/gotestyourself/gotestsum/releases/download/v1.6.4/gotestsum_1.6.4_linux_amd64.tar.gz - sudo tar -C /usr/local/bin -xzf gotestsum_1.6.4_linux_amd64.tar.gz - rm gotestsum_1.6.4_linux_amd64.tar.gz + wget https://github.com/gotestyourself/gotestsum/releases/download/v$GOTESTSUM_VERSION/gotestsum_$GOTESTSUM_VERSION_linux_amd64.tar.gz + sudo tar -C /usr/local/bin -xzf gotestsum_$GOTESTSUM_VERSION_linux_amd64.tar.gz + rm gotestsum_$GOTESTSUM_VERSION_linux_amd64.tar.gz - - run: mkdir -p /tmp/test-results + - run: mkdir -p $TEST_RESULTS - name: go mod download working-directory: ${{inputs.directory}} @@ -46,5 +53,5 @@ jobs: - name: Run tests working-directory: ${{inputs.directory}} run: | - gotestsum --junitfile /tmp/test-results/gotestsum-report.xml ./... -- -p 4 + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 From 4de296b289345fc9895a75b77f20edda5ffac1a3 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 12:05:44 -0500 Subject: [PATCH 308/418] use environment variables and pass in go version to reusable workflows --- .github/workflows/reusable-unit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-unit.yml b/.github/workflows/reusable-unit.yml index d4ec6372d5..a9e72e6afc 100644 --- a/.github/workflows/reusable-unit.yml +++ b/.github/workflows/reusable-unit.yml @@ -26,7 +26,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: ${{inpusts.go-version}} + go-version: ${{inputs.go-version}} - name: Setup go mod cache uses: actions/cache@v2 From 3097f21a54b838685bcfc17086fde43df4403b0d Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 12:19:42 -0500 Subject: [PATCH 309/418] environment variables may not work --- .github/workflows/build-and-test.yml | 28 ++++++++++++++-------------- .github/workflows/reusable-unit.yml | 10 +++++----- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 33edfca801..8966d1a9d1 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -31,14 +31,14 @@ jobs: go-fmt-vet-helm-gen: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: $HELM_GEN_PATH - go-version: $GO_VERSION + directory: ${{env.HELM_GEN_PATH}} + go-version: ${{env.GO_VERSION}} unit-helm-gen: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: $HELM_GEN_PATH - go-version: $GO_VERSION + directory: ${{env.HELM_GEN_PATH}} + go-version: ${{env.GO_VERSION}} needs: [go-fmt-vet-helm-gen, validate-helm-gen] unit-test-helm-template: @@ -59,8 +59,8 @@ jobs: go-fmt-vet-control-plane: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: $CONTROL_PLANE_PATH - go-version: $GO_VERSION + directory: ${{env.CONTROL_PLANE_PATH}} + go-version: ${{env.GO_VERSION}} test-control-plane: runs-on: ubuntu-latest @@ -105,27 +105,27 @@ jobs: go-fmt-vet-acceptance: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: $ACCEPTANCE_MOD_PATH - go-version: $GO_VERSION + directory: ${{env.ACCEPTANCE_MOD_PATH}} + go-version: ${{env.GO_VERSION}} unit-acceptance-framework: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: $ACCEPTANCE_FRAMEWORK_PATH - go-version: $GO_VERSION + directory: ${{env.ACCEPTANCE_FRAMEWORK_PATH}} + go-version: ${{env.GO_VERSION}} needs: go-fmt-vet-acceptance go-fmt-vet-cli: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: $CLI_PATH - go-version: $GO_VERSION + directory: ${{env.CLI_PATH}} + go-version: ${{env.GO_VERSION}} unit-cli: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: $CLI_PATH - go-version: $GO_VERSION + directory: ${{env.CLI_PATH}} + go-version: ${{env.GO_VERSION}} needs: go-fmt-vet-cli dev-upload-docker: diff --git a/.github/workflows/reusable-unit.yml b/.github/workflows/reusable-unit.yml index a9e72e6afc..fa24cf8283 100644 --- a/.github/workflows/reusable-unit.yml +++ b/.github/workflows/reusable-unit.yml @@ -40,11 +40,11 @@ jobs: - name: Install gotestsum run: | - wget https://github.com/gotestyourself/gotestsum/releases/download/v$GOTESTSUM_VERSION/gotestsum_$GOTESTSUM_VERSION_linux_amd64.tar.gz - sudo tar -C /usr/local/bin -xzf gotestsum_$GOTESTSUM_VERSION_linux_amd64.tar.gz - rm gotestsum_$GOTESTSUM_VERSION_linux_amd64.tar.gz + wget https://github.com/gotestyourself/gotestsum/releases/download/v${{env.GOTESTSUM_VERSION}}/gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - - run: mkdir -p $TEST_RESULTS + - run: mkdir -p ${{env.TEST_RESULTS}} - name: go mod download working-directory: ${{inputs.directory}} @@ -53,5 +53,5 @@ jobs: - name: Run tests working-directory: ${{inputs.directory}} run: | - gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 + gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml ./... -- -p 4 From de006e052bb6e391a5282309c53d5389edf97335 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 12:32:38 -0500 Subject: [PATCH 310/418] environment variables only work at the steps level --- .github/workflows/build-and-test.yml | 41 ++++++++++------------------ .github/workflows/reusable-unit.yml | 2 +- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8966d1a9d1..435fb3ed24 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -7,19 +7,6 @@ on: - crt-build-and-tests pull_request: -env: - CONTROL_PLANE_PATH: control-plane - CLI_PATH: cli - ACCEPTANCE_MOD_PATH: acceptance - ACCEPTANCE_TEST_PATH: acceptance/tests - ACCEPTANCE_FRAMEWORK_PATH: acceptance/framework - CHARTS_CONSUL_PATH: charts/consul - HELM_GEN_PATH: hack/helm-reference-gen - TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests - GO_VERSION: 1.17.2 # Controls what golang version to use. Passed in as a variable to reusable workflows - jobs: validate-helm-gen: runs-on: ubuntu-latest @@ -31,14 +18,14 @@ jobs: go-fmt-vet-helm-gen: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: ${{env.HELM_GEN_PATH}} - go-version: ${{env.GO_VERSION}} + directory: hack/helm-reference-gen + go-version: 1.17.2 unit-helm-gen: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: ${{env.HELM_GEN_PATH}} - go-version: ${{env.GO_VERSION}} + directory: hack/helm-reference-gen + go-version: 1.17.2 needs: [go-fmt-vet-helm-gen, validate-helm-gen] unit-test-helm-template: @@ -59,8 +46,8 @@ jobs: go-fmt-vet-control-plane: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: ${{env.CONTROL_PLANE_PATH}} - go-version: ${{env.GO_VERSION}} + directory: control-plane + go-version: 1.17.2 test-control-plane: runs-on: ubuntu-latest @@ -105,27 +92,27 @@ jobs: go-fmt-vet-acceptance: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: ${{env.ACCEPTANCE_MOD_PATH}} - go-version: ${{env.GO_VERSION}} + directory: acceptance + go-version: 1.17.2 unit-acceptance-framework: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: ${{env.ACCEPTANCE_FRAMEWORK_PATH}} - go-version: ${{env.GO_VERSION}} + directory: accepance/framework + go-version: 1.17.2 needs: go-fmt-vet-acceptance go-fmt-vet-cli: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: - directory: ${{env.CLI_PATH}} - go-version: ${{env.GO_VERSION}} + directory: cli + go-version: 1.17.2 unit-cli: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: ${{env.CLI_PATH}} - go-version: ${{env.GO_VERSION}} + directory: cli + go-version: 1.17.2 needs: go-fmt-vet-cli dev-upload-docker: diff --git a/.github/workflows/reusable-unit.yml b/.github/workflows/reusable-unit.yml index fa24cf8283..ef557c228c 100644 --- a/.github/workflows/reusable-unit.yml +++ b/.github/workflows/reusable-unit.yml @@ -10,7 +10,7 @@ on: required: true type: string - +# Environment variables can only be used at the step level env: TEST_RESULTS: /tmp/test-results # path to where test results are saved GOTESTSUM_VERSION: 1.6.4 From fb8576a9f7592fea2369ba7041382b339933de51 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 12:36:27 -0500 Subject: [PATCH 311/418] environment variables only work at the steps level --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 435fb3ed24..9118a9cde1 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -98,7 +98,7 @@ jobs: unit-acceptance-framework: uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: - directory: accepance/framework + directory: acceptance/framework go-version: 1.17.2 needs: go-fmt-vet-acceptance From fe2882104971aab358de6328b820972f3aea9d0f Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 15:19:56 -0500 Subject: [PATCH 312/418] validate helm gen and run test-control-plane --- .github/workflows/build-and-test.yml | 106 ++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 9118a9cde1..6f660378bf 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -7,13 +7,37 @@ on: - crt-build-and-tests pull_request: +env: + TEST_RESULTS: /tmp/test-results # path to where test results are saved + CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests + jobs: validate-helm-gen: runs-on: ubuntu-latest steps: - - name: TODO - run: - echo "Filler" + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: ${{inputs.go-version}} + + - name: Setup go mod cache + uses: actions/cache@v2 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Validate helm gen + working-directory: hack/helm-reference-gen + run: | + go run ./... -validate go-fmt-vet-helm-gen: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests @@ -52,17 +76,81 @@ jobs: test-control-plane: runs-on: ubuntu-latest steps: - - name: TODO - run: - echo "Filler" + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: ${{inputs.go-version}} + + - name: Setup go mod cache + uses: actions/cache@v2 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Install gotestsum + run: | + wget https://github.com/gotestyourself/gotestsum/releases/download/v${{env.GOTESTSUM_VERSION}}/gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + + - run: mkdir -p ${{env.TEST_RESULTS}} + + - name: Run go tests + run: | + wget https://releases.hashicorp.com/consul/${{env.CONSUL_VERSION}}/consul_${{env.CONSUL_VERSION}}_linux_amd64.zip && \ + unzip consul_${{env.CONSUL_VERSION}}_linux_amd64.zip -d ${{env.HOME}}/bin && + rm consul_${{env.CONSUL_VERSION}}_linux_amd64.zip + PACKAGE_NAMES=$(go list ./...) + gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES + + + needs: [lint-control-plane, go-fmt-vet-control-plane] test-enterprise-control-plane: runs-on: ubuntu-latest steps: - - name: TODO - run: - echo "Filler" + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: ${{inputs.go-version}} + + - name: Setup go mod cache + uses: actions/cache@v2 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Install gotestsum + run: | + wget https://github.com/gotestyourself/gotestsum/releases/download/v${{env.GOTESTSUM_VERSION}}/gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + + - run: mkdir -p ${{env.TEST_RESULTS}} + + - name: Run go tests + run: | + wget https://releases.hashicorp.com/consul/${{env.CONSUL_ENT_VERSION}}/consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip && \ + unzip consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip -d ${{env.HOME}}/bin && + rm consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip + PACKAGE_NAMES=$(go list ./...) + gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES + needs: [lint-control-plane, go-fmt-vet-control-plane] build-distros-amd64: From fe86ab1610c80e93f01783ccf2e311c913b8d423 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 15:28:00 -0500 Subject: [PATCH 313/418] missing gotestsum version --- .github/workflows/build-and-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6f660378bf..fc7396d288 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -11,6 +11,7 @@ env: TEST_RESULTS: /tmp/test-results # path to where test results are saved CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests + GOTESTSUM_VERSION: 1.6.4 jobs: validate-helm-gen: From ba43d654e2304b202aedc8624cec9ef1937b8bf6 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 15:40:55 -0500 Subject: [PATCH 314/418] try out bats runs --- .github/workflows/build-and-test.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index fc7396d288..c51280d448 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -53,12 +53,16 @@ jobs: go-version: 1.17.2 needs: [go-fmt-vet-helm-gen, validate-helm-gen] - unit-test-helm-template: + unit-test-helm-templates: runs-on: ubuntu-latest + container: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 steps: - - name: TODO - run: - echo "Filler" + - name: Checkout code + uses: actions/checkout@v2 + + - name: Run Unit Tests + working-directory: charts/consul + run: bats --jobs 4 ./test/unit needs: [unit-helm-gen] lint-control-plane: @@ -218,7 +222,7 @@ jobs: - name: TODO run: echo "Filler" - needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-template] + needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] acceptance: runs-on: ubuntu-latest @@ -226,7 +230,7 @@ jobs: - name: TODO run: echo "Filler" - needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-template] + needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] From 3857eea343ce725161d4706b2eb23754397e6596 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 15:55:02 -0500 Subject: [PATCH 315/418] test-control-plane missing install dir and run docker bats as room --- .github/workflows/build-and-test.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index c51280d448..2ae87838de 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -55,7 +55,9 @@ jobs: unit-test-helm-templates: runs-on: ubuntu-latest - container: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + container: + image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + options: --user root steps: - name: Checkout code uses: actions/checkout@v2 @@ -109,14 +111,12 @@ jobs: - name: Run go tests run: | - wget https://releases.hashicorp.com/consul/${{env.CONSUL_VERSION}}/consul_${{env.CONSUL_VERSION}}_linux_amd64.zip && \ - unzip consul_${{env.CONSUL_VERSION}}_linux_amd64.zip -d ${{env.HOME}}/bin && - rm consul_${{env.CONSUL_VERSION}}_linux_amd64.zip - PACKAGE_NAMES=$(go list ./...) - gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES - - - + mkdir -p ${{env.HOME}}/bin + wget https://releases.hashicorp.com/consul/${{env.CONSUL_VERSION}}/consul_${{env.CONSUL_VERSION}}_linux_amd64.zip && \ + unzip consul_${{env.CONSUL_VERSION}}_linux_amd64.zip -d ${{env.HOME}}/bin && \ + rm consul_${{env.CONSUL_VERSION}}_linux_amd64.zip + PACKAGE_NAMES=$(go list ./...) + gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] test-enterprise-control-plane: @@ -150,12 +150,12 @@ jobs: - name: Run go tests run: | - wget https://releases.hashicorp.com/consul/${{env.CONSUL_ENT_VERSION}}/consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip && \ - unzip consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip -d ${{env.HOME}}/bin && - rm consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip + mkdir -p ${{env.HOME}}/bin + wget https://releases.hashicorp.com/consul/${{env.CONSUL_ENT_VERSION}}/consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip && \ + unzip consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip -d ${{env.HOME}}/bin && \ + rm consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES - needs: [lint-control-plane, go-fmt-vet-control-plane] build-distros-amd64: From 1a46f90f6cec6f9baf4a8701872e56fc9c782fd8 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 16:04:30 -0500 Subject: [PATCH 316/418] make consul executable --- .github/workflows/build-and-test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2ae87838de..6f9f46af14 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -115,6 +115,7 @@ jobs: wget https://releases.hashicorp.com/consul/${{env.CONSUL_VERSION}}/consul_${{env.CONSUL_VERSION}}_linux_amd64.zip && \ unzip consul_${{env.CONSUL_VERSION}}_linux_amd64.zip -d ${{env.HOME}}/bin && \ rm consul_${{env.CONSUL_VERSION}}_linux_amd64.zip + chmod +x -p ${{env.HOME}}/bin/consul PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] @@ -154,8 +155,9 @@ jobs: wget https://releases.hashicorp.com/consul/${{env.CONSUL_ENT_VERSION}}/consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip && \ unzip consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip -d ${{env.HOME}}/bin && \ rm consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip - PACKAGE_NAMES=$(go list ./...) - gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES + chmod +x ${{env.HOME}}/bin/consul + PACKAGE_NAMES=$(go list ./...) + gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] build-distros-amd64: From 93cc206579578cd467420f7f92f67811271efd21 Mon Sep 17 00:00:00 2001 From: David Yu Date: Mon, 28 Feb 2022 13:12:25 -0800 Subject: [PATCH 317/418] Escape : due to JSX issues on Helm reference docs (#1064) --- charts/consul/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/consul/values.yaml b/charts/consul/values.yaml index f22d7059d0..4d019b36be 100644 --- a/charts/consul/values.yaml +++ b/charts/consul/values.yaml @@ -433,7 +433,7 @@ global: # The name of the primary datacenter. primaryDatacenter: "" - # A list of addresses of the primary mesh gateways in the form :. + # A list of addresses of the primary mesh gateways in the form `:`. # (e.g. ["1.1.1.1:443", "2.3.4.5:443"] # @type: array primaryGateways: [] From 68a7a340fd2fe406a7b085201cb7646b940121f3 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 16:17:14 -0500 Subject: [PATCH 318/418] does just using $HOME work? --- .github/workflows/build-and-test.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6f9f46af14..c7eeab2802 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -111,11 +111,11 @@ jobs: - name: Run go tests run: | - mkdir -p ${{env.HOME}}/bin + mkdir -p $HOME/bin wget https://releases.hashicorp.com/consul/${{env.CONSUL_VERSION}}/consul_${{env.CONSUL_VERSION}}_linux_amd64.zip && \ - unzip consul_${{env.CONSUL_VERSION}}_linux_amd64.zip -d ${{env.HOME}}/bin && \ + unzip consul_${{env.CONSUL_VERSION}}_linux_amd64.zip -d $HOME/bin && \ rm consul_${{env.CONSUL_VERSION}}_linux_amd64.zip - chmod +x -p ${{env.HOME}}/bin/consul + chmod +x $HOME/bin/consul PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] @@ -151,11 +151,11 @@ jobs: - name: Run go tests run: | - mkdir -p ${{env.HOME}}/bin + mkdir -p $HOME/bin wget https://releases.hashicorp.com/consul/${{env.CONSUL_ENT_VERSION}}/consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip && \ - unzip consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip -d ${{env.HOME}}/bin && \ + unzip consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip -d $HOME/bin && \ rm consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip - chmod +x ${{env.HOME}}/bin/consul + chmod +x $HOME/bin/consul PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] From c0cfbaff7b17ade358d0132cc4c667d3ec6ebd43 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 28 Feb 2022 16:31:53 -0500 Subject: [PATCH 319/418] was missing working-dir for test-control-plane --- .github/workflows/build-and-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index c7eeab2802..087464968c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -110,6 +110,7 @@ jobs: - run: mkdir -p ${{env.TEST_RESULTS}} - name: Run go tests + working-directory: control-plane run: | mkdir -p $HOME/bin wget https://releases.hashicorp.com/consul/${{env.CONSUL_VERSION}}/consul_${{env.CONSUL_VERSION}}_linux_amd64.zip && \ @@ -150,6 +151,7 @@ jobs: - run: mkdir -p ${{env.TEST_RESULTS}} - name: Run go tests + working-directory: control-plane run: | mkdir -p $HOME/bin wget https://releases.hashicorp.com/consul/${{env.CONSUL_ENT_VERSION}}/consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip && \ From b1e752d01bd11f224d0c3ded1ba41bba33d17b9b Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 1 Mar 2022 10:23:52 -0500 Subject: [PATCH 320/418] set the correct go version --- .github/workflows/build-and-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 087464968c..3b78335e65 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -23,7 +23,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: ${{inputs.go-version}} + go-version: 1.17.2 - name: Setup go mod cache uses: actions/cache@v2 @@ -89,7 +89,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: ${{inputs.go-version}} + go-version: 1.17.2 - name: Setup go mod cache uses: actions/cache@v2 @@ -130,7 +130,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: ${{inputs.go-version}} + go-version: 1.17.2 - name: Setup go mod cache uses: actions/cache@v2 From d6e9dca3ef4811981840eb2185ab8ddb215a8cda Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 1 Mar 2022 11:08:29 -0500 Subject: [PATCH 321/418] add $HOME/bin to the path so that consul can be found --- .github/workflows/build-and-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 3b78335e65..0bfaf6b0b3 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -117,6 +117,7 @@ jobs: unzip consul_${{env.CONSUL_VERSION}}_linux_amd64.zip -d $HOME/bin && \ rm consul_${{env.CONSUL_VERSION}}_linux_amd64.zip chmod +x $HOME/bin/consul + echo "$HOME/bin" >> $GITHUB_PATH PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] @@ -158,6 +159,7 @@ jobs: unzip consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip -d $HOME/bin && \ rm consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip chmod +x $HOME/bin/consul + echo "$HOME/bin" >> $GITHUB_PATH PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] From 98b72462a4ac9cfc184997843318762f8bec02cd Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 1 Mar 2022 11:30:33 -0500 Subject: [PATCH 322/418] I guess path is not in path...wut --- .github/workflows/build-and-test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 0bfaf6b0b3..fc415b50d5 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -118,6 +118,8 @@ jobs: rm consul_${{env.CONSUL_VERSION}}_linux_amd64.zip chmod +x $HOME/bin/consul echo "$HOME/bin" >> $GITHUB_PATH + env + ls $HOME/bin PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] @@ -160,6 +162,8 @@ jobs: rm consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip chmod +x $HOME/bin/consul echo "$HOME/bin" >> $GITHUB_PATH + env + ls $HOME/bin PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] From 3189dc0b829030a1c53c567867de0dd6452c8bc9 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 1 Mar 2022 11:50:45 -0500 Subject: [PATCH 323/418] updating path has to be done in another action --- .github/workflows/build-and-test.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index fc415b50d5..40e42f41f4 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -108,6 +108,7 @@ jobs: rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - run: mkdir -p ${{env.TEST_RESULTS}} + - run: echo "$HOME/bin" >> $GITHUB_PATH - name: Run go tests working-directory: control-plane @@ -117,9 +118,6 @@ jobs: unzip consul_${{env.CONSUL_VERSION}}_linux_amd64.zip -d $HOME/bin && \ rm consul_${{env.CONSUL_VERSION}}_linux_amd64.zip chmod +x $HOME/bin/consul - echo "$HOME/bin" >> $GITHUB_PATH - env - ls $HOME/bin PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] @@ -152,6 +150,7 @@ jobs: rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - run: mkdir -p ${{env.TEST_RESULTS}} + - run: echo "$HOME/bin" >> $GITHUB_PATH - name: Run go tests working-directory: control-plane @@ -161,9 +160,6 @@ jobs: unzip consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip -d $HOME/bin && \ rm consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip chmod +x $HOME/bin/consul - echo "$HOME/bin" >> $GITHUB_PATH - env - ls $HOME/bin PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES needs: [lint-control-plane, go-fmt-vet-control-plane] From ca14917f2f10aba2facd5309672de1fdb936e315 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 1 Mar 2022 14:49:29 -0500 Subject: [PATCH 324/418] try to build distros --- .github/workflows/build-and-test.yml | 78 ++++++++++++++++++---------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 40e42f41f4..591740697c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -47,13 +47,14 @@ jobs: go-version: 1.17.2 unit-helm-gen: + needs: [go-fmt-vet-helm-gen, validate-helm-gen] uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: hack/helm-reference-gen go-version: 1.17.2 - needs: [go-fmt-vet-helm-gen, validate-helm-gen] unit-test-helm-templates: + needs: [unit-helm-gen] runs-on: ubuntu-latest container: image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 @@ -65,7 +66,6 @@ jobs: - name: Run Unit Tests working-directory: charts/consul run: bats --jobs 4 ./test/unit - needs: [unit-helm-gen] lint-control-plane: runs-on: ubuntu-latest @@ -81,6 +81,7 @@ jobs: go-version: 1.17.2 test-control-plane: + needs: [lint-control-plane, go-fmt-vet-control-plane] runs-on: ubuntu-latest steps: - name: Checkout code @@ -107,8 +108,10 @@ jobs: sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - - run: mkdir -p ${{env.TEST_RESULTS}} - - run: echo "$HOME/bin" >> $GITHUB_PATH + - name: Setup environment + run: + mkdir -p ${{env.TEST_RESULTS}} + echo "$HOME/bin" >> $GITHUB_PATH - name: Run go tests working-directory: control-plane @@ -120,9 +123,9 @@ jobs: chmod +x $HOME/bin/consul PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES - needs: [lint-control-plane, go-fmt-vet-control-plane] test-enterprise-control-plane: + needs: [lint-control-plane, go-fmt-vet-control-plane] runs-on: ubuntu-latest steps: - name: Checkout code @@ -149,8 +152,10 @@ jobs: sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - - run: mkdir -p ${{env.TEST_RESULTS}} - - run: echo "$HOME/bin" >> $GITHUB_PATH + - name: Setup environment + run: + mkdir -p ${{env.TEST_RESULTS}} + echo "$HOME/bin" >> $GITHUB_PATH - name: Run go tests working-directory: control-plane @@ -162,31 +167,62 @@ jobs: chmod +x $HOME/bin/consul PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES - needs: [lint-control-plane, go-fmt-vet-control-plane] + + build-distros: + #needs: [test-control-plane, test-enterprise-control-plane] + needs: test-control-plane + runs-on: ubuntu-latest + strategy: + matrix: + include: + - {go: "1.17.2", goos: "linux", goarch: "386"} + - {go: "1.17.5", goos: "linux", goarch: "amd64"} + - {go: "1.17.5", goos: "linux", goarch: "arm"} + - {go: "1.17.5", goos: "linux", goarch: "arm64"} + fail-fast: true + + name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build + steps: + - uses: actions/checkout@v2 + + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go }} + + - name: Build + working-directory: control-plane + env: + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} + CGO_ENABLED: 0 + run: | + XC_OS=${{ matrix.goos }} XC_ARCH=${{ matrix.goarch }} ./build-support/scripts/build-local.sh + build-distros-amd64: + needs: [test-control-plane, test-enterprise-control-plane] runs-on: ubuntu-latest steps: - name: TODO run: echo "Filler" - needs: [test-control-plane, test-enterprise-control-plane] build-distros-arm-arm64: + needs: [test-control-plane, test-enterprise-control-plane] runs-on: ubuntu-latest steps: - name: TODO run: echo "Filler" - needs: [test-control-plane, test-enterprise-control-plane] build-distros-386: + needs: [test-control-plane, test-enterprise-control-plane] runs-on: ubuntu-latest steps: - name: TODO run: echo "Filler" - needs: [test-control-plane, test-enterprise-control-plane] go-fmt-vet-acceptance: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests @@ -195,11 +231,11 @@ jobs: go-version: 1.17.2 unit-acceptance-framework: + needs: go-fmt-vet-acceptance uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: acceptance/framework go-version: 1.17.2 - needs: go-fmt-vet-acceptance go-fmt-vet-cli: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests @@ -208,42 +244,32 @@ jobs: go-version: 1.17.2 unit-cli: + needs: go-fmt-vet-cli uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: cli go-version: 1.17.2 - needs: go-fmt-vet-cli dev-upload-docker: + needs: build-distros-amd64 runs-on: ubuntu-latest steps: - name: TODO run: echo "Filler" - needs: build-distros-amd64 acceptance-tproxy: + needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] runs-on: ubuntu-latest steps: - name: TODO run: echo "Filler" - needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] acceptance: + needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] runs-on: ubuntu-latest steps: - name: TODO run: echo "Filler" - needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] - - - - - - - - - - From eb518a0a05f90f5b47744c3b2de1eb4c981ec25f Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 1 Mar 2022 15:13:10 -0500 Subject: [PATCH 325/418] github actions have weird bugs --- .github/workflows/build-and-test.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 591740697c..14c52073e7 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -108,10 +108,8 @@ jobs: sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - - name: Setup environment - run: - mkdir -p ${{env.TEST_RESULTS}} - echo "$HOME/bin" >> $GITHUB_PATH + - run: mkdir -p ${{env.TEST_RESULTS}} + - run: echo "$HOME/bin" >> $GITHUB_PATH - name: Run go tests working-directory: control-plane @@ -152,10 +150,8 @@ jobs: sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - - name: Setup environment - run: - mkdir -p ${{env.TEST_RESULTS}} - echo "$HOME/bin" >> $GITHUB_PATH + - run: mkdir -p ${{env.TEST_RESULTS}} + - run: echo "$HOME/bin" >> $GITHUB_PATH - name: Run go tests working-directory: control-plane From 5cda1f585ff53aafa84f83fe3d7a7545a3914916 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 1 Mar 2022 16:57:21 -0500 Subject: [PATCH 326/418] build archives --- .github/workflows/build-and-test.yml | 31 ++++++---------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 14c52073e7..a542a2d91e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -194,31 +194,12 @@ jobs: CGO_ENABLED: 0 run: | XC_OS=${{ matrix.goos }} XC_ARCH=${{ matrix.goarch }} ./build-support/scripts/build-local.sh + zip -r -j consul-k8s_${{ matrix.goos }}_${{ matrix.goarch }}.zip bin - - build-distros-amd64: - needs: [test-control-plane, test-enterprise-control-plane] - runs-on: ubuntu-latest - steps: - - name: TODO - run: - echo "Filler" - - build-distros-arm-arm64: - needs: [test-control-plane, test-enterprise-control-plane] - runs-on: ubuntu-latest - steps: - - name: TODO - run: - echo "Filler" - - build-distros-386: - needs: [test-control-plane, test-enterprise-control-plane] - runs-on: ubuntu-latest - steps: - - name: TODO - run: - echo "Filler" + - uses: actions/upload-artifact@v2 + with: + name: consul-k8s_${{ matrix.goos }}_${{ matrix.goarch }}.zip + path: consul-k8s_${{ matrix.goos }}_${{ matrix.goarch }}.zip go-fmt-vet-acceptance: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests @@ -247,7 +228,7 @@ jobs: go-version: 1.17.2 dev-upload-docker: - needs: build-distros-amd64 + needs: build-distros runs-on: ubuntu-latest steps: - name: TODO From f9779b9ab04b38ed3decb785c0d76c6b3602cf8e Mon Sep 17 00:00:00 2001 From: Kyle Schochenmaier Date: Tue, 1 Mar 2022 19:00:04 -0600 Subject: [PATCH 327/418] update docs to align with new makefile (#1063) --- CONTRIBUTING.md | 8 ++++---- hack/helm-reference-gen/main.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a4ee4db86a..ee6fc827dc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -953,12 +953,12 @@ To generate the docs and update the `helm.mdx` file: ```shell-session cd /path/to/consul-k8s ``` -1. Run `make gen-docs` using the path to your consul (not consul-k8s) repo: +1. Run `make gen-helm-docs` using the path to your consul (not consul-k8s) repo: ```shell-session - make gen-docs consul= + make gen-helm-docs consul= # Examples: - # make gen-docs consul=/Users/my-name/code/hashicorp/consul - # make gen-docs consul=../consul + # make gen-helm-docs consul=/Users/my-name/code/hashicorp/consul + # make gen-helm-docs consul=../consul ``` 1. Open up a pull request to `hashicorp/consul` (in addition to your `hashicorp/consul-k8s` pull request) diff --git a/hack/helm-reference-gen/main.go b/hack/helm-reference-gen/main.go index 23bd74e8cd..9560a281c8 100644 --- a/hack/helm-reference-gen/main.go +++ b/hack/helm-reference-gen/main.go @@ -3,7 +3,7 @@ package main // This script generates markdown documentation out of the values.yaml file // for use on consul.io. // -// Usage: make gen-docs [consul-repo-path] [-validate] +// Usage: make gen-helm-docs [consul-repo-path] [-validate] // Where [consul-repo-path] is the location of the hashicorp/consul repo. Defaults to ../../../consul. // If -validate is set, the generated docs won't be output anywhere. // This is useful in CI to ensure the generation will succeed. From be4663a676331ae5d009aa264a8cd09fcf73cd2b Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 1 Mar 2022 23:43:15 -0500 Subject: [PATCH 328/418] upload-artifact was not looking in control-plane directory --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a542a2d91e..2a5c69965b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -199,7 +199,7 @@ jobs: - uses: actions/upload-artifact@v2 with: name: consul-k8s_${{ matrix.goos }}_${{ matrix.goarch }}.zip - path: consul-k8s_${{ matrix.goos }}_${{ matrix.goarch }}.zip + path: control-plane/consul-k8s_${{ matrix.goos }}_${{ matrix.goarch }}.zip go-fmt-vet-acceptance: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests From 70d403a0001e18df2e247e414126e0602677fa45 Mon Sep 17 00:00:00 2001 From: John Murret Date: Wed, 2 Mar 2022 09:19:49 -0700 Subject: [PATCH 329/418] Correcting paths to accpetance tests. (#1066) --- CONTRIBUTING.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee6fc827dc..80cb9f8b57 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -476,10 +476,10 @@ rebase the branch on main, fixing any conflicts along the way before the code ca ``` ### Update consul-k8s Acceptance Tests -1. Add a test resource to `test/acceptance/tests/fixtures/crds/ingressgateway.yaml`. Ideally it requires +1. Add a test resource to `acceptance/tests/fixtures/crds/ingressgateway.yaml`. Ideally it requires no other resources. For example, I used a `tcp` service so it didn't require a `ServiceDefaults` resource to set its protocol to something else. -1. Update `charts/consul/test/acceptance/tests/controller/controller_test.go` and `charts/consul/test/acceptance/tests/controller/controller_namespaces_test.go`. +1. Update `acceptance/tests/controller/controller_test.go` and `acceptance/tests/controller/controller_namespaces_test.go`. 1. Test locally, then submit a PR that uses your Docker image as `global.imageK8S`. --- @@ -614,7 +614,7 @@ To run a specific test by name use the `--filter` flag: To run the acceptance tests: - cd charts/consul/test/acceptance/tests + cd acceptance/tests go test ./... -p 1 The above command will run all tests that can run against a single Kubernetes cluster, @@ -791,14 +791,14 @@ If you are adding a feature that fits thematically with one of the existing test then you need to add your test cases to the existing test files. Otherwise, you will need to create a new test suite. -We recommend to start by either copying the [example test](test/acceptance/tests/example/example_test.go) -or the whole [example test suite](test/acceptance/tests/example), +We recommend to start by either copying the [example test](acceptance/tests/example/example_test.go) +or the whole [example test suite](acceptance/tests/example), depending on the test you need to add. #### Adding Test Suites -To add a test suite, copy the [example test suite](test/acceptance/tests/example) -and uncomment the code you need in the [`main_test.go`](test/acceptance/tests/example/main_test.go) file. +To add a test suite, copy the [example test suite](acceptance/tests/example) +and uncomment the code you need in the [`main_test.go`](acceptance/tests/example/main_test.go) file. At a minimum, this file needs to contain the following: @@ -840,7 +840,7 @@ func TestMain(m *testing.M) { #### Example Test -We recommend using the [example test](test/acceptance/tests/example/example_test.go) +We recommend using the [example test](acceptance/tests/example/example_test.go) as a starting point for adding your tests. To write a test, you need access to the environment and context to run it against. @@ -874,7 +874,7 @@ func TestExample(t *testing.T) { } ``` -Please see [mesh gateway tests](test/acceptance/tests/mesh-gateway/mesh_gateway_test.go) +Please see [mesh gateway tests](acceptance/tests/mesh-gateway/mesh_gateway_test.go) for an example of how to use write a test that uses multiple contexts. #### Writing Assertions From ce0ee2a8eda3d5e1fc0c042bd92ce298baa78cfe Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 2 Mar 2022 15:06:20 -0500 Subject: [PATCH 330/418] Smoke tests for the CLI `upgrade` command (#1019) * Add Upgrade command to cli_cluster * Change connect_helper to take configuration (setting up for the upgrade path) * Add the ConnectInject on upgrade test * Move client and cluster onto struct * AdditionalHelmValues instead of double accounting for helmValues * Fix autoencrypt getting set on upgrade test * Set `static-server` back to healthy * Move pod creation to Install method * Move MergeMaps to helpers * Move tests from CLI to connect * Merge mine and @ishustava's Upgrade impls * Move cluster interface to its own file * Refactor consul cluster code * Change tests to use cluster enum * Uncomment other install tests * Write out upgrade tests that don't restart the client * Abort upgrade if test has previously failed * Fix godot errors * s/True/NotNil/g on Upgrade * Pass t into methods and inline kustomize * Move secure check up to test level Co-authored-by: Nitya Dhanushkodi --- acceptance/framework/consul/cli_cluster.go | 152 +++++++----- acceptance/framework/consul/cluster.go | 32 +++ .../{consul_cluster.go => helm_cluster.go} | 12 - ...l_cluster_test.go => helm_cluster_test.go} | 0 acceptance/framework/helpers/helpers_test.go | 45 ++++ acceptance/tests/cli/main_test.go | 15 -- acceptance/tests/cli/smoke_test.go | 35 --- acceptance/tests/connect/connect_helper.go | 219 +++++++++++++----- .../tests/connect/connect_inject_test.go | 121 +++++++++- 9 files changed, 438 insertions(+), 193 deletions(-) create mode 100644 acceptance/framework/consul/cluster.go rename acceptance/framework/consul/{consul_cluster.go => helm_cluster.go} (97%) rename acceptance/framework/consul/{consul_cluster_test.go => helm_cluster_test.go} (100%) create mode 100644 acceptance/framework/helpers/helpers_test.go delete mode 100644 acceptance/tests/cli/main_test.go delete mode 100644 acceptance/tests/cli/smoke_test.go diff --git a/acceptance/framework/consul/cli_cluster.go b/acceptance/framework/consul/cli_cluster.go index 27191b7fa3..b62140d783 100644 --- a/acceptance/framework/consul/cli_cluster.go +++ b/acceptance/framework/consul/cli_cluster.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "os/exec" + "strings" "testing" "time" @@ -45,6 +46,8 @@ type CLICluster struct { logger terratestLogger.TestLogger } +// NewCLICluster creates a new Consul cluster struct which can be used to create +// and destroy a Consul cluster using the Consul K8s CLI. func NewCLICluster( t *testing.T, helmValues map[string]string, @@ -52,8 +55,8 @@ func NewCLICluster( cfg *config.TestConfig, releaseName string, ) *CLICluster { - - // Create the namespace so the PSPs, SCCs, and enterprise secret can be created in the right namespace. + // Create the namespace so the PSPs, SCCs, and enterprise secret can be + // created in the right namespace. createOrUpdateNamespace(t, ctx.KubernetesClient(t), consulNS) if cfg.EnablePodSecurityPolicies { @@ -86,6 +89,7 @@ func NewCLICluster( KubectlOptions: kopts, Logger: logger, } + return &CLICluster{ ctx: ctx, helmOptions: hopts, @@ -102,92 +106,98 @@ func NewCLICluster( } } -func (h *CLICluster) Create(t *testing.T) { +// Create uses the `consul-k8s install` command to create a Consul cluster. The command itself will fail if there are +// prior installations of Consul in the cluster so it is sufficient to run the install command without a pre-check. +func (c *CLICluster) Create(t *testing.T) { t.Helper() // Make sure we delete the cluster if we receive an interrupt signal and // register cleanup so that we delete the cluster when test finishes. - helpers.Cleanup(t, h.noCleanupOnFailure, func() { - h.Destroy(t) + helpers.Cleanup(t, c.noCleanupOnFailure, func() { + c.Destroy(t) }) - // The install command itself will fail if there are prior installations, so it's sufficient to just run the install - // command. + // Set the args for running the install command. args := []string{"install"} - kubeconfig := h.kubeConfig - if kubeconfig != "" { - args = append(args, "-kubeconfig", kubeconfig) + args = c.setKube(args) + + for k, v := range c.values { + args = append(args, "-set", fmt.Sprintf("%s=%s", k, v)) } - kubecontext := h.kubeContext - if kubecontext != "" { - args = append(args, "-context", kubecontext) + + // Match the timeout for the helm tests. + args = append(args, "-timeout", "15m") + args = append(args, "-auto-approve") + + out, err := c.runCLI(args) + if err != nil { + c.logger.Logf(t, "error running command `consul-k8s %s`: %s", strings.Join(args, " "), err.Error()) + c.logger.Logf(t, "command stdout: %s", string(out)) } + require.NoError(t, err) - for k, v := range h.values { - args = append(args, "-set", fmt.Sprintf("%s=%s", k, v)) + k8s.WaitForAllPodsToBeReady(t, c.kubernetesClient, consulNS, fmt.Sprintf("release=%s", c.releaseName)) +} +// Upgrade uses the `consul-k8s upgrade` command to upgrade a Consul cluster. +func (c *CLICluster) Upgrade(t *testing.T, helmValues map[string]string) { + t.Helper() + + k8s.WritePodsDebugInfoIfFailed(t, c.kubectlOptions, c.debugDirectory, "release="+c.releaseName) + if t.Failed() { + c.logger.Logf(t, "skipping upgrade due to previous failure") + return + } + + // Set the args for running the upgrade command. + args := []string{"upgrade"} + args = c.setKube(args) + + helpers.MergeMaps(c.helmOptions.SetValues, helmValues) + for k, v := range c.helmOptions.SetValues { + args = append(args, "-set", fmt.Sprintf("%s=%s", k, v)) } // Match the timeout for the helm tests. args = append(args, "-timeout", "15m") args = append(args, "-auto-approve") - // Use `go run` so that the CLI is recompiled and therefore uses the local - // charts directory rather than the directory from whenever it was last - // compiled. - cmd := exec.Command("go", append([]string{"run", "."}, args...)...) - cmd.Dir = config.CLIPath - out, err := cmd.Output() + out, err := c.runCLI(args) if err != nil { - h.logger.Logf(t, "error running command [ consul-k8s %s ]: %s", args, err.Error()) - h.logger.Logf(t, "command stdout: %s", string(out)) + c.logger.Logf(t, "error running command `consul-k8s %s`: %s", strings.Join(args, " "), err.Error()) + c.logger.Logf(t, "command stdout: %s", string(out)) } require.NoError(t, err) - k8s.WaitForAllPodsToBeReady(t, h.kubernetesClient, consulNS, fmt.Sprintf("release=%s", h.releaseName)) + k8s.WaitForAllPodsToBeReady(t, c.kubernetesClient, consulNS, fmt.Sprintf("release=%s", c.releaseName)) } -func (h *CLICluster) Destroy(t *testing.T) { +// Destroy uses the `consul-k8s uninstall` command to destroy a Consul cluster. +func (c *CLICluster) Destroy(t *testing.T) { t.Helper() - k8s.WritePodsDebugInfoIfFailed(t, h.kubectlOptions, h.debugDirectory, "release="+h.releaseName) + k8s.WritePodsDebugInfoIfFailed(t, c.kubectlOptions, c.debugDirectory, "release="+c.releaseName) + // Set the args for running the uninstall command. args := []string{"uninstall"} - kubeconfig := h.kubeConfig - if kubeconfig != "" { - args = append(args, "-kubeconfig", kubeconfig) - } - kubecontext := h.kubeContext - if kubecontext != "" { - args = append(args, "-context", kubecontext) - } + args = c.setKube(args) args = append(args, "-auto-approve", "-wipe-data") // Use `go run` so that the CLI is recompiled and therefore uses the local // charts directory rather than the directory from whenever it was last // compiled. - cmd := exec.Command("go", append([]string{"run", "."}, args...)...) - cmd.Dir = config.CLIPath - out, err := cmd.Output() + out, err := c.runCLI(args) if err != nil { - h.logger.Logf(t, "error running command [ consul-k8s %s ]: %s", args, err.Error()) - h.logger.Logf(t, "command stdout: %s", string(out)) + c.logger.Logf(t, "error running command `consul-k8s %s`: %s", strings.Join(args, " "), err.Error()) + c.logger.Logf(t, "command stdout: %s", string(out)) } require.NoError(t, err) } -func (h *CLICluster) Upgrade(t *testing.T, helmValues map[string]string) { +func (c *CLICluster) SetupConsulClient(t *testing.T, secure bool) *api.Client { t.Helper() - helpers.MergeMaps(h.helmOptions.SetValues, helmValues) - helm.Upgrade(t, h.helmOptions, config.HelmChartPath, h.releaseName) - k8s.WaitForAllPodsToBeReady(t, h.kubernetesClient, h.helmOptions.KubectlOptions.Namespace, fmt.Sprintf("release=%s", h.releaseName)) -} - -func (h *CLICluster) SetupConsulClient(t *testing.T, secure bool) *api.Client { - t.Helper() - - namespace := h.kubectlOptions.Namespace + namespace := c.kubectlOptions.Namespace config := api.DefaultConfig() localPort := terratestk8s.GetAvailablePort(t) remotePort := 8500 // use non-secure by default @@ -206,17 +216,17 @@ func (h *CLICluster) SetupConsulClient(t *testing.T, secure bool) *api.Client { // In secondary servers, we don't create a bootstrap token since ACLs are only bootstrapped in the primary. // Instead, we provide a replication token that serves the role of the bootstrap token. - aclSecretName := fmt.Sprintf("%s-consul-bootstrap-acl-token", h.releaseName) - if h.releaseName == CLIReleaseName { + aclSecretName := fmt.Sprintf("%s-consul-bootstrap-acl-token", c.releaseName) + if c.releaseName == CLIReleaseName { aclSecretName = "consul-bootstrap-acl-token" } - aclSecret, err := h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), aclSecretName, metav1.GetOptions{}) + aclSecret, err := c.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), aclSecretName, metav1.GetOptions{}) if err != nil && errors.IsNotFound(err) { - federationSecret := fmt.Sprintf("%s-consul-federation", h.releaseName) - if h.releaseName == CLIReleaseName { + federationSecret := fmt.Sprintf("%s-consul-federation", c.releaseName) + if c.releaseName == CLIReleaseName { federationSecret = "consul-federation" } - aclSecret, err = h.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), federationSecret, metav1.GetOptions{}) + aclSecret, err = c.kubernetesClient.CoreV1().Secrets(namespace).Get(context.Background(), federationSecret, metav1.GetOptions{}) require.NoError(t, err) config.Token = string(aclSecret.Data["replicationToken"]) } else if err == nil { @@ -226,17 +236,17 @@ func (h *CLICluster) SetupConsulClient(t *testing.T, secure bool) *api.Client { } } - serverPod := fmt.Sprintf("%s-consul-server-0", h.releaseName) - if h.releaseName == CLIReleaseName { + serverPod := fmt.Sprintf("%s-consul-server-0", c.releaseName) + if c.releaseName == CLIReleaseName { serverPod = "consul-server-0" } tunnel := terratestk8s.NewTunnelWithLogger( - h.kubectlOptions, + c.kubectlOptions, terratestk8s.ResourceTypePod, serverPod, localPort, remotePort, - h.logger) + c.logger) // Retry creating the port forward since it can fail occasionally. retry.RunWith(&retry.Counter{Wait: 1 * time.Second, Count: 3}, t, func(r *retry.R) { @@ -271,3 +281,27 @@ func createOrUpdateNamespace(t *testing.T, client kubernetes.Interface, namespac require.NoError(t, err) } } + +// setKube adds the args for KubeConfig and KubeCluster if they have been set on the CLICluster. +func (c *CLICluster) setKube(args []string) []string { + kubeconfig := c.kubeConfig + if kubeconfig != "" { + args = append(args, "-kubeconfig", kubeconfig) + } + + kubecontext := c.kubeContext + if kubecontext != "" { + args = append(args, "-context", kubecontext) + } + + return args +} + +// runCLI runs the CLI with the given args. +// Use `go run` so that the CLI is recompiled and therefore uses the local +// charts directory rather than the directory from whenever it was last compiled. +func (c *CLICluster) runCLI(args []string) ([]byte, error) { + cmd := exec.Command("go", append([]string{"run", "."}, args...)...) + cmd.Dir = config.CLIPath + return cmd.Output() +} diff --git a/acceptance/framework/consul/cluster.go b/acceptance/framework/consul/cluster.go new file mode 100644 index 0000000000..15f4dd7722 --- /dev/null +++ b/acceptance/framework/consul/cluster.go @@ -0,0 +1,32 @@ +package consul + +import ( + "testing" + + "github.com/hashicorp/consul/api" +) + +// Cluster represents a consul cluster object. +type Cluster interface { + // SetupConsulClient returns a new Consul client. + SetupConsulClient(t *testing.T, secure bool) *api.Client + + // Create creates a new Consul Cluster. + Create(t *testing.T) + + // Upgrade modifies the cluster in-place by merging the helm values + // from the initial install with helmValues. Any keys that were previously set + // will be overridden by the helmValues keys. + Upgrade(t *testing.T, helmValues map[string]string) + + // Destroy destroys the cluster + Destroy(t *testing.T) +} + +// ClusterKind represents the kind of Consul cluster being used (e.g. "Helm" or "CLI"). +type ClusterKind int + +const ( + Helm ClusterKind = iota + CLI +) diff --git a/acceptance/framework/consul/consul_cluster.go b/acceptance/framework/consul/helm_cluster.go similarity index 97% rename from acceptance/framework/consul/consul_cluster.go rename to acceptance/framework/consul/helm_cluster.go index 3842809660..d1f092d5e5 100644 --- a/acceptance/framework/consul/consul_cluster.go +++ b/acceptance/framework/consul/helm_cluster.go @@ -26,17 +26,6 @@ import ( "k8s.io/client-go/kubernetes" ) -// Cluster represents a consul cluster object. -type Cluster interface { - Create(t *testing.T) - Destroy(t *testing.T) - // Upgrade runs helm upgrade. It will merge the helm values from the - // initial install with helmValues. Any keys that were previously set - // will be overridden by the helmValues keys. - Upgrade(t *testing.T, helmValues map[string]string) - SetupConsulClient(t *testing.T, secure bool) *api.Client -} - // HelmCluster implements Cluster and uses Helm // to create, destroy, and upgrade consul. type HelmCluster struct { @@ -61,7 +50,6 @@ func NewHelmCluster( cfg *config.TestConfig, releaseName string, ) *HelmCluster { - if cfg.EnablePodSecurityPolicies { configurePodSecurityPolicies(t, ctx.KubernetesClient(t), cfg, ctx.KubectlOptions(t).Namespace) } diff --git a/acceptance/framework/consul/consul_cluster_test.go b/acceptance/framework/consul/helm_cluster_test.go similarity index 100% rename from acceptance/framework/consul/consul_cluster_test.go rename to acceptance/framework/consul/helm_cluster_test.go diff --git a/acceptance/framework/helpers/helpers_test.go b/acceptance/framework/helpers/helpers_test.go new file mode 100644 index 0000000000..c1b4a916e2 --- /dev/null +++ b/acceptance/framework/helpers/helpers_test.go @@ -0,0 +1,45 @@ +package helpers + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMergeMaps(t *testing.T) { + cases := map[string]struct { + a, b, expected map[string]string + }{ + "b overwrites a": { + a: map[string]string{ + "foo": "bar", + }, + b: map[string]string{ + "foo": "baz", + }, + expected: map[string]string{ + "foo": "baz", + }, + }, + "no overlap": { + a: map[string]string{ + "foo": "bar", + }, + b: map[string]string{ + "bar": "baz", + }, + expected: map[string]string{ + "foo": "bar", + "bar": "baz", + }, + }, + } + + for name, c := range cases { + t.Run(name, func(t *testing.T) { + actual := c.a + MergeMaps(actual, c.b) + require.Equal(t, c.expected, actual) + }) + } +} diff --git a/acceptance/tests/cli/main_test.go b/acceptance/tests/cli/main_test.go deleted file mode 100644 index 85cef25abe..0000000000 --- a/acceptance/tests/cli/main_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package cli - -import ( - "os" - "testing" - - testsuite "github.com/hashicorp/consul-k8s/acceptance/framework/suite" -) - -var suite testsuite.Suite - -func TestMain(m *testing.M) { - suite = testsuite.NewSuite(m) - os.Exit(suite.Run()) -} diff --git a/acceptance/tests/cli/smoke_test.go b/acceptance/tests/cli/smoke_test.go deleted file mode 100644 index 51bf2bdbb2..0000000000 --- a/acceptance/tests/cli/smoke_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package cli - -import ( - "fmt" - "testing" - - "github.com/hashicorp/consul-k8s/acceptance/tests/connect" -) - -// TestCLIConnectInject is a smoke test that the CLI works with Helm hooks. It sets the -// connect.ConnectInjectConnectivityCheck cli flag to true, causing the Create() and Destroy() methods to use the CLI -// for installation/uninstallation. The connect.ConnectInjectConnectivityCheck test leverages secure mode which will -// enable ACLs and TLS, which are set up via Helm hooks. This allows us to verify that core service mesh functionality -// with non-trivial Helm settings are set up appropriately with the CLI. -func TestCLIConnectInject(t *testing.T) { - cases := []struct { - secure bool - autoEncrypt bool - }{ - {false, false}, - {true, false}, - {true, true}, - } - - for _, c := range cases { - name := fmt.Sprintf("secure: %t; auto-encrypt: %t", c.secure, c.autoEncrypt) - t.Run(name, func(t *testing.T) { - cfg := suite.Config() - ctx := suite.Environment().DefaultContext(t) - - connect.ConnectInjectConnectivityCheck(t, ctx, cfg, c.secure, c.autoEncrypt, true) - - }) - } -} diff --git a/acceptance/tests/connect/connect_helper.go b/acceptance/tests/connect/connect_helper.go index cf7853c1b3..4a8efc3319 100644 --- a/acceptance/tests/connect/connect_helper.go +++ b/acceptance/tests/connect/connect_helper.go @@ -17,40 +17,84 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -const staticClientName = "static-client" -const staticServerName = "static-server" +const ( + staticClientName = "static-client" + staticServerName = "static-server" +) -// ConnectInjectConnectivityCheck is a helper function used by the connect tests and cli smoke tests to test service -// mesh connectivity. -func ConnectInjectConnectivityCheck(t *testing.T, ctx environment.TestContext, cfg *config.TestConfig, secure bool, autoEncrypt bool, cli bool) { - helmValues := map[string]string{ - "connectInject.enabled": "true", +// ConnectHelper configures a Consul cluster for connect injection tests. +// It also provides helper methods to exercise the connect functionality. +type ConnectHelper struct { + // ClusterKind is the kind of Consul cluster to use (e.g. "Helm", "CLI"). + ClusterKind consul.ClusterKind - "global.tls.enabled": strconv.FormatBool(secure), - "global.tls.enableAutoEncrypt": strconv.FormatBool(autoEncrypt), - "global.acls.manageSystemACLs": strconv.FormatBool(secure), - } + // Secure configures the Helm chart for the test to use ACL tokens. + Secure bool - releaseName := helpers.RandomName() - var consulCluster consul.Cluster - if cli { - consulCluster = consul.NewCLICluster(t, helmValues, ctx, cfg, consul.CLIReleaseName) - } else { - consulCluster = consul.NewHelmCluster(t, helmValues, ctx, cfg, releaseName) + // AutoEncrypt configures the Helm chart for the test to use AutoEncrypt. + AutoEncrypt bool + + // HelmValues are the additional helm values to use when installing or + // upgrading the cluster beyond connectInject.enabled, global.tls.enabled, + // global.tls.enableAutoEncrypt, global.acls.mangageSystemACLs which are + // set by the Secure and AutoEncrypt fields. + HelmValues map[string]string + + // RelaseName is the name of the Consul cluster. + ReleaseName string + + Ctx environment.TestContext + Cfg *config.TestConfig + + // consulCluster is the cluster to use for the test. + consulCluster consul.Cluster + + // consulClient is the client used to test service mesh connectivity. + consulClient *api.Client +} + +// Setup creates a new cluster using the New*Cluster function and assigns it +// to the consulCluster field. +func (c *ConnectHelper) Setup(t *testing.T) { + switch c.ClusterKind { + case consul.Helm: + c.consulCluster = consul.NewHelmCluster(t, c.helmValues(), c.Ctx, c.Cfg, c.ReleaseName) + case consul.CLI: + c.consulCluster = consul.NewCLICluster(t, c.helmValues(), c.Ctx, c.Cfg, c.ReleaseName) } +} + +// Install uses the consulCluster to install Consul onto the Kubernetes cluster. +func (c *ConnectHelper) Install(t *testing.T) { + logger.Log(t, "Installing Consul cluster") + c.consulCluster.Create(t) + c.consulClient = c.consulCluster.SetupConsulClient(t, c.Secure) +} - consulCluster.Create(t) +// Upgrade uses the existing Consul cluster and upgrades it using Helm values +// set by the Secure, AutoEncrypt, and HelmValues fields. +func (c *ConnectHelper) Upgrade(t *testing.T) { + require.NotNil(t, c.consulCluster, "consulCluster must be set before calling Upgrade (Call Install first).") + require.NotNil(t, c.consulClient, "consulClient must be set before calling Upgrade (Call Install first).") - consulClient := consulCluster.SetupConsulClient(t, secure) + logger.Log(t, "upgrading Consul cluster") + c.consulCluster.Upgrade(t, c.helmValues()) +} +// DeployClientAndServer deploys a client and server pod to the Kubernetes +// cluster which will be used to test service mesh connectivity. If the Secure +// flag is true, a pre-check is done to ensure that the ACL tokens for the test +// are deleted. The status of the deployment and injection is checked after the +// deployment is complete to ensure success. +func (c *ConnectHelper) DeployClientAndServer(t *testing.T) { // Check that the ACL token is deleted. - if secure { - // We need to register the cleanup function before we create the deployments - // because golang will execute them in reverse order i.e. the last registered - // cleanup function will be executed first. + if c.Secure { + // We need to register the cleanup function before we create the + // deployments because golang will execute them in reverse order + // (i.e. the last registered cleanup function will be executed first). t.Cleanup(func() { retry.Run(t, func(r *retry.R) { - tokens, _, err := consulClient.ACL().TokenList(nil) + tokens, _, err := c.consulClient.ACL().TokenList(nil) require.NoError(r, err) for _, token := range tokens { require.NotContains(r, token.Description, staticServerName) @@ -61,67 +105,114 @@ func ConnectInjectConnectivityCheck(t *testing.T, ctx environment.TestContext, c } logger.Log(t, "creating static-server and static-client deployments") - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-server-inject") - if cfg.EnableTransparentProxy { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") + + k8s.DeployKustomize(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.DebugDirectory, "../fixtures/cases/static-server-inject") + if c.Cfg.EnableTransparentProxy { + k8s.DeployKustomize(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.DebugDirectory, "../fixtures/cases/static-client-tproxy") } else { - k8s.DeployKustomize(t, ctx.KubectlOptions(t), cfg.NoCleanupOnFailure, cfg.DebugDirectory, "../fixtures/cases/static-client-inject") + k8s.DeployKustomize(t, c.Ctx.KubectlOptions(t), c.Cfg.NoCleanupOnFailure, c.Cfg.DebugDirectory, "../fixtures/cases/static-client-inject") } - // Check that both static-server and static-client have been injected and now have 2 containers. + // Check that both static-server and static-client have been injected and + // now have 2 containers. for _, labelSelector := range []string{"app=static-server", "app=static-client"} { - podList, err := ctx.KubernetesClient(t).CoreV1().Pods(ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ + podList, err := c.Ctx.KubernetesClient(t).CoreV1().Pods(c.Ctx.KubectlOptions(t).Namespace).List(context.Background(), metav1.ListOptions{ LabelSelector: labelSelector, }) require.NoError(t, err) require.Len(t, podList.Items, 1) require.Len(t, podList.Items[0].Spec.Containers, 2) } +} - if secure { - logger.Log(t, "checking that the connection is not successful because there's no intention") - if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), staticClientName, "http://static-server") - } else { - k8s.CheckStaticServerConnectionFailing(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") - } - - logger.Log(t, "creating intention") - _, _, err := consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ - Kind: api.ServiceIntentions, - Name: staticServerName, - Sources: []*api.SourceIntention{ - { - Name: staticClientName, - Action: api.IntentionActionAllow, - }, - }, - }, nil) - require.NoError(t, err) +// TestConnectionFailureWithoutIntention ensures the connection to the static +// server fails when no intentions are configured. +func (c *ConnectHelper) TestConnectionFailureWithoutIntention(t *testing.T) { + logger.Log(t, "checking that the connection is not successful because there's no intention") + if c.Cfg.EnableTransparentProxy { + k8s.CheckStaticServerConnectionFailing(t, c.Ctx.KubectlOptions(t), staticClientName, "http://static-server") + } else { + k8s.CheckStaticServerConnectionFailing(t, c.Ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") } +} +// CreateIntention creates an intention for the static-server pod to connect to +// the static-client pod. +func (c *ConnectHelper) CreateIntention(t *testing.T) { + logger.Log(t, "creating intention") + _, _, err := c.consulClient.ConfigEntries().Set(&api.ServiceIntentionsConfigEntry{ + Kind: api.ServiceIntentions, + Name: staticServerName, + Sources: []*api.SourceIntention{ + { + Name: staticClientName, + Action: api.IntentionActionAllow, + }, + }, + }, nil) + require.NoError(t, err) +} + +// TestConnectionSuccessful ensures the static-server pod can connect to the +// static-client pod once the intention is set. +func (c *ConnectHelper) TestConnectionSuccess(t *testing.T) { logger.Log(t, "checking that connection is successful") - if cfg.EnableTransparentProxy { + if c.Cfg.EnableTransparentProxy { // todo: add an assertion that the traffic is going through the proxy - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://static-server") + k8s.CheckStaticServerConnectionSuccessful(t, c.Ctx.KubectlOptions(t), staticClientName, "http://static-server") } else { - k8s.CheckStaticServerConnectionSuccessful(t, ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") + k8s.CheckStaticServerConnectionSuccessful(t, c.Ctx.KubectlOptions(t), staticClientName, "http://localhost:1234") } +} +// TestConnectionFailureWhenUnhealthy sets the static-server pod to be unhealthy +// and ensures the connection fails. It restores the pod to a healthy state +// after this check. +func (c *ConnectHelper) TestConnectionFailureWhenUnhealthy(t *testing.T) { // Test that kubernetes readiness status is synced to Consul. - // Create the file so that the readiness probe of the static-server pod fails. + // Create a file called "unhealthy" at "/tmp/" so that the readiness probe + // of the static-server pod fails. logger.Log(t, "testing k8s -> consul health checks sync by making the static-server unhealthy") - k8s.RunKubectl(t, ctx.KubectlOptions(t), "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") - - // The readiness probe should take a moment to be reflected in Consul, CheckStaticServerConnection will retry - // until Consul marks the service instance unavailable for mesh traffic, causing the connection to fail. - // We are expecting a "connection reset by peer" error because in a case of health checks, - // there will be no healthy proxy host to connect to. That's why we can't assert that we receive an empty reply - // from server, which is the case when a connection is unsuccessful due to intentions in other tests. + k8s.RunKubectl(t, c.Ctx.KubectlOptions(t), "exec", "deploy/"+staticServerName, "--", "touch", "/tmp/unhealthy") + + // The readiness probe should take a moment to be reflected in Consul, + // CheckStaticServerConnection will retry until Consul marks the service + // instance unavailable for mesh traffic, causing the connection to fail. + // We are expecting a "connection reset by peer" error because in a case of + // health checks, there will be no healthy proxy host to connect to. + // That's why we can't assert that we receive an empty reply from server, + // which is the case when a connection is unsuccessful due to intentions in + // other tests. logger.Log(t, "checking that connection is unsuccessful") - if cfg.EnableTransparentProxy { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server", "curl: (7) Failed to connect to static-server port 80: Connection refused"}, "", "http://static-server") + if c.Cfg.EnableTransparentProxy { + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, c.Ctx.KubectlOptions(t), staticClientName, false, []string{ + "curl: (56) Recv failure: Connection reset by peer", + "curl: (52) Empty reply from server", + "curl: (7) Failed to connect to static-server port 80: Connection refused", + }, "", "http://static-server") } else { - k8s.CheckStaticServerConnectionMultipleFailureMessages(t, ctx.KubectlOptions(t), staticClientName, false, []string{"curl: (56) Recv failure: Connection reset by peer", "curl: (52) Empty reply from server"}, "", "http://localhost:1234") + k8s.CheckStaticServerConnectionMultipleFailureMessages(t, c.Ctx.KubectlOptions(t), staticClientName, false, []string{ + "curl: (56) Recv failure: Connection reset by peer", + "curl: (52) Empty reply from server", + }, "", "http://localhost:1234") + } + + // Return the static-server to a "healthy state". + k8s.RunKubectl(t, c.Ctx.KubectlOptions(t), "exec", "deploy/"+staticServerName, "--", "rm", "/tmp/unhealthy") +} + +// helmValues uses the Secure and AutoEncrypt fields to set values for the Helm +// Chart which are merged with the HelmValues field with the values set by the +// Secure and AutoEncrypt fields taking precedence. +func (c *ConnectHelper) helmValues() map[string]string { + helmValues := map[string]string{ + "connectInject.enabled": "true", + "global.tls.enabled": strconv.FormatBool(c.Secure), + "global.tls.enableAutoEncrypt": strconv.FormatBool(c.AutoEncrypt), + "global.acls.manageSystemACLs": strconv.FormatBool(c.Secure), } + + helpers.MergeMaps(helmValues, c.HelmValues) + + return helmValues } diff --git a/acceptance/tests/connect/connect_inject_test.go b/acceptance/tests/connect/connect_inject_test.go index bf4d8a7047..c8737db0b6 100644 --- a/acceptance/tests/connect/connect_inject_test.go +++ b/acceptance/tests/connect/connect_inject_test.go @@ -18,25 +18,130 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// Test that Connect works in a default and a secure installation. +// TestConnectInject tests that Connect works in a default and a secure installation. func TestConnectInject(t *testing.T) { - cases := []struct { + cases := map[string]struct { + clusterKind consul.ClusterKind + releaseName string secure bool autoEncrypt bool }{ - {false, false}, - {true, false}, - {true, true}, + "Helm install without secure or auto-encrypt": { + clusterKind: consul.Helm, + releaseName: helpers.RandomName(), + }, + "Helm install with secure": { + clusterKind: consul.Helm, + releaseName: helpers.RandomName(), + secure: true, + }, + "Helm install with secure and auto-encrypt": { + clusterKind: consul.Helm, + releaseName: helpers.RandomName(), + secure: true, + autoEncrypt: true, + }, + "CLI install without secure or auto-encrypt": { + clusterKind: consul.CLI, + releaseName: consul.CLIReleaseName, + }, + "CLI install with secure": { + clusterKind: consul.CLI, + releaseName: consul.CLIReleaseName, + secure: true, + }, + "CLI install with secure and auto-encrypt": { + clusterKind: consul.CLI, + releaseName: consul.CLIReleaseName, + secure: true, + autoEncrypt: true, + }, } - for _, c := range cases { - name := fmt.Sprintf("secure: %t; auto-encrypt: %t", c.secure, c.autoEncrypt) + for name, c := range cases { + t.Run(name, func(t *testing.T) { + cfg := suite.Config() + ctx := suite.Environment().DefaultContext(t) + + connHelper := ConnectHelper{ + ClusterKind: c.clusterKind, + Secure: c.secure, + AutoEncrypt: c.autoEncrypt, + ReleaseName: c.releaseName, + Ctx: ctx, + Cfg: cfg, + } + + connHelper.Setup(t) + + connHelper.Install(t) + connHelper.DeployClientAndServer(t) + if c.secure { + connHelper.TestConnectionFailureWithoutIntention(t) + connHelper.CreateIntention(t) + } + connHelper.TestConnectionSuccess(t) + connHelper.TestConnectionFailureWhenUnhealthy(t) + }) + } +} + +// TestConnectInjectOnUpgrade tests that Connect works before and after an +// upgrade is performed on the cluster. +func TestConnectInjectOnUpgrade(t *testing.T) { + cases := map[string]struct { + clusterKind consul.ClusterKind + releaseName string + initial, upgrade map[string]string + }{ + "CLI upgrade changes nothing": { + clusterKind: consul.CLI, + releaseName: consul.CLIReleaseName, + }, + "CLI upgrade to enable ingressGateway": { + clusterKind: consul.CLI, + releaseName: consul.CLIReleaseName, + initial: map[string]string{}, + upgrade: map[string]string{ + "ingressGateways.enabled": "true", + "ingressGateways.defaults.replicas": "1", + }, + }, + "CLI upgrade to enable UI": { + clusterKind: consul.CLI, + releaseName: consul.CLIReleaseName, + initial: map[string]string{}, + upgrade: map[string]string{ + "ui.enabled": "true", + }, + }, + } + + for name, c := range cases { t.Run(name, func(t *testing.T) { cfg := suite.Config() ctx := suite.Environment().DefaultContext(t) - ConnectInjectConnectivityCheck(t, ctx, cfg, c.secure, c.autoEncrypt, false) + connHelper := ConnectHelper{ + ClusterKind: c.clusterKind, + HelmValues: c.initial, + ReleaseName: c.releaseName, + Ctx: ctx, + Cfg: cfg, + } + + connHelper.Setup(t) + + connHelper.Install(t) + connHelper.DeployClientAndServer(t) + connHelper.TestConnectionSuccess(t) + connHelper.TestConnectionFailureWhenUnhealthy(t) + + connHelper.HelmValues = c.upgrade + connHelper.Upgrade(t) + connHelper.TestConnectionSuccess(t) + connHelper.TestConnectionFailureWhenUnhealthy(t) }) } } From d191757b787444f093ad7839e7da1af118e858da Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Wed, 2 Mar 2022 16:26:04 -0500 Subject: [PATCH 331/418] get docker build working --- .github/workflows/build-and-test.yml | 24 +++++++++++++++++++++--- control-plane/Makefile | 6 +++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2a5c69965b..f721e55601 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -13,6 +13,10 @@ env: CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests GOTESTSUM_VERSION: 1.6.4 +# TODO: upload tests somewhere. An artifact? +# TODO: prevent running some things on forks? +# TODO: fix caching. Maybe cache on the first job + jobs: validate-helm-gen: runs-on: ubuntu-latest @@ -230,10 +234,24 @@ jobs: dev-upload-docker: needs: build-distros runs-on: ubuntu-latest + + env: + GITHUB_PULL_REQUEST: ${{github.event.pull_request.number}} steps: - - name: TODO - run: - echo "Filler" + + - uses: actions/checkout@v2 + + - uses: actions/download-artifact@v3 + with: + name: my-artifact + path: control-plane/consul-k8s_linux_amd64.zip + + - name: Docker build + working-directory: control-plane + run: | + mkdir -p pkg/bin/linux_amd64 + unzip control-plane/consul-k8s_linux_amd64.zip /pkg/bin/linux_amd64 + make ci.dev-docker acceptance-tproxy: needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] diff --git a/control-plane/Makefile b/control-plane/Makefile index d882018031..0c2c60fb75 100644 --- a/control-plane/Makefile +++ b/control-plane/Makefile @@ -35,9 +35,9 @@ ci.dev-docker: @echo "Building consul-k8s Development container - $(CI_DEV_DOCKER_IMAGE_NAME)" @docker build -t '$(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT)' \ --build-arg CONSUL_K8S_IMAGE_VERSION=$(CONSUL_K8S_IMAGE_VERSION) \ - --label COMMIT_SHA=$(CIRCLE_SHA1) \ - --label PULL_REQUEST=$(CIRCLE_PULL_REQUEST) \ - --label CIRCLE_BUILD_URL=$(CIRCLE_BUILD_URL) \ + --label COMMIT_SHA=$(GITHUB_SHA) \ + --label PULL_REQUEST=$(GITHIB_PULL_REQUEST) \ + --label GITHUB_BUILD_URL=$(GITHUB_SERVER_URL)/$(GITHUB_REPOSITORY)/actions/runs/$(GITHUB_RUN_ID) \ $(CI_DEV_DOCKER_WORKDIR) -f $(CURDIR)/build-support/docker/Dev.dockerfile @echo $(DOCKER_PASS) | docker login -u="$(DOCKER_USER)" --password-stdin @echo "Pushing dev image to: https://cloud.docker.com/u/$(CI_DEV_DOCKER_NAMESPACE)/repository/docker/$(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME)" From 779de509abfaa856910e1d07177e541ceab1fb8c Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Wed, 2 Mar 2022 16:39:04 -0500 Subject: [PATCH 332/418] forgot the artifact name --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f721e55601..b561ebe9ae 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -243,7 +243,7 @@ jobs: - uses: actions/download-artifact@v3 with: - name: my-artifact + name: consul-k8s_linux_amd64.zip path: control-plane/consul-k8s_linux_amd64.zip - name: Docker build From 7c5a1ef93debd57c892f8b63cbd04ef3bf105a5f Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Wed, 2 Mar 2022 18:01:25 -0500 Subject: [PATCH 333/418] wrong path for the build binary --- .github/workflows/build-and-test.yml | 36 ++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b561ebe9ae..bedd5a4939 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -238,7 +238,6 @@ jobs: env: GITHUB_PULL_REQUEST: ${{github.event.pull_request.number}} steps: - - uses: actions/checkout@v2 - uses: actions/download-artifact@v3 @@ -250,16 +249,43 @@ jobs: working-directory: control-plane run: | mkdir -p pkg/bin/linux_amd64 - unzip control-plane/consul-k8s_linux_amd64.zip /pkg/bin/linux_amd64 + unzip consul-k8s_linux_amd64.zip /pkg/bin/linux_amd64 make ci.dev-docker acceptance-tproxy: needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] runs-on: ubuntu-latest steps: - - name: TODO - run: - echo "Filler" + - uses: actions/checkout@v2 + + - name: Create Kind Cluster + uses: helm/kind-action@v1.2.0 + with: + version: 1.22.4 + + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: 1.17.2 + + - name: Setup go mod cache + uses: actions/cache@v2 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Go mod download + working-directory: acceptance + run: go mod download + + - run: mkdir -p ${{env.TEST_RESULTS}} + + - name: Run acceptance tests + acceptance: needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] From 4bc8394996c578567f59754f929f7fa7b1c8cb42 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Wed, 2 Mar 2022 18:02:59 -0500 Subject: [PATCH 334/418] wrong path for the build binary --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index bedd5a4939..8eae129569 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -284,7 +284,7 @@ jobs: - run: mkdir -p ${{env.TEST_RESULTS}} - - name: Run acceptance tests + # - name: Run acceptance tests acceptance: From a59a87582f2b6d6302e0f8ab887c4e8f63394c7f Mon Sep 17 00:00:00 2001 From: Alvin Huang <17609145+alvin-huang@users.noreply.github.com> Date: Wed, 2 Mar 2022 18:03:43 -0500 Subject: [PATCH 335/418] change helm trigger branch from master to main (#1069) --- .circleci/config.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2bf464fc1a..2be1b488b5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,8 +12,8 @@ executors: CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests -control-plane-path : &control-plane-path control-plane -cli-path : &cli-path cli +control-plane-path: &control-plane-path control-plane +cli-path: &cli-path cli acceptance-mod-path: &acceptance-mod-path acceptance acceptance-test-path: &acceptance-test-path acceptance/tests acceptance-framework-path: &acceptance-framework-path acceptance/framework @@ -891,7 +891,7 @@ jobs: -X POST \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ - -d "{\"branch\": \"master\",\"parameters\":{\"SOURCE_REPO\": \"${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}\",\"SOURCE_TAG\": \"${CIRCLE_TAG}\"}}" \ + -d "{\"branch\": \"main\",\"parameters\":{\"SOURCE_REPO\": \"${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}\",\"SOURCE_TAG\": \"${CIRCLE_TAG}\"}}" \ "${CIRCLE_ENDPOINT}/${CIRCLE_PROJECT}/pipeline" - slack/status: fail_only: true @@ -981,10 +981,10 @@ workflows: - cleanup-gcp-resources - cleanup-azure-resources - cleanup-eks-resources -# Disable until we can use UBI images. -# - acceptance-openshift: -# requires: -# - cleanup-azure-resources + # Disable until we can use UBI images. + # - acceptance-openshift: + # requires: + # - cleanup-azure-resources - acceptance-gke-1-20: requires: - cleanup-gcp-resources From e089d5dbec07b6eeb1b7624f6ad4b23a4152a465 Mon Sep 17 00:00:00 2001 From: Thomas Eckert Date: Wed, 2 Mar 2022 18:06:09 -0500 Subject: [PATCH 336/418] Increase wait for all pods to be ready from 10 to 11 minutes (#1065) * Increase timeout from 15m to 20m * Reset timeout on consul cluster to 15m * Extend wait for pods to be ready from 10m to 11m * Go fmt'd --- acceptance/framework/k8s/helpers.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/acceptance/framework/k8s/helpers.go b/acceptance/framework/k8s/helpers.go index dabb617876..1b895a5e17 100644 --- a/acceptance/framework/k8s/helpers.go +++ b/acceptance/framework/k8s/helpers.go @@ -32,7 +32,7 @@ func KubernetesAPIServerHostFromOptions(t *testing.T, options *terratestk8s.Kube } // WaitForAllPodsToBeReady waits until all pods with the provided podLabelSelector -// are in the ready status. It checks every 5 seconds for a total of 20 tries. +// are in the ready status. It checks every second for 11 minutes. // If there is at least one container in a pod that isn't ready after that, // it fails the test. func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespace, podLabelSelector string) { @@ -40,10 +40,10 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac logger.Logf(t, "Waiting for pods with label %q to be ready.", podLabelSelector) - // Wait up to 10m. + // Wait up to 11m. // On Azure, volume provisioning can sometimes take close to 5 min, // so we need to give a bit more time for pods to become healthy. - counter := &retry.Counter{Count: 600, Wait: 1 * time.Second} + counter := &retry.Counter{Count: 11 * 60, Wait: 1 * time.Second} retry.RunWith(counter, t, func(r *retry.R) { pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) require.NoError(r, err) From 9f2a14901c0ee04faa45eafe780bda6e0e7bbb50 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Wed, 2 Mar 2022 19:28:47 -0500 Subject: [PATCH 337/418] dev-upload-docker not finding binary --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8eae129569..965d6531fc 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -243,7 +243,7 @@ jobs: - uses: actions/download-artifact@v3 with: name: consul-k8s_linux_amd64.zip - path: control-plane/consul-k8s_linux_amd64.zip + path: consul-k8s_linux_amd64.zip - name: Docker build working-directory: control-plane From 388dbbf6a70cc080150bef3985faeb049956c18d Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Wed, 2 Mar 2022 21:59:01 -0500 Subject: [PATCH 338/418] pass consul license as environment variable and download binary to control-plane directory --- .github/workflows/build-and-test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 965d6531fc..dcf18df416 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -49,6 +49,7 @@ jobs: with: directory: hack/helm-reference-gen go-version: 1.17.2 + CONSUL_LICENSE: ${{secrets.CONSUL_LICENSE}} unit-helm-gen: needs: [go-fmt-vet-helm-gen, validate-helm-gen] @@ -129,6 +130,8 @@ jobs: test-enterprise-control-plane: needs: [lint-control-plane, go-fmt-vet-control-plane] runs-on: ubuntu-latest + env: + CONSUL_LICENSE: ${{secrets.CONSUL_LICENSE}} steps: - name: Checkout code uses: actions/checkout@v2 @@ -243,7 +246,7 @@ jobs: - uses: actions/download-artifact@v3 with: name: consul-k8s_linux_amd64.zip - path: consul-k8s_linux_amd64.zip + path: control-plane/consul-k8s_linux_amd64.zip - name: Docker build working-directory: control-plane From 5c1b38204ca8ab556542e79d83f7c3b726419e42 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Wed, 2 Mar 2022 22:11:26 -0500 Subject: [PATCH 339/418] messed up the secret name --- .github/workflows/build-and-test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index dcf18df416..02c2834108 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -49,7 +49,6 @@ jobs: with: directory: hack/helm-reference-gen go-version: 1.17.2 - CONSUL_LICENSE: ${{secrets.CONSUL_LICENSE}} unit-helm-gen: needs: [go-fmt-vet-helm-gen, validate-helm-gen] From 5665b8163ea5a145246ed8f85844b2b63ac95908 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Wed, 2 Mar 2022 22:32:33 -0500 Subject: [PATCH 340/418] things acting weird --- .github/workflows/build-and-test.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 02c2834108..f62fc69cd0 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -242,16 +242,17 @@ jobs: steps: - uses: actions/checkout@v2 + - run: mkdir -p control-plane/pkg/bin/linux_amd64 + - uses: actions/download-artifact@v3 with: name: consul-k8s_linux_amd64.zip - path: control-plane/consul-k8s_linux_amd64.zip + path: control-plane/pkg/bin/linux_amd64/consul-k8s_linux_amd64.zip - name: Docker build working-directory: control-plane run: | - mkdir -p pkg/bin/linux_amd64 - unzip consul-k8s_linux_amd64.zip /pkg/bin/linux_amd64 + unzip /pkg/bin/linux_amd64/consul-k8s_linux_amd64.zip make ci.dev-docker acceptance-tproxy: From a45442b6ce96a899d2204d71bd2ecf07ef5fed93 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 00:25:15 -0500 Subject: [PATCH 341/418] figure out what is going wrong with this binary not being found --- .github/workflows/build-and-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f62fc69cd0..896a34d501 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -252,6 +252,8 @@ jobs: - name: Docker build working-directory: control-plane run: | + ls /pkg/bin/linux_amd64 + ls unzip /pkg/bin/linux_amd64/consul-k8s_linux_amd64.zip make ci.dev-docker From 823b99cbaa54734f30d5022f3d2e89f915b8ba8c Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 09:38:13 -0500 Subject: [PATCH 342/418] figure out what is going wrong with this binary not being found --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 896a34d501..d80a3babb5 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -252,7 +252,7 @@ jobs: - name: Docker build working-directory: control-plane run: | - ls /pkg/bin/linux_amd64 + pwd ls unzip /pkg/bin/linux_amd64/consul-k8s_linux_amd64.zip make ci.dev-docker From 6010d6cce1f9e69ac09f6d691b6a9845fdc11e30 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 10:05:23 -0500 Subject: [PATCH 343/418] such a pain to test --- .github/workflows/build-and-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index d80a3babb5..8d1aa0a2d6 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -247,14 +247,14 @@ jobs: - uses: actions/download-artifact@v3 with: name: consul-k8s_linux_amd64.zip - path: control-plane/pkg/bin/linux_amd64/consul-k8s_linux_amd64.zip + path: consul-k8s_linux_amd64.zip - name: Docker build working-directory: control-plane run: | pwd ls - unzip /pkg/bin/linux_amd64/consul-k8s_linux_amd64.zip + unzip consul-k8s_linux_amd64.zip -d ./pkg/bin make ci.dev-docker acceptance-tproxy: From ce37efe256caad10e4e7240f7fc6bbfd2c6ae210 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 10:27:46 -0500 Subject: [PATCH 344/418] download-artifact does not work too well --- .github/workflows/build-and-test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8d1aa0a2d6..7e3fcd08f3 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -247,14 +247,13 @@ jobs: - uses: actions/download-artifact@v3 with: name: consul-k8s_linux_amd64.zip - path: consul-k8s_linux_amd64.zip - name: Docker build working-directory: control-plane run: | pwd ls - unzip consul-k8s_linux_amd64.zip -d ./pkg/bin + unzip consul-k8s_linux_amd64.zip -d ./pkg/bin/linux_amd64 make ci.dev-docker acceptance-tproxy: From 5d2f271f490eb73212e27b94062259544f94695f Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 11:08:37 -0500 Subject: [PATCH 345/418] I think I have it, maybe --- .github/workflows/build-and-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7e3fcd08f3..b3feec8cf2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -172,7 +172,6 @@ jobs: build-distros: #needs: [test-control-plane, test-enterprise-control-plane] - needs: test-control-plane runs-on: ubuntu-latest strategy: matrix: @@ -247,13 +246,14 @@ jobs: - uses: actions/download-artifact@v3 with: name: consul-k8s_linux_amd64.zip + path: control-plane - name: Docker build working-directory: control-plane run: | pwd ls - unzip consul-k8s_linux_amd64.zip -d ./pkg/bin/linux_amd64 + unzip ${{steps.download.outputs.download-path}}/consul-k8s_linux_amd64.zip -d ./pkg/bin/linux_amd64 make ci.dev-docker acceptance-tproxy: From 9969d55f3ecea6632bd75fe4801b5b441412589c Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 11:16:08 -0500 Subject: [PATCH 346/418] I think I have it, maybe --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b3feec8cf2..f74ae5767f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -253,7 +253,7 @@ jobs: run: | pwd ls - unzip ${{steps.download.outputs.download-path}}/consul-k8s_linux_amd64.zip -d ./pkg/bin/linux_amd64 + unzip consul-k8s_linux_amd64.zip -d ./pkg/bin/linux_amd64 make ci.dev-docker acceptance-tproxy: From 0a19f9dfefb67694b64203b350646a492b658c28 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Thu, 3 Mar 2022 09:21:04 -0700 Subject: [PATCH 347/418] Remove unused update-helm-charts-index job (#1071) --- .circleci/config.yml | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2be1b488b5..6b7115efb1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -868,35 +868,6 @@ jobs: fail_only: true failure_message: "Acceptance tests against Kind with Kubernetes v1.22 failed. Check the logs at: ${CIRCLE_BUILD_URL}" - update-helm-charts-index: - docker: - - image: docker.mirror.hashicorp.services/circleci/golang:latest - steps: - - checkout - - run: - name: verify chart version matches tag version - working_directory: *charts-consul-path - command: | - GO111MODULE=on go get github.com/mikefarah/yq/v2 - git_tag=$(echo "${CIRCLE_TAG#v}") - chart_tag=$(yq r Chart.yaml version) - if [ "${git_tag}" != "${chart_tag}" ]; then - echo "chart version (${chart_tag}) did not match git version (${git_tag})" - exit 1 - fi - - run: - name: update helm-charts index - command: | - curl --show-error --silent --fail --user "${CIRCLE_TOKEN}:" \ - -X POST \ - -H 'Content-Type: application/json' \ - -H 'Accept: application/json' \ - -d "{\"branch\": \"main\",\"parameters\":{\"SOURCE_REPO\": \"${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}\",\"SOURCE_TAG\": \"${CIRCLE_TAG}\"}}" \ - "${CIRCLE_ENDPOINT}/${CIRCLE_PROJECT}/pipeline" - - slack/status: - fail_only: true - failure_message: "Failed to trigger an update to the helm charts index. Check the logs at: ${CIRCLE_BUILD_URL}" - workflows: version: 2 test-and-build: From 5d83d3b436a07b70f4e7d0965ecd671101adcb67 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 11:22:37 -0500 Subject: [PATCH 348/418] was missing docker user and pass --- .github/workflows/build-and-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f74ae5767f..8ef1fb422f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -238,6 +238,8 @@ jobs: env: GITHUB_PULL_REQUEST: ${{github.event.pull_request.number}} + DOCKER_USER: ${{secrets.DOCKER_USER}} + DOCKER_PASS: ${{secrets.DOCKER_PASS}} steps: - uses: actions/checkout@v2 @@ -251,8 +253,6 @@ jobs: - name: Docker build working-directory: control-plane run: | - pwd - ls unzip consul-k8s_linux_amd64.zip -d ./pkg/bin/linux_amd64 make ci.dev-docker From 827358f1721781820f2c6292f5ef182e311b99b7 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 13:04:19 -0500 Subject: [PATCH 349/418] use the docker action to log in --- control-plane/Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/control-plane/Makefile b/control-plane/Makefile index 0c2c60fb75..96e75c7df2 100644 --- a/control-plane/Makefile +++ b/control-plane/Makefile @@ -27,7 +27,7 @@ CONSUL_K8S_IMAGE_VERSION?=latest ci.dev-tree: @$(SHELL) $(CURDIR)/build-support/scripts/dev.sh $(DEV_PUSH_ARG) -# In CircleCI, the linux binary will be attached from a previous step at pkg/bin/linux_amd64/. This make target +# In Github Actions, the linux binary will be attached from a previous step at pkg/bin/linux_amd64/. This make target # should only run in CI and not locally. ci.dev-docker: @echo "Pulling consul-k8s container image - $(CONSUL_K8S_IMAGE_VERSION)" @@ -39,10 +39,10 @@ ci.dev-docker: --label PULL_REQUEST=$(GITHIB_PULL_REQUEST) \ --label GITHUB_BUILD_URL=$(GITHUB_SERVER_URL)/$(GITHUB_REPOSITORY)/actions/runs/$(GITHUB_RUN_ID) \ $(CI_DEV_DOCKER_WORKDIR) -f $(CURDIR)/build-support/docker/Dev.dockerfile - @echo $(DOCKER_PASS) | docker login -u="$(DOCKER_USER)" --password-stdin +# @echo $(DOCKER_PASS) | docker login -u="$(DOCKER_USER)" --password-stdin @echo "Pushing dev image to: https://cloud.docker.com/u/$(CI_DEV_DOCKER_NAMESPACE)/repository/docker/$(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME)" @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) -ifeq ($(CIRCLE_BRANCH), main) +ifeq ($(GITHUB_REF_NAME(), main) @docker tag $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest endif From 3a62ff9cd7b841f8a0bfaab64426da6deb3a46c2 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 13:10:00 -0500 Subject: [PATCH 350/418] where is the docker login? --- .github/workflows/build-and-test.yml | 7 +++++-- control-plane/Makefile | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8ef1fb422f..9947fe6e90 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -238,8 +238,6 @@ jobs: env: GITHUB_PULL_REQUEST: ${{github.event.pull_request.number}} - DOCKER_USER: ${{secrets.DOCKER_USER}} - DOCKER_PASS: ${{secrets.DOCKER_PASS}} steps: - uses: actions/checkout@v2 @@ -250,6 +248,11 @@ jobs: name: consul-k8s_linux_amd64.zip path: control-plane + - uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_USER }} + password: ${{ secrets.DOCKER_PASS }} + - name: Docker build working-directory: control-plane run: | diff --git a/control-plane/Makefile b/control-plane/Makefile index 96e75c7df2..57e67aad48 100644 --- a/control-plane/Makefile +++ b/control-plane/Makefile @@ -42,7 +42,7 @@ ci.dev-docker: # @echo $(DOCKER_PASS) | docker login -u="$(DOCKER_USER)" --password-stdin @echo "Pushing dev image to: https://cloud.docker.com/u/$(CI_DEV_DOCKER_NAMESPACE)/repository/docker/$(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME)" @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) -ifeq ($(GITHUB_REF_NAME(), main) +ifeq ($(GITHUB_REF_NAME), main) @docker tag $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest endif From 0db7a3b053667211dba3184d4326b6070d837f35 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 13:38:13 -0500 Subject: [PATCH 351/418] use a docker token instead of pass --- .github/workflows/build-and-test.yml | 7 ++----- control-plane/Makefile | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 9947fe6e90..8ef1fb422f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -238,6 +238,8 @@ jobs: env: GITHUB_PULL_REQUEST: ${{github.event.pull_request.number}} + DOCKER_USER: ${{secrets.DOCKER_USER}} + DOCKER_PASS: ${{secrets.DOCKER_PASS}} steps: - uses: actions/checkout@v2 @@ -248,11 +250,6 @@ jobs: name: consul-k8s_linux_amd64.zip path: control-plane - - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_USER }} - password: ${{ secrets.DOCKER_PASS }} - - name: Docker build working-directory: control-plane run: | diff --git a/control-plane/Makefile b/control-plane/Makefile index 57e67aad48..54654927a4 100644 --- a/control-plane/Makefile +++ b/control-plane/Makefile @@ -39,7 +39,7 @@ ci.dev-docker: --label PULL_REQUEST=$(GITHIB_PULL_REQUEST) \ --label GITHUB_BUILD_URL=$(GITHUB_SERVER_URL)/$(GITHUB_REPOSITORY)/actions/runs/$(GITHUB_RUN_ID) \ $(CI_DEV_DOCKER_WORKDIR) -f $(CURDIR)/build-support/docker/Dev.dockerfile -# @echo $(DOCKER_PASS) | docker login -u="$(DOCKER_USER)" --password-stdin + @echo $(DOCKER_PASS) | docker login -u="$(DOCKER_USER)" --password-stdin @echo "Pushing dev image to: https://cloud.docker.com/u/$(CI_DEV_DOCKER_NAMESPACE)/repository/docker/$(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME)" @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) ifeq ($(GITHUB_REF_NAME), main) From 6d4483fc48551b1ef1a7add3078ea502971616ee Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 16:39:06 -0500 Subject: [PATCH 352/418] this will fail but I have to try --- .github/workflows/build-and-test.yml | 36 ++--------- .github/workflows/reusable-acceptance.yml | 77 +++++++++++++++++++++++ acceptance/go.mod | 3 + acceptance/go.sum | 4 ++ 4 files changed, 88 insertions(+), 32 deletions(-) create mode 100644 .github/workflows/reusable-acceptance.yml diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8ef1fb422f..6a5e55b906 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -258,38 +258,10 @@ jobs: acceptance-tproxy: needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Create Kind Cluster - uses: helm/kind-action@v1.2.0 - with: - version: 1.22.4 - - - name: Setup go - uses: actions/setup-go@v2 - with: - go-version: 1.17.2 - - - name: Setup go mod cache - uses: actions/cache@v2 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - - name: Go mod download - working-directory: acceptance - run: go mod download - - - run: mkdir -p ${{env.TEST_RESULTS}} - - # - name: Run acceptance tests - + uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests + with: + directory: acceptance + go-version: 1.17.2 acceptance: needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml new file mode 100644 index 0000000000..159b5f4b8f --- /dev/null +++ b/.github/workflows/reusable-acceptance.yml @@ -0,0 +1,77 @@ +name: reusable-acceptance + +on: + workflow_call: + inputs: + directory: + required: true + type: string + go-version: + required: true + type: string + consul-k8s-image: + required: false + type: string +# default: docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest + additional-flags: + required: false + type: string +# Environment variables can only be used at the step level +env: + TEST_RESULTS: /tmp/test-results # path to where test results are saved + GOTESTSUM_VERSION: 1.6.4 + +jobs: + execute: + runs-on: ubuntu-latest + strategy: + matrix: + parallelism: [3] + index: [0,1,2] + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: ${{inputs.go-version}} + + - name: Setup go mod cache + uses: actions/cache@v2 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + +# TODO: Clean this up +# - name: Install gotestsum +# run: | +# wget https://github.com/gotestyourself/gotestsum/releases/download/v${{env.GOTESTSUM_VERSION}}/gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz +# sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz +# rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + + - name: Install gosplitter + run: go get github.com/Songmu/gotesplit/cmd/gotesplit + + - run: mkdir -p ${{env.TEST_RESULTS}} + + - name: go mod download + working-directory: ${{inputs.directory}} + run: go mod download + +# TODO: do not run on forks + - name: Run acceptance tests + working-directory: ${{inputs.directory}} + run: | + gotesplit -total ${{ matrix.parallelism }} -index ${{ matrix.index }} -junit-dir ${{ env.TEST_RESULTS}} ./... -- \ + $${ inputs.additional-flags }} \ + -enable-enterprise \ + -enable-multi-cluster \ + -debug-directory=${{env.TEST_RESULTS}}/debug \ + -consul-k8s-image=${{inputs.consul-k8s-image}} + diff --git a/acceptance/go.mod b/acceptance/go.mod index 3c31530573..33e9367128 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -17,6 +17,7 @@ require ( require ( cloud.google.com/go v0.54.0 // indirect + github.com/Songmu/gotesplit v0.1.2 // indirect github.com/armon/go-metrics v0.3.9 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/aws/aws-sdk-go v1.30.27 // indirect @@ -59,6 +60,7 @@ require ( github.com/imdario/mergo v0.3.12 // indirect github.com/jmespath/go-jmespath v0.3.0 // indirect github.com/json-iterator/go v1.1.11 // indirect + github.com/jstemmer/go-junit-report v0.9.1 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.13 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect @@ -85,6 +87,7 @@ require ( golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect golang.org/x/text v0.3.6 // indirect diff --git a/acceptance/go.sum b/acceptance/go.sum index 1953df0322..4013c9f92b 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -81,6 +81,8 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Songmu/gotesplit v0.1.2 h1:8PJ0j62PdBdvNFsX6Hufr5qp1bQGXJZS5dWA7dc+U6Y= +github.com/Songmu/gotesplit v0.1.2/go.mod h1:SE1mdkM3jyX4cjjs4N2nhYjfntqf2VdvxgMCIzsJNoo= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -508,6 +510,7 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -941,6 +944,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= From ac150a9c7ec4d781798d6de45ec1f0f6ac91c98a Mon Sep 17 00:00:00 2001 From: John Murret Date: Thu, 3 Mar 2022 15:17:49 -0700 Subject: [PATCH 353/418] updating make control-plane-dev to work ondarwin/arm64. Update helmversion for bats tests (#1073) --- CONTRIBUTING.md | 8 ++++++-- control-plane/build-support/functions/20-build.sh | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 80cb9f8b57..f9c6861bdb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -582,7 +582,7 @@ The acceptance tests require a Kubernetes cluster with a configured `kubectl`. ```bash brew install python-yq ``` -* [Helm 3](https://helm.sh) (Helm 2 is not supported) +* [Helm 3](https://helm.sh) (Currently, must use v3.6.3. Also, Helm 2 is not supported) ```bash brew install kubernetes-helm ``` @@ -611,7 +611,11 @@ To run a specific test by name use the `--filter` flag: bats ./charts/consul/test/unit/.bats --filter "my test name" #### Acceptance Tests - +##### Pre-requisites +* [gox](https://github.com/mitchellh/gox) (v1.14+) + ```bash + brew install gox + ``` To run the acceptance tests: cd acceptance/tests diff --git a/control-plane/build-support/functions/20-build.sh b/control-plane/build-support/functions/20-build.sh index 539647aa26..dd1551589f 100644 --- a/control-plane/build-support/functions/20-build.sh +++ b/control-plane/build-support/functions/20-build.sh @@ -242,7 +242,6 @@ function build_consul_local { CGO_ENABLED=0 gox \ -os="${build_os}" \ -arch="${build_arch}" \ - -osarch="!darwin/arm !darwin/arm64" \ -ldflags="${GOLDFLAGS}" \ -parallel="${GOXPARALLEL:-"-1"}" \ -output "pkg.bin.new/${extra_dir}{{.OS}}_{{.Arch}}/${bin_name}" \ From 49a3df7e93e8c6175bd2236125e395a7a998fa4e Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 17:55:50 -0500 Subject: [PATCH 354/418] fix additonal flags --- .github/workflows/build-and-test.yml | 1 + .github/workflows/reusable-acceptance.yml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6a5e55b906..87da194f52 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -262,6 +262,7 @@ jobs: with: directory: acceptance go-version: 1.17.2 + additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" -enable-transparent-proxy acceptance: needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 159b5f4b8f..83575bac83 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -16,6 +16,7 @@ on: additional-flags: required: false type: string + default: "" # Environment variables can only be used at the step level env: TEST_RESULTS: /tmp/test-results # path to where test results are saved @@ -69,7 +70,7 @@ jobs: working-directory: ${{inputs.directory}} run: | gotesplit -total ${{ matrix.parallelism }} -index ${{ matrix.index }} -junit-dir ${{ env.TEST_RESULTS}} ./... -- \ - $${ inputs.additional-flags }} \ + $${{ inputs.additional-flags }} \ -enable-enterprise \ -enable-multi-cluster \ -debug-directory=${{env.TEST_RESULTS}}/debug \ From c41693328f79c02ca3883d6595781bfb51705357 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 18:21:27 -0500 Subject: [PATCH 355/418] what is ehBuse-kind? --- .github/workflows/reusable-acceptance.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 83575bac83..00e3648f58 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -12,7 +12,7 @@ on: consul-k8s-image: required: false type: string -# default: docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest + default: docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest additional-flags: required: false type: string @@ -70,7 +70,7 @@ jobs: working-directory: ${{inputs.directory}} run: | gotesplit -total ${{ matrix.parallelism }} -index ${{ matrix.index }} -junit-dir ${{ env.TEST_RESULTS}} ./... -- \ - $${{ inputs.additional-flags }} \ + ${{ inputs.additional-flags }} \ -enable-enterprise \ -enable-multi-cluster \ -debug-directory=${{env.TEST_RESULTS}}/debug \ From b0783d99e84e888b519ec32ac6b1526af5fe8608 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 18:33:36 -0500 Subject: [PATCH 356/418] have to quote things to prevent character mashing --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 87da194f52..b2106ea5eb 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -262,7 +262,7 @@ jobs: with: directory: acceptance go-version: 1.17.2 - additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" -enable-transparent-proxy + additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-transparent-proxy" acceptance: needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] From 23725783ddbcc97c5dac8c79155a679d98d9d341 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 22:28:19 -0500 Subject: [PATCH 357/418] use the acceptance/tests path --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b2106ea5eb..ff00df889d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -260,7 +260,7 @@ jobs: needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests with: - directory: acceptance + directory: acceptance/tests go-version: 1.17.2 additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-transparent-proxy" From f3c19aecfc85d742c8f1250fdfe8a65fc30a6eff Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 23:37:45 -0500 Subject: [PATCH 358/418] manually split tests --- .github/workflows/reusable-acceptance.yml | 70 ++++++++++++++--------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 00e3648f58..bb6f24e333 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -3,20 +3,24 @@ name: reusable-acceptance on: workflow_call: inputs: + additional-flags: + required: false + type: string + default: "" + consul-k8s-image: + required: false + type: string + default: docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest directory: required: true type: string go-version: required: true type: string - consul-k8s-image: - required: false - type: string - default: docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest - additional-flags: - required: false + test-packages: + required: true type: string - default: "" + # Environment variables can only be used at the step level env: TEST_RESULTS: /tmp/test-results # path to where test results are saved @@ -27,8 +31,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - parallelism: [3] - index: [0,1,2] + include: # I am really sorry for this but I could not find a way to automatically split our tests into several runners. For now, split manually. + - {runner: "1", test-packages: "basic cli connect consul-dns controller example"} + - {runner: "2", test-packages: "fixtures ingress-gateway mesh-gateway metrics"} + - {runner: "3", test-packages: "partitions sync terminating-gateway vault"} + fail-fast: true steps: - name: Checkout code @@ -49,15 +56,11 @@ jobs: restore-keys: | ${{ runner.os }}-go- -# TODO: Clean this up -# - name: Install gotestsum -# run: | -# wget https://github.com/gotestyourself/gotestsum/releases/download/v${{env.GOTESTSUM_VERSION}}/gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz -# sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz -# rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - - - name: Install gosplitter - run: go get github.com/Songmu/gotesplit/cmd/gotesplit + - name: Install gotestsum + run: | + wget https://github.com/gotestyourself/gotestsum/releases/download/v${{env.GOTESTSUM_VERSION}}/gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - run: mkdir -p ${{env.TEST_RESULTS}} @@ -66,13 +69,28 @@ jobs: run: go mod download # TODO: do not run on forks - - name: Run acceptance tests + - name: Run acceptance tests ${{matrix.runner}} working-directory: ${{inputs.directory}} run: | - gotesplit -total ${{ matrix.parallelism }} -index ${{ matrix.index }} -junit-dir ${{ env.TEST_RESULTS}} ./... -- \ - ${{ inputs.additional-flags }} \ - -enable-enterprise \ - -enable-multi-cluster \ - -debug-directory=${{env.TEST_RESULTS}}/debug \ - -consul-k8s-image=${{inputs.consul-k8s-image}} - + # We have to run the tests for each package separately so that we can + # exit early if any test fails (-failfast only works within a single + # package). + exit_code=0 + echo "Running packages: ${{ matrix.test-packages }}" + for pkg in $pkgs + do + if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ + ${{ inputs.additional-flags }} \ + -enable-enterprise \ + -enable-multi-cluster \ + -debug-directory=${{ env.TEST_RESULTS}}/debug \ + -consul-k8s-image=${{ inputs.consul-k8s-image }} + then + echo "Tests in ${pkg} failed, aborting early" + exit_code=1 + break + fi + done + gotestsum --raw-command --junitfile "${{ env.TEST_RESULTS }}/gotestsum-report.xml" -- cat jsonfile* + exit $exit_code + From 2d7097628be8372ec3c120ce9a2d25f72e1a6d53 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 3 Mar 2022 23:38:30 -0500 Subject: [PATCH 359/418] manually split tests --- .github/workflows/reusable-acceptance.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index bb6f24e333..eeb86ba45e 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -17,9 +17,6 @@ on: go-version: required: true type: string - test-packages: - required: true - type: string # Environment variables can only be used at the step level env: From 7b78231b6f9036171beeae1bb40a9f60ac1deb92 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 00:04:32 -0500 Subject: [PATCH 360/418] pump out some test output --- .github/workflows/reusable-acceptance.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index eeb86ba45e..91ae8c100b 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -24,7 +24,7 @@ env: GOTESTSUM_VERSION: 1.6.4 jobs: - execute: + a: runs-on: ubuntu-latest strategy: matrix: @@ -74,9 +74,10 @@ jobs: # package). exit_code=0 echo "Running packages: ${{ matrix.test-packages }}" - for pkg in $pkgs + for pkg in ${{ matrix.test-package }} do - if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ + # if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ + if ! gotestsum --format=testname --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ ${{ inputs.additional-flags }} \ -enable-enterprise \ -enable-multi-cluster \ From 7857c8c42c69197319463c0ad67cf40d9c71e12d Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 00:21:09 -0500 Subject: [PATCH 361/418] make sure these are running --- .github/workflows/reusable-acceptance.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 91ae8c100b..e382ded0a7 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -77,7 +77,7 @@ jobs: for pkg in ${{ matrix.test-package }} do # if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ - if ! gotestsum --format=testname --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ + if ! gotestsum --format=testname -- $pkg -p 1 -timeout 2h -failfast \ ${{ inputs.additional-flags }} \ -enable-enterprise \ -enable-multi-cluster \ @@ -89,6 +89,6 @@ jobs: break fi done - gotestsum --raw-command --junitfile "${{ env.TEST_RESULTS }}/gotestsum-report.xml" -- cat jsonfile* + # gotestsum --raw-command --junitfile "${{ env.TEST_RESULTS }}/gotestsum-report.xml" -- cat jsonfile* exit $exit_code From 38c54beab6c441e49626184f9efdfa777bf81b82 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 09:37:41 -0500 Subject: [PATCH 362/418] acceptance script does not seem to run --- .github/workflows/reusable-acceptance.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index e382ded0a7..f9d75150db 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -64,19 +64,21 @@ jobs: - name: go mod download working-directory: ${{inputs.directory}} run: go mod download - + + # We have to run the tests for each package separately so that we can + # exit early if any test fails (-failfast only works within a single + # package). # TODO: do not run on forks - name: Run acceptance tests ${{matrix.runner}} working-directory: ${{inputs.directory}} run: | - # We have to run the tests for each package separately so that we can - # exit early if any test fails (-failfast only works within a single - # package). exit_code=0 echo "Running packages: ${{ matrix.test-packages }}" - for pkg in ${{ matrix.test-package }} + IFS=' ' + for pkg in "${{ matrix.test-package }}" do - # if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ + echo "Testing package: $pkg" + # if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast k if ! gotestsum --format=testname -- $pkg -p 1 -timeout 2h -failfast \ ${{ inputs.additional-flags }} \ -enable-enterprise \ From 261c2aa6ca35dfb62599fd1c358df1cb9cb83011 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 09:53:47 -0500 Subject: [PATCH 363/418] see if we can use an env for go version, add lint-control-plane --- .github/workflows/build-and-test.yml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ff00df889d..df131e315d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -12,6 +12,7 @@ env: CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests GOTESTSUM_VERSION: 1.6.4 + GO_VERSION: 1.17.2 # TODO: upload tests somewhere. An artifact? # TODO: prevent running some things on forks? @@ -27,7 +28,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} - name: Setup go mod cache uses: actions/cache@v2 @@ -74,9 +75,13 @@ jobs: lint-control-plane: runs-on: ubuntu-latest steps: - - name: TODO - run: - echo "Filler" + - name: Checkout code + uses: actions/checkout@v2 + + - run: go get -u github.com/hashicorp/lint-consul-retry && lint-consul-retry + - name: Run lint + working-directory: control-plane + run: go run hack/lint-api-new-client/main.go go-fmt-vet-control-plane: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests From a5267ad8502f79a212edeaca7c4317b75b430d82 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 10:01:53 -0500 Subject: [PATCH 364/418] proper package splitting --- .github/workflows/reusable-acceptance.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index f9d75150db..fa47861361 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -74,8 +74,7 @@ jobs: run: | exit_code=0 echo "Running packages: ${{ matrix.test-packages }}" - IFS=' ' - for pkg in "${{ matrix.test-package }}" + for pkg in $(echo ${{ matrix.test-packages }}) do echo "Testing package: $pkg" # if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast k From d813f5d1647b707030f18077af7428fd81562784 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 10:11:14 -0500 Subject: [PATCH 365/418] use env.GO_VERSION everywhere and try to fix control-plane-lint --- .github/workflows/build-and-test.yml | 32 +++++++++++++++------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index df131e315d..423fa529c7 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -49,14 +49,14 @@ jobs: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: directory: hack/helm-reference-gen - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} unit-helm-gen: needs: [go-fmt-vet-helm-gen, validate-helm-gen] uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: hack/helm-reference-gen - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} unit-test-helm-templates: needs: [unit-helm-gen] @@ -78,7 +78,8 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - - run: go get -u github.com/hashicorp/lint-consul-retry && lint-consul-retry + - run: go get -u github.com/hashicorp/lint-consul-retry + - run: lint-consul-retry - name: Run lint working-directory: control-plane run: go run hack/lint-api-new-client/main.go @@ -87,7 +88,7 @@ jobs: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: directory: control-plane - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} test-control-plane: needs: [lint-control-plane, go-fmt-vet-control-plane] @@ -99,7 +100,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} - name: Setup go mod cache uses: actions/cache@v2 @@ -143,7 +144,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} - name: Setup go mod cache uses: actions/cache@v2 @@ -176,15 +177,16 @@ jobs: gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES build-distros: +#TODO: Fix #needs: [test-control-plane, test-enterprise-control-plane] runs-on: ubuntu-latest strategy: matrix: include: - - {go: "1.17.2", goos: "linux", goarch: "386"} - - {go: "1.17.5", goos: "linux", goarch: "amd64"} - - {go: "1.17.5", goos: "linux", goarch: "arm"} - - {go: "1.17.5", goos: "linux", goarch: "arm64"} + - {go: "${{ env.GO_VERSION }}", goos: "linux", goarch: "386"} + - {go: "${{ env.GO_VERSION }}", goos: "linux", goarch: "amd64"} + - {go: "${{ env.GO_VERSION }}", goos: "linux", goarch: "arm"} + - {go: "${{ env.GO_VERSION }}", goos: "linux", goarch: "arm64"} fail-fast: true name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build @@ -215,27 +217,27 @@ jobs: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: directory: acceptance - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} unit-acceptance-framework: needs: go-fmt-vet-acceptance uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: acceptance/framework - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} go-fmt-vet-cli: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: directory: cli - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} unit-cli: needs: go-fmt-vet-cli uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: cli - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} dev-upload-docker: needs: build-distros @@ -266,7 +268,7 @@ jobs: uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests with: directory: acceptance/tests - go-version: 1.17.2 + go-version: ${{ env.GO_VERSION }} additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-transparent-proxy" acceptance: From 77cc8ce413b23646d218d7331a5d558b159f8160 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 10:26:36 -0500 Subject: [PATCH 366/418] you can use env variables with actions but not reusabled workflows, also not finding packages in acceptance --- .github/workflows/build-and-test.yml | 33 +++++++++++------------ .github/workflows/reusable-acceptance.yml | 23 ++++++++-------- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 423fa529c7..57b87bd233 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -11,8 +11,7 @@ env: TEST_RESULTS: /tmp/test-results # path to where test results are saved CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests - GOTESTSUM_VERSION: 1.6.4 - GO_VERSION: 1.17.2 + GOTESTSUM_VERSION: 1.6.4 # You cannot use environment variables with workflows. The gotestsum version is hardcoded in the reusable workflows too. # TODO: upload tests somewhere. An artifact? # TODO: prevent running some things on forks? @@ -28,7 +27,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 - name: Setup go mod cache uses: actions/cache@v2 @@ -49,14 +48,14 @@ jobs: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: directory: hack/helm-reference-gen - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 unit-helm-gen: needs: [go-fmt-vet-helm-gen, validate-helm-gen] uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: hack/helm-reference-gen - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 unit-test-helm-templates: needs: [unit-helm-gen] @@ -88,7 +87,7 @@ jobs: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: directory: control-plane - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 test-control-plane: needs: [lint-control-plane, go-fmt-vet-control-plane] @@ -100,7 +99,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 - name: Setup go mod cache uses: actions/cache@v2 @@ -144,7 +143,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 - name: Setup go mod cache uses: actions/cache@v2 @@ -183,10 +182,10 @@ jobs: strategy: matrix: include: - - {go: "${{ env.GO_VERSION }}", goos: "linux", goarch: "386"} - - {go: "${{ env.GO_VERSION }}", goos: "linux", goarch: "amd64"} - - {go: "${{ env.GO_VERSION }}", goos: "linux", goarch: "arm"} - - {go: "${{ env.GO_VERSION }}", goos: "linux", goarch: "arm64"} + - {go: "1.17.2", goos: "linux", goarch: "386"} + - {go: "1.17.2", goos: "linux", goarch: "amd64"} + - {go: "1.17.2", goos: "linux", goarch: "arm"} + - {go: "1.17.2", goos: "linux", goarch: "arm64"} fail-fast: true name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build @@ -217,27 +216,27 @@ jobs: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: directory: acceptance - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 unit-acceptance-framework: needs: go-fmt-vet-acceptance uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: acceptance/framework - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 go-fmt-vet-cli: uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests with: directory: cli - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 unit-cli: needs: go-fmt-vet-cli uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: cli - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 dev-upload-docker: needs: build-distros @@ -268,7 +267,7 @@ jobs: uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests with: directory: acceptance/tests - go-version: ${{ env.GO_VERSION }} + go-version: 1.17.2 additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-transparent-proxy" acceptance: diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index fa47861361..edb9387a36 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -41,7 +41,7 @@ jobs: - name: Setup go uses: actions/setup-go@v2 with: - go-version: ${{inputs.go-version}} + go-version: ${{ inputs.go-version }} - name: Setup go mod cache uses: actions/cache@v2 @@ -55,34 +55,33 @@ jobs: - name: Install gotestsum run: | - wget https://github.com/gotestyourself/gotestsum/releases/download/v${{env.GOTESTSUM_VERSION}}/gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - sudo tar -C /usr/local/bin -xzf gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz - rm gotestsum_${{env.GOTESTSUM_VERSION}}_linux_amd64.tar.gz + wget https://github.com/gotestyourself/gotestsum/releases/download/v${{ env.GOTESTSUM_VERSION }}/gotestsum_${{ env.GOTESTSUM_VERSION }}_linux_amd64.tar.gz + sudo tar -C /usr/local/bin -xzf gotestsum_${{ env.GOTESTSUM_VERSION }}_linux_amd64.tar.gz + rm gotestsum_${{ env.GOTESTSUM_VERSION }}_linux_amd64.tar.gz - - run: mkdir -p ${{env.TEST_RESULTS}} + - run: mkdir -p ${{ env.TEST_RESULTS }} - name: go mod download - working-directory: ${{inputs.directory}} + working-directory: ${{ inputs.directory }} run: go mod download # We have to run the tests for each package separately so that we can # exit early if any test fails (-failfast only works within a single # package). # TODO: do not run on forks - - name: Run acceptance tests ${{matrix.runner}} - working-directory: ${{inputs.directory}} + - name: Run acceptance tests ${{ matrix.runner }} + working-directory: ${{ inputs.directory }} run: | exit_code=0 echo "Running packages: ${{ matrix.test-packages }}" for pkg in $(echo ${{ matrix.test-packages }}) do - echo "Testing package: $pkg" - # if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast k - if ! gotestsum --format=testname -- $pkg -p 1 -timeout 2h -failfast \ + echo "Testing package: ${pkg}" + if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ ${{ inputs.additional-flags }} \ -enable-enterprise \ -enable-multi-cluster \ - -debug-directory=${{ env.TEST_RESULTS}}/debug \ + -debug-directory=${{ env.TEST_RESULTS }}/debug \ -consul-k8s-image=${{ inputs.consul-k8s-image }} then echo "Tests in ${pkg} failed, aborting early" From dc685346a88a59b348a1e5907981e81d3b242558 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 10:30:48 -0500 Subject: [PATCH 367/418] add GOPATH/bin to path so that lint-control-plane will run --- .github/workflows/build-and-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 57b87bd233..5f9ad73612 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -78,6 +78,7 @@ jobs: uses: actions/checkout@v2 - run: go get -u github.com/hashicorp/lint-consul-retry + - run: echo "$GOPATH/bin" >> $GITHUB_PATH - run: lint-consul-retry - name: Run lint working-directory: control-plane From 84d8ecde11b790bfae11be78483af627b361ff60 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 10:42:02 -0500 Subject: [PATCH 368/418] setup go when linting, run acceptance sooner --- .github/workflows/build-and-test.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 5f9ad73612..dad4666417 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -76,10 +76,14 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v2 - - - run: go get -u github.com/hashicorp/lint-consul-retry - - run: echo "$GOPATH/bin" >> $GITHUB_PATH - - run: lint-consul-retry + + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: 1.17.2 + + - run: go get -u github.com/hashicorp/lint-consul-retry && lint-consul-retry + - name: Run lint working-directory: control-plane run: go run hack/lint-api-new-client/main.go @@ -264,7 +268,9 @@ jobs: make ci.dev-docker acceptance-tproxy: - needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] +#TODO: Fix + #needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] + needs: dev-upload-docker uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests with: directory: acceptance/tests From 2410e385ee824ae135f31c0a9124a0ae5f1d16b6 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 11:04:51 -0500 Subject: [PATCH 369/418] try installing gotestsum with inputs and try fixing gotestsum package variable --- .github/workflows/build-and-test.yml | 1 + .github/workflows/reusable-acceptance.yml | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index dad4666417..19cbbd7ea5 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -276,6 +276,7 @@ jobs: directory: acceptance/tests go-version: 1.17.2 additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-transparent-proxy" + gotestsum-version: 1.6.4 acceptance: needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index edb9387a36..c0796c959c 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -17,11 +17,13 @@ on: go-version: required: true type: string + gotestsum-verison: + required: true + type: string # Environment variables can only be used at the step level env: TEST_RESULTS: /tmp/test-results # path to where test results are saved - GOTESTSUM_VERSION: 1.6.4 jobs: a: @@ -55,9 +57,9 @@ jobs: - name: Install gotestsum run: | - wget https://github.com/gotestyourself/gotestsum/releases/download/v${{ env.GOTESTSUM_VERSION }}/gotestsum_${{ env.GOTESTSUM_VERSION }}_linux_amd64.tar.gz - sudo tar -C /usr/local/bin -xzf gotestsum_${{ env.GOTESTSUM_VERSION }}_linux_amd64.tar.gz - rm gotestsum_${{ env.GOTESTSUM_VERSION }}_linux_amd64.tar.gz + wget https://github.com/gotestyourself/gotestsum/releases/download/v"${{ inputs.gotestsum-version }}"/gotestsum_"${{ inputs.gotestsum-version }}"_linux_amd64.tar.gz + sudo tar -C /usr/local/bin -xzf gotestsum_"${{ inputs.gotestsum-version }}"_linux_amd64.tar.gz + rm gotestsum_"${{ inputs.gotestsum-version }}"_linux_amd64.tar.gz - run: mkdir -p ${{ env.TEST_RESULTS }} @@ -77,7 +79,7 @@ jobs: for pkg in $(echo ${{ matrix.test-packages }}) do echo "Testing package: ${pkg}" - if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ + if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} --packages="${pkg}" -- -p 1 -timeout 2h -failfast \ ${{ inputs.additional-flags }} \ -enable-enterprise \ -enable-multi-cluster \ From 72ac909b46f8917252ffe51c1db19ca9682395f6 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 11:06:13 -0500 Subject: [PATCH 370/418] try installing gotestsum with inputs and try fixing gotestsum package variable --- .github/workflows/reusable-acceptance.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index c0796c959c..4b2fd7f277 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -17,7 +17,7 @@ on: go-version: required: true type: string - gotestsum-verison: + gotestsum-version: required: true type: string From 614e8bb19a73ed13d69c22da0083e7216ade1c78 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 11:09:02 -0500 Subject: [PATCH 371/418] try installing gotestsum with inputs and try fixing gotestsum package variable --- .github/workflows/build-and-test.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 19cbbd7ea5..85a71e8c4f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -187,10 +187,11 @@ jobs: strategy: matrix: include: - - {go: "1.17.2", goos: "linux", goarch: "386"} +#TODO: fix + # - {go: "1.17.2", goos: "linux", goarch: "386"} - {go: "1.17.2", goos: "linux", goarch: "amd64"} - - {go: "1.17.2", goos: "linux", goarch: "arm"} - - {go: "1.17.2", goos: "linux", goarch: "arm64"} + #- {go: "1.17.2", goos: "linux", goarch: "arm"} + # - {go: "1.17.2", goos: "linux", goarch: "arm64"} fail-fast: true name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build From 84406a9e8c3deaa8d0f955c4d6edf52c7d6b4270 Mon Sep 17 00:00:00 2001 From: John Murret Date: Fri, 4 Mar 2022 09:13:38 -0700 Subject: [PATCH 372/418] Set DOCKER_DEFAULT_PLATFORM for make control-plane-dev-docker so that M1/arm64machines do not have failures in k8s due to manifest reflecting arm64 architecture rather than amd64. (#1074) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1cd32824cb..f9de460b05 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ control-plane-dev: ## Build consul-k8s-control-plane binary. control-plane-dev-docker: ## Build consul-k8s-control-plane dev Docker image. @$(SHELL) $(CURDIR)/control-plane/build-support/scripts/build-local.sh -o linux -a amd64 - @docker build -t '$(DEV_IMAGE)' \ + @DOCKER_DEFAULT_PLATFORM=linux/amd64 docker build -t '$(DEV_IMAGE)' \ --build-arg 'GIT_COMMIT=$(GIT_COMMIT)' \ --build-arg 'GIT_DIRTY=$(GIT_DIRTY)' \ --build-arg 'GIT_DESCRIBE=$(GIT_DESCRIBE)' \ From 1e261f381218ba847592bd3875407cf181610edb Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 11:15:36 -0500 Subject: [PATCH 373/418] find the tests! --- .github/workflows/reusable-acceptance.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 4b2fd7f277..a5292d7229 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -79,12 +79,16 @@ jobs: for pkg in $(echo ${{ matrix.test-packages }}) do echo "Testing package: ${pkg}" - if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} --packages="${pkg}" -- -p 1 -timeout 2h -failfast \ + pwd + ls + cd ${pkg} + if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} --packages="./..." -- -p 1 -timeout 2h -failfast \ ${{ inputs.additional-flags }} \ -enable-enterprise \ -enable-multi-cluster \ -debug-directory=${{ env.TEST_RESULTS }}/debug \ -consul-k8s-image=${{ inputs.consul-k8s-image }} + cd .. then echo "Tests in ${pkg} failed, aborting early" exit_code=1 From d2b7a6a0c6e31b07d437ec52e0bca7036c3bac47 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 11:29:08 -0500 Subject: [PATCH 374/418] It helps if you test the correct packages --- .github/workflows/reusable-acceptance.yml | 10 +++------- acceptance/tests/fixtures/jsonfile-blah | 0 acceptance/tests/jsonfile-blah | 0 3 files changed, 3 insertions(+), 7 deletions(-) create mode 100644 acceptance/tests/fixtures/jsonfile-blah create mode 100644 acceptance/tests/jsonfile-blah diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index a5292d7229..fd74003daf 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -31,8 +31,8 @@ jobs: strategy: matrix: include: # I am really sorry for this but I could not find a way to automatically split our tests into several runners. For now, split manually. - - {runner: "1", test-packages: "basic cli connect consul-dns controller example"} - - {runner: "2", test-packages: "fixtures ingress-gateway mesh-gateway metrics"} + - {runner: "1", test-packages: "basic cli connect consul-dns controller"} + - {runner: "2", test-packages: "example ingress-gateway mesh-gateway metrics"} - {runner: "3", test-packages: "partitions sync terminating-gateway vault"} fail-fast: true @@ -79,16 +79,12 @@ jobs: for pkg in $(echo ${{ matrix.test-packages }}) do echo "Testing package: ${pkg}" - pwd - ls - cd ${pkg} - if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} --packages="./..." -- -p 1 -timeout 2h -failfast \ + if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- ${pkg} -p 1 -timeout 2h -failfast \ ${{ inputs.additional-flags }} \ -enable-enterprise \ -enable-multi-cluster \ -debug-directory=${{ env.TEST_RESULTS }}/debug \ -consul-k8s-image=${{ inputs.consul-k8s-image }} - cd .. then echo "Tests in ${pkg} failed, aborting early" exit_code=1 diff --git a/acceptance/tests/fixtures/jsonfile-blah b/acceptance/tests/fixtures/jsonfile-blah new file mode 100644 index 0000000000..e69de29bb2 diff --git a/acceptance/tests/jsonfile-blah b/acceptance/tests/jsonfile-blah new file mode 100644 index 0000000000..e69de29bb2 From 138e1e3b25fa6bb1fe4f284ab10a527163ec6abb Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 11:29:22 -0500 Subject: [PATCH 375/418] It helps if you test the correct packages --- acceptance/tests/jsonfile-blah | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 acceptance/tests/jsonfile-blah diff --git a/acceptance/tests/jsonfile-blah b/acceptance/tests/jsonfile-blah deleted file mode 100644 index e69de29bb2..0000000000 From a9fbc128106968413c198f8370503da33840b8ff Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 11:42:47 -0500 Subject: [PATCH 376/418] need full package name --- .github/workflows/reusable-acceptance.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index fd74003daf..3ffebc225a 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -78,8 +78,10 @@ jobs: echo "Running packages: ${{ matrix.test-packages }}" for pkg in $(echo ${{ matrix.test-packages }}) do - echo "Testing package: ${pkg}" - if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- ${pkg} -p 1 -timeout 2h -failfast \ + fullpkg="github.com/hashicorp/consul-k8s/${{ inputs.directory }}/${pkg}" + echo "Testing package: ${fullpkg}" + + if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- ${fullpkg} -p 1 -timeout 2h -failfast \ ${{ inputs.additional-flags }} \ -enable-enterprise \ -enable-multi-cluster \ From 74b308d4894a08227869d87b0b69b477410d8a20 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 12:02:20 -0500 Subject: [PATCH 377/418] but why are you failing? --- .github/workflows/reusable-acceptance.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 3ffebc225a..b137cc1145 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -80,8 +80,7 @@ jobs: do fullpkg="github.com/hashicorp/consul-k8s/${{ inputs.directory }}/${pkg}" echo "Testing package: ${fullpkg}" - - if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- ${fullpkg} -p 1 -timeout 2h -failfast \ + if ! gotestsum --jsonfile=jsonfile-${pkg////-} -- ${fullpkg} -p 1 -timeout 2h -failfast \ ${{ inputs.additional-flags }} \ -enable-enterprise \ -enable-multi-cluster \ From 622aab48b13f3d19edc707f480c1615ec354b327 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 12:57:57 -0500 Subject: [PATCH 378/418] need to pull in the enterprise license --- .github/workflows/reusable-acceptance.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index b137cc1145..97df2c8abb 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -35,7 +35,8 @@ jobs: - {runner: "2", test-packages: "example ingress-gateway mesh-gateway metrics"} - {runner: "3", test-packages: "partitions sync terminating-gateway vault"} fail-fast: true - + env: + CONSUL_ENT_LICENSE: ${{secrets.CONSUL_LICENSE}} steps: - name: Checkout code uses: actions/checkout@v2 From d6d43595f682cfdc840aa482fe975093c0cc28a7 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 13:10:01 -0500 Subject: [PATCH 379/418] I see the license, do you see the license? --- .github/workflows/reusable-acceptance.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 97df2c8abb..6d739e00d9 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -36,7 +36,8 @@ jobs: - {runner: "3", test-packages: "partitions sync terminating-gateway vault"} fail-fast: true env: - CONSUL_ENT_LICENSE: ${{secrets.CONSUL_LICENSE}} + CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_LICENSE }} + CONSUL_LICENSE: ${{ secrets.CONSUL_LICENSE }} steps: - name: Checkout code uses: actions/checkout@v2 From f381ef7048879dd3814bfb204852aa4e0cb64f8d Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 13:17:04 -0500 Subject: [PATCH 380/418] context matters --- .github/workflows/reusable-acceptance.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 6d739e00d9..37ee1c690a 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -35,9 +35,6 @@ jobs: - {runner: "2", test-packages: "example ingress-gateway mesh-gateway metrics"} - {runner: "3", test-packages: "partitions sync terminating-gateway vault"} fail-fast: true - env: - CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_LICENSE }} - CONSUL_LICENSE: ${{ secrets.CONSUL_LICENSE }} steps: - name: Checkout code uses: actions/checkout@v2 @@ -76,6 +73,7 @@ jobs: - name: Run acceptance tests ${{ matrix.runner }} working-directory: ${{ inputs.directory }} run: | + export CONSUL_ENT_LICENSE=${{ secrets.CONSUL_LICENSE }} exit_code=0 echo "Running packages: ${{ matrix.test-packages }}" for pkg in $(echo ${{ matrix.test-packages }}) From cdb43343761493b7f157182b26ceb2e490c626be Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 13:48:11 -0500 Subject: [PATCH 381/418] set as top level environmetn variables --- .github/workflows/reusable-acceptance.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 37ee1c690a..56fac21150 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -24,6 +24,8 @@ on: # Environment variables can only be used at the step level env: TEST_RESULTS: /tmp/test-results # path to where test results are saved + CONSUL_LICENSE: ${{ secrets.CONSUL_LICENSE }} + CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_LICENSE }} jobs: a: @@ -73,7 +75,6 @@ jobs: - name: Run acceptance tests ${{ matrix.runner }} working-directory: ${{ inputs.directory }} run: | - export CONSUL_ENT_LICENSE=${{ secrets.CONSUL_LICENSE }} exit_code=0 echo "Running packages: ${{ matrix.test-packages }}" for pkg in $(echo ${{ matrix.test-packages }}) From 989d0e70cc4155f7cd23c20089558e22c9116948 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 16:12:38 -0500 Subject: [PATCH 382/418] try again --- .github/workflows/reusable-acceptance.yml | 3 +-- .github/workflows/reusable-go-fmt-vet.yml | 2 +- .github/workflows/reusable-unit.yml | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 56fac21150..f38cd868b2 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -24,8 +24,7 @@ on: # Environment variables can only be used at the step level env: TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_LICENSE: ${{ secrets.CONSUL_LICENSE }} - CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_LICENSE }} + CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_ENT_LICENSE }} jobs: a: diff --git a/.github/workflows/reusable-go-fmt-vet.yml b/.github/workflows/reusable-go-fmt-vet.yml index 718008d122..edd0595adf 100644 --- a/.github/workflows/reusable-go-fmt-vet.yml +++ b/.github/workflows/reusable-go-fmt-vet.yml @@ -12,7 +12,7 @@ on: jobs: - execute: + a: runs-on: ubuntu-latest steps: diff --git a/.github/workflows/reusable-unit.yml b/.github/workflows/reusable-unit.yml index ef557c228c..7e25022a65 100644 --- a/.github/workflows/reusable-unit.yml +++ b/.github/workflows/reusable-unit.yml @@ -16,7 +16,7 @@ env: GOTESTSUM_VERSION: 1.6.4 jobs: - execute: + a: runs-on: ubuntu-latest steps: From 78cae7943a64d34a47f27d8cd511322a65a446a5 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 16:18:57 -0500 Subject: [PATCH 383/418] have to explicitely pass in secrets --- .github/workflows/build-and-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 85a71e8c4f..0b4c4524e8 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -278,6 +278,8 @@ jobs: go-version: 1.17.2 additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-transparent-proxy" gotestsum-version: 1.6.4 + secrets: + CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_ENT_LICENSE }} acceptance: needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] From 8dc8f871dd14c5113eb837d8efba591e74aa1d65 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 16:25:58 -0500 Subject: [PATCH 384/418] have to explicitely pass in secrets --- .github/workflows/reusable-acceptance.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index f38cd868b2..5a8df734d8 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -20,6 +20,9 @@ on: gotestsum-version: required: true type: string + secrets: + CONSUL_ENT_LICENSE: + required: true # Environment variables can only be used at the step level env: @@ -29,7 +32,7 @@ env: jobs: a: runs-on: ubuntu-latest - strategy: + strategy: matrix: include: # I am really sorry for this but I could not find a way to automatically split our tests into several runners. For now, split manually. - {runner: "1", test-packages: "basic cli connect consul-dns controller"} From a802e18c61a71b7d92d8914c8678c4a8b5b8e5fd Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 17:03:24 -0500 Subject: [PATCH 385/418] do not fail as fast so that I can see if anything passes --- .github/workflows/reusable-acceptance.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 5a8df734d8..5b1dac954a 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -38,7 +38,8 @@ jobs: - {runner: "1", test-packages: "basic cli connect consul-dns controller"} - {runner: "2", test-packages: "example ingress-gateway mesh-gateway metrics"} - {runner: "3", test-packages: "partitions sync terminating-gateway vault"} - fail-fast: true +#TODO: set back to true + fail-fast: false steps: - name: Checkout code uses: actions/checkout@v2 From f7346e920ec3e65d1236720d8813549339f49933 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 17:28:03 -0500 Subject: [PATCH 386/418] need to create kind clusters --- .github/workflows/reusable-acceptance.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 5b1dac954a..7a9f13f8c1 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -20,6 +20,10 @@ on: gotestsum-version: required: true type: string + kind-version: + required: false + type: string + default: "v1.22.4" secrets: CONSUL_ENT_LICENSE: required: true @@ -70,7 +74,12 @@ jobs: - name: go mod download working-directory: ${{ inputs.directory }} run: go mod download - + + - name: Create kind clusters + run: | + kind create cluster --name dc1 --image kindest/node:${{ inputs.kind-version }} + kind create cluster --name dc2 --image kindest/node:${{ inputs.kind-version }} + # We have to run the tests for each package separately so that we can # exit early if any test fails (-failfast only works within a single # package). From 93906dbe1bd0e38bf2b90d52ea6dccff8be95120 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 20:16:02 -0500 Subject: [PATCH 387/418] split tests a litle more evenly --- .github/workflows/reusable-acceptance.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 7a9f13f8c1..3d77430d7e 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -39,9 +39,9 @@ jobs: strategy: matrix: include: # I am really sorry for this but I could not find a way to automatically split our tests into several runners. For now, split manually. - - {runner: "1", test-packages: "basic cli connect consul-dns controller"} - - {runner: "2", test-packages: "example ingress-gateway mesh-gateway metrics"} - - {runner: "3", test-packages: "partitions sync terminating-gateway vault"} + - {runner: "1", test-packages: "basic cli connect consul-dns controller example"} + - {runner: "2", test-packages: "ingress-gateway mesh-gateway metrics partitions"} + - {runner: "3", test-packages: "sync terminating-gateway vault"} #TODO: set back to true fail-fast: false steps: From 3fbe658b8e5378f4a4143f487a3e3ecd3e8dd955 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Fri, 4 Mar 2022 22:53:34 -0500 Subject: [PATCH 388/418] remove cli tests as they were removed and have 6 runners just like CircleCI --- .github/workflows/reusable-acceptance.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 3d77430d7e..34048fa57e 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -39,9 +39,13 @@ jobs: strategy: matrix: include: # I am really sorry for this but I could not find a way to automatically split our tests into several runners. For now, split manually. - - {runner: "1", test-packages: "basic cli connect consul-dns controller example"} - - {runner: "2", test-packages: "ingress-gateway mesh-gateway metrics partitions"} - - {runner: "3", test-packages: "sync terminating-gateway vault"} + - {runner: "1", test-packages: "basic connect"} + - {runner: "2", test-packages: "consul-dns controller example"} + - {runner: "3", test-packages: "example ingress-gateway mesh-gateway"} + - {runner: "4", test-packages: "mesh-gateway metrics"} + - {runner: "5", test-packages: "partitions sync"} + - {runner: "6", test-packages: "terminating-gateway vault"} + #TODO: set back to true fail-fast: false steps: From a73d6235613e3229baf92ff7f5c1558638955e4e Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Sun, 6 Mar 2022 11:50:48 -0500 Subject: [PATCH 389/418] add acceptance too --- .github/workflows/build-and-test.yml | 18 ++++++++++++------ .github/workflows/reusable-acceptance.yml | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 0b4c4524e8..bf5280c47f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -282,9 +282,15 @@ jobs: CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_ENT_LICENSE }} acceptance: - needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] - runs-on: ubuntu-latest - steps: - - name: TODO - run: - echo "Filler" + #needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] + needs: dev-upload-docker + uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests + with: + directory: acceptance/tests + go-version: 1.17.2 + additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2" + gotestsum-version: 1.6.4 + secrets: + CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_ENT_LICENSE }} + + diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 34048fa57e..24ba2c3914 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -109,6 +109,6 @@ jobs: break fi done - # gotestsum --raw-command --junitfile "${{ env.TEST_RESULTS }}/gotestsum-report.xml" -- cat jsonfile* + gotestsum --raw-command --junitfile "${{ env.TEST_RESULTS }}/gotestsum-report.xml" -- cat jsonfile* exit $exit_code From 7e99ba0bb836657cc6c3bbf93cb76f2dcfd516e9 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Sun, 6 Mar 2022 21:58:39 -0500 Subject: [PATCH 390/418] wait 20 minutes for pods to be up --- acceptance/framework/k8s/helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acceptance/framework/k8s/helpers.go b/acceptance/framework/k8s/helpers.go index 1b895a5e17..f99d3e6510 100644 --- a/acceptance/framework/k8s/helpers.go +++ b/acceptance/framework/k8s/helpers.go @@ -43,7 +43,7 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac // Wait up to 11m. // On Azure, volume provisioning can sometimes take close to 5 min, // so we need to give a bit more time for pods to become healthy. - counter := &retry.Counter{Count: 11 * 60, Wait: 1 * time.Second} + counter := &retry.Counter{Count: 20 * 60, Wait: 1 * time.Second} retry.RunWith(counter, t, func(r *retry.R) { pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) require.NoError(r, err) From d1d1b7ddbac1ae308eef3a430143fc90a688b4a7 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Sun, 6 Mar 2022 23:25:58 -0500 Subject: [PATCH 391/418] shuffle tests a little bit and increase timeout to 30 minutes for pod timeout --- .github/workflows/reusable-acceptance.yml | 11 +++++------ acceptance/framework/k8s/helpers.go | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 24ba2c3914..44572263b1 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -39,12 +39,11 @@ jobs: strategy: matrix: include: # I am really sorry for this but I could not find a way to automatically split our tests into several runners. For now, split manually. - - {runner: "1", test-packages: "basic connect"} - - {runner: "2", test-packages: "consul-dns controller example"} - - {runner: "3", test-packages: "example ingress-gateway mesh-gateway"} - - {runner: "4", test-packages: "mesh-gateway metrics"} - - {runner: "5", test-packages: "partitions sync"} - - {runner: "6", test-packages: "terminating-gateway vault"} + - {runner: "0", test-packages: "basic connect consul-dns"} + - {runner: "1", test-packages: "controller example ingress-gateway"} + - {runner: "2", test-packages: "mesh-gateway metrics"} + - {runner: "3", test-packages: "partitions sync terminating-gateway"} + - {runner: "4", test-packages: "vault"} #TODO: set back to true fail-fast: false diff --git a/acceptance/framework/k8s/helpers.go b/acceptance/framework/k8s/helpers.go index f99d3e6510..f2c4b6eaf7 100644 --- a/acceptance/framework/k8s/helpers.go +++ b/acceptance/framework/k8s/helpers.go @@ -43,7 +43,7 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac // Wait up to 11m. // On Azure, volume provisioning can sometimes take close to 5 min, // so we need to give a bit more time for pods to become healthy. - counter := &retry.Counter{Count: 20 * 60, Wait: 1 * time.Second} + counter := &retry.Counter{Count: 30 * 60, Wait: 1 * time.Second} retry.RunWith(counter, t, func(r *retry.R) { pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) require.NoError(r, err) From 865baa0438507cbc49951a152070b1f21b1a853a Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 7 Mar 2022 11:47:57 -0500 Subject: [PATCH 392/418] Try to upload test report --- .github/workflows/reusable-acceptance.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 44572263b1..277d42aae2 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -110,4 +110,9 @@ jobs: done gotestsum --raw-command --junitfile "${{ env.TEST_RESULTS }}/gotestsum-report.xml" -- cat jsonfile* exit $exit_code - + + - name: Upload tests + - uses: actions/upload-artifact@v2 + with: + name: gotestsum-report.xml + path: ${{ env.TEST_RESULTS }}/gotestsum-report.xml From e93bca6ec4679da74437276afb839a0186d435b5 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 7 Mar 2022 11:49:53 -0500 Subject: [PATCH 393/418] Try to upload test report --- .github/workflows/reusable-acceptance.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 277d42aae2..ae7dfd6a6d 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -112,7 +112,7 @@ jobs: exit $exit_code - name: Upload tests - - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v2 with: name: gotestsum-report.xml path: ${{ env.TEST_RESULTS }}/gotestsum-report.xml From 27aeda31c33e516a5cc51a52e383e3f23efffc63 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Mon, 7 Mar 2022 12:03:05 -0700 Subject: [PATCH 394/418] Fix flakey vault test (#1080) --- acceptance/framework/vault/vault_cluster.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acceptance/framework/vault/vault_cluster.go b/acceptance/framework/vault/vault_cluster.go index d42a4fb896..6e265ddb51 100644 --- a/acceptance/framework/vault/vault_cluster.go +++ b/acceptance/framework/vault/vault_cluster.go @@ -172,8 +172,8 @@ func (v *VaultCluster) ConfigureAuthMethod(t *testing.T, vaultClient *vapi.Clien var sa *corev1.ServiceAccount retry.Run(t, func(r *retry.R) { sa, err = v.kubernetesClient.CoreV1().ServiceAccounts(saNS).Get(context.Background(), saName, metav1.GetOptions{}) - require.NoError(t, err) - require.Len(t, sa.Secrets, 1) + require.NoError(r, err) + require.Len(r, sa.Secrets, 1) }) v.logger.Logf(t, "updating vault kubernetes auth config for %s auth path", authPath) From f3f3398a0a78e5d8800703489ac9f637b06f0892 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 7 Mar 2022 14:13:46 -0500 Subject: [PATCH 395/418] try out vault test fix and always run test uploads --- .github/workflows/reusable-acceptance.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index ae7dfd6a6d..44662fa34b 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -112,6 +112,7 @@ jobs: exit $exit_code - name: Upload tests + if: always() uses: actions/upload-artifact@v2 with: name: gotestsum-report.xml From a594ac8bd472bbb774cf05ec8a98b17cf32b87c3 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 7 Mar 2022 15:45:27 -0500 Subject: [PATCH 396/418] change artifact name so that we can get test results --- .github/workflows/reusable-acceptance.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 44662fa34b..0dfd4a8259 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -39,10 +39,11 @@ jobs: strategy: matrix: include: # I am really sorry for this but I could not find a way to automatically split our tests into several runners. For now, split manually. - - {runner: "0", test-packages: "basic connect consul-dns"} - - {runner: "1", test-packages: "controller example ingress-gateway"} - - {runner: "2", test-packages: "mesh-gateway metrics"} - - {runner: "3", test-packages: "partitions sync terminating-gateway"} +#TODO: Fix + # - {runner: "0", test-packages: "basic connect consul-dns"} + #- {runner: "1", test-packages: "controller example ingress-gateway"} + #- {runner: "2", test-packages: "mesh-gateway metrics"} + #- {runner: "3", test-packages: "partitions sync terminating-gateway"} - {runner: "4", test-packages: "vault"} #TODO: set back to true @@ -108,12 +109,12 @@ jobs: break fi done - gotestsum --raw-command --junitfile "${{ env.TEST_RESULTS }}/gotestsum-report.xml" -- cat jsonfile* + gotestsum --raw-command --junitfile "${{ env.TEST_RESULTS }}/gotestsum-report.xml" -- cat jsonfile* exit $exit_code - name: Upload tests if: always() uses: actions/upload-artifact@v2 with: - name: gotestsum-report.xml + name: ${{ matrix.packages }}-gotestsum-report.xml path: ${{ env.TEST_RESULTS }}/gotestsum-report.xml From bb6055c40c0b95e3f59bfefefc5bee78fec824e9 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 7 Mar 2022 16:32:21 -0500 Subject: [PATCH 397/418] upload debug info --- .github/workflows/reusable-acceptance.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 0dfd4a8259..ea17ad7e71 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -116,5 +116,13 @@ jobs: if: always() uses: actions/upload-artifact@v2 with: - name: ${{ matrix.packages }}-gotestsum-report.xml + name: ${{ matrix.test-packages }}-gotestsum-report.xml path: ${{ env.TEST_RESULTS }}/gotestsum-report.xml + + - name: Upload debug (on failure) + if: failure() + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.test-packages }}-debug-info + path: ${{ env.TEST_RESULTS }}/debug + From ea8c212d594708aabbd5e4cd55b3503f0a0470a3 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 7 Mar 2022 17:25:26 -0500 Subject: [PATCH 398/418] add names to test artifacts --- .github/workflows/build-and-test.yml | 2 ++ .github/workflows/reusable-acceptance.yml | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index bf5280c47f..39d2a26915 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -274,6 +274,7 @@ jobs: needs: dev-upload-docker uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests with: + name: acceptance-tproxy directory: acceptance/tests go-version: 1.17.2 additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-transparent-proxy" @@ -286,6 +287,7 @@ jobs: needs: dev-upload-docker uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests with: + name: acceptance directory: acceptance/tests go-version: 1.17.2 additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2" diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index ea17ad7e71..62ad6dea01 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -3,6 +3,9 @@ name: reusable-acceptance on: workflow_call: inputs: + name: + required: true + type: string additional-flags: required: false type: string @@ -116,13 +119,13 @@ jobs: if: always() uses: actions/upload-artifact@v2 with: - name: ${{ matrix.test-packages }}-gotestsum-report.xml + name: ${{ inputs.name }}-${{ matrix.test-packages }}-gotestsum-report.xml path: ${{ env.TEST_RESULTS }}/gotestsum-report.xml - name: Upload debug (on failure) if: failure() uses: actions/upload-artifact@v2 with: - name: ${{ matrix.test-packages }}-debug-info + name: ${{ inputs.name }}-${{ matrix.test-packages }}-debug-info path: ${{ env.TEST_RESULTS }}/debug From c19a75658dae8b28052ddeaef3ef47efa7560ab1 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 8 Mar 2022 11:56:32 -0500 Subject: [PATCH 399/418] get proper github actions working and only a piece of circleci --- .circleci/config.yml | 638 ++++++++++++++++++++++ .github/workflows/build-and-test.yml | 120 ++-- .github/workflows/reusable-acceptance.yml | 15 +- .github/workflows/reusable-go-fmt-vet.yml | 1 - 4 files changed, 699 insertions(+), 75 deletions(-) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000000..a6222882d1 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,638 @@ +# Originally from consul-k8s +version: 2.1 +orbs: + slack: circleci/slack@3.4.2 +# reusable 'executor' object for jobs +executors: + go: + docker: + - image: docker.mirror.hashicorp.services/cimg/go:1.17.5 + environment: + TEST_RESULTS: /tmp/test-results # path to where test results are saved + CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests + +control-plane-path: &control-plane-path control-plane +cli-path: &cli-path cli +acceptance-mod-path: &acceptance-mod-path acceptance +acceptance-test-path: &acceptance-test-path acceptance/tests +acceptance-framework-path: &acceptance-framework-path acceptance/framework +charts-consul-path: &charts-consul-path charts/consul +helm-gen-path: &helm-gen-path hack/helm-reference-gen +gke-terraform-path: &gke-terraform-path charts/consul/test/terraform/gke +eks-terraform-path: &eks-terraform-path charts/consul/test/terraform/eks +aks-terraform-path: &aks-terraform-path charts/consul/test/terraform/aks +openshift-terraform-path: &openshift-terraform-path charts/consul/test/terraform/openshift + +commands: + install-prereqs: + steps: + - run: + name: Install gotestsum, kind, kubectl, and helm + command: | + wget https://golang.org/dl/go1.17.5.linux-amd64.tar.gz + sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.5.linux-amd64.tar.gz + rm go1.17.5.linux-amd64.tar.gz + echo 'export PATH=$PATH:/usr/local/go/bin' >> $BASH_ENV + + wget https://github.com/gotestyourself/gotestsum/releases/download/v1.6.4/gotestsum_1.6.4_linux_amd64.tar.gz + sudo tar -C /usr/local/bin -xzf gotestsum_1.6.4_linux_amd64.tar.gz + rm gotestsum_1.6.4_linux_amd64.tar.gz + + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.0/kind-linux-amd64 + chmod +x ./kind + sudo mv ./kind /usr/local/bin/kind + + curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl" + chmod +x ./kubectl + sudo mv ./kubectl /usr/local/bin/kubectl + + wget https://get.helm.sh/helm-v3.7.0-linux-amd64.tar.gz + tar -zxvf helm-v3.7.0-linux-amd64.tar.gz + sudo mv linux-amd64/helm /usr/local/bin/helm + + create-kind-clusters: + parameters: + version: + type: string + steps: + - run: + name: Create kind clusters + command: | + kind create cluster --name dc1 --image kindest/node:<< parameters.version >> + kind create cluster --name dc2 --image kindest/node:<< parameters.version >> + run-acceptance-tests: + parameters: + failfast: + type: boolean + default: false + additional-flags: + type: string + consul-k8s-image: + type: string + default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" + go-path: + type: string + default: "/home/circleci/.go_workspace" + steps: + - when: + condition: << parameters.failfast >> + steps: + - run: + name: Run acceptance tests + working_directory: *acceptance-test-path + no_output_timeout: 2h + command: | + # Enterprise tests can't run on fork PRs because they require + # a secret. + if [ -z "$CIRCLE_PR_NUMBER" ]; then + ENABLE_ENTERPRISE=true + fi + + # We have to run the tests for each package separately so that we can + # exit early if any test fails (-failfast only works within a single + # package). + exit_code=0 + pkgs=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname) + echo "Running $(echo $pkgs | wc -w) packages:" + echo $pkgs + for pkg in $pkgs + do + if ! gotestsum --no-summary=all --jsonfile=jsonfile-${pkg////-} -- $pkg -p 1 -timeout 2h -failfast \ + << parameters.additional-flags >> \ + ${ENABLE_ENTERPRISE:+-enable-enterprise} \ + -enable-multi-cluster \ + -debug-directory="$TEST_RESULTS/debug" \ + -consul-k8s-image=<< parameters.consul-k8s-image >> + then + echo "Tests in ${pkg} failed, aborting early" + exit_code=1 + break + fi + done + gotestsum --raw-command --junitfile "$TEST_RESULTS/gotestsum-report.xml" -- cat jsonfile* + exit $exit_code + + - unless: + condition: << parameters.failfast >> + steps: + - run: + name: Run acceptance tests + working_directory: *acceptance-test-path + no_output_timeout: 2h + command: | + # Enterprise tests can't run on fork PRs because they require + # a secret. + if [ -z "$CIRCLE_PR_NUMBER" ]; then + ENABLE_ENTERPRISE=true + fi + + pkgs=$(go list ./... | circleci tests split --split-by=timings --timings-type=classname) + echo "Running $pkgs" + gotestsum --junitfile "$TEST_RESULTS/gotestsum-report.xml" -- $pkgs -p 1 -timeout 2h -failfast \ + << parameters.additional-flags >> \ + -enable-multi-cluster \ + ${ENABLE_ENTERPRISE:+-enable-enterprise} \ + -debug-directory="$TEST_RESULTS/debug" \ + -consul-k8s-image=<< parameters.consul-k8s-image >> + +jobs: + build-distro: # defines a parameterized job + description: A job that will build the os/arch distro set by XC_OS and XC_ARCH + parameters: + OS: + description: What OSes to build + default: "" + type: string + ARCH: + description: What architectures to build + default: "" + type: string + executor: go + environment: + GOXPARALLEL: 2 # CircleCI containers are 2 CPU x 4GB RAM + steps: + - checkout + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} + - run: + name: build local + working_directory: *control-plane-path + command: XC_OS="<< parameters.OS >>" XC_ARCH="<< parameters.ARCH >>" ./build-support/scripts/build-local.sh + # persist to downstream job + - persist_to_workspace: + root: . + paths: + - control-plane/pkg/bin + # save dev build to CircleCI + - store_artifacts: + path: ./control-plane/pkg/bin + + # upload dev docker image + dev-upload-docker: + executor: go + steps: + - checkout + # get consul-k8s binary + - attach_workspace: + at: . + - setup_remote_docker + - run: + name: make ci.dev-docker + working_directory: *control-plane-path + command: make ci.dev-docker + + acceptance: + environment: + - TEST_RESULTS: /tmp/test-results + machine: + image: ubuntu-2004:202010-01 + resource_class: xlarge + parallelism: 6 + steps: + - checkout + - install-prereqs + - create-kind-clusters: + version: "v1.22.4" + - restore_cache: + keys: + - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} + - run: + name: go mod download + working_directory: *acceptance-mod-path + command: go mod download + - save_cache: + key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} + paths: + - ~/.go_workspace/pkg/mod + - run: mkdir -p $TEST_RESULTS + - run-acceptance-tests: + failfast: true + additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + + acceptance-tproxy: + environment: + - TEST_RESULTS: /tmp/test-results + machine: + image: ubuntu-2004:202010-01 + resource_class: xlarge + parallelism: 6 + steps: + - checkout + - install-prereqs + - create-kind-clusters: + version: "v1.22.4" + - restore_cache: + keys: + - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} + - run: + name: go mod download + working_directory: *acceptance-mod-path + command: go mod download + - save_cache: + key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} + paths: + - ~/.go_workspace/pkg/mod + - run: mkdir -p $TEST_RESULTS + - run-acceptance-tests: + failfast: true + additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" -enable-transparent-proxy + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + + ########################## + # CLEANUP CLOUD RESOURCES + ########################## + cleanup-gcp-resources: + docker: + - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + steps: + - run: + name: cleanup leftover resources + command: | + echo "${GOOGLE_CREDENTIALS}" | gcloud auth activate-service-account --key-file=- + clusters=$(gcloud container clusters list --zone us-central1-a --project ${CLOUDSDK_CORE_PROJECT} --format json | jq -r '.[] | select(.name | test("^consul-k8s-\\d+$")) | .name') + for cluster in $clusters; do + echo "Deleting $cluster GKE cluster" + gcloud container clusters delete $cluster --zone us-central1-a --project ${CLOUDSDK_CORE_PROJECT} --quiet + done + - slack/status: + fail_only: true + failure_message: "GKE cleanup failed" + + cleanup-azure-resources: + docker: + - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + steps: + - run: + name: cleanup leftover resources + command: | + az login --service-principal -u "$ARM_CLIENT_ID" -p "$ARM_CLIENT_SECRET" --tenant "$ARM_TENANT_ID" > /dev/null + resource_groups=$(az group list -o json | jq -r '.[] | select(.name | test("^consul-k8s-\\d+$")) | .name') + for group in $resource_groups; do + echo "Deleting $group resource group" + az group delete -n $group --yes + done + - slack/status: + fail_only: true + failure_message: "AKS cleanup failed" + + cleanup-eks-resources: + docker: + - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + steps: + - checkout + - run: + name: cleanup eks resources + command: | + # Assume the role and set environment variables. + aws sts assume-role --role-arn "$AWS_ROLE_ARN" --role-session-name "consul-helm-$CIRCLE_BUILD_NUM" --duration-seconds 10800 > assume-role.json + export AWS_ACCESS_KEY_ID="$(jq -r .Credentials.AccessKeyId assume-role.json)" + export AWS_SECRET_ACCESS_KEY="$(jq -r .Credentials.SecretAccessKey assume-role.json)" + export AWS_SESSION_TOKEN="$(jq -r .Credentials.SessionToken assume-role.json)" + + make ci.aws-acceptance-test-cleanup + - slack/status: + fail_only: true + failure_message: "EKS cleanup failed" + + ######################## + # ACCEPTANCE TESTS + ######################## + acceptance-gke-1-20: + environment: + - TEST_RESULTS: /tmp/test-results + docker: + # This image is built from test/docker/Test.dockerfile + - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + + steps: + - run: + name: Exit if forked PR + command: | + if [ -n "$CIRCLE_PR_NUMBER" ]; then + echo "Skipping acceptance tests for forked PRs; marking step successful." + circleci step halt + fi + + - checkout + + - run: + name: terraform init & apply + working_directory: *gke-terraform-path + command: | + terraform init + echo "${GOOGLE_CREDENTIALS}" | gcloud auth activate-service-account --key-file=- + + # On GKE, we're setting the build number instead of build URL because label values + # cannot contain '/'. + terraform apply \ + -var project=${CLOUDSDK_CORE_PROJECT} \ + -var init_cli=true \ + -var cluster_count=2 \ + -var labels="{\"build_number\": \"$CIRCLE_BUILD_NUM\"}" \ + -auto-approve + + primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) + secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) + + echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV + echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + + - run: mkdir -p $TEST_RESULTS + + - run-acceptance-tests: + additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-pod-security-policies -enable-transparent-proxy + + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + + - run: + name: terraform destroy + working_directory: *gke-terraform-path + command: | + terraform destroy -var project=${CLOUDSDK_CORE_PROJECT} -auto-approve + when: always + + - slack/status: + fail_only: true + failure_message: "GKE acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" + + acceptance-aks-1-21: + environment: + - TEST_RESULTS: /tmp/test-results + docker: + # This image is built from test/docker/Test.dockerfile + - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + + steps: + - checkout + + - run: + name: terraform init & apply + working_directory: *aks-terraform-path + command: | + terraform init + + terraform apply \ + -var client_id="$ARM_CLIENT_ID" \ + -var client_secret="$ARM_CLIENT_SECRET" \ + -var cluster_count=2 \ + -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" \ + -auto-approve + + primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) + secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) + + echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV + echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + + - run: mkdir -p $TEST_RESULTS + + - run-acceptance-tests: + additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-transparent-proxy + + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + + - run: + name: terraform destroy + working_directory: *aks-terraform-path + command: | + terraform destroy -auto-approve + when: always + + - slack/status: + fail_only: true + failure_message: "AKS acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" + + acceptance-eks-1-19: + environment: + - TEST_RESULTS: /tmp/test-results + docker: + # This image is built from test/docker/Test.dockerfile + - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + + steps: + - checkout + + - run: + name: configure aws + command: | + aws configure --profile helm_user set aws_access_key_id "$AWS_ACCESS_KEY_ID" + aws configure --profile helm_user set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY" + aws configure set role_arn "$AWS_ROLE_ARN" + aws configure set source_profile helm_user + + echo "unset AWS_ACCESS_KEY_ID" >> $BASH_ENV + echo "unset AWS_SECRET_ACCESS_KEY" >> $BASH_ENV + + - run: + name: terraform init & apply + working_directory: *eks-terraform-path + command: | + terraform init + + terraform apply -var cluster_count=2 -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" -auto-approve + + primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) + secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) + + echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV + echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + + - run: mkdir -p $TEST_RESULTS + + - run-acceptance-tests: + additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-transparent-proxy + + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + + - run: + name: terraform destroy + working_directory: *eks-terraform-path + command: | + terraform destroy -var cluster_count=2 -auto-approve + when: always + + - slack/status: + fail_only: true + failure_message: "EKS acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" + + acceptance-openshift: + environment: + TEST_RESULTS: /tmp/test-results + parallelism: 1 + docker: + # This image is built from test/docker/Test.dockerfile + - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + + steps: + - checkout + - run: + name: terraform init & apply + working_directory: *openshift-terraform-path + command: | + terraform init + az login --service-principal -u "$ARM_CLIENT_ID" -p "$ARM_CLIENT_SECRET" --tenant "$ARM_TENANT_ID" > /dev/null + terraform apply \ + -var cluster_count=2 \ + -var tags="{\"build_url\": \"$CIRCLE_BUILD_URL\"}" \ + -auto-approve + + primary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[0]) + secondary_kubeconfig=$(terraform output -json | jq -r .kubeconfigs.value[1]) + + echo "export primary_kubeconfig=$primary_kubeconfig" >> $BASH_ENV + echo "export secondary_kubeconfig=$secondary_kubeconfig" >> $BASH_ENV + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + + - run: mkdir -p $TEST_RESULTS + + - run-acceptance-tests: + additional-flags: -kubeconfig="$primary_kubeconfig" -secondary-kubeconfig="$secondary_kubeconfig" -enable-openshift -enable-transparent-proxy + + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + + - run: + name: terraform destroy + working_directory: *openshift-terraform-path + command: | + terraform destroy -auto-approve + when: always + + - slack/status: + fail_only: true + failure_message: "OpenShift acceptance tests failed. Check the logs at: ${CIRCLE_BUILD_URL}" + + acceptance-kind-1-23: + environment: + - TEST_RESULTS: /tmp/test-results + machine: + image: ubuntu-2004:202010-01 + resource_class: xlarge + steps: + - checkout + - install-prereqs + - create-kind-clusters: + version: "v1.23.0" + - restore_cache: + keys: + - consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} + - run: + name: go mod download + working_directory: *acceptance-mod-path + command: go mod download + - save_cache: + key: consul-helm-modcache-v2-{{ checksum "acceptance/go.mod" }} + paths: + - ~/.go_workspace/pkg/mod + - run: mkdir -p $TEST_RESULTS + - run-acceptance-tests: + additional-flags: -use-kind -kubecontext="kind-dc1" -secondary-kubecontext="kind-dc2" -enable-transparent-proxy + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + - slack/status: + fail_only: true + failure_message: "Acceptance tests against Kind with Kubernetes v1.22 failed. Check the logs at: ${CIRCLE_BUILD_URL}" + +workflows: + version: 2 + test-and-build: + jobs: + # Build control plane binaries + - build-distro: + OS: "freebsd linux windows" + ARCH: "386" + name: build-distros-386 + - build-distro: + OS: "darwin freebsd linux solaris windows" + ARCH: "amd64" + name: build-distros-amd64 + - build-distro: + OS: "linux" + ARCH: "arm arm64" + name: build-distros-arm-arm64 + - dev-upload-docker: + context: consul-ci + requires: + - build-distros-amd64 + # Run acceptance tests using the docker image built for the control plane + - acceptance: + requires: + - dev-upload-docker + - unit-test-helm-templates + - unit-acceptance-framework + - unit-cli + - acceptance-tproxy: + requires: + - dev-upload-docker + - unit-test-helm-templates + - unit-acceptance-framework + - unit-cli + nightly-acceptance-tests: + triggers: + - schedule: + cron: "0 0 * * *" + filters: + branches: + only: + - main + jobs: + - cleanup-gcp-resources + - cleanup-azure-resources + - cleanup-eks-resources + # Disable until we can use UBI images. + # - acceptance-openshift: + # requires: + # - cleanup-azure-resources + - acceptance-gke-1-20: + requires: + - cleanup-gcp-resources + - acceptance-eks-1-19: + requires: + - cleanup-eks-resources + - acceptance-aks-1-21: + requires: + - cleanup-azure-resources + - acceptance-kind-1-23 diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 39d2a26915..bb3db908f8 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,11 +1,6 @@ name: test-and-build on: push: - tags: - - v* - branches: - - crt-build-and-tests - pull_request: env: TEST_RESULTS: /tmp/test-results # path to where test results are saved @@ -13,10 +8,6 @@ env: CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests GOTESTSUM_VERSION: 1.6.4 # You cannot use environment variables with workflows. The gotestsum version is hardcoded in the reusable workflows too. -# TODO: upload tests somewhere. An artifact? -# TODO: prevent running some things on forks? -# TODO: fix caching. Maybe cache on the first job - jobs: validate-helm-gen: runs-on: ubuntu-latest @@ -181,17 +172,15 @@ jobs: gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES build-distros: -#TODO: Fix - #needs: [test-control-plane, test-enterprise-control-plane] + needs: [test-control-plane, test-enterprise-control-plane] runs-on: ubuntu-latest strategy: matrix: include: -#TODO: fix - # - {go: "1.17.2", goos: "linux", goarch: "386"} + - {go: "1.17.2", goos: "linux", goarch: "386"} - {go: "1.17.2", goos: "linux", goarch: "amd64"} - #- {go: "1.17.2", goos: "linux", goarch: "arm"} - # - {go: "1.17.2", goos: "linux", goarch: "arm64"} + - {go: "1.17.2", goos: "linux", goarch: "arm"} + - {go: "1.17.2", goos: "linux", goarch: "arm64"} fail-fast: true name: Go ${{ matrix.go }} ${{ matrix.goos }} ${{ matrix.goarch }} build @@ -244,55 +233,56 @@ jobs: directory: cli go-version: 1.17.2 - dev-upload-docker: - needs: build-distros - runs-on: ubuntu-latest - - env: - GITHUB_PULL_REQUEST: ${{github.event.pull_request.number}} - DOCKER_USER: ${{secrets.DOCKER_USER}} - DOCKER_PASS: ${{secrets.DOCKER_PASS}} - steps: - - uses: actions/checkout@v2 - - - run: mkdir -p control-plane/pkg/bin/linux_amd64 - - - uses: actions/download-artifact@v3 - with: - name: consul-k8s_linux_amd64.zip - path: control-plane - - - name: Docker build - working-directory: control-plane - run: | - unzip consul-k8s_linux_amd64.zip -d ./pkg/bin/linux_amd64 - make ci.dev-docker - - acceptance-tproxy: -#TODO: Fix - #needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] - needs: dev-upload-docker - uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests - with: - name: acceptance-tproxy - directory: acceptance/tests - go-version: 1.17.2 - additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-transparent-proxy" - gotestsum-version: 1.6.4 - secrets: - CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_ENT_LICENSE }} - - acceptance: - #needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] - needs: dev-upload-docker - uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests - with: - name: acceptance - directory: acceptance/tests - go-version: 1.17.2 - additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2" - gotestsum-version: 1.6.4 - secrets: - CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_ENT_LICENSE }} +# Disabling for now until we get faster VMs to run acceptance tests +# dev-upload-docker: +# if: github.repository_owner == 'hashicorp' # Do not run on forks as this requires secrets +# needs: build-distros +# runs-on: ubuntu-latest +# +# env: +# GITHUB_PULL_REQUEST: ${{github.event.pull_request.number}} +# DOCKER_USER: ${{secrets.DOCKER_USER}} +# DOCKER_PASS: ${{secrets.DOCKER_PASS}} +# steps: +# - uses: actions/checkout@v2 +# +# - run: mkdir -p control-plane/pkg/bin/linux_amd64 +# +# - uses: actions/download-artifact@v3 +# with: +# name: consul-k8s_linux_amd64.zip +# path: control-plane +# +# - name: Docker build +# working-directory: control-plane +# run: | +# unzip consul-k8s_linux_amd64.zip -d ./pkg/bin/linux_amd64 +# make ci.dev-docker +# +# acceptance-tproxy: +# needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] +# needs: dev-upload-docker +# uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests +# with: +# name: acceptance-tproxy +# directory: acceptance/tests +# go-version: 1.17.2 +# additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2 -enable-transparent-proxy" +# gotestsum-version: 1.6.4 +# secrets: +# CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_ENT_LICENSE }} +# +# acceptance: +# #needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] +# needs: dev-upload-docker +# uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests +# with: +# name: acceptance +# directory: acceptance/tests +# go-version: 1.17.2 +# additional-flags: "-use-kind -kubecontext=kind-dc1 -secondary-kubecontext=kind-dc2" +# gotestsum-version: 1.6.4 +# secrets: +# CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_ENT_LICENSE }} diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 62ad6dea01..24e6dfdab2 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -42,15 +42,13 @@ jobs: strategy: matrix: include: # I am really sorry for this but I could not find a way to automatically split our tests into several runners. For now, split manually. -#TODO: Fix - # - {runner: "0", test-packages: "basic connect consul-dns"} - #- {runner: "1", test-packages: "controller example ingress-gateway"} - #- {runner: "2", test-packages: "mesh-gateway metrics"} - #- {runner: "3", test-packages: "partitions sync terminating-gateway"} + - {runner: "0", test-packages: "basic connect consul-dns"} + - {runner: "1", test-packages: "controller example ingress-gateway"} + - {runner: "2", test-packages: "mesh-gateway metrics"} + - {runner: "3", test-packages: "partitions sync terminating-gateway"} - {runner: "4", test-packages: "vault"} -#TODO: set back to true - fail-fast: false + fail-fast: true steps: - name: Checkout code uses: actions/checkout@v2 @@ -90,9 +88,9 @@ jobs: # We have to run the tests for each package separately so that we can # exit early if any test fails (-failfast only works within a single # package). -# TODO: do not run on forks - name: Run acceptance tests ${{ matrix.runner }} working-directory: ${{ inputs.directory }} + if: github.repository_owner == 'hashicorp' # This prevents running on forks run: | exit_code=0 echo "Running packages: ${{ matrix.test-packages }}" @@ -128,4 +126,3 @@ jobs: with: name: ${{ inputs.name }}-${{ matrix.test-packages }}-debug-info path: ${{ env.TEST_RESULTS }}/debug - diff --git a/.github/workflows/reusable-go-fmt-vet.yml b/.github/workflows/reusable-go-fmt-vet.yml index edd0595adf..e5e602c3ae 100644 --- a/.github/workflows/reusable-go-fmt-vet.yml +++ b/.github/workflows/reusable-go-fmt-vet.yml @@ -10,7 +10,6 @@ on: required: true type: string - jobs: a: runs-on: ubuntu-latest From bcc3276fc09f3ed6aa23a83dedd95a1a35387412 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 8 Mar 2022 12:01:53 -0500 Subject: [PATCH 400/418] remove acceptance tests requirements --- .circleci/config.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a6222882d1..23a0713ad5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -601,15 +601,9 @@ workflows: - acceptance: requires: - dev-upload-docker - - unit-test-helm-templates - - unit-acceptance-framework - - unit-cli - acceptance-tproxy: requires: - dev-upload-docker - - unit-test-helm-templates - - unit-acceptance-framework - - unit-cli nightly-acceptance-tests: triggers: - schedule: From a5889dbdb12f02c40ce4b197a1b9da46c439b801 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 8 Mar 2022 13:33:49 -0500 Subject: [PATCH 401/418] remove unused anchors --- .circleci/config.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 23a0713ad5..c5693b20d4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,12 +13,8 @@ executors: CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests control-plane-path: &control-plane-path control-plane -cli-path: &cli-path cli acceptance-mod-path: &acceptance-mod-path acceptance acceptance-test-path: &acceptance-test-path acceptance/tests -acceptance-framework-path: &acceptance-framework-path acceptance/framework -charts-consul-path: &charts-consul-path charts/consul -helm-gen-path: &helm-gen-path hack/helm-reference-gen gke-terraform-path: &gke-terraform-path charts/consul/test/terraform/gke eks-terraform-path: &eks-terraform-path charts/consul/test/terraform/eks aks-terraform-path: &aks-terraform-path charts/consul/test/terraform/aks From 9941e8dd81a913781858d5329c345ce5e9fc635c Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 8 Mar 2022 13:47:38 -0500 Subject: [PATCH 402/418] circleci isnt working --- .circleci/config.yml | 342 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 341 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c5693b20d4..6b7115efb1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,8 +13,12 @@ executors: CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests control-plane-path: &control-plane-path control-plane +cli-path: &cli-path cli acceptance-mod-path: &acceptance-mod-path acceptance acceptance-test-path: &acceptance-test-path acceptance/tests +acceptance-framework-path: &acceptance-framework-path acceptance/framework +charts-consul-path: &charts-consul-path charts/consul +helm-gen-path: &helm-gen-path hack/helm-reference-gen gke-terraform-path: &gke-terraform-path charts/consul/test/terraform/gke eks-terraform-path: &eks-terraform-path charts/consul/test/terraform/eks aks-terraform-path: &aks-terraform-path charts/consul/test/terraform/aks @@ -133,6 +137,112 @@ commands: -consul-k8s-image=<< parameters.consul-k8s-image >> jobs: + go-fmt-and-vet-control-plane: + executor: go + steps: + - checkout + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} + + - run: + name: go mod download + working_directory: *control-plane-path + command: go mod download + + # Save go module cache if the go.mod file has changed + - save_cache: + key: consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} + paths: + - "/home/circleci/go/pkg/mod" + + # check go fmt output because it does not report non-zero when there are fmt changes + - run: + name: check go fmt + working_directory: *control-plane-path + command: | + files=$(go fmt ./...) + if [ -n "$files" ]; then + echo "The following file(s) do not conform to go fmt:" + echo "$files" + exit 1 + fi + - run: cd control-plane && go vet ./... + + lint-control-plane: + executor: go + steps: + - checkout + - run: go get -u github.com/hashicorp/lint-consul-retry && lint-consul-retry + - run: + name: run lint + working_directory: *control-plane-path + command: go run hack/lint-api-new-client/main.go + + test-control-plane: + executor: go + environment: + TEST_RESULTS: /tmp/test-results + parallelism: 1 + steps: + - checkout + - run: mkdir -p $TEST_RESULTS + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} + + # run go tests with gotestsum + - run: + name: run go tests + working_directory: *control-plane-path + command: | + # download and install the consul binary + wget https://releases.hashicorp.com/consul/"${CONSUL_VERSION}"/consul_"${CONSUL_VERSION}"_linux_amd64.zip && \ + unzip consul_"${CONSUL_VERSION}"_linux_amd64.zip -d /home/circleci/bin && + rm consul_"${CONSUL_VERSION}"_linux_amd64.zip + PACKAGE_NAMES=$(go list ./...) + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES + + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + + test-enterprise-control-plane: + executor: go + environment: + TEST_RESULTS: /tmp/test-results + parallelism: 1 + steps: + - checkout + - run: mkdir -p $TEST_RESULTS + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-k8s-modcache-v2-{{ checksum "control-plane/go.mod" }} + + # run go tests with gotestsum + - run: + name: run enterprise go tests + working_directory: *control-plane-path + command: | + # download and install the consul binary + wget https://releases.hashicorp.com/consul/"${CONSUL_ENT_VERSION}"/consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip && \ + unzip consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip -d /home/circleci/bin && + rm consul_"${CONSUL_ENT_VERSION}"_linux_amd64.zip + PACKAGE_NAMES=$(go list ./...) + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES + + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + build-distro: # defines a parameterized job description: A job that will build the os/arch distro set by XC_OS and XC_ARCH parameters: @@ -181,6 +291,192 @@ jobs: working_directory: *control-plane-path command: make ci.dev-docker + unit-cli: + executor: go + steps: + - checkout + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-k8s-cli-modcache-v2-{{ checksum "cli/go.mod" }} + + - run: + name: go mod download + working_directory: *cli-path + command: go mod download + + # Save go module cache if the go.mod file has changed + - save_cache: + key: consul-k8s-cli-modcache-v2-{{ checksum "cli/go.mod" }} + paths: + - "/home/circleci/go/pkg/mod" + + - run: mkdir -p $TEST_RESULTS + + - run: + name: Run tests + working_directory: *cli-path + command: | + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 + + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + + go-fmt-and-vet-acceptance: + executor: go + steps: + - checkout + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + + - run: + name: go mod download + working_directory: *acceptance-mod-path + command: go mod download + + # Save go module cache if the go.mod file has changed + - save_cache: + key: consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + paths: + - "/home/circleci/go/pkg/mod" + + # check go fmt output because it does not report non-zero when there are fmt changes + - run: + name: check go fmt + working_directory: *acceptance-mod-path + command: | + files=$(go fmt ./...) + if [ -n "$files" ]; then + echo "The following file(s) do not conform to go fmt:" + echo "$files" + exit 1 + fi + + - run: + name: go vet + working_directory: *acceptance-mod-path + command: go vet ./... + + go-fmt-and-vet-helm-gen: + executor: go + steps: + - checkout + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + + - run: + name: go mod download + working_directory: *helm-gen-path + command: go mod download + + # Save go module cache if the go.mod file has changed + - save_cache: + key: consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + paths: + - "/home/circleci/go/pkg/mod" + + # check go fmt output because it does not report non-zero when there are fmt changes + - run: + name: check go fmt + working_directory: *helm-gen-path + command: | + files=$(go fmt ./...) + if [ -n "$files" ]; then + echo "The following file(s) do not conform to go fmt:" + echo "$files" + exit 1 + fi + + - run: + name: go vet + working_directory: *helm-gen-path + command: go vet ./... + + unit-acceptance-framework: + executor: go + steps: + - checkout + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-helm-acceptance-modcache-v2-{{ checksum "acceptance/go.mod" }} + + - run: mkdir -p $TEST_RESULTS + + - run: + name: Run tests + working_directory: *acceptance-framework-path + command: | + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 + + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + + unit-helm-gen: + executor: go + steps: + - checkout + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + + - run: mkdir -p $TEST_RESULTS + + - run: + name: Run tests + working_directory: *helm-gen-path + command: | + gotestsum --junitfile $TEST_RESULTS/gotestsum-report.xml ./... -- -p 4 + + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + + validate-helm-gen: + executor: go + steps: + - checkout + + # Restore go module cache if there is one + - restore_cache: + keys: + - consul-helm-helm-gen-modcache-v2-{{ checksum "charts/consul/hack/helm-reference-gen/go.mod" }} + + - run: mkdir -p $TEST_RESULTS + + - run: + name: Validate helm gen + working_directory: *helm-gen-path + command: | + go run ./... -validate + + unit-test-helm-templates: + docker: + - image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 + + steps: + - checkout + + - run: + name: Run Unit Tests + working_directory: charts/consul + command: bats --jobs 4 ./test/unit + acceptance: environment: - TEST_RESULTS: /tmp/test-results @@ -576,19 +872,57 @@ workflows: version: 2 test-and-build: jobs: - # Build control plane binaries + # Fmt, vet, lint control plane and helm code + - go-fmt-and-vet-control-plane + - lint-control-plane + - go-fmt-and-vet-acceptance + - go-fmt-and-vet-helm-gen + # Unit test control plane + - test-control-plane: + requires: + - go-fmt-and-vet-control-plane + - lint-control-plane + - test-enterprise-control-plane: + filters: + branches: + # Forked pull requests have CIRCLE_BRANCH set to pull/XXX. + ignore: /pull\/[0-9]+/ + requires: + - go-fmt-and-vet-control-plane + - lint-control-plane + # Unit test CLI + - unit-cli + # Unit tests for go modules in helm and bats tests for templates + - unit-acceptance-framework: + requires: + - go-fmt-and-vet-acceptance + - unit-helm-gen: + requires: + - go-fmt-and-vet-helm-gen + - validate-helm-gen + - unit-test-helm-templates + # Build control plane binaries - build-distro: OS: "freebsd linux windows" ARCH: "386" name: build-distros-386 + requires: + - test-control-plane + - test-enterprise-control-plane - build-distro: OS: "darwin freebsd linux solaris windows" ARCH: "amd64" name: build-distros-amd64 + requires: + - test-control-plane + - test-enterprise-control-plane - build-distro: OS: "linux" ARCH: "arm arm64" name: build-distros-arm-arm64 + requires: + - test-control-plane + - test-enterprise-control-plane - dev-upload-docker: context: consul-ci requires: @@ -597,9 +931,15 @@ workflows: - acceptance: requires: - dev-upload-docker + - unit-test-helm-templates + - unit-acceptance-framework + - unit-cli - acceptance-tproxy: requires: - dev-upload-docker + - unit-test-helm-templates + - unit-acceptance-framework + - unit-cli nightly-acceptance-tests: triggers: - schedule: From 03d2ee745f996cca0393c648d86b1c8f38aaef8d Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 8 Mar 2022 15:34:47 -0500 Subject: [PATCH 403/418] remove duplicate jobs --- .circleci/config.yml | 57 ++++---------------------------------------- 1 file changed, 4 insertions(+), 53 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6b7115efb1..4653e676d5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -872,57 +872,14 @@ workflows: version: 2 test-and-build: jobs: - # Fmt, vet, lint control plane and helm code - - go-fmt-and-vet-control-plane - - lint-control-plane - - go-fmt-and-vet-acceptance - - go-fmt-and-vet-helm-gen - # Unit test control plane - - test-control-plane: - requires: - - go-fmt-and-vet-control-plane - - lint-control-plane - - test-enterprise-control-plane: - filters: - branches: - # Forked pull requests have CIRCLE_BRANCH set to pull/XXX. - ignore: /pull\/[0-9]+/ - requires: - - go-fmt-and-vet-control-plane - - lint-control-plane - # Unit test CLI - - unit-cli - # Unit tests for go modules in helm and bats tests for templates - - unit-acceptance-framework: - requires: - - go-fmt-and-vet-acceptance - - unit-helm-gen: - requires: - - go-fmt-and-vet-helm-gen - - validate-helm-gen - - unit-test-helm-templates - # Build control plane binaries - - build-distro: - OS: "freebsd linux windows" - ARCH: "386" - name: build-distros-386 - requires: - - test-control-plane - - test-enterprise-control-plane + # Build this one control-plane binary so that acceptance and acceptance-tproxy will run + # The rest of these CircleCI jobs have been migrated to Github Actions. We need to wait until + # the summer of 2022 for larger puplic Github Action VMs be available before the acceptance tests can + # be moved - build-distro: OS: "darwin freebsd linux solaris windows" ARCH: "amd64" name: build-distros-amd64 - requires: - - test-control-plane - - test-enterprise-control-plane - - build-distro: - OS: "linux" - ARCH: "arm arm64" - name: build-distros-arm-arm64 - requires: - - test-control-plane - - test-enterprise-control-plane - dev-upload-docker: context: consul-ci requires: @@ -931,15 +888,9 @@ workflows: - acceptance: requires: - dev-upload-docker - - unit-test-helm-templates - - unit-acceptance-framework - - unit-cli - acceptance-tproxy: requires: - dev-upload-docker - - unit-test-helm-templates - - unit-acceptance-framework - - unit-cli nightly-acceptance-tests: triggers: - schedule: From 8018e01b3f00ef42dece5cdfd961cef8e1233a85 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 8 Mar 2022 16:00:53 -0500 Subject: [PATCH 404/418] reset to main and add note about acceptance tests running in CircleCI --- .github/workflows/build-and-test.yml | 3 ++- acceptance/framework/k8s/helpers.go | 2 +- acceptance/go.mod | 3 --- acceptance/go.sum | 4 ---- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index bb3db908f8..571041aa16 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -233,7 +233,8 @@ jobs: directory: cli go-version: 1.17.2 -# Disabling for now until we get faster VMs to run acceptance tests +# Disabling for now until we get faster VMs to run acceptance tests. Faster VMs for Github Actions are supposed +# to be available in the summer of 2022. For now, run the dev-upload docker and acceptance tests in CircleCI # dev-upload-docker: # if: github.repository_owner == 'hashicorp' # Do not run on forks as this requires secrets # needs: build-distros diff --git a/acceptance/framework/k8s/helpers.go b/acceptance/framework/k8s/helpers.go index f2c4b6eaf7..1b895a5e17 100644 --- a/acceptance/framework/k8s/helpers.go +++ b/acceptance/framework/k8s/helpers.go @@ -43,7 +43,7 @@ func WaitForAllPodsToBeReady(t *testing.T, client kubernetes.Interface, namespac // Wait up to 11m. // On Azure, volume provisioning can sometimes take close to 5 min, // so we need to give a bit more time for pods to become healthy. - counter := &retry.Counter{Count: 30 * 60, Wait: 1 * time.Second} + counter := &retry.Counter{Count: 11 * 60, Wait: 1 * time.Second} retry.RunWith(counter, t, func(r *retry.R) { pods, err := client.CoreV1().Pods(namespace).List(context.Background(), metav1.ListOptions{LabelSelector: podLabelSelector}) require.NoError(r, err) diff --git a/acceptance/go.mod b/acceptance/go.mod index 33e9367128..3c31530573 100644 --- a/acceptance/go.mod +++ b/acceptance/go.mod @@ -17,7 +17,6 @@ require ( require ( cloud.google.com/go v0.54.0 // indirect - github.com/Songmu/gotesplit v0.1.2 // indirect github.com/armon/go-metrics v0.3.9 // indirect github.com/armon/go-radix v1.0.0 // indirect github.com/aws/aws-sdk-go v1.30.27 // indirect @@ -60,7 +59,6 @@ require ( github.com/imdario/mergo v0.3.12 // indirect github.com/jmespath/go-jmespath v0.3.0 // indirect github.com/json-iterator/go v1.1.11 // indirect - github.com/jstemmer/go-junit-report v0.9.1 // indirect github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.13 // indirect github.com/mitchellh/copystructure v1.0.0 // indirect @@ -87,7 +85,6 @@ require ( golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect golang.org/x/text v0.3.6 // indirect diff --git a/acceptance/go.sum b/acceptance/go.sum index 4013c9f92b..1953df0322 100644 --- a/acceptance/go.sum +++ b/acceptance/go.sum @@ -81,8 +81,6 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/Songmu/gotesplit v0.1.2 h1:8PJ0j62PdBdvNFsX6Hufr5qp1bQGXJZS5dWA7dc+U6Y= -github.com/Songmu/gotesplit v0.1.2/go.mod h1:SE1mdkM3jyX4cjjs4N2nhYjfntqf2VdvxgMCIzsJNoo= github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -510,7 +508,6 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/ github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= @@ -944,7 +941,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= From b79dff2ecb0ca48a4290231893352d6a78371d4d Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 8 Mar 2022 16:01:59 -0500 Subject: [PATCH 405/418] remove random file --- acceptance/tests/fixtures/jsonfile-blah | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 acceptance/tests/fixtures/jsonfile-blah diff --git a/acceptance/tests/fixtures/jsonfile-blah b/acceptance/tests/fixtures/jsonfile-blah deleted file mode 100644 index e69de29bb2..0000000000 From b38338ff2f7e792ab1726803fbdae62bf90244f2 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 10 Mar 2022 10:51:44 -0500 Subject: [PATCH 406/418] Move from gofmt-vet to golangci-lint, update acceptance Makefile targets, split downloads and tests into two steps --- .github/workflows/build-and-test.yml | 43 +++++++++++-------- .../workflows/golangci-lint-acceptance.yml | 23 ---------- .github/workflows/golangci-lint-cli.yml | 20 --------- .../workflows/golangci-lint-control-plane.yml | 23 ---------- ...fmt-vet.yml => reusable-golangci-lint.yml} | 20 +++------ .golangci.yml | 1 + control-plane/Makefile | 25 ++++++++++- 7 files changed, 56 insertions(+), 99 deletions(-) delete mode 100644 .github/workflows/golangci-lint-acceptance.yml delete mode 100644 .github/workflows/golangci-lint-cli.yml delete mode 100644 .github/workflows/golangci-lint-control-plane.yml rename .github/workflows/{reusable-go-fmt-vet.yml => reusable-golangci-lint.yml} (66%) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 571041aa16..1440bbc865 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -35,14 +35,14 @@ jobs: run: | go run ./... -validate - go-fmt-vet-helm-gen: - uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests + golangci-lint-helm-gen: + uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@crt-build-and-tests with: directory: hack/helm-reference-gen go-version: 1.17.2 unit-helm-gen: - needs: [go-fmt-vet-helm-gen, validate-helm-gen] + needs: [golangci-lint-helm-gen, validate-helm-gen] uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: hack/helm-reference-gen @@ -53,7 +53,7 @@ jobs: runs-on: ubuntu-latest container: image: docker.mirror.hashicorp.services/hashicorpdev/consul-helm-test:0.10.0 - options: --user root + options: --user 1001 steps: - name: Checkout code uses: actions/checkout@v2 @@ -79,14 +79,14 @@ jobs: working-directory: control-plane run: go run hack/lint-api-new-client/main.go - go-fmt-vet-control-plane: - uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests + golangci-lint-control-plane: + uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@crt-build-and-tests with: directory: control-plane go-version: 1.17.2 test-control-plane: - needs: [lint-control-plane, go-fmt-vet-control-plane] + needs: [lint-control-plane, golangci-lint-control-plane] runs-on: ubuntu-latest steps: - name: Checkout code @@ -116,7 +116,7 @@ jobs: - run: mkdir -p ${{env.TEST_RESULTS}} - run: echo "$HOME/bin" >> $GITHUB_PATH - - name: Run go tests + - name: Download consul working-directory: control-plane run: | mkdir -p $HOME/bin @@ -124,11 +124,16 @@ jobs: unzip consul_${{env.CONSUL_VERSION}}_linux_amd64.zip -d $HOME/bin && \ rm consul_${{env.CONSUL_VERSION}}_linux_amd64.zip chmod +x $HOME/bin/consul + + - name: Run go tests + working-directory: control-plane + run: | PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -p 4 $PACKAGE_NAMES test-enterprise-control-plane: - needs: [lint-control-plane, go-fmt-vet-control-plane] + if: github.repository_owner == 'hashicorp' # Do not run on forks as this requires secrets + needs: [lint-control-plane, golangci-lint-control-plane] runs-on: ubuntu-latest env: CONSUL_LICENSE: ${{secrets.CONSUL_LICENSE}} @@ -160,7 +165,7 @@ jobs: - run: mkdir -p ${{env.TEST_RESULTS}} - run: echo "$HOME/bin" >> $GITHUB_PATH - - name: Run go tests + - name: Download consul working-directory: control-plane run: | mkdir -p $HOME/bin @@ -168,6 +173,10 @@ jobs: unzip consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip -d $HOME/bin && \ rm consul_${{env.CONSUL_ENT_VERSION}}_linux_amd64.zip chmod +x $HOME/bin/consul + + - name: Run go tests + working-directory: control-plane + run: | PACKAGE_NAMES=$(go list ./...) gotestsum --junitfile ${{env.TEST_RESULTS}}/gotestsum-report.xml -- -tags=enterprise -p 4 $PACKAGE_NAMES @@ -207,27 +216,27 @@ jobs: name: consul-k8s_${{ matrix.goos }}_${{ matrix.goarch }}.zip path: control-plane/consul-k8s_${{ matrix.goos }}_${{ matrix.goarch }}.zip - go-fmt-vet-acceptance: - uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests + golangci-lint-acceptance: + uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@crt-build-and-tests with: directory: acceptance go-version: 1.17.2 unit-acceptance-framework: - needs: go-fmt-vet-acceptance + needs: golangci-lint-acceptance uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: acceptance/framework go-version: 1.17.2 - go-fmt-vet-cli: - uses: hashicorp/consul-k8s/.github/workflows/reusable-go-fmt-vet.yml@crt-build-and-tests + golangci-lint-cli: + uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@crt-build-and-tests with: directory: cli go-version: 1.17.2 unit-cli: - needs: go-fmt-vet-cli + needs: golangci-lint-cli uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests with: directory: cli @@ -258,7 +267,7 @@ jobs: # working-directory: control-plane # run: | # unzip consul-k8s_linux_amd64.zip -d ./pkg/bin/linux_amd64 -# make ci.dev-docker +# make ci.dev-docker-github # # acceptance-tproxy: # needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] diff --git a/.github/workflows/golangci-lint-acceptance.yml b/.github/workflows/golangci-lint-acceptance.yml deleted file mode 100644 index d41efb33af..0000000000 --- a/.github/workflows/golangci-lint-acceptance.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: golangci-lint-acceptance -on: - push: - tags: - - v* - branches: - - main - pull_request: -jobs: - golangci: - name: lint-acceptance - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: golangci-lint-acceptance - uses: golangci/golangci-lint-action@v2 - with: - version: v1.41.1 - # Optional: working directory, useful for monorepos - # TODO: we may need to modify this when monorepo comes, it could be helpful for when we test - # only control-plane components in a PR, or some other scenario. - # working-directory: somedir - working-directory: acceptance diff --git a/.github/workflows/golangci-lint-cli.yml b/.github/workflows/golangci-lint-cli.yml deleted file mode 100644 index 50860bbabb..0000000000 --- a/.github/workflows/golangci-lint-cli.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: golangci-lint-cli -on: - push: - tags: - - v* - branches: - - main - pull_request: -jobs: - golangci: - name: lint-cli - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: golangci-lint-cli - uses: golangci/golangci-lint-action@v2 - with: - version: v1.41.1 - # Optional: working directory, useful for monorepos - working-directory: cli diff --git a/.github/workflows/golangci-lint-control-plane.yml b/.github/workflows/golangci-lint-control-plane.yml deleted file mode 100644 index 4112818cb0..0000000000 --- a/.github/workflows/golangci-lint-control-plane.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: golangci-lint-control-plane -on: - push: - tags: - - v* - branches: - - main - pull_request: -jobs: - golangci: - name: lint-control-plane - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: golangci-lint - uses: golangci/golangci-lint-action@v2 - with: - version: v1.41.1 - # Optional: working directory, useful for monorepos - # TODO: we may need to modify this when monorepo comes, it could be helpful for when we test - # only control-plane components in a PR, or some other scenario. - # working-directory: somedir - working-directory: control-plane diff --git a/.github/workflows/reusable-go-fmt-vet.yml b/.github/workflows/reusable-golangci-lint.yml similarity index 66% rename from .github/workflows/reusable-go-fmt-vet.yml rename to .github/workflows/reusable-golangci-lint.yml index e5e602c3ae..f6f6fcac36 100644 --- a/.github/workflows/reusable-go-fmt-vet.yml +++ b/.github/workflows/reusable-golangci-lint.yml @@ -1,4 +1,4 @@ -name: go-fmt-and-vet +name: golangci-lint on: workflow_call: @@ -37,16 +37,8 @@ jobs: working-directory: ${{inputs.directory}} run: go mod download - - name: check go fmt - working-directory: ${{inputs.directory}} - run: | - files=$(go fmt ./...) - if [ -n "$files" ]; then - echo "The following file(s) do not conform to go fmt:" - echo "$files" - exit 1 - fi - - - name: go vet - working-directory: ${{inputs.directory}} - run: go vet ./... + - name: golangci-lint-${{inputs.directory}} + uses: golangci/golangci-lint-action@v2 + with: + version: v1.41.1 + working-directory: ${inputs.directory} diff --git a/.golangci.yml b/.golangci.yml index 99e8b2ee8c..f96c523906 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -3,6 +3,7 @@ linters: enable: - gofmt - godot + - govet # TODO: re-enable things as we have main cleaned up vs the defaults #- stylecheck #- goconst diff --git a/control-plane/Makefile b/control-plane/Makefile index 54654927a4..eb174b3c1c 100644 --- a/control-plane/Makefile +++ b/control-plane/Makefile @@ -27,9 +27,30 @@ CONSUL_K8S_IMAGE_VERSION?=latest ci.dev-tree: @$(SHELL) $(CURDIR)/build-support/scripts/dev.sh $(DEV_PUSH_ARG) -# In Github Actions, the linux binary will be attached from a previous step at pkg/bin/linux_amd64/. This make target +# TODO: Remove this ci.dev-docker target once we move the acceptance tests to Github Actions. +# In CircleCI, the linux binary will be attached from a previous step at pkg/bin/linux_amd64/. This make target # should only run in CI and not locally. ci.dev-docker: + @echo "Pulling consul-k8s container image - $(CONSUL_K8S_IMAGE_VERSION)" + @docker pull hashicorp/consul-k8s:$(CONSUL_K8S_IMAGE_VERSION) >/dev/null #todo change this back after pulling it the first time since the dockerfile is FROM this image + @echo "Building consul-k8s Development container - $(CI_DEV_DOCKER_IMAGE_NAME)" + @docker build -t '$(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT)' \ + --build-arg CONSUL_K8S_IMAGE_VERSION=$(CONSUL_K8S_IMAGE_VERSION) \ + --label COMMIT_SHA=$(CIRCLE_SHA1) \ + --label PULL_REQUEST=$(CIRCLE_PULL_REQUEST) \ + --label CIRCLE_BUILD_URL=$(CIRCLE_BUILD_URL) \ + $(CI_DEV_DOCKER_WORKDIR) -f $(CURDIR)/build-support/docker/Dev.dockerfile + @echo $(DOCKER_PASS) | docker login -u="$(DOCKER_USER)" --password-stdin + @echo "Pushing dev image to: https://cloud.docker.com/u/$(CI_DEV_DOCKER_NAMESPACE)/repository/docker/$(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME)" + @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) +ifeq ($(CIRCLE_BRANCH), main) + @docker tag $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):$(GIT_COMMIT) $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest + @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest +endif + +# In Github Actions, the linux binary will be attached from a previous step at pkg/bin/linux_amd64/. This make target +# should only run in CI and not locally. +ci.dev-docker-github: @echo "Pulling consul-k8s container image - $(CONSUL_K8S_IMAGE_VERSION)" @docker pull hashicorp/consul-k8s:$(CONSUL_K8S_IMAGE_VERSION) >/dev/null #todo change this back after pulling it the first time since the dockerfile is FROM this image @echo "Building consul-k8s Development container - $(CI_DEV_DOCKER_IMAGE_NAME)" @@ -47,4 +68,4 @@ ifeq ($(GITHUB_REF_NAME), main) @docker push $(CI_DEV_DOCKER_NAMESPACE)/$(CI_DEV_DOCKER_IMAGE_NAME):latest endif -.PHONY: ci.dev-tree ci.dev-docker +.PHONY: ci.dev-tree ci.dev-docker ci.dev-docker-github From c9cdb3dce00e2af0229644301a34c38f464c255e Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 10 Mar 2022 11:01:49 -0500 Subject: [PATCH 407/418] missing some brackets and should not have to install everything --- .github/workflows/reusable-golangci-lint.yml | 21 +------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/.github/workflows/reusable-golangci-lint.yml b/.github/workflows/reusable-golangci-lint.yml index f6f6fcac36..d82ec5513d 100644 --- a/.github/workflows/reusable-golangci-lint.yml +++ b/.github/workflows/reusable-golangci-lint.yml @@ -18,27 +18,8 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - - name: Setup go - uses: actions/setup-go@v2 - with: - go-version: ${{inputs.go-version}} - - - name: Setup go mod cache - uses: actions/cache@v2 - with: - path: | - ~/.cache/go-build - ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-go- - - - name: go mod download - working-directory: ${{inputs.directory}} - run: go mod download - - name: golangci-lint-${{inputs.directory}} uses: golangci/golangci-lint-action@v2 with: version: v1.41.1 - working-directory: ${inputs.directory} + working-directory: ${{inputs.directory}} From 11d05ada6b8a85e5d2267ff8d2d6ff51ef9be2f1 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 10 Mar 2022 11:33:49 -0500 Subject: [PATCH 408/418] a small workaround to get pipelines working --- .github/workflows/build-and-test.yml | 2 ++ .github/workflows/reusable-golangci-lint.yml | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 1440bbc865..d511ec82bf 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -40,6 +40,8 @@ jobs: with: directory: hack/helm-reference-gen go-version: 1.17.2 + #TODO: This is a workaround in order to get pipelines working. godot and staticcheck fail for helm-reference-gen + args: "--no-config --disable-all --enable gofmt,govet" unit-helm-gen: needs: [golangci-lint-helm-gen, validate-helm-gen] diff --git a/.github/workflows/reusable-golangci-lint.yml b/.github/workflows/reusable-golangci-lint.yml index d82ec5513d..4ae27a02e0 100644 --- a/.github/workflows/reusable-golangci-lint.yml +++ b/.github/workflows/reusable-golangci-lint.yml @@ -9,6 +9,9 @@ on: go-version: required: true type: string + args: + required: false + type: string jobs: a: @@ -23,3 +26,4 @@ jobs: with: version: v1.41.1 working-directory: ${{inputs.directory}} + args: ${{inputs.args}} From 5289184dc00e5d8805e103abb4adfe9bed838042 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 10 Mar 2022 14:52:53 -0500 Subject: [PATCH 409/418] try job as a name --- .github/workflows/reusable-golangci-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-golangci-lint.yml b/.github/workflows/reusable-golangci-lint.yml index 4ae27a02e0..5475e7ae75 100644 --- a/.github/workflows/reusable-golangci-lint.yml +++ b/.github/workflows/reusable-golangci-lint.yml @@ -14,7 +14,7 @@ on: type: string jobs: - a: + job: runs-on: ubuntu-latest steps: From cdc9ed5df3bce4a07c2313fdd15239a988b4ae19 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 10 Mar 2022 14:55:06 -0500 Subject: [PATCH 410/418] use job as a name everywhere for reusable workflows --- .github/workflows/reusable-acceptance.yml | 2 +- .github/workflows/reusable-unit.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-acceptance.yml b/.github/workflows/reusable-acceptance.yml index 24e6dfdab2..56389bb346 100644 --- a/.github/workflows/reusable-acceptance.yml +++ b/.github/workflows/reusable-acceptance.yml @@ -37,7 +37,7 @@ env: CONSUL_ENT_LICENSE: ${{ secrets.CONSUL_ENT_LICENSE }} jobs: - a: + job: runs-on: ubuntu-latest strategy: matrix: diff --git a/.github/workflows/reusable-unit.yml b/.github/workflows/reusable-unit.yml index 7e25022a65..1183e1922c 100644 --- a/.github/workflows/reusable-unit.yml +++ b/.github/workflows/reusable-unit.yml @@ -16,7 +16,7 @@ env: GOTESTSUM_VERSION: 1.6.4 jobs: - a: + job: runs-on: ubuntu-latest steps: From 8294f353d78977a368a48de0b351c01b5b8ebd78 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Thu, 10 Mar 2022 15:12:23 -0500 Subject: [PATCH 411/418] set branch to main (tests will fail) --- .github/workflows/build-and-test.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index d511ec82bf..8ebb4fb3b2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -36,7 +36,7 @@ jobs: go run ./... -validate golangci-lint-helm-gen: - uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@crt-build-and-tests + uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@main with: directory: hack/helm-reference-gen go-version: 1.17.2 @@ -45,7 +45,7 @@ jobs: unit-helm-gen: needs: [golangci-lint-helm-gen, validate-helm-gen] - uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests + uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@main with: directory: hack/helm-reference-gen go-version: 1.17.2 @@ -82,7 +82,7 @@ jobs: run: go run hack/lint-api-new-client/main.go golangci-lint-control-plane: - uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@crt-build-and-tests + uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@main with: directory: control-plane go-version: 1.17.2 @@ -219,27 +219,27 @@ jobs: path: control-plane/consul-k8s_${{ matrix.goos }}_${{ matrix.goarch }}.zip golangci-lint-acceptance: - uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@crt-build-and-tests + uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@main with: directory: acceptance go-version: 1.17.2 unit-acceptance-framework: needs: golangci-lint-acceptance - uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests + uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@main with: directory: acceptance/framework go-version: 1.17.2 golangci-lint-cli: - uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@crt-build-and-tests + uses: hashicorp/consul-k8s/.github/workflows/reusable-golangci-lint.yml@main with: directory: cli go-version: 1.17.2 unit-cli: needs: golangci-lint-cli - uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@crt-build-and-tests + uses: hashicorp/consul-k8s/.github/workflows/reusable-unit.yml@main with: directory: cli go-version: 1.17.2 @@ -274,7 +274,7 @@ jobs: # acceptance-tproxy: # needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] # needs: dev-upload-docker -# uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests +# uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@main # with: # name: acceptance-tproxy # directory: acceptance/tests @@ -287,7 +287,7 @@ jobs: # acceptance: # #needs: [unit-cli, dev-upload-docker, unit-acceptance-framework, unit-test-helm-templates] # needs: dev-upload-docker -# uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@crt-build-and-tests +# uses: hashicorp/consul-k8s/.github/workflows/reusable-acceptance.yml@main # with: # name: acceptance # directory: acceptance/tests From abe9b40043b99e2b88051979f954b5d24aa503e0 Mon Sep 17 00:00:00 2001 From: Nathan Coleman Date: Thu, 10 Mar 2022 17:12:50 -0500 Subject: [PATCH 412/418] Allow API Gateway controller to get Namespaces (#1092) * Allow API Gateway controller to get Namespaces * Add CHANGELOG entry * Update CHANGELOG.md Co-authored-by: Kyle Schochenmaier Co-authored-by: Kyle Schochenmaier --- CHANGELOG.md | 2 ++ .../templates/api-gateway-controller-clusterrole.yaml | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b93e0074d..e17bca969c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ BREAKING CHANGES: IMPROVEMENTS: * Control Plane * Upgrade Docker image Alpine version from 3.14 to 3.15. [[GH-1058](https://github.com/hashicorp/consul-k8s/pull/1058)] +* Helm + * API Gateway: Allow controller to read Kubernetes namespaces in order to determine if route is allowed for gateway. [[GH-1092](https://github.com/hashicorp/consul-k8s/pull/1092)] ## 0.41.1 (February 24, 2022) diff --git a/charts/consul/templates/api-gateway-controller-clusterrole.yaml b/charts/consul/templates/api-gateway-controller-clusterrole.yaml index 143d7a09e6..9f9acb2e86 100644 --- a/charts/consul/templates/api-gateway-controller-clusterrole.yaml +++ b/charts/consul/templates/api-gateway-controller-clusterrole.yaml @@ -72,6 +72,14 @@ rules: verbs: - create - patch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch - apiGroups: - "" resources: From 879b0419325e74e265c43ea53230d7f1d1c27ce3 Mon Sep 17 00:00:00 2001 From: John Murret Date: Fri, 11 Mar 2022 14:21:34 -0700 Subject: [PATCH 413/418] Updating GitHub Actions config to use Consul v1.11.4 (#1096) --- .github/workflows/build-and-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8ebb4fb3b2..21a9892005 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -4,8 +4,8 @@ on: env: TEST_RESULTS: /tmp/test-results # path to where test results are saved - CONSUL_VERSION: 1.11.2 # Consul's OSS version to use in tests - CONSUL_ENT_VERSION: 1.11.2+ent # Consul's enterprise version to use in tests + CONSUL_VERSION: 1.11.4 # Consul's OSS version to use in tests + CONSUL_ENT_VERSION: 1.11.4+ent # Consul's enterprise version to use in tests GOTESTSUM_VERSION: 1.6.4 # You cannot use environment variables with workflows. The gotestsum version is hardcoded in the reusable workflows too. jobs: From fbf493a092bc551e7d2a96770b1a3ef248948943 Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Mon, 14 Mar 2022 15:26:50 -0700 Subject: [PATCH 414/418] Give error if imageK8s is used (#1087) --- charts/consul/templates/client-daemonset.yaml | 1 + charts/consul/test/unit/client-daemonset.bats | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/charts/consul/templates/client-daemonset.yaml b/charts/consul/templates/client-daemonset.yaml index 170aa9e4a7..d5d4a07de0 100644 --- a/charts/consul/templates/client-daemonset.yaml +++ b/charts/consul/templates/client-daemonset.yaml @@ -1,3 +1,4 @@ +{{- if .Values.global.imageK8s }}{{ fail "global.imageK8s is not a valid key, use global.imageK8S (note the capital 'S')" }}{{ end -}} {{- if (or (and (ne (.Values.client.enabled | toString) "-") .Values.client.enabled) (and (eq (.Values.client.enabled | toString) "-") .Values.global.enabled)) }} {{- if (and (and .Values.global.tls.enabled .Values.global.tls.httpsOnly) (and .Values.global.metrics.enabled .Values.global.metrics.enableAgentMetrics))}}{{ fail "global.metrics.enableAgentMetrics cannot be enabled if TLS (HTTPS only) is enabled" }}{{ end -}} {{- $serverEnabled := (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) -}} diff --git a/charts/consul/test/unit/client-daemonset.bats b/charts/consul/test/unit/client-daemonset.bats index b596f857e0..eb1c2b5048 100755 --- a/charts/consul/test/unit/client-daemonset.bats +++ b/charts/consul/test/unit/client-daemonset.bats @@ -1952,4 +1952,18 @@ rollingUpdate: . | tee /dev/stderr | yq -r '.spec.template.metadata.annotations.foo' | tee /dev/stderr) [ "${actual}" = "bar" ] +} + +#-------------------------------------------------------------------- +# global.imageK8s + +@test "client/DaemonSet: errors on global.imageK8s" { + cd `chart_dir` + run helm template \ + -s templates/client-daemonset.yaml \ + --set 'global.imageK8s=something' \ + . + + [ "$status" -eq 1 ] + [[ "$output" =~ "global.imageK8s is not a valid key, use global.imageK8S (note the capital 'S')" ]] } \ No newline at end of file From 320ac1e816094a124711b9ddab1c7816818f8553 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Tue, 15 Mar 2022 17:05:18 -0400 Subject: [PATCH 415/418] Use SHA instead of latest for acceptance tests (#1099) --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4653e676d5..99f28279e0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,7 +70,7 @@ commands: type: string consul-k8s-image: type: string - default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:latest" + default: "docker.mirror.hashicorp.services/hashicorpdev/consul-k8s-control-plane:$(git rev-parse --short HEAD)" go-path: type: string default: "/home/circleci/.go_workspace" From f8a4c2969d909ecefdf57d756df894c95a388ec8 Mon Sep 17 00:00:00 2001 From: Iryna Shustava Date: Tue, 15 Mar 2022 15:46:50 -0600 Subject: [PATCH 416/418] Update comment for annotationService to reflect the docs (#1100) Fixes #1097 --- control-plane/connect-inject/annotations.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/control-plane/connect-inject/annotations.go b/control-plane/connect-inject/annotations.go index ec723d80fd..2189a9f31c 100644 --- a/control-plane/connect-inject/annotations.go +++ b/control-plane/connect-inject/annotations.go @@ -16,8 +16,8 @@ const ( // be set to a truthy or falsy value, as parseable by strconv.ParseBool. annotationInject = "consul.hashicorp.com/connect-inject" - // annotationService is the name of the service to proxy. This defaults - // to the name of the first container. + // annotationService is the name of the service to proxy. + // This defaults to the name of the Kubernetes service associated with the pod. annotationService = "consul.hashicorp.com/connect-service" // annotationPort is the name or value of the port to proxy incoming From 639e8ccf251b935922dd5f65389071d0989f619d Mon Sep 17 00:00:00 2001 From: Luke Kysow <1034429+lkysow@users.noreply.github.com> Date: Mon, 21 Mar 2022 12:15:39 -0700 Subject: [PATCH 417/418] Fix PSPs for clients/mesh gateways for hostPorts (#1090) When hostNetwork is true, Kube sets all container ports as host ports. --- CHANGELOG.md | 4 +++ .../templates/client-podsecuritypolicy.yaml | 6 ++++- .../mesh-gateway-podsecuritypolicy.yaml | 8 ++++++ .../test/unit/client-podsecuritypolicy.bats | 14 ++++++++++ .../unit/mesh-gateway-podsecuritypolicy.bats | 26 +++++++++++++++++++ 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e17bca969c..8643d3dce7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ IMPROVEMENTS: * Helm * API Gateway: Allow controller to read Kubernetes namespaces in order to determine if route is allowed for gateway. [[GH-1092](https://github.com/hashicorp/consul-k8s/pull/1092)] +BUG FIXES: +* Helm + * Fix PodSecurityPolicies for clients/mesh gateways when hostNetwork is used. [[GH-1090](https://github.com/hashicorp/consul-k8s/pull/1090)] + ## 0.41.1 (February 24, 2022) BUG FIXES: diff --git a/charts/consul/templates/client-podsecuritypolicy.yaml b/charts/consul/templates/client-podsecuritypolicy.yaml index 15950f75fd..0121bdf586 100644 --- a/charts/consul/templates/client-podsecuritypolicy.yaml +++ b/charts/consul/templates/client-podsecuritypolicy.yaml @@ -49,10 +49,14 @@ spec: - min: 8502 max: 8502 {{- end }} - {{- if .Values.client.exposeGossipPorts }} + {{- if (or .Values.client.exposeGossipPorts .Values.client.hostNetwork) }} - min: 8301 max: 8301 {{- end }} + {{- if .Values.client.hostNetwork }} + - min: 8600 + max: 8600 + {{- end }} hostIPC: false hostPID: false runAsUser: diff --git a/charts/consul/templates/mesh-gateway-podsecuritypolicy.yaml b/charts/consul/templates/mesh-gateway-podsecuritypolicy.yaml index 5257b79ed4..b5bbb2fa03 100644 --- a/charts/consul/templates/mesh-gateway-podsecuritypolicy.yaml +++ b/charts/consul/templates/mesh-gateway-podsecuritypolicy.yaml @@ -30,6 +30,14 @@ spec: {{- else }} hostNetwork: false {{- end }} + hostPorts: + {{- if .Values.meshGateway.hostPort }} + - min: {{ .Values.meshGateway.hostPort }} + max: {{ .Values.meshGateway.hostPort }} + {{- else if .Values.meshGateway.hostNetwork }} + - min: {{ .Values.meshGateway.containerPort }} + max: {{ .Values.meshGateway.containerPort }} + {{- end }} hostIPC: false hostPID: false runAsUser: diff --git a/charts/consul/test/unit/client-podsecuritypolicy.bats b/charts/consul/test/unit/client-podsecuritypolicy.bats index 701bd3a850..a37d4ec147 100644 --- a/charts/consul/test/unit/client-podsecuritypolicy.bats +++ b/charts/consul/test/unit/client-podsecuritypolicy.bats @@ -140,7 +140,21 @@ load _helpers [ "${actual}" = "true" ] } +@test "client/PodSecurityPolicy: hostPorts when hostNetwork=true" { + # hostPorts must be allowed because when Kube sets all container ports as host ports when hostNetwork is true. + cd `chart_dir` + local actual=$(helm template \ + -s templates/client-podsecuritypolicy.yaml \ + --set 'global.enablePodSecurityPolicies=true' \ + --set 'client.hostNetwork=true' \ + . | tee /dev/stderr | + yq -c '.spec.hostPorts' | tee /dev/stderr) + [ "${actual}" = '[{"min":8500,"max":8500},{"min":8502,"max":8502},{"min":8301,"max":8301},{"min":8600,"max":8600}]' ] +} + +#-------------------------------------------------------------------- # client.hostNetwork = false + @test "client/PodSecurityPolicy: enabled with global.enablePodSecurityPolicies=true and default hostNetwork=false" { cd `chart_dir` local actual=$(helm template \ diff --git a/charts/consul/test/unit/mesh-gateway-podsecuritypolicy.bats b/charts/consul/test/unit/mesh-gateway-podsecuritypolicy.bats index 66e71d97bb..22565c9b02 100644 --- a/charts/consul/test/unit/mesh-gateway-podsecuritypolicy.bats +++ b/charts/consul/test/unit/mesh-gateway-podsecuritypolicy.bats @@ -45,3 +45,29 @@ load _helpers yq '.spec.hostNetwork' | tee /dev/stderr) [ "${actual}" = "true" ] } + +@test "meshGateway/PodSecurityPolicy: hostPorts are allowed when setting hostPort" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/mesh-gateway-podsecuritypolicy.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.enablePodSecurityPolicies=true' \ + --set 'meshGateway.hostPort=9999' \ + . | tee /dev/stderr | + yq -c '.spec.hostPorts' | tee /dev/stderr) + [ "${actual}" = '[{"min":9999,"max":9999}]' ] +} + +@test "meshGateway/PodSecurityPolicy: hostPorts are allowed when hostNetwork=true" { + cd `chart_dir` + local actual=$(helm template \ + -s templates/mesh-gateway-podsecuritypolicy.yaml \ + --set 'meshGateway.enabled=true' \ + --set 'connectInject.enabled=true' \ + --set 'global.enablePodSecurityPolicies=true' \ + --set 'meshGateway.hostNetwork=true' \ + . | tee /dev/stderr | + yq -c '.spec.hostPorts' | tee /dev/stderr) + [ "${actual}" = '[{"min":8443,"max":8443}]' ] +} From 45ad8dd3cd2a1ba53b6745c1628f199ca8740019 Mon Sep 17 00:00:00 2001 From: Curt Bushko Date: Mon, 21 Mar 2022 16:01:51 -0400 Subject: [PATCH 418/418] bug: exec'ing into consul server container no longer works when tls is enabled (#1103) - add bats tests for CONSUL_CACERT in server - add acceptance vault test to make sure consul members command works --- acceptance/tests/vault/vault_test.go | 15 +++++++++++++++ .../consul/templates/server-statefulset.yaml | 4 ++++ .../consul/test/unit/server-statefulset.bats | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/acceptance/tests/vault/vault_test.go b/acceptance/tests/vault/vault_test.go index ed4410999b..dcf151f231 100644 --- a/acceptance/tests/vault/vault_test.go +++ b/acceptance/tests/vault/vault_test.go @@ -1,14 +1,18 @@ package vault import ( + "context" + "fmt" "testing" + terratestLogger "github.com/gruntwork-io/terratest/modules/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/consul" "github.com/hashicorp/consul-k8s/acceptance/framework/helpers" "github.com/hashicorp/consul-k8s/acceptance/framework/k8s" "github.com/hashicorp/consul-k8s/acceptance/framework/logger" "github.com/hashicorp/consul-k8s/acceptance/framework/vault" "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const staticClientName = "static-client" @@ -111,6 +115,17 @@ func TestVault(t *testing.T) { require.NoError(t, err) require.Equal(t, caConfig.Provider, "vault") + // Validate that consul sever is running correctly and the consul members command works + tokenSecret, err := ctx.KubernetesClient(t).CoreV1().Secrets(ns).Get(context.Background(), fmt.Sprintf("%s-consul-bootstrap-acl-token", consulReleaseName), metav1.GetOptions{}) + require.NoError(t, err) + token := string(tokenSecret.Data["token"]) + + logger.Log(t, "Confirming that we can run Consul commands when exec'ing into server container") + membersOutput, err := k8s.RunKubectlAndGetOutputWithLoggerE(t, ctx.KubectlOptions(t), terratestLogger.Discard, "exec", fmt.Sprintf("%s-consul-server-0", consulReleaseName), "-c", "consul", "--", "sh", "-c", fmt.Sprintf("CONSUL_HTTP_TOKEN=%s consul members", token)) + logger.Logf(t, "Members: \n%s", membersOutput) + require.NoError(t, err) + require.Contains(t, membersOutput, fmt.Sprintf("%s-consul-server-0", consulReleaseName)) + if cfg.EnableEnterprise { // Validate that the enterprise license is set correctly. logger.Log(t, "Validating the enterprise license has been set correctly.") diff --git a/charts/consul/templates/server-statefulset.yaml b/charts/consul/templates/server-statefulset.yaml index e2eda87dc5..0d669f3a81 100644 --- a/charts/consul/templates/server-statefulset.yaml +++ b/charts/consul/templates/server-statefulset.yaml @@ -223,7 +223,11 @@ spec: - name: CONSUL_HTTP_ADDR value: https://localhost:8501 - name: CONSUL_CACERT + {{- if .Values.global.secretsBackend.vault.enabled }} + value: /vault/secrets/serverca.crt + {{- else }} value: /consul/tls/ca/tls.crt + {{- end }} {{- end }} {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: CONSUL_LICENSE_PATH diff --git a/charts/consul/test/unit/server-statefulset.bats b/charts/consul/test/unit/server-statefulset.bats index 45aa6ea443..fc08cdcc3f 100755 --- a/charts/consul/test/unit/server-statefulset.bats +++ b/charts/consul/test/unit/server-statefulset.bats @@ -1113,6 +1113,25 @@ load _helpers [ "${actual}" = "/consul/tls/ca/tls.crt" ] } +@test "server/StatefulSet: sets Consul environment variables when global.tls.enabled and global.secretsBackend.vault.enabled" { + cd `chart_dir` + local env=$(helm template \ + -s templates/server-statefulset.yaml \ + --set 'global.tls.enabled=true' \ + --set 'global.tls.enableAutoEncrypt=true' \ + --set 'global.secretsBackend.vault.enabled=true' \ + --set 'global.secretsBackend.vault.consulClientRole=foo' \ + --set 'global.secretsBackend.vault.consulServerRole=test' \ + --set 'global.secretsBackend.vault.consulCARole=test' \ + --set 'global.tls.caCert.secretName=pki_int/cert/ca' \ + . | tee /dev/stderr | + yq -r '.spec.template.spec.containers[0].env[]' | tee /dev/stderr) + + local actual + actual=$(echo $env | jq -r '. | select(.name == "CONSUL_CACERT") | .value' | tee /dev/stderr) + [ "${actual}" = "/vault/secrets/serverca.crt" ] +} + @test "server/StatefulSet: sets verify_* flags to true by default when global.tls.enabled" { cd `chart_dir` local command=$(helm template \