diff --git a/charts/consul/test/unit/gateway-resources-configmap.bats b/charts/consul/test/unit/gateway-resources-configmap.bats index 4b76e55d39..e827644792 100644 --- a/charts/consul/test/unit/gateway-resources-configmap.bats +++ b/charts/consul/test/unit/gateway-resources-configmap.bats @@ -73,6 +73,117 @@ target=templates/gateway-resources-configmap.yaml [ "$resources" != null ] } +#-------------------------------------------------------------------- +# Mesh Gateway logLevel configuration + +@test "gateway-resources/ConfigMap: Mesh Gateway logLevel default configuration" { + cd `chart_dir` + local config=$(helm template \ + -s $target \ + --set 'meshGateway.enabled=true' \ + --set 'global.experiments[0]=resource-apis' \ + --set 'ui.enabled=false' \ + . | tee /dev/stderr | + yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) + + local actual=$(echo "$config" | yq -r '.container.consul.logging.level') + [ "${actual}" = 'info' ] + + local actual=$(echo "$config" | yq -r '.initContainer.consul.logging.level') + [ "${actual}" = 'info' ] +} + + +@test "gateway-resources/ConfigMap: Mesh Gateway logLevel custom global configuration" { + cd `chart_dir` + local config=$(helm template \ + -s $target \ + --set 'meshGateway.enabled=true' \ + --set 'global.experiments[0]=resource-apis' \ + --set 'ui.enabled=false' \ + --set 'global.logLevel=debug' \ + . | tee /dev/stderr | + yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) + + local actual=$(echo "$config" | yq -r '.container.consul.logging.level') + [ "${actual}" = 'debug' ] + + local actual=$(echo "$config" | yq -r '.initContainer.consul.logging.level') + [ "${actual}" = 'debug' ] +} + +@test "gateway-resources/ConfigMap: Mesh Gateway logLevel custom meshGateway configuration" { + cd `chart_dir` + local config=$(helm template \ + -s $target \ + --set 'meshGateway.enabled=true' \ + --set 'global.experiments[0]=resource-apis' \ + --set 'ui.enabled=false' \ + --set 'meshGateway.logLevel=debug' \ + . | tee /dev/stderr | + yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) + + local actual=$(echo "$config" | yq -r '.container.consul.logging.level') + [ "${actual}" = 'debug' ] + + local actual=$(echo "$config" | yq -r '.initContainer.consul.logging.level') + [ "${actual}" = 'debug' ] +} + +@test "gateway-resources/ConfigMap: Mesh Gateway logLevel custom meshGateway configuration overrides global configuration" { + cd `chart_dir` + local config=$(helm template \ + -s $target \ + --set 'meshGateway.enabled=true' \ + --set 'global.experiments[0]=resource-apis' \ + --set 'ui.enabled=false' \ + --set 'global.logLevel=error' \ + --set 'meshGateway.logLevel=debug' \ + . | tee /dev/stderr | + yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment' | tee /dev/stderr) + + local actual=$(echo "$config" | yq -r '.container.consul.logging.level') + [ "${actual}" = 'debug' ] + + local actual=$(echo "$config" | yq -r '.initContainer.consul.logging.level') + [ "${actual}" = 'debug' ] +} + +#-------------------------------------------------------------------- +# Mesh Gateway Extra Labels configuration + +@test "gateway-resources/ConfigMap: Mesh Gateway gets Extra Labels when set" { + cd `chart_dir` + local actual=$(helm template \ + -s $target \ + --set 'connectInject.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'global.experiments[0]=resource-apis' \ + --set 'ui.enabled=false' \ + --set 'global.extraLabels.foo'='bar' \ + . | tee /dev/stderr | + yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment.labels.set.foo' | tee /dev/stderr + ) + [ "$actual" = 'bar' ] +} + +#-------------------------------------------------------------------- +# Mesh Gateway annotations configuration + +@test "gateway-resources/ConfigMap: Mesh Gateway gets annotations when set" { + cd `chart_dir` + local actual=$(helm template \ + -s $target \ + --set 'connectInject.enabled=true' \ + --set 'meshGateway.enabled=true' \ + --set 'global.experiments[0]=resource-apis' \ + --set 'ui.enabled=false' \ + --set 'meshGateway.annotations.foo'='bar' \ + . | tee /dev/stderr | + yq -r '.data["config.yaml"]' | yq -r '.gatewayClassConfigs[0].spec.deployment.annotations.set.foo' | tee /dev/stderr + ) + [ "$actual" = 'bar' ] +} #-------------------------------------------------------------------- # Mesh Gateway WAN Address configuration diff --git a/control-plane/gateways/builder.go b/control-plane/gateways/builder.go index 53dcbe03ec..e43e6dd890 100644 --- a/control-plane/gateways/builder.go +++ b/control-plane/gateways/builder.go @@ -7,12 +7,17 @@ import ( meshv2beta1 "github.com/hashicorp/consul-k8s/control-plane/api/mesh/v2beta1" ) +// meshGatewayBuilder is a helper struct for building the Kubernetes resources for a mesh gateway. +// This includes Deployment, Role, Service, and ServiceAccount resources. +// Configuration is combined from the MeshGateway, GatewayConfig, and GatewayClassConfig. type meshGatewayBuilder struct { gateway *meshv2beta1.MeshGateway config GatewayConfig gcc *meshv2beta1.GatewayClassConfig } +// NewMeshGatewayBuilder returns a new meshGatewayBuilder for the given MeshGateway, +// GatewayConfig, and GatewayClassConfig. func NewMeshGatewayBuilder(gateway *meshv2beta1.MeshGateway, gatewayConfig GatewayConfig, gatewayClassConfig *meshv2beta1.GatewayClassConfig) *meshGatewayBuilder { return &meshGatewayBuilder{ gateway: gateway, diff --git a/control-plane/gateways/constants.go b/control-plane/gateways/constants.go new file mode 100644 index 0000000000..7ca89ef1f7 --- /dev/null +++ b/control-plane/gateways/constants.go @@ -0,0 +1,33 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package gateways + +const ( + // General environment variables. + envPodName = "POD_NAME" + envPodNamespace = "POD_NAMESPACE" + envNodeName = "NODE_NAME" + envTmpDir = "TMPDIR" + + // Dataplane Configuration Environment variables. + envDPProxyId = "DP_PROXY_ID" + envDPCredentialLoginMeta = "DP_CREDENTIAL_LOGIN_META" + envDPServiceNodeName = "DP_SERVICE_NODE_NAME" + + // Init Container Configuration Environment variables. + envConsulAddresses = "CONSUL_ADDRESSES" + envConsulGRPCPort = "CONSUL_GRPC_PORT" + envConsulHTTPPort = "CONSUL_HTTP_PORT" + envConsulAPITimeout = "CONSUL_API_TIMEOUT" + envConsulNodeName = "CONSUL_NODE_NAME" + envConsulLoginAuthMethod = "CONSUL_LOGIN_AUTH_METHOD" + envConsulLoginBearerTokenFile = "CONSUL_LOGIN_BEARER_TOKEN_FILE" + envConsulLoginMeta = "CONSUL_LOGIN_META" + envConsulLoginPartition = "CONSUL_LOGIN_PARTITION" + envConsulNamespace = "CONSUL_NAMESPACE" + envConsulPartition = "CONSUL_PARTITION" + + // defaultBearerTokenFile is the default location where the init container will store the bearer token for the dataplane container to read. + defaultBearerTokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token" +) diff --git a/control-plane/gateways/deployment.go b/control-plane/gateways/deployment.go index eb0d7e89f5..bf944503b8 100644 --- a/control-plane/gateways/deployment.go +++ b/control-plane/gateways/deployment.go @@ -51,7 +51,7 @@ func (b *meshGatewayBuilder) deploymentSpec() (*appsv1.DeploymentSpec, error) { return nil, err } - container, err := consulDataplaneContainer(b.config, containerConfig, b.gateway.Name, b.gateway.Namespace) + container, err := b.consulDataplaneContainer(containerConfig) if err != nil { return nil, err } diff --git a/control-plane/gateways/deployment_dataplane_container.go b/control-plane/gateways/deployment_dataplane_container.go index 9e34c24b52..967c8b6f1e 100644 --- a/control-plane/gateways/deployment_dataplane_container.go +++ b/control-plane/gateways/deployment_dataplane_container.go @@ -27,7 +27,7 @@ const ( volumeName = "consul-mesh-inject-data" ) -func consulDataplaneContainer(config GatewayConfig, containerConfig v2beta1.GatewayClassContainerConfig, name, namespace string) (corev1.Container, error) { +func (b *meshGatewayBuilder) consulDataplaneContainer(containerConfig v2beta1.GatewayClassContainerConfig) (corev1.Container, error) { // Extract the service account token's volume mount. var ( err error @@ -36,11 +36,11 @@ func consulDataplaneContainer(config GatewayConfig, containerConfig v2beta1.Gate resources := containerConfig.Resources - if config.AuthMethod != "" { + if b.config.AuthMethod != "" { bearerTokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token" } - args, err := getDataplaneArgs(namespace, config, bearerTokenFile, name) + args, err := b.dataplaneArgs(bearerTokenFile) if err != nil { return corev1.Container{}, err } @@ -56,8 +56,8 @@ func consulDataplaneContainer(config GatewayConfig, containerConfig v2beta1.Gate } container := corev1.Container{ - Name: name, - Image: config.ImageDataplane, + Name: b.gateway.Name, + Image: b.config.ImageDataplane, // We need to set tmp dir to an ephemeral volume that we're mounting so that // consul-dataplane can write files to it. Otherwise, it wouldn't be able to @@ -66,23 +66,23 @@ func consulDataplaneContainer(config GatewayConfig, containerConfig v2beta1.Gate // TODO(nathancoleman): I don't believe consul-dataplane needs to write anymore, investigate. Env: []corev1.EnvVar{ { - Name: "DP_PROXY_ID", + Name: envDPProxyId, ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.name"}, }, }, { - Name: "POD_NAMESPACE", + Name: envPodNamespace, ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.namespace"}, }, }, { - Name: "TMPDIR", + Name: envTmpDir, Value: constants.MeshV2VolumePath, }, { - Name: "NODE_NAME", + Name: envNodeName, ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "spec.nodeName", @@ -90,15 +90,11 @@ func consulDataplaneContainer(config GatewayConfig, containerConfig v2beta1.Gate }, }, { - Name: "DP_CREDENTIAL_LOGIN_META", + Name: envDPCredentialLoginMeta, Value: "pod=$(POD_NAMESPACE)/$(DP_PROXY_ID)", }, { - Name: "DP_CREDENTIAL_LOGIN_META1", - Value: "pod=$(POD_NAMESPACE)/$(DP_PROXY_ID)", - }, - { - Name: "DP_SERVICE_NODE_NAME", + Name: envDPServiceNodeName, Value: "$(NODE_NAME)-virtual", }, }, @@ -157,36 +153,36 @@ func consulDataplaneContainer(config GatewayConfig, containerConfig v2beta1.Gate return container, nil } -func getDataplaneArgs(namespace string, config GatewayConfig, bearerTokenFile string, name string) ([]string, error) { +func (b *meshGatewayBuilder) dataplaneArgs(bearerTokenFile string) ([]string, error) { args := []string{ - "-addresses", config.ConsulConfig.Address, - "-grpc-port=" + strconv.Itoa(config.ConsulConfig.GRPCPort), - "-log-level=" + config.LogLevel, - "-log-json=" + strconv.FormatBool(config.LogJSON), + "-addresses", b.config.ConsulConfig.Address, + "-grpc-port=" + strconv.Itoa(b.config.ConsulConfig.GRPCPort), + "-log-level=" + b.logLevelForDataplaneContainer(), + "-log-json=" + strconv.FormatBool(b.config.LogJSON), "-envoy-concurrency=" + defaultEnvoyProxyConcurrency, } - consulNamespace := namespaces.ConsulNamespace(namespace, config.ConsulTenancyConfig.EnableConsulNamespaces, config.ConsulTenancyConfig.ConsulDestinationNamespace, config.ConsulTenancyConfig.EnableConsulNamespaces, config.ConsulTenancyConfig.NSMirroringPrefix) + consulNamespace := namespaces.ConsulNamespace(b.gateway.Namespace, b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.ConsulDestinationNamespace, b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.NSMirroringPrefix) - if config.AuthMethod != "" { + if b.config.AuthMethod != "" { args = append(args, "-credential-type=login", - "-login-auth-method="+config.AuthMethod, + "-login-auth-method="+b.config.AuthMethod, "-login-bearer-token-path="+bearerTokenFile, - "-login-meta="+fmt.Sprintf("gateway=%s/%s", namespace, name), + "-login-meta="+fmt.Sprintf("gateway=%s/%s", b.gateway.Namespace, b.gateway.Name), ) - if config.ConsulTenancyConfig.ConsulPartition != "" { - args = append(args, "-login-partition="+config.ConsulTenancyConfig.ConsulPartition) + if b.config.ConsulTenancyConfig.ConsulPartition != "" { + args = append(args, "-login-partition="+b.config.ConsulTenancyConfig.ConsulPartition) } } - if config.ConsulTenancyConfig.EnableConsulNamespaces { + if b.config.ConsulTenancyConfig.EnableConsulNamespaces { args = append(args, "-service-namespace="+consulNamespace) } - if config.ConsulTenancyConfig.ConsulPartition != "" { - args = append(args, "-service-partition="+config.ConsulTenancyConfig.ConsulPartition) + if b.config.ConsulTenancyConfig.ConsulPartition != "" { + args = append(args, "-service-partition="+b.config.ConsulTenancyConfig.ConsulPartition) } - args = append(args, buildTLSArgs(config)...) + args = append(args, buildTLSArgs(b.config)...) // Configure the readiness port on the dataplane sidecar if proxy health checks are enabled. args = append(args, fmt.Sprintf("%s=%d", "-envoy-ready-bind-port", constants.ProxyDefaultHealthPort)) diff --git a/control-plane/gateways/deployment_init_container.go b/control-plane/gateways/deployment_init_container.go index c6fdcbeff6..14230b98df 100644 --- a/control-plane/gateways/deployment_init_container.go +++ b/control-plane/gateways/deployment_init_container.go @@ -19,7 +19,10 @@ import ( const ( injectInitContainerName = "consul-mesh-init" initContainersUserAndGroupID = 5996 - defaultBearerTokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token" +) + +var ( + tpl = template.Must(template.New("root").Parse(strings.TrimSpace(initContainerCommandTpl))) ) type initContainerCommandData struct { @@ -37,11 +40,16 @@ type initContainerCommandData struct { func (b *meshGatewayBuilder) initContainer() (corev1.Container, error) { data := initContainerCommandData{ AuthMethod: b.config.AuthMethod, - LogLevel: b.config.LogLevel, + LogLevel: b.logLevelForInitContainer(), LogJSON: b.config.LogJSON, ServiceName: b.gateway.Name, ServiceAccountName: b.serviceAccountName(), } + // Render the command + var buf bytes.Buffer + if err := tpl.Execute(&buf, &data); err != nil { + return corev1.Container{}, err + } // Create expected volume mounts volMounts := []corev1.VolumeMount{ @@ -56,14 +64,6 @@ func (b *meshGatewayBuilder) initContainer() (corev1.Container, error) { bearerTokenFile = defaultBearerTokenFile } - // Render the command - var buf bytes.Buffer - tpl := template.Must(template.New("root").Parse(strings.TrimSpace(initContainerCommandTpl))) - - if err := tpl.Execute(&buf, &data); err != nil { - return corev1.Container{}, err - } - consulNamespace := namespaces.ConsulNamespace(b.gateway.Namespace, b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.ConsulDestinationNamespace, b.config.ConsulTenancyConfig.EnableConsulNamespaces, b.config.ConsulTenancyConfig.NSMirroringPrefix) initContainerName := injectInitContainerName @@ -73,19 +73,19 @@ func (b *meshGatewayBuilder) initContainer() (corev1.Container, error) { Env: []corev1.EnvVar{ { - Name: "POD_NAME", + Name: envPodName, ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.name"}, }, }, { - Name: "POD_NAMESPACE", + Name: envPodNamespace, ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{FieldPath: "metadata.namespace"}, }, }, { - Name: "NODE_NAME", + Name: envNodeName, ValueFrom: &corev1.EnvVarSource{ FieldRef: &corev1.ObjectFieldSelector{ FieldPath: "spec.nodeName", @@ -93,23 +93,23 @@ func (b *meshGatewayBuilder) initContainer() (corev1.Container, error) { }, }, { - Name: "CONSUL_ADDRESSES", + Name: envConsulAddresses, Value: b.config.ConsulConfig.Address, }, { - Name: "CONSUL_GRPC_PORT", + Name: envConsulGRPCPort, Value: strconv.Itoa(b.config.ConsulConfig.GRPCPort), }, { - Name: "CONSUL_HTTP_PORT", + Name: envConsulHTTPPort, Value: strconv.Itoa(b.config.ConsulConfig.HTTPPort), }, { - Name: "CONSUL_API_TIMEOUT", + Name: envConsulAPITimeout, Value: b.config.ConsulConfig.APITimeout.String(), }, { - Name: "CONSUL_NODE_NAME", + Name: envConsulNodeName, Value: "$(NODE_NAME)-virtual", }, }, @@ -121,28 +121,28 @@ func (b *meshGatewayBuilder) initContainer() (corev1.Container, error) { if b.config.AuthMethod != "" { container.Env = append(container.Env, corev1.EnvVar{ - Name: "CONSUL_LOGIN_AUTH_METHOD", + Name: envConsulLoginAuthMethod, Value: b.config.AuthMethod, }, corev1.EnvVar{ - Name: "CONSUL_LOGIN_BEARER_TOKEN_FILE", + Name: envConsulLoginBearerTokenFile, Value: bearerTokenFile, }, corev1.EnvVar{ - Name: "CONSUL_LOGIN_META", + Name: envConsulLoginMeta, Value: "pod=$(POD_NAMESPACE)/$(POD_NAME)", }) if b.config.ConsulTenancyConfig.ConsulPartition != "" { container.Env = append(container.Env, corev1.EnvVar{ - Name: "CONSUL_LOGIN_PARTITION", + Name: envConsulLoginPartition, Value: b.config.ConsulTenancyConfig.ConsulPartition, }) } } container.Env = append(container.Env, corev1.EnvVar{ - Name: "CONSUL_NAMESPACE", + Name: envConsulNamespace, Value: consulNamespace, }) @@ -165,7 +165,7 @@ func (b *meshGatewayBuilder) initContainer() (corev1.Container, error) { if b.config.ConsulTenancyConfig.ConsulPartition != "" { container.Env = append(container.Env, corev1.EnvVar{ - Name: "CONSUL_PARTITION", + Name: envConsulPartition, Value: b.config.ConsulTenancyConfig.ConsulPartition, }) } diff --git a/control-plane/gateways/deployment_test.go b/control-plane/gateways/deployment_test.go index dbd58a2c0f..37fcb80c59 100644 --- a/control-plane/gateways/deployment_test.go +++ b/control-plane/gateways/deployment_test.go @@ -80,6 +80,11 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { "release": "consul", }, }, + Annotations: meshv2beta1.GatewayClassAnnotationsLabelsConfig{ + Set: map[string]string{ + "a": "b", + }, + }, }, Deployment: meshv2beta1.GatewayClassDeploymentConfig{ Affinity: &corev1.Affinity{ @@ -103,9 +108,26 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { }, }, }, + GatewayClassAnnotationsAndLabels: meshv2beta1.GatewayClassAnnotationsAndLabels{ + Labels: meshv2beta1.GatewayClassAnnotationsLabelsConfig{ + Set: map[string]string{ + "foo": "bar", + }, + }, + Annotations: meshv2beta1.GatewayClassAnnotationsLabelsConfig{ + Set: map[string]string{ + "baz": "qux", + }, + }, + }, Container: &meshv2beta1.GatewayClassContainerConfig{ HostPort: 8080, PortModifier: 8000, + Consul: meshv2beta1.GatewayClassConsulConfig{ + Logging: meshv2beta1.GatewayClassConsulLoggingConfig{ + Level: "debug", + }, + }, }, NodeSelector: map[string]string{"beta.kubernetes.io/arch": "amd64"}, Replicas: &meshv2beta1.GatewayClassReplicasConfig{ @@ -132,6 +154,11 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { "memory": resource.MustParse("228Mi"), }, }, + Consul: meshv2beta1.GatewayClassConsulConfig{ + Logging: meshv2beta1.GatewayClassConsulLoggingConfig{ + Level: "debug", + }, + }, }, }, }, @@ -145,9 +172,12 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { "chart": "consul-helm", "heritage": "Helm", "release": "consul", + "foo": "bar", + }, + Annotations: map[string]string{ + "a": "b", + "baz": "qux", }, - - Annotations: map[string]string{}, }, Spec: appsv1.DeploymentSpec{ Replicas: pointer.Int32(1), @@ -158,6 +188,7 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { "chart": "consul-helm", "heritage": "Helm", "release": "consul", + "foo": "bar", }, }, Template: corev1.PodTemplateSpec{ @@ -167,9 +198,9 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { "app": "consul", "chart": "consul-helm", "heritage": "Helm", + "foo": "bar", "release": "consul", }, - Annotations: map[string]string{ constants.AnnotationGatewayKind: meshGatewayAnnotationKind, constants.AnnotationMeshInject: "false", @@ -196,7 +227,7 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { Command: []string{ "/bin/sh", "-ec", - "consul-k8s-control-plane mesh-init \\\n -proxy-name=${POD_NAME} \\\n -namespace=${POD_NAMESPACE} \\\n -log-json=false", + "consul-k8s-control-plane mesh-init \\\n -proxy-name=${POD_NAME} \\\n -namespace=${POD_NAMESPACE} \\\n -log-level=debug \\\n -log-json=false", }, Env: []corev1.EnvVar{ { @@ -279,7 +310,7 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { "-addresses", "", "-grpc-port=0", - "-log-level=", + "-log-level=debug", "-log-json=false", "-envoy-concurrency=1", "-tls-disabled", @@ -336,10 +367,6 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { Name: "DP_CREDENTIAL_LOGIN_META", Value: "pod=$(POD_NAMESPACE)/$(DP_PROXY_ID)", }, - { - Name: "DP_CREDENTIAL_LOGIN_META1", - Value: "pod=$(POD_NAMESPACE)/$(DP_PROXY_ID)", - }, { Name: "DP_SERVICE_NODE_NAME", Value: "$(NODE_NAME)-virtual", @@ -494,6 +521,11 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { Container: &meshv2beta1.GatewayClassContainerConfig{ HostPort: 8080, PortModifier: 8000, + Consul: meshv2beta1.GatewayClassConsulConfig{ + Logging: meshv2beta1.GatewayClassConsulLoggingConfig{ + Level: "debug", + }, + }, }, NodeSelector: map[string]string{"beta.kubernetes.io/arch": "amd64"}, Replicas: &meshv2beta1.GatewayClassReplicasConfig{ @@ -509,6 +541,23 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { WhenUnsatisfiable: "DoNotSchedule", }, }, + InitContainer: &meshv2beta1.GatewayClassInitContainerConfig{ + Resources: &corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + "cpu": resource.MustParse("100m"), + "memory": resource.MustParse("128Mi"), + }, + Limits: corev1.ResourceList{ + "cpu": resource.MustParse("200m"), + "memory": resource.MustParse("228Mi"), + }, + }, + Consul: meshv2beta1.GatewayClassConsulConfig{ + Logging: meshv2beta1.GatewayClassConsulLoggingConfig{ + Level: "debug", + }, + }, + }, }, }, }, @@ -571,7 +620,7 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { Command: []string{ "/bin/sh", "-ec", - "consul-k8s-control-plane mesh-init \\\n -proxy-name=${POD_NAME} \\\n -namespace=${POD_NAMESPACE} \\\n -log-json=false", + "consul-k8s-control-plane mesh-init \\\n -proxy-name=${POD_NAME} \\\n -namespace=${POD_NAMESPACE} \\\n -log-level=debug \\\n -log-json=false", }, Env: []corev1.EnvVar{ { @@ -641,7 +690,16 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { Value: "", }, }, - Resources: corev1.ResourceRequirements{}, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + "cpu": resource.MustParse("100m"), + "memory": resource.MustParse("128Mi"), + }, + Limits: corev1.ResourceList{ + "cpu": resource.MustParse("200m"), + "memory": resource.MustParse("228Mi"), + }, + }, VolumeMounts: []corev1.VolumeMount{ { Name: "consul-mesh-inject-data", @@ -657,7 +715,7 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { "-addresses", "", "-grpc-port=0", - "-log-level=", + "-log-level=debug", "-log-json=false", "-envoy-concurrency=1", "-ca-certs=/consul/mesh-inject/consul-ca.pem", @@ -714,10 +772,6 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { Name: "DP_CREDENTIAL_LOGIN_META", Value: "pod=$(POD_NAMESPACE)/$(DP_PROXY_ID)", }, - { - Name: "DP_CREDENTIAL_LOGIN_META1", - Value: "pod=$(POD_NAMESPACE)/$(DP_PROXY_ID)", - }, { Name: "DP_SERVICE_NODE_NAME", Value: "$(NODE_NAME)-virtual", @@ -1003,10 +1057,6 @@ func Test_meshGatewayBuilder_Deployment(t *testing.T) { Name: "DP_CREDENTIAL_LOGIN_META", Value: "pod=$(POD_NAMESPACE)/$(DP_PROXY_ID)", }, - { - Name: "DP_CREDENTIAL_LOGIN_META1", - Value: "pod=$(POD_NAMESPACE)/$(DP_PROXY_ID)", - }, { Name: "DP_SERVICE_NODE_NAME", Value: "$(NODE_NAME)-virtual", diff --git a/control-plane/gateways/config.go b/control-plane/gateways/gateway_config.go similarity index 73% rename from control-plane/gateways/config.go rename to control-plane/gateways/gateway_config.go index 265678ea8c..551dc175b2 100644 --- a/control-plane/gateways/config.go +++ b/control-plane/gateways/gateway_config.go @@ -17,6 +17,7 @@ type GatewayConfig struct { // AuthMethod method used to authenticate with Consul Server. AuthMethod string + // ConsulTenancyConfig is the configuration for the Consul Tenancy feature. ConsulTenancyConfig common.ConsulTenancyConfig // LogLevel is the logging level of the deployed Consul Dataplanes. @@ -42,7 +43,13 @@ type GatewayConfig struct { MapPrivilegedServicePorts int } +// GatewayResources is a collection of Kubernetes resources for a Gateway. type GatewayResources struct { + // GatewayClassConfigs is a list of GatewayClassConfig resources which are + // responsible for defining configuration shared across all gateway kinds. GatewayClassConfigs []*v2beta1.GatewayClassConfig `json:"gatewayClassConfigs"` - MeshGateways []*v2beta1.MeshGateway `json:"meshGateways"` + // MeshGateways is a list of MeshGateway resources which are responsible for + // defining the configuration for a specific mesh gateway. + // Deployments of mesh gateways have a one-to-one relationship with MeshGateway resources. + MeshGateways []*v2beta1.MeshGateway `json:"meshGateways"` } diff --git a/control-plane/gateways/metadata.go b/control-plane/gateways/metadata.go index 32357c63a7..e1479ef3f2 100644 --- a/control-plane/gateways/metadata.go +++ b/control-plane/gateways/metadata.go @@ -60,6 +60,30 @@ func (b *meshGatewayBuilder) labelsForDeployment() map[string]string { return labels } +func (b *meshGatewayBuilder) logLevelForDataplaneContainer() string { + if b.config.LogLevel != "" { + return b.config.LogLevel + } + + if b.gcc == nil || b.gcc.Spec.Deployment.Container == nil { + return "" + } + + return b.gcc.Spec.Deployment.Container.Consul.Logging.Level +} + +func (b *meshGatewayBuilder) logLevelForInitContainer() string { + if b.config.LogLevel != "" { + return b.config.LogLevel + } + + if b.gcc == nil || b.gcc.Spec.Deployment.InitContainer == nil { + return "" + } + + return b.gcc.Spec.Deployment.InitContainer.Consul.Logging.Level +} + func (b *meshGatewayBuilder) labelsForRole() map[string]string { if b.gcc == nil { return defaultLabels diff --git a/control-plane/gateways/metadata_test.go b/control-plane/gateways/metadata_test.go index b0c1496884..7505867992 100644 --- a/control-plane/gateways/metadata_test.go +++ b/control-plane/gateways/metadata_test.go @@ -259,6 +259,53 @@ func TestNewMeshGatewayBuilder_Labels(t *testing.T) { } } +// The LogLevel for deployment containers may be set on the Gateway Class Config or the Gateway Config. +// If it is set on both, the Gateway Config takes precedence. +func TestMeshGatewayBuilder_LogLevel(t *testing.T) { + debug := "debug" + info := "info" + + testCases := map[string]struct { + GatewayLogLevel string + GCCLogLevel string + }{ + "Set on Gateway": { + GatewayLogLevel: debug, + GCCLogLevel: "", + }, + "Set on GCC": { + GatewayLogLevel: "", + GCCLogLevel: debug, + }, + "Set on both": { + GatewayLogLevel: debug, + GCCLogLevel: info, + }, + } + + for name, testCase := range testCases { + t.Run(name, func(t *testing.T) { + + gcc := &meshv2beta1.GatewayClassConfig{ + Spec: meshv2beta1.GatewayClassConfigSpec{ + Deployment: meshv2beta1.GatewayClassDeploymentConfig{ + Container: &meshv2beta1.GatewayClassContainerConfig{ + Consul: meshv2beta1.GatewayClassConsulConfig{ + Logging: meshv2beta1.GatewayClassConsulLoggingConfig{ + Level: testCase.GCCLogLevel, + }, + }, + }, + }, + }, + } + b := NewMeshGatewayBuilder(&meshv2beta1.MeshGateway{}, GatewayConfig{LogLevel: testCase.GatewayLogLevel}, gcc) + + assert.Equal(t, debug, b.logLevelForDataplaneContainer()) + }) + } +} + func Test_computeAnnotationsOrLabels(t *testing.T) { gatewaySet := map[string]string{ "service.beta.kubernetes.io/aws-load-balancer-internal": "true", // Will not be inherited