diff --git a/src/go/k8s/.golangci.yml b/src/go/k8s/.golangci.yml index f657eb354c5f8..78f2723fc39e8 100644 --- a/src/go/k8s/.golangci.yml +++ b/src/go/k8s/.golangci.yml @@ -26,10 +26,11 @@ linters-settings: misspell: locale: US nolintlint: - allow-leading-space: true # don't require machine-readable nolint directives (i.e. with no leading space) allow-unused: false # report any unused nolint directives require-explanation: false # don't require an explanation for nolint directives require-specific: false # don't require nolint directives to be specific about which linter is being skipped + revive: + confidence: 0.8 linters: # please, do not use `enable-all`: it's deprecated and will be removed soon. diff --git a/src/go/k8s/apis/redpanda/v1alpha1/cluster_types.go b/src/go/k8s/apis/redpanda/v1alpha1/cluster_types.go index 6d325b5ef7a5a..b7eb17988936b 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/cluster_types.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/cluster_types.go @@ -50,11 +50,12 @@ type RedpandaResourceRequirements struct { // * Is limited by 2Gi per core if requests.memory is set. // // Example: -// in: minimum requirement per core, 2GB -// in: Requests.Memory, 16GB -// => maxAllowedCores = 8 -// if requestedCores == 8, set smp = 8 (with 2GB per core) -// if requestedCores == 4, set smp = 4 (with 4GB per core) +// +// in: minimum requirement per core, 2GB +// in: Requests.Memory, 16GB +// => maxAllowedCores = 8 +// if requestedCores == 8, set smp = 8 (with 2GB per core) +// if requestedCores == 4, set smp = 4 (with 4GB per core) func (r *RedpandaResourceRequirements) RedpandaCPU() *resource.Quantity { q := r.Redpanda.Cpu() if q == nil || q.IsZero() { @@ -257,17 +258,33 @@ type StorageSpec struct { // used as a external listener. This port is tight to the autogenerated // host port. The collision between Kafka external, Kafka internal, // Admin, Pandaproxy, Schema Registry and RPC port is checked in the webhook. +// An optional endpointTemplate can be used to configure advertised addresses +// for Kafka API and Pandaproxy, while it is disallowed for other listeners. type ExternalConnectivityConfig struct { // Enabled enables the external connectivity feature Enabled bool `json:"enabled,omitempty"` // Subdomain can be used to change the behavior of an advertised // KafkaAPI. Each broker advertises Kafka API as follows - // BROKER_ID.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT. + // ENDPOINT.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT. // If Subdomain is empty then each broker advertises Kafka // API as PUBLIC_NODE_IP:EXTERNAL_KAFKA_API_PORT. // If TLS is enabled then this subdomain will be requested // as a subject alternative name. Subdomain string `json:"subdomain,omitempty"` + // EndpointTemplate is a Golang template string that allows customizing each + // broker advertised address. + // Redpanda uses the format BROKER_ID.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT by + // default for advertised addresses. When an EndpointTemplate is + // provided, then the BROKER_ID part is replaced with the endpoint + // computed from the template. + // The following variables are available to the template: + // - Index: the Redpanda broker progressive number + // - HostIP: the ip address of the Node, as reported in pod status + // + // Common template functions from Sprig (http://masterminds.github.io/sprig/) + // are also available. The set of available functions is limited to hermetic + // functions because template application needs to be deterministic. + EndpointTemplate string `json:"endpointTemplate,omitempty"` // The preferred address type to be assigned to the external // advertised addresses. The valid types are ExternalDNS, // ExternalIP, InternalDNS, InternalIP, and Hostname. @@ -908,12 +925,14 @@ type TLSConfig struct { // Kafka API // GetPort returns API port +// //nolint:gocritic // TODO KafkaAPI is now 81 bytes, consider a pointer func (k KafkaAPI) GetPort() int { return k.Port } // GetTLS returns API TLSConfig +// //nolint:gocritic // TODO KafkaAPI is now 81 bytes, consider a pointer func (k KafkaAPI) GetTLS() *TLSConfig { return &TLSConfig{ @@ -925,6 +944,7 @@ func (k KafkaAPI) GetTLS() *TLSConfig { } // GetExternal returns API's ExternalConnectivityConfig +// //nolint:gocritic // TODO KafkaAPI is now 81 bytes, consider a pointer func (k KafkaAPI) GetExternal() *ExternalConnectivityConfig { return &k.External diff --git a/src/go/k8s/apis/redpanda/v1alpha1/cluster_types_test.go b/src/go/k8s/apis/redpanda/v1alpha1/cluster_types_test.go index e4a8e2fe3c1a6..3140464cdbe64 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/cluster_types_test.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/cluster_types_test.go @@ -21,7 +21,7 @@ import ( "k8s.io/utils/pointer" ) -// nolint:funlen // this is ok for a test +//nolint:funlen // this is ok for a test func TestRedpandaResourceRequirements(t *testing.T) { type test struct { name string diff --git a/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook.go b/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook.go index 664054b6f81ef..b857157bdab11 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook.go @@ -15,6 +15,7 @@ import ( "strconv" cmmeta "github.com/jetstack/cert-manager/pkg/apis/meta/v1" + "github.com/redpanda-data/redpanda/src/go/k8s/pkg/utils" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" @@ -277,6 +278,12 @@ func (r *Cluster) validateAdminListeners() field.ErrorList { r.Spec.Configuration.AdminAPI, "bootstrap loadbalancer not available for http admin api")) } + if externalAdmin != nil && externalAdmin.External.EndpointTemplate != "" { + allErrs = append(allErrs, + field.Invalid(field.NewPath("spec").Child("configuration").Child("adminApi"), + r.Spec.Configuration.AdminAPI, + "cannot provide an endpoint template for admin listener")) + } // for now only one listener can have TLS to be backward compatible with v1alpha1 API foundListenerWithTLS := false @@ -306,6 +313,7 @@ func (r *Cluster) validateKafkaListeners() field.ErrorList { } var external *KafkaAPI + var externalIdx int for i, p := range r.Spec.Configuration.KafkaAPI { if p.External.Enabled { if external != nil { @@ -315,6 +323,7 @@ func (r *Cluster) validateKafkaListeners() field.ErrorList { "only one kafka api listener can be marked as external")) } external = &r.Spec.Configuration.KafkaAPI[i] + externalIdx = i } } @@ -357,10 +366,36 @@ func (r *Cluster) validateKafkaListeners() field.ErrorList { r.Spec.Configuration.KafkaAPI, "bootstrap port cannot be empty")) } + //nolint:dupl // not identical + if external != nil && external.External.EndpointTemplate != "" { + if external.External.Subdomain == "" { + allErrs = append(allErrs, + field.Invalid(field.NewPath("spec").Child("configuration").Child("kafkaApi").Index(externalIdx).Child("external"), + external.External, + "endpointTemplate can only be used in combination with subdomain")) + } + + err := checkValidEndpointTemplate(external.External.EndpointTemplate) + if err != nil { + log.Error(err, "Invalid endpoint template received", "template", external.External.EndpointTemplate) + allErrs = append(allErrs, + field.Invalid(field.NewPath("spec").Child("configuration").Child("kafkaApi").Index(externalIdx).Child("external").Child("endpointTemplate"), + external.External.EndpointTemplate, + fmt.Sprintf("template is invalid: %v", err))) + } + } return allErrs } +func checkValidEndpointTemplate(tmpl string) error { + // Using an example input to ensure that the template expression is allowed + data := utils.NewEndpointTemplateData(0, "1.2.3.4") + _, err := utils.ComputeEndpoint(tmpl, data) + return err +} + +//nolint:funlen,gocyclo // it's a sequence of checks func (r *Cluster) validatePandaproxyListeners() field.ErrorList { var allErrs field.ErrorList var proxyExternal *PandaproxyAPI @@ -412,6 +447,25 @@ func (r *Cluster) validatePandaproxyListeners() field.ErrorList { r.Spec.Configuration.PandaproxyAPI[i], "sudomain of external pandaproxy must be the same as kafka's")) } + //nolint:dupl // not identical + if kafkaExternal != nil && proxyExternal.External.EndpointTemplate != "" { + if proxyExternal.External.Subdomain == "" { + allErrs = append(allErrs, + field.Invalid(field.NewPath("spec").Child("configuration").Child("pandaproxyApi").Index(i).Child("external"), + proxyExternal.External, + "endpointTemplate can only be used in combination with subdomain")) + } + + err := checkValidEndpointTemplate(proxyExternal.External.EndpointTemplate) + if err != nil { + log.Error(err, "Invalid endpoint template received", "template", proxyExternal.External.EndpointTemplate) + allErrs = append(allErrs, + field.Invalid(field.NewPath("spec").Child("configuration").Child("pandaproxyApi").Index(i). + Child("external").Child("endpointTemplate"), + proxyExternal.External.EndpointTemplate, + fmt.Sprintf("template is invalid: %v", err))) + } + } } // for now only one listener can have TLS to be backward compatible with v1alpha1 API @@ -510,6 +564,13 @@ func (r *Cluster) validateSchemaRegistryListener() field.ErrorList { r.Spec.Configuration.SchemaRegistry.External, "bootstrap loadbalancer not available for schema reigstry")) } + if schemaRegistry.External.EndpointTemplate != "" { + allErrs = append(allErrs, + field.Invalid(field.NewPath("spec").Child("configuration").Child("schemaRegistry").Child("external").Child("endpointTemplate"), + r.Spec.Configuration.SchemaRegistry.External.EndpointTemplate, + "cannot provide an endpoint template for schema registry")) + } + return allErrs } diff --git a/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook_test.go b/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook_test.go index 4eab69e3e2757..02e13028ef425 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook_test.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/cluster_webhook_test.go @@ -27,7 +27,7 @@ import ( "k8s.io/utils/pointer" ) -// nolint:funlen // this is ok for a test +//nolint:funlen // this is ok for a test func TestDefault(t *testing.T) { type test struct { name string @@ -780,7 +780,7 @@ func TestCreation(t *testing.T) { assert.Error(t, err) }) - // nolint:dupl // the values are different + //nolint:dupl // the values are different t.Run("incorrect redpanda memory (need <= limit)", func(t *testing.T) { memory := redpandaCluster.DeepCopy() memory.Spec.Resources = v1alpha1.RedpandaResourceRequirements{ @@ -804,7 +804,7 @@ func TestCreation(t *testing.T) { assert.Error(t, err) }) - // nolint:dupl // the values are different + //nolint:dupl // the values are different t.Run("correct redpanda memory", func(t *testing.T) { memory := redpandaCluster.DeepCopy() memory.Spec.Resources = v1alpha1.RedpandaResourceRequirements{ @@ -828,7 +828,7 @@ func TestCreation(t *testing.T) { assert.NoError(t, err) }) - // nolint:dupl // the values are different + //nolint:dupl // the values are different t.Run("correct redpanda memory (boundary check)", func(t *testing.T) { memory := redpandaCluster.DeepCopy() memory.Spec.Resources = v1alpha1.RedpandaResourceRequirements{ @@ -1022,6 +1022,118 @@ func TestCreation(t *testing.T) { err := rp.ValidateCreate() assert.Error(t, err) }) + t.Run("endpoint template not allowed for schemaregistry", func(t *testing.T) { + rp := redpandaCluster.DeepCopy() + const commonDomain = "company.org" + + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + }}) + rp.Spec.Configuration.SchemaRegistry = &v1alpha1.SchemaRegistryAPI{External: &v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + EndpointTemplate: "xxx", + }} + err := rp.ValidateCreate() + assert.Error(t, err) + }) + //nolint:dupl // not really a duplicate + t.Run("endpoint template not allowed for adminapi", func(t *testing.T) { + rp := redpandaCluster.DeepCopy() + const commonDomain = "company.org" + + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + }}) + rp.Spec.Configuration.AdminAPI = append(rp.Spec.Configuration.AdminAPI, v1alpha1.AdminAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + EndpointTemplate: "xxx", + }}) + err := rp.ValidateCreate() + assert.Error(t, err) + }) + t.Run("endpoint template without subdomain is not allowed in kafka API", func(t *testing.T) { + rp := redpandaCluster.DeepCopy() + + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + EndpointTemplate: "xxx", + }}) + err := rp.ValidateCreate() + assert.Error(t, err) + }) + t.Run("endpoint template without subdomain is not allowed in pandaproxy API", func(t *testing.T) { + rp := redpandaCluster.DeepCopy() + + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + }}) + rp.Spec.Configuration.PandaproxyAPI = append(rp.Spec.Configuration.PandaproxyAPI, v1alpha1.PandaproxyAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + EndpointTemplate: "xxx", + }}) + err := rp.ValidateCreate() + assert.Error(t, err) + }) + t.Run("invalid endpoint template in kafka API", func(t *testing.T) { + rp := redpandaCluster.DeepCopy() + + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: "example.com", + EndpointTemplate: "{{.Inexistent}}", + }}) + err := rp.ValidateCreate() + assert.Error(t, err) + }) + t.Run("valid endpoint template in kafka API", func(t *testing.T) { + rp := redpandaCluster.DeepCopy() + + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: "example.com", + EndpointTemplate: "{{.Index}}-broker", + }}) + err := rp.ValidateCreate() + assert.NoError(t, err) + }) + //nolint:dupl // not really a duplicate + t.Run("invalid endpoint template in pandaproxy API", func(t *testing.T) { + rp := redpandaCluster.DeepCopy() + + const commonDomain = "mydomain" + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + }}) + rp.Spec.Configuration.PandaproxyAPI = append(rp.Spec.Configuration.PandaproxyAPI, v1alpha1.PandaproxyAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + EndpointTemplate: "{{.Index | nonexistent }}", + }}) + err := rp.ValidateCreate() + assert.Error(t, err) + }) + //nolint:dupl // not really a duplicate + t.Run("valid endpoint template in pandaproxy API", func(t *testing.T) { + rp := redpandaCluster.DeepCopy() + + const commonDomain = "mydomain" + rp.Spec.Configuration.KafkaAPI = append(rp.Spec.Configuration.KafkaAPI, v1alpha1.KafkaAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + }}) + rp.Spec.Configuration.PandaproxyAPI = append(rp.Spec.Configuration.PandaproxyAPI, v1alpha1.PandaproxyAPI{External: v1alpha1.ExternalConnectivityConfig{ + Enabled: true, + Subdomain: commonDomain, + EndpointTemplate: "{{.Index}}-pp", + }}) + err := rp.ValidateCreate() + assert.NoError(t, err) + }) } func TestSchemaRegistryValidations(t *testing.T) { @@ -1233,7 +1345,7 @@ func TestExternalKafkaPortSpecified(t *testing.T) { func TestKafkaTLSRules(t *testing.T) { rpCluster := validRedpandaCluster() - // nolint:dupl // the tests are not duplicates + //nolint:dupl // the tests are not duplicates t.Run("different issuer for two tls listeners", func(t *testing.T) { newRp := rpCluster.DeepCopy() newRp.Spec.Configuration.KafkaAPI[0].TLS = v1alpha1.KafkaAPITLS{ @@ -1256,7 +1368,7 @@ func TestKafkaTLSRules(t *testing.T) { assert.Error(t, err) }) - // nolint:dupl // the tests are not duplicates + //nolint:dupl // the tests are not duplicates t.Run("same issuer for two tls listeners is allowed", func(t *testing.T) { newRp := rpCluster.DeepCopy() newRp.Spec.Configuration.KafkaAPI[0].TLS = v1alpha1.KafkaAPITLS{ @@ -1279,7 +1391,7 @@ func TestKafkaTLSRules(t *testing.T) { assert.NoError(t, err) }) - // nolint:dupl // the tests are not duplicates + //nolint:dupl // the tests are not duplicates t.Run("different nodeSecretRef for two tls listeners", func(t *testing.T) { newRp := rpCluster.DeepCopy() newRp.Spec.Configuration.KafkaAPI[0].TLS = v1alpha1.KafkaAPITLS{ @@ -1302,7 +1414,7 @@ func TestKafkaTLSRules(t *testing.T) { assert.Error(t, err) }) - // nolint:dupl // the tests are not duplicates + //nolint:dupl // the tests are not duplicates t.Run("same nodesecretref for two tls listeners is allowed", func(t *testing.T) { newRp := rpCluster.DeepCopy() newRp.Spec.Configuration.KafkaAPI[0].TLS = v1alpha1.KafkaAPITLS{ diff --git a/src/go/k8s/apis/redpanda/v1alpha1/common_types.go b/src/go/k8s/apis/redpanda/v1alpha1/common_types.go index e3d23ea9f627a..278ff9506e226 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/common_types.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/common_types.go @@ -42,7 +42,7 @@ func (s *SecretKeyRef) GetValue(secret *corev1.Secret, defaultKey string) ([]byt value, ok := secret.Data[key] if !ok { - return nil, fmt.Errorf("getting value from Secret %s/%s: key %s not found", s.Namespace, s.Name, key) // nolint:goerr113 // no need to declare new error type + return nil, fmt.Errorf("getting value from Secret %s/%s: key %s not found", s.Namespace, s.Name, key) //nolint:goerr113 // no need to declare new error type } return value, nil } diff --git a/src/go/k8s/apis/redpanda/v1alpha1/groupversion_info.go b/src/go/k8s/apis/redpanda/v1alpha1/groupversion_info.go index f6a10d9653cab..06195eeea4ac0 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/groupversion_info.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/groupversion_info.go @@ -8,8 +8,8 @@ // by the Apache License, Version 2.0 // Package v1alpha1 contains API Schema definitions for the redpanda v1alpha1 API group -//+kubebuilder:object:generate=true -//+groupName=redpanda.vectorized.io +// +kubebuilder:object:generate=true +// +groupName=redpanda.vectorized.io package v1alpha1 import ( diff --git a/src/go/k8s/apis/redpanda/v1alpha1/webhook_suite_test.go b/src/go/k8s/apis/redpanda/v1alpha1/webhook_suite_test.go index 8ee2c833dd938..6919016a09a11 100644 --- a/src/go/k8s/apis/redpanda/v1alpha1/webhook_suite_test.go +++ b/src/go/k8s/apis/redpanda/v1alpha1/webhook_suite_test.go @@ -21,7 +21,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" redpandav1alpha1 "github.com/redpanda-data/redpanda/src/go/k8s/apis/redpanda/v1alpha1" - admissionv1beta1 "k8s.io/api/admission/v1beta1" // nolint:goimports // crlfmt + admissionv1beta1 "k8s.io/api/admission/v1beta1" //nolint:goimports // crlfmt //+kubebuilder:scaffold:imports "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" @@ -108,7 +108,7 @@ var _ = BeforeSuite(func() { dialer := &net.Dialer{Timeout: time.Second} addrPort := fmt.Sprintf("%s:%d", webhookInstallOptions.LocalServingHost, webhookInstallOptions.LocalServingPort) Eventually(func() error { - // nolint:gosec // the tests can have insecure verify flag set to true + //nolint:gosec // the tests can have insecure verify flag set to true conn, err := tls.DialWithDialer(dialer, "tcp", addrPort, &tls.Config{InsecureSkipVerify: true}) if err != nil { return err diff --git a/src/go/k8s/cmd/configurator/main.go b/src/go/k8s/cmd/configurator/main.go index 34cf8db968865..d773b02b86caa 100644 --- a/src/go/k8s/cmd/configurator/main.go +++ b/src/go/k8s/cmd/configurator/main.go @@ -21,6 +21,7 @@ import ( "github.com/hashicorp/go-multierror" "github.com/redpanda-data/redpanda/src/go/k8s/pkg/networking" + "github.com/redpanda-data/redpanda/src/go/k8s/pkg/utils" "github.com/redpanda-data/redpanda/src/go/rpk/pkg/config" "github.com/spf13/afero" "gopkg.in/yaml.v3" @@ -31,33 +32,39 @@ import ( ) const ( - hostNameEnvVar = "HOSTNAME" - svcFQDNEnvVar = "SERVICE_FQDN" - configSourceDirEnvVar = "CONFIG_SOURCE_DIR" - configDestinationEnvVar = "CONFIG_DESTINATION" - redpandaRPCPortEnvVar = "REDPANDA_RPC_PORT" - nodeNameEnvVar = "NODE_NAME" - externalConnectivityEnvVar = "EXTERNAL_CONNECTIVITY" - externalConnectivitySubDomainEnvVar = "EXTERNAL_CONNECTIVITY_SUBDOMAIN" - externalConnectivityAddressTypeEnvVar = "EXTERNAL_CONNECTIVITY_ADDRESS_TYPE" - hostPortEnvVar = "HOST_PORT" - proxyHostPortEnvVar = "PROXY_HOST_PORT" + hostNameEnvVar = "HOSTNAME" + svcFQDNEnvVar = "SERVICE_FQDN" + configSourceDirEnvVar = "CONFIG_SOURCE_DIR" + configDestinationEnvVar = "CONFIG_DESTINATION" + redpandaRPCPortEnvVar = "REDPANDA_RPC_PORT" + nodeNameEnvVar = "NODE_NAME" + externalConnectivityEnvVar = "EXTERNAL_CONNECTIVITY" + externalConnectivitySubDomainEnvVar = "EXTERNAL_CONNECTIVITY_SUBDOMAIN" + externalConnectivityAddressTypeEnvVar = "EXTERNAL_CONNECTIVITY_ADDRESS_TYPE" + externalConnectivityKafkaEndpointTemplateEnvVar = "EXTERNAL_CONNECTIVITY_KAFKA_ENDPOINT_TEMPLATE" + externalConnectivityPandaProxyEndpointTemplateEnvVar = "EXTERNAL_CONNECTIVITY_PANDA_PROXY_ENDPOINT_TEMPLATE" + hostIPEnvVar = "HOST_IP_ADDRESS" + hostPortEnvVar = "HOST_PORT" + proxyHostPortEnvVar = "PROXY_HOST_PORT" ) type brokerID int type configuratorConfig struct { - hostName string - svcFQDN string - configSourceDir string - configDestination string - nodeName string - subdomain string - externalConnectivity bool - externalConnectivityAddressType corev1.NodeAddressType - redpandaRPCPort int - hostPort int - proxyHostPort int + hostName string + svcFQDN string + configSourceDir string + configDestination string + nodeName string + subdomain string + externalConnectivity bool + externalConnectivityAddressType corev1.NodeAddressType + externalConnectivityKafkaEndpointTemplate string + externalConnectivityPandaProxyEndpointTemplate string + redpandaRPCPort int + hostPort int + proxyHostPort int + hostIP string } func (c *configuratorConfig) String() string { @@ -205,8 +212,14 @@ func registerAdvertisedKafkaAPI( } if len(c.subdomain) > 0 { + data := utils.NewEndpointTemplateData(int(index), c.hostIP) + ep, err := utils.ComputeEndpoint(c.externalConnectivityKafkaEndpointTemplate, data) + if err != nil { + return err + } + cfg.Redpanda.AdvertisedKafkaAPI = append(cfg.Redpanda.AdvertisedKafkaAPI, config.NamedSocketAddress{ - Address: fmt.Sprintf("%d.%s", index, c.subdomain), + Address: fmt.Sprintf("%s.%s", ep, c.subdomain), Port: c.hostPort, Name: "kafka-external", }) @@ -244,8 +257,14 @@ func registerAdvertisedPandaproxyAPI( // Pandaproxy uses the Kafka API subdomain. if len(c.subdomain) > 0 { + data := utils.NewEndpointTemplateData(int(index), c.hostIP) + ep, err := utils.ComputeEndpoint(c.externalConnectivityPandaProxyEndpointTemplate, data) + if err != nil { + return err + } + cfg.Pandaproxy.AdvertisedPandaproxyAPI = append(cfg.Pandaproxy.AdvertisedPandaproxyAPI, config.NamedSocketAddress{ - Address: fmt.Sprintf("%d.%s", index, c.subdomain), + Address: fmt.Sprintf("%s.%s", ep, c.subdomain), Port: c.proxyHostPort, Name: "proxy-external", }) @@ -278,6 +297,7 @@ func getExternalIP(node *corev1.Node) string { return "" } +//nolint:funlen // envs are many func checkEnvVars() (configuratorConfig, error) { var result error var extCon string @@ -326,6 +346,18 @@ func checkEnvVars() (configuratorConfig, error) { value: &hostPort, name: hostPortEnvVar, }, + { + value: &c.externalConnectivityKafkaEndpointTemplate, + name: externalConnectivityKafkaEndpointTemplateEnvVar, + }, + { + value: &c.externalConnectivityPandaProxyEndpointTemplate, + name: externalConnectivityPandaProxyEndpointTemplateEnvVar, + }, + { + value: &c.hostIP, + name: hostIPEnvVar, + }, } for _, envVar := range envVarList { v, exist := os.LookupEnv(envVar.name) diff --git a/src/go/k8s/config/crd/bases/redpanda.vectorized.io_clusters.yaml b/src/go/k8s/config/crd/bases/redpanda.vectorized.io_clusters.yaml index dbfa839710323..750de1f3ab718 100644 --- a/src/go/k8s/config/crd/bases/redpanda.vectorized.io_clusters.yaml +++ b/src/go/k8s/config/crd/bases/redpanda.vectorized.io_clusters.yaml @@ -182,6 +182,21 @@ spec: description: Enabled enables the external connectivity feature type: boolean + endpointTemplate: + description: "EndpointTemplate is a Golang template + string that allows customizing each broker advertised + address. Redpanda uses the format BROKER_ID.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT + by default for advertised addresses. When an EndpointTemplate + is provided, then the BROKER_ID part is replaced with + the endpoint computed from the template. The following + variables are available to the template: - Index: + the Redpanda broker progressive number - HostIP: the + ip address of the Node, as reported in pod status + \n Common template functions from Sprig (http://masterminds.github.io/sprig/) + are also available. The set of available functions + is limited to hermetic functions because template + application needs to be deterministic." + type: string preferredAddressType: description: The preferred address type to be assigned to the external advertised addresses. The valid types @@ -194,7 +209,7 @@ spec: subdomain: description: Subdomain can be used to change the behavior of an advertised KafkaAPI. Each broker advertises - Kafka API as follows BROKER_ID.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT. + Kafka API as follows ENDPOINT.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT. If Subdomain is empty then each broker advertises Kafka API as PUBLIC_NODE_IP:EXTERNAL_KAFKA_API_PORT. If TLS is enabled then this subdomain will be requested @@ -251,6 +266,21 @@ spec: description: Enabled enables the external connectivity feature type: boolean + endpointTemplate: + description: "EndpointTemplate is a Golang template + string that allows customizing each broker advertised + address. Redpanda uses the format BROKER_ID.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT + by default for advertised addresses. When an EndpointTemplate + is provided, then the BROKER_ID part is replaced with + the endpoint computed from the template. The following + variables are available to the template: - Index: + the Redpanda broker progressive number - HostIP: the + ip address of the Node, as reported in pod status + \n Common template functions from Sprig (http://masterminds.github.io/sprig/) + are also available. The set of available functions + is limited to hermetic functions because template + application needs to be deterministic." + type: string preferredAddressType: description: The preferred address type to be assigned to the external advertised addresses. The valid types @@ -263,7 +293,7 @@ spec: subdomain: description: Subdomain can be used to change the behavior of an advertised KafkaAPI. Each broker advertises - Kafka API as follows BROKER_ID.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT. + Kafka API as follows ENDPOINT.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT. If Subdomain is empty then each broker advertises Kafka API as PUBLIC_NODE_IP:EXTERNAL_KAFKA_API_PORT. If TLS is enabled then this subdomain will be requested @@ -384,6 +414,21 @@ spec: description: Enabled enables the external connectivity feature type: boolean + endpointTemplate: + description: "EndpointTemplate is a Golang template + string that allows customizing each broker advertised + address. Redpanda uses the format BROKER_ID.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT + by default for advertised addresses. When an EndpointTemplate + is provided, then the BROKER_ID part is replaced with + the endpoint computed from the template. The following + variables are available to the template: - Index: + the Redpanda broker progressive number - HostIP: the + ip address of the Node, as reported in pod status + \n Common template functions from Sprig (http://masterminds.github.io/sprig/) + are also available. The set of available functions + is limited to hermetic functions because template + application needs to be deterministic." + type: string preferredAddressType: description: The preferred address type to be assigned to the external advertised addresses. The valid types @@ -396,7 +441,7 @@ spec: subdomain: description: Subdomain can be used to change the behavior of an advertised KafkaAPI. Each broker advertises - Kafka API as follows BROKER_ID.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT. + Kafka API as follows ENDPOINT.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT. If Subdomain is empty then each broker advertises Kafka API as PUBLIC_NODE_IP:EXTERNAL_KAFKA_API_PORT. If TLS is enabled then this subdomain will be requested @@ -450,6 +495,21 @@ spec: description: Enabled enables the external connectivity feature type: boolean + endpointTemplate: + description: "EndpointTemplate is a Golang template string + that allows customizing each broker advertised address. + Redpanda uses the format BROKER_ID.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT + by default for advertised addresses. When an EndpointTemplate + is provided, then the BROKER_ID part is replaced with + the endpoint computed from the template. The following + variables are available to the template: - Index: the + Redpanda broker progressive number - HostIP: the ip + address of the Node, as reported in pod status \n Common + template functions from Sprig (http://masterminds.github.io/sprig/) + are also available. The set of available functions is + limited to hermetic functions because template application + needs to be deterministic." + type: string preferredAddressType: description: The preferred address type to be assigned to the external advertised addresses. The valid types @@ -462,7 +522,7 @@ spec: subdomain: description: Subdomain can be used to change the behavior of an advertised KafkaAPI. Each broker advertises Kafka - API as follows BROKER_ID.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT. + API as follows ENDPOINT.SUBDOMAIN:EXTERNAL_KAFKA_API_PORT. If Subdomain is empty then each broker advertises Kafka API as PUBLIC_NODE_IP:EXTERNAL_KAFKA_API_PORT. If TLS is enabled then this subdomain will be requested as diff --git a/src/go/k8s/controllers/redpanda/cluster_controller.go b/src/go/k8s/controllers/redpanda/cluster_controller.go index f2e095acb341f..572afeb85922c 100644 --- a/src/go/k8s/controllers/redpanda/cluster_controller.go +++ b/src/go/k8s/controllers/redpanda/cluster_controller.go @@ -15,6 +15,7 @@ import ( "errors" "fmt" "reflect" + "strconv" "strings" "time" @@ -26,6 +27,7 @@ import ( "github.com/redpanda-data/redpanda/src/go/k8s/pkg/resources" "github.com/redpanda-data/redpanda/src/go/k8s/pkg/resources/certmanager" resourcetypes "github.com/redpanda-data/redpanda/src/go/k8s/pkg/resources/types" + "github.com/redpanda-data/redpanda/src/go/k8s/pkg/utils" "github.com/redpanda-data/redpanda/src/go/rpk/pkg/api/admin" "github.com/redpanda-data/redpanda/src/go/rpk/pkg/config" appsv1 "k8s.io/api/apps/v1" @@ -78,7 +80,8 @@ type ClusterReconciler struct { // // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.7.0/pkg/reconcile -// nolint:funlen // todo break down +// +//nolint:funlen // todo break down func (r *ClusterReconciler) Reconcile( ctx context.Context, req ctrl.Request, ) (ctrl.Result, error) { @@ -295,7 +298,7 @@ func (r *ClusterReconciler) reportStatus( } observedNodesInternal := make([]string, 0, len(observedPods.Items)) - // nolint:gocritic // the copies are necessary for further redpandacluster updates + //nolint:gocritic // the copies are necessary for further redpandacluster updates for _, item := range observedPods.Items { observedNodesInternal = append(observedNodesInternal, fmt.Sprintf("%s.%s", item.Name, internalFQDN)) } @@ -380,7 +383,7 @@ func (r *ClusterReconciler) WithClusterDomain( return r } -// nolint:funlen,gocyclo // External nodes list should be refactored +//nolint:funlen,gocyclo // External nodes list should be refactored func (r *ClusterReconciler) createExternalNodesList( ctx context.Context, pods []corev1.Pod, @@ -421,8 +424,7 @@ func (r *ClusterReconciler) createExternalNodesList( } for i := range pods { - prefixLen := len(pods[i].GenerateName) - podName := pods[i].Name[prefixLen:] + pod := pods[i] if externalKafkaListener != nil && needExternalIP(externalKafkaListener.External) || externalAdminListener != nil && needExternalIP(externalAdminListener.External) || @@ -434,7 +436,10 @@ func (r *ClusterReconciler) createExternalNodesList( } if externalKafkaListener != nil && len(externalKafkaListener.External.Subdomain) > 0 { - address := subdomainAddress(podName, externalKafkaListener.External.Subdomain, getNodePort(&nodePortSvc, resources.ExternalListenerName)) + address, err := subdomainAddress(externalKafkaListener.External.EndpointTemplate, &pod, externalKafkaListener.External.Subdomain, getNodePort(&nodePortSvc, resources.ExternalListenerName)) + if err != nil { + return nil, err + } result.External = append(result.External, address) } else if externalKafkaListener != nil { result.External = append(result.External, @@ -445,7 +450,10 @@ func (r *ClusterReconciler) createExternalNodesList( } if externalAdminListener != nil && len(externalAdminListener.External.Subdomain) > 0 { - address := subdomainAddress(podName, externalAdminListener.External.Subdomain, getNodePort(&nodePortSvc, resources.AdminPortExternalName)) + address, err := subdomainAddress(externalAdminListener.External.EndpointTemplate, &pod, externalAdminListener.External.Subdomain, getNodePort(&nodePortSvc, resources.AdminPortExternalName)) + if err != nil { + return nil, err + } result.ExternalAdmin = append(result.ExternalAdmin, address) } else if externalAdminListener != nil { result.ExternalAdmin = append(result.ExternalAdmin, @@ -456,7 +464,10 @@ func (r *ClusterReconciler) createExternalNodesList( } if externalProxyListener != nil && len(externalProxyListener.External.Subdomain) > 0 { - address := subdomainAddress(podName, externalProxyListener.External.Subdomain, getNodePort(&nodePortSvc, resources.PandaproxyPortExternalName)) + address, err := subdomainAddress(externalProxyListener.External.EndpointTemplate, &pod, externalProxyListener.External.Subdomain, getNodePort(&nodePortSvc, resources.PandaproxyPortExternalName)) + if err != nil { + return nil, err + } result.ExternalPandaproxy = append(result.ExternalPandaproxy, address) } else if externalProxyListener != nil { result.ExternalPandaproxy = append(result.ExternalPandaproxy, @@ -541,12 +552,25 @@ func needExternalIP(external redpandav1alpha1.ExternalConnectivityConfig) bool { return external.Subdomain == "" } -func subdomainAddress(name, subdomain string, port int32) string { +func subdomainAddress( + tmpl string, pod *corev1.Pod, subdomain string, port int32, +) (string, error) { + prefixLen := len(pod.GenerateName) + index, err := strconv.Atoi(pod.Name[prefixLen:]) + if err != nil { + return "", fmt.Errorf("could not parse node ID from pod name %s: %w", pod.Name, err) + } + data := utils.NewEndpointTemplateData(index, pod.Status.HostIP) + ep, err := utils.ComputeEndpoint(tmpl, data) + if err != nil { + return "", err + } + return fmt.Sprintf("%s.%s:%d", - name, + ep, subdomain, port, - ) + ), nil } func getExternalIP(node *corev1.Node) string { diff --git a/src/go/k8s/controllers/redpanda/cluster_controller_configuration.go b/src/go/k8s/controllers/redpanda/cluster_controller_configuration.go index 47e8551c55330..0610cca48e626 100644 --- a/src/go/k8s/controllers/redpanda/cluster_controller_configuration.go +++ b/src/go/k8s/controllers/redpanda/cluster_controller_configuration.go @@ -28,7 +28,8 @@ import ( ) // reconcileConfiguration ensures that the cluster configuration is synchronized with expected data -// nolint:funlen // splitting makes it difficult to follow +// +//nolint:funlen // splitting makes it difficult to follow func (r *ClusterReconciler) reconcileConfiguration( ctx context.Context, redpandaCluster *redpandav1alpha1.Cluster, @@ -345,7 +346,7 @@ func (r *ClusterReconciler) synchronizeStatusWithCluster( return redpandaCluster.Status.GetCondition(conditionData.Type), nil } -// nolint:gocritic // I like this if else chain +//nolint:gocritic // I like this if else chain func mapStatusToCondition( clusterStatus admin.ConfigStatusResponse, ) redpandav1alpha1.ClusterCondition { diff --git a/src/go/k8s/controllers/redpanda/cluster_controller_configuration_drift.go b/src/go/k8s/controllers/redpanda/cluster_controller_configuration_drift.go index ed5cbb1a77abe..c5ba1eaa05367 100644 --- a/src/go/k8s/controllers/redpanda/cluster_controller_configuration_drift.go +++ b/src/go/k8s/controllers/redpanda/cluster_controller_configuration_drift.go @@ -48,7 +48,8 @@ type ClusterConfigurationDriftReconciler struct { } // Reconcile detects drift in configuration for clusters and schedules a patch. -// nolint:funlen // May be broken down +// +//nolint:funlen // May be broken down func (r *ClusterConfigurationDriftReconciler) Reconcile( ctx context.Context, req ctrl.Request, ) (ctrl.Result, error) { diff --git a/src/go/k8s/controllers/redpanda/console_controller.go b/src/go/k8s/controllers/redpanda/console_controller.go index 5667e967f55f3..67a31fbb8b2d2 100644 --- a/src/go/k8s/controllers/redpanda/console_controller.go +++ b/src/go/k8s/controllers/redpanda/console_controller.go @@ -74,7 +74,7 @@ func (r *ConsoleReconciler) Reconcile( } // Checks if Console is valid to be created in specified namespace if !console.IsAllowedNamespace() { - err := fmt.Errorf("invalid Console namespace") // nolint:goerr113 // no need to declare new error type + err := fmt.Errorf("invalid Console namespace") //nolint:goerr113 // no need to declare new error type log.Error(err, "Console must be created in Redpanda namespace. Set --allow-console-any-ns=true to enable") return ctrl.Result{}, err } @@ -159,7 +159,7 @@ func (r *Reconciling) Do( resources.NewIngress(r.Client, console, r.Scheme, subdomain, console.GetName(), consolepkg.ServicePortName, log).WithTLS(resources.LEClusterIssuer, fmt.Sprintf("%s-redpanda", cluster.GetName())), } for _, each := range applyResources { - if err := each.Ensure(ctx); err != nil { // nolint:gocritic // more readable + if err := each.Ensure(ctx); err != nil { //nolint:gocritic // more readable var ra *resources.RequeueAfterError if errors.As(err, &ra) { log.V(debugLogLevel).Info(fmt.Sprintf("Requeue ensuring resource after %d: %s", ra.RequeueAfter, ra.Msg)) diff --git a/src/go/k8s/controllers/redpanda/console_controller_test.go b/src/go/k8s/controllers/redpanda/console_controller_test.go index f3229b2bc62be..6f934eadc8ffa 100644 --- a/src/go/k8s/controllers/redpanda/console_controller_test.go +++ b/src/go/k8s/controllers/redpanda/console_controller_test.go @@ -268,7 +268,7 @@ var _ = Describe("Console controller", func() { var ( googleName = fmt.Sprintf("%s-google", ConsoleName) - googleClientId = "123456654321-abcdefghi123456abcdefghi123456ab.apps.googleusercontent.com" // nolint:stylecheck,revive // Console uses clientId naming + googleClientId = "123456654321-abcdefghi123456abcdefghi123456ab.apps.googleusercontent.com" //nolint:stylecheck // Console uses clientId naming googleClientSecret = "some-random-client-secret" ) diff --git a/src/go/k8s/controllers/redpanda/suite_test.go b/src/go/k8s/controllers/redpanda/suite_test.go index 2769946b08d16..6140dd4d7ee1b 100644 --- a/src/go/k8s/controllers/redpanda/suite_test.go +++ b/src/go/k8s/controllers/redpanda/suite_test.go @@ -355,7 +355,7 @@ func (m *mockAdminAPI) GetFeatures( }, nil } -// nolint:gocritic // It's test API +//nolint:gocritic // It's test API func (m *mockAdminAPI) RegisterPropertySchema( name string, metadata admin.ConfigPropertyMetadata, ) { @@ -422,7 +422,7 @@ func (m *mockAdminAPI) GetNodeConfig( return admin.NodeConfig{}, nil } -// nolint:goerr113 // test code +//nolint:goerr113 // test code func (s *scopedMockAdminAPI) GetNodeConfig( ctx context.Context, ) (admin.NodeConfig, error) { @@ -508,7 +508,7 @@ func (m *mockAdminAPI) DisableMaintenanceMode(_ context.Context, _ int) error { return nil } -// nolint:goerr113 // test code +//nolint:goerr113 // test code func (m *mockAdminAPI) SetBrokerStatus( id int, status admin.MembershipStatus, ) error { diff --git a/src/go/k8s/go.mod b/src/go/k8s/go.mod index e0982415fc84f..550347eb8d6a4 100644 --- a/src/go/k8s/go.mod +++ b/src/go/k8s/go.mod @@ -4,6 +4,7 @@ go 1.17 require ( github.com/Masterminds/semver/v3 v3.1.1 + github.com/Masterminds/sprig/v3 v3.2.2 github.com/banzaicloud/k8s-objectmatcher v1.7.0 github.com/cloudhut/common v0.6.0 github.com/go-logr/logr v0.4.0 @@ -37,6 +38,7 @@ require ( 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/Masterminds/goutils v1.1.1 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect github.com/ProtonMail/go-crypto v0.0.0-20220517143526-88bb52951d5b // indirect github.com/acomagu/bufpipe v1.0.3 // indirect @@ -69,6 +71,7 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/huandu/xstrings v1.3.1 // indirect github.com/imdario/mergo v0.3.13 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect @@ -82,7 +85,9 @@ require ( github.com/klauspost/compress v1.15.9 // indirect github.com/linkedin/goavro/v2 v2.11.1 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/nxadm/tail v1.4.8 // indirect @@ -94,7 +99,9 @@ require ( github.com/prometheus/procfs v0.7.3 // indirect github.com/sergi/go-diff v1.2.0 // indirect github.com/sethgrid/pester v1.2.0 // indirect + github.com/shopspring/decimal v1.2.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect + github.com/spf13/cast v1.3.1 // indirect github.com/spf13/cobra v1.5.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/twmb/franz-go/pkg/kmsg v1.2.0 // indirect diff --git a/src/go/k8s/go.sum b/src/go/k8s/go.sum index 4be6b17b0611f..fa82244c3a000 100644 --- a/src/go/k8s/go.sum +++ b/src/go/k8s/go.sum @@ -94,8 +94,12 @@ github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +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/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/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= +github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= @@ -577,6 +581,8 @@ github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKe github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= +github.com/huandu/xstrings v1.3.1/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/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -702,6 +708,7 @@ github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3N 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/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -716,6 +723,7 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= @@ -876,6 +884,8 @@ github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sethgrid/pester v1.2.0 h1:adC9RS29rRUef3rIKWPOuP1Jm3/MmB6ke+OhE5giENI= github.com/sethgrid/pester v1.2.0/go.mod h1:hEUINb4RqvDxtoCaU0BNT/HV4ig5kfgOasrf1xcvr0A= +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= @@ -895,6 +905,8 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= 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.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= @@ -1030,6 +1042,7 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U 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-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +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-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= diff --git a/src/go/k8s/main.go b/src/go/k8s/main.go index 6189a875df83e..6e1a701764237 100644 --- a/src/go/k8s/main.go +++ b/src/go/k8s/main.go @@ -40,7 +40,7 @@ var ( setupLog = ctrl.Log.WithName("setup") ) -// nolint:wsl // the init was generated by kubebuilder +//nolint:wsl // the init was generated by kubebuilder func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) utilruntime.Must(redpandav1alpha1.AddToScheme(scheme)) @@ -48,7 +48,7 @@ func init() { //+kubebuilder:scaffold:scheme } -// nolint:funlen // length looks good +//nolint:funlen // length looks good func main() { var ( clusterDomain string @@ -168,6 +168,18 @@ func main() { os.Exit(1) } + if webhookEnabled { + hookServer := mgr.GetWebhookServer() + if err := mgr.AddReadyzCheck("webhook", hookServer.StartedChecker()); err != nil { + setupLog.Error(err, "unable to create ready check") + os.Exit(1) + } + + if err := mgr.AddHealthzCheck("webhook", hookServer.StartedChecker()); err != nil { + setupLog.Error(err, "unable to create health check") + os.Exit(1) + } + } setupLog.Info("Starting manager") if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { diff --git a/src/go/k8s/pkg/admin/admin.go b/src/go/k8s/pkg/admin/admin.go index 897e6d29f399c..a645160f0df78 100644 --- a/src/go/k8s/pkg/admin/admin.go +++ b/src/go/k8s/pkg/admin/admin.go @@ -75,7 +75,8 @@ func NewInternalAdminAPI( } // AdminAPIClient is a sub interface of the admin API containing what we need in the operator -// nolint:revive // usually package is called adminutils +// + type AdminAPIClient interface { Config(ctx context.Context) (admin.Config, error) ClusterConfigStatus(ctx context.Context, sendToLeader bool) (admin.ConfigStatusResponse, error) @@ -99,7 +100,8 @@ type AdminAPIClient interface { var _ AdminAPIClient = &admin.AdminAPI{} // AdminAPIClientFactory is an abstract constructor of admin API clients -// nolint:revive // usually package is called adminutils +// + type AdminAPIClientFactory func( ctx context.Context, k8sClient client.Reader, diff --git a/src/go/k8s/pkg/console/configmap.go b/src/go/k8s/pkg/console/configmap.go index 66bf898b41b77..faf89ed9acd0b 100644 --- a/src/go/k8s/pkg/console/configmap.go +++ b/src/go/k8s/pkg/console/configmap.go @@ -188,7 +188,7 @@ var ( ) func (cm *ConfigMap) genLogin(ctx context.Context) (e EnterpriseLogin, err error) { - if provider := cm.consoleobj.Spec.Login; provider != nil { // nolint:nestif // login config is complex + if provider := cm.consoleobj.Spec.Login; provider != nil { //nolint:nestif // login config is complex enterpriseLogin := EnterpriseLogin{ Enabled: provider.Enabled, } @@ -289,7 +289,7 @@ var ( // REF https://github.com/redpanda-data/console/blob/master/backend/pkg/schema/client.go#L60 DefaultCaFilePath = "/etc/ssl/certs/ca-certificates.crt" - SchemaRegistryTLSDir = "/redpanda/schema-registry" // nolint:revive // readable enough + SchemaRegistryTLSDir = "/redpanda/schema-registry" SchemaRegistryTLSCaFilePath = fmt.Sprintf("%s/%s", SchemaRegistryTLSDir, "ca.crt") SchemaRegistryTLSCertFilePath = fmt.Sprintf("%s/%s", SchemaRegistryTLSDir, "tls.crt") SchemaRegistryTLSKeyFilePath = fmt.Sprintf("%s/%s", SchemaRegistryTLSDir, "tls.key") @@ -469,7 +469,7 @@ func (cm *ConfigMap) delete(ctx context.Context, skip string) error { if err := cm.List(ctx, cms, client.MatchingLabels(labels.ForConsole(cm.consoleobj)), client.InNamespace(cm.consoleobj.GetNamespace())); err != nil { return err } - for _, obj := range cms.Items { // nolint:gocritic // more readable, configmap list is few + for _, obj := range cms.Items { //nolint:gocritic // more readable, configmap list is few if skip != "" && skip == obj.GetName() { continue } diff --git a/src/go/k8s/pkg/console/console.go b/src/go/k8s/pkg/console/console.go index 3c03c7e1e8cca..4a69cb52e1ce1 100644 --- a/src/go/k8s/pkg/console/console.go +++ b/src/go/k8s/pkg/console/console.go @@ -23,7 +23,7 @@ const ( ) // ConsoleConfig is the config passed to the Redpanda Console app -type ConsoleConfig struct { // nolint:revive // more readable +type ConsoleConfig struct { // Grabbed from https://github.com/redpanda-data/console/ // Copying the config types because they don't have Enterprise fields and not all fields are supported yet MetricsNamespace string `json:"metricsNamespace" yaml:"metricsNamespace"` diff --git a/src/go/k8s/pkg/console/deployment.go b/src/go/k8s/pkg/console/deployment.go index a3f1ab5b59d60..b2ccb5fdf89bd 100644 --- a/src/go/k8s/pkg/console/deployment.go +++ b/src/go/k8s/pkg/console/deployment.go @@ -187,7 +187,7 @@ func (d *Deployment) ensureSyncedSecrets(ctx context.Context) (string, error) { if d.clusterobj.IsSchemaRegistryMutualTLSEnabled() { clientCert, exists := d.store.GetSchemaRegistryClientCert(d.clusterobj) if !exists { - return "", fmt.Errorf("get schema registry client certificate: %s", "not found") // nolint:goerr113 // no need to declare new error type + return "", fmt.Errorf("get schema registry client certificate: %s", "not found") //nolint:goerr113 // no need to declare new error type } certfile := getOrEmpty("tls.crt", clientCert.Data) keyfile := getOrEmpty("tls.key", clientCert.Data) @@ -200,7 +200,7 @@ func (d *Deployment) ensureSyncedSecrets(ctx context.Context) (string, error) { if ca.useCaCert() { caCert, exists := d.store.GetSchemaRegistryNodeCert(d.clusterobj) if !exists { - return "", fmt.Errorf("get schema registry node certificate: %s", "not found") // nolint:goerr113 // no need to declare new error type + return "", fmt.Errorf("get schema registry node certificate: %s", "not found") //nolint:goerr113 // no need to declare new error type } cafile := getOrEmpty("ca.crt", caCert.Data) data["ca.crt"] = []byte(cafile) diff --git a/src/go/k8s/pkg/console/store.go b/src/go/k8s/pkg/console/store.go index 538a17a34a656..a8567ce1caa6c 100644 --- a/src/go/k8s/pkg/console/store.go +++ b/src/go/k8s/pkg/console/store.go @@ -36,7 +36,7 @@ func NewStore(cl client.Client) *Store { // Sync synchronizes watched resources to the store func (s *Store) Sync(cluster *redpandav1alpha1.Cluster) error { - if cluster.IsSchemaRegistryTLSEnabled() { // nolint:nestif // sync is complex + if cluster.IsSchemaRegistryTLSEnabled() { //nolint:nestif // sync is complex if cluster.IsSchemaRegistryMutualTLSEnabled() { schemaRegistryClientCert, err := syncSchemaRegistryCert( s.context, diff --git a/src/go/k8s/pkg/networking/ports_test.go b/src/go/k8s/pkg/networking/ports_test.go index f5e6dd07b848f..c701ce90c87fa 100644 --- a/src/go/k8s/pkg/networking/ports_test.go +++ b/src/go/k8s/pkg/networking/ports_test.go @@ -18,7 +18,7 @@ import ( "github.com/stretchr/testify/assert" ) -// nolint:funlen // this is ok for a test +//nolint:funlen // this is ok for a test func TestRedpandaPorts(t *testing.T) { tests := []struct { name string diff --git a/src/go/k8s/pkg/resources/certmanager/type_helpers_test.go b/src/go/k8s/pkg/resources/certmanager/type_helpers_test.go index f867b80eebc9b..aee332b7d2334 100644 --- a/src/go/k8s/pkg/resources/certmanager/type_helpers_test.go +++ b/src/go/k8s/pkg/resources/certmanager/type_helpers_test.go @@ -26,7 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" ) -// nolint:funlen // the subtests might causes linter to complain +//nolint:funlen // the subtests might causes linter to complain func TestClusterCertificates(t *testing.T) { secret := corev1.Secret{ ObjectMeta: v1.ObjectMeta{ diff --git a/src/go/k8s/pkg/resources/cluster_service.go b/src/go/k8s/pkg/resources/cluster_service.go index 9d4930b7dc371..982bf98cbe907 100644 --- a/src/go/k8s/pkg/resources/cluster_service.go +++ b/src/go/k8s/pkg/resources/cluster_service.go @@ -58,7 +58,8 @@ func NewClusterService( } // Ensure will manage kubernetes v1.Service for redpanda.vectorized.io custom resource -// nolint:dupl // TODO multiple services have the same Ensure function +// +//nolint:dupl // TODO multiple services have the same Ensure function func (r *ClusterServiceResource) Ensure(ctx context.Context) error { if len(r.svcPorts) == 0 { return nil diff --git a/src/go/k8s/pkg/resources/configmap.go b/src/go/k8s/pkg/resources/configmap.go index f2b77b9096f0b..00e9d1403461c 100644 --- a/src/go/k8s/pkg/resources/configmap.go +++ b/src/go/k8s/pkg/resources/configmap.go @@ -12,7 +12,7 @@ package resources import ( "bytes" "context" - "crypto/md5" // nolint:gosec // this is not encrypting secure info + "crypto/md5" //nolint:gosec // this is not encrypting secure info "crypto/rand" "encoding/json" "errors" @@ -211,7 +211,8 @@ func (r *ConfigMapResource) obj(ctx context.Context) (k8sclient.Object, error) { } // CreateConfiguration creates a global configuration for the current cluster -// nolint:funlen // let's keep the configuration in one function for now and refactor later +// +//nolint:funlen // let's keep the configuration in one function for now and refactor later func (r *ConfigMapResource) CreateConfiguration( ctx context.Context, ) (*configuration.GlobalConfiguration, error) { @@ -650,7 +651,7 @@ func (r *ConfigMapResource) GetNodeConfigHash( } configMap := obj.(*corev1.ConfigMap) configString = configMap.Data[configKey] - md5Hash := md5.Sum([]byte(configString)) // nolint:gosec // this is not encrypting secure info + md5Hash := md5.Sum([]byte(configString)) //nolint:gosec // this is not encrypting secure info return fmt.Sprintf("%x", md5Hash), nil } diff --git a/src/go/k8s/pkg/resources/configuration/configuration.go b/src/go/k8s/pkg/resources/configuration/configuration.go index 90ffc453181bc..7a66a4dc42ecc 100644 --- a/src/go/k8s/pkg/resources/configuration/configuration.go +++ b/src/go/k8s/pkg/resources/configuration/configuration.go @@ -11,7 +11,7 @@ package configuration import ( - "crypto/md5" // nolint:gosec // this is not encrypting secure info + "crypto/md5" //nolint:gosec // this is not encrypting secure info "fmt" "reflect" "strings" @@ -69,7 +69,8 @@ func (c *GlobalConfiguration) SetAdditionalRedpandaProperty( } // AppendToAdditionalRedpandaProperty allows appending values to string slices in additional redpanda properties. -// nolint:goerr113 // no need to define static error +// +//nolint:goerr113 // no need to define static error func (c *GlobalConfiguration) AppendToAdditionalRedpandaProperty( key string, value string, ) error { @@ -111,7 +112,7 @@ func (c *GlobalConfiguration) GetCentralizedConfigurationHash( return "", err } // We keep using md5 for having the same format as node hash - md5Hash := md5.Sum(serialized.BootstrapFile) // nolint:gosec // this is not encrypting secure info + md5Hash := md5.Sum(serialized.BootstrapFile) //nolint:gosec // this is not encrypting secure info return fmt.Sprintf("%x", md5Hash), nil } @@ -131,7 +132,7 @@ func (c *GlobalConfiguration) GetNodeConfigurationHash() (string, error) { if err != nil { return "", err } - md5Hash := md5.Sum(serialized.RedpandaFile) // nolint:gosec // this is not encrypting secure info + md5Hash := md5.Sum(serialized.RedpandaFile) //nolint:gosec // this is not encrypting secure info return fmt.Sprintf("%x", md5Hash), nil } diff --git a/src/go/k8s/pkg/resources/configuration/configuration_modes.go b/src/go/k8s/pkg/resources/configuration/configuration_modes.go index 8833aa53ccfce..d159ebf4b8b87 100644 --- a/src/go/k8s/pkg/resources/configuration/configuration_modes.go +++ b/src/go/k8s/pkg/resources/configuration/configuration_modes.go @@ -165,7 +165,8 @@ func builtInType(value string) bool { } // isEmpty helps to keep the "omitempty" behavior on additional fields -// nolint:exhaustive // just care about these types +// +//nolint:exhaustive // just care about these types func isEmpty(val interface{}) bool { if val == nil { return true diff --git a/src/go/k8s/pkg/resources/configuration/patch.go b/src/go/k8s/pkg/resources/configuration/patch.go index 168fd68ba20ba..fc728657acfaf 100644 --- a/src/go/k8s/pkg/resources/configuration/patch.go +++ b/src/go/k8s/pkg/resources/configuration/patch.go @@ -97,7 +97,8 @@ func ThreeWayMerge( // PropertiesEqual tries to compare two property values using metadata information about the schema, // falling back to loose comparison in case of missing data (e.g. it happens with unknown properties). -// nolint:gocritic // code more readable +// +//nolint:gocritic // code more readable func PropertiesEqual( log logr.Logger, v1, v2 interface{}, metadata admin.ConfigPropertyMetadata, ) bool { diff --git a/src/go/k8s/pkg/resources/configuration/patch_test.go b/src/go/k8s/pkg/resources/configuration/patch_test.go index 8eb529c3d5844..b10ed420ad84c 100644 --- a/src/go/k8s/pkg/resources/configuration/patch_test.go +++ b/src/go/k8s/pkg/resources/configuration/patch_test.go @@ -132,7 +132,7 @@ func TestString(t *testing.T) { assert.Equal(t, "+a +c -e -f -x", p.String()) } -// nolint:funlen // it's a table test +//nolint:funlen // it's a table test func TestPropertyEquality(t *testing.T) { var nilPointer *int tests := []struct { diff --git a/src/go/k8s/pkg/resources/ingress.go b/src/go/k8s/pkg/resources/ingress.go index 85fa728298ea8..55068a6d4881d 100644 --- a/src/go/k8s/pkg/resources/ingress.go +++ b/src/go/k8s/pkg/resources/ingress.go @@ -28,7 +28,7 @@ const ( nginx = "nginx" // SSLPassthroughAnnotation is the annotation for ingress nginx SSL passthrough - SSLPassthroughAnnotation = "nginx.ingress.kubernetes.io/ssl-passthrough" // nolint:gosec // This value does not contain credentials. + SSLPassthroughAnnotation = "nginx.ingress.kubernetes.io/ssl-passthrough" //nolint:gosec // This value does not contain credentials. debugLogLevel = 4 @@ -204,7 +204,7 @@ func objectLabels(obj metav1.Object) (labels.CommonLabels, error) { case *redpandav1alpha1.Console: objLabels = labels.ForConsole(o) default: - return nil, fmt.Errorf("expected object to be Cluster or Console") // nolint:goerr113 // no need to declare new error type + return nil, fmt.Errorf("expected object to be Cluster or Console") //nolint:goerr113 // no need to declare new error type } return objLabels, nil } diff --git a/src/go/k8s/pkg/resources/lb_service.go b/src/go/k8s/pkg/resources/lb_service.go index 8ff840985d2d9..fd20601ba1fd0 100644 --- a/src/go/k8s/pkg/resources/lb_service.go +++ b/src/go/k8s/pkg/resources/lb_service.go @@ -61,7 +61,8 @@ func NewLoadBalancerService( } // Ensure manages load-balancer v1.Service for redpanda.vectorized.io -// nolint:dupl // TODO multiple services have the same Ensure function +// +//nolint:dupl // TODO multiple services have the same Ensure function func (r *LoadBalancerServiceResource) Ensure(ctx context.Context) error { if len(r.svcPorts) == 0 { return nil diff --git a/src/go/k8s/pkg/resources/resource_integration_test.go b/src/go/k8s/pkg/resources/resource_integration_test.go index 43327f631f4f8..8b1e4be08ef75 100644 --- a/src/go/k8s/pkg/resources/resource_integration_test.go +++ b/src/go/k8s/pkg/resources/resource_integration_test.go @@ -187,7 +187,7 @@ func TestEnsure_ConfigMap(t *testing.T) { } } -// nolint:funlen // the subtests might causes linter to complain +//nolint:funlen // the subtests might causes linter to complain func TestEnsure_HeadlessService(t *testing.T) { t.Run("create-headless-service", func(t *testing.T) { cluster := pandaCluster() diff --git a/src/go/k8s/pkg/resources/statefulset.go b/src/go/k8s/pkg/resources/statefulset.go index 7be55cc0050c3..96210afce0b45 100644 --- a/src/go/k8s/pkg/resources/statefulset.go +++ b/src/go/k8s/pkg/resources/statefulset.go @@ -260,7 +260,8 @@ func preparePVCResource( } // obj returns resource managed client.Object -// nolint:funlen // The complexity of obj function will be address in the next version TODO +// +//nolint:funlen // The complexity of obj function will be address in the next version func (r *StatefulSetResource) obj( ctx context.Context, ) (k8sclient.Object, error) { @@ -279,17 +280,26 @@ func (r *StatefulSetResource) obj( nodeSelector := r.pandaCluster.Spec.NodeSelector if len(r.pandaCluster.Spec.Configuration.KafkaAPI) == 0 { - // TODO + // TODO: Fix this return nil, nil } externalListener := r.pandaCluster.ExternalListener() externalSubdomain := "" externalAddressType := "" + externalEndpointTemplate := "" if externalListener != nil { externalSubdomain = externalListener.External.Subdomain externalAddressType = externalListener.External.PreferredAddressType + externalEndpointTemplate = externalListener.External.EndpointTemplate + } + + externalPandaProxyAPI := r.pandaCluster.PandaproxyAPIExternal() + externalPandaProxyEndpointTemplate := "" + if externalPandaProxyAPI != nil { + externalPandaProxyEndpointTemplate = externalPandaProxyAPI.External.EndpointTemplate } + tlsVolumes, tlsVolumeMounts := r.volumeProvider.Volumes() // We set statefulset replicas via status.currentReplicas in order to control it from the handleScaling function @@ -387,6 +397,23 @@ func (r *StatefulSetResource) obj( Name: "EXTERNAL_CONNECTIVITY_ADDRESS_TYPE", Value: externalAddressType, }, + { + Name: "EXTERNAL_CONNECTIVITY_KAFKA_ENDPOINT_TEMPLATE", + Value: externalEndpointTemplate, + }, + { + Name: "EXTERNAL_CONNECTIVITY_PANDA_PROXY_ENDPOINT_TEMPLATE", + Value: externalPandaProxyEndpointTemplate, + }, + { + Name: "HOST_IP_ADDRESS", + ValueFrom: &corev1.EnvVarSource{ + FieldRef: &corev1.ObjectFieldSelector{ + APIVersion: "v1", + FieldPath: "status.hostIP", + }, + }, + }, { Name: "HOST_PORT", Value: r.getNodePort(ExternalListenerName), @@ -584,7 +611,7 @@ func (r *StatefulSetResource) getPostStartHook() *corev1.Handler { } } -// nolint:goconst // no need +//nolint:goconst // no need func (r *StatefulSetResource) composeCURLMaintenanceCommand( options string, urlOverwrite *string, ) string { diff --git a/src/go/k8s/pkg/resources/statefulset_scale.go b/src/go/k8s/pkg/resources/statefulset_scale.go index 47b323b0f13a3..6b9c6abad56f2 100644 --- a/src/go/k8s/pkg/resources/statefulset_scale.go +++ b/src/go/k8s/pkg/resources/statefulset_scale.go @@ -64,7 +64,7 @@ const ( // The strategy implemented here (to initialize the cluster at 1 replica, then upscaling to the desired number, without hacks on the seed server list), // should fix this problem, since the list of seeds servers will be the same in all nodes once the cluster is created. // -// nolint:nestif // for clarity +//nolint:nestif // for clarity func (r *StatefulSetResource) handleScaling(ctx context.Context) error { if r.pandaCluster.Status.DecommissioningNode != nil { decommissionTargetReplicas := *r.pandaCluster.Status.DecommissioningNode diff --git a/src/go/k8s/pkg/resources/statefulset_test.go b/src/go/k8s/pkg/resources/statefulset_test.go index 6b069a7bda58d..4929f50606165 100644 --- a/src/go/k8s/pkg/resources/statefulset_test.go +++ b/src/go/k8s/pkg/resources/statefulset_test.go @@ -30,7 +30,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" ) -// nolint:funlen // Test function can have more than 100 lines +//nolint:funlen // Test function can have more than 100 lines func TestEnsure(t *testing.T) { cluster := pandaCluster() stsResource := stsFromCluster(cluster) diff --git a/src/go/k8s/pkg/resources/statefulset_update_test.go b/src/go/k8s/pkg/resources/statefulset_update_test.go index 10e6f36ba8a0f..27b6ba763de00 100644 --- a/src/go/k8s/pkg/resources/statefulset_update_test.go +++ b/src/go/k8s/pkg/resources/statefulset_update_test.go @@ -7,7 +7,7 @@ // the Business Source License, use of this software will be governed // by the Apache License, Version 2.0 -package resources // nolint:testpackage // needed to test private method +package resources //nolint:testpackage // needed to test private method import ( "testing" diff --git a/src/go/k8s/webhooks/redpanda/console_webhook.go b/src/go/k8s/webhooks/redpanda/console_webhook.go index f8118a7e4c2ff..dccac29560cc5 100644 --- a/src/go/k8s/webhooks/redpanda/console_webhook.go +++ b/src/go/k8s/webhooks/redpanda/console_webhook.go @@ -25,7 +25,7 @@ type ConsoleValidator struct { // Handle processes admission for Console func (v *ConsoleValidator) Handle( - ctx context.Context, req admission.Request, // nolint:gocritic // interface not require pointer + ctx context.Context, req admission.Request, //nolint:gocritic // interface not require pointer ) admission.Response { console := &redpandav1alpha1.Console{} @@ -88,7 +88,7 @@ type ConsoleDefaulter struct { // Handle processes admission for Console func (m *ConsoleDefaulter) Handle( - ctx context.Context, req admission.Request, // nolint:gocritic // interface not require pointer + ctx context.Context, req admission.Request, //nolint:gocritic // interface not require pointer ) admission.Response { console := &redpandav1alpha1.Console{}