diff --git a/druid/client.go b/druid/client.go index 24f28349..5516f7a2 100644 --- a/druid/client.go +++ b/druid/client.go @@ -17,14 +17,11 @@ limitations under the License. package druid import ( - "bytes" "encoding/json" "fmt" - "log" "time" druidgo "github.com/grafadruid/go-druid" - "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" "k8s.io/klog/v2" health "kmodules.xyz/client-go/tools/healthchecker" @@ -117,55 +114,15 @@ func (c *Client) CheckDataSourceExistence() (bool, error) { return false, errors.Wrap(err, "failed to marshal json response") } rawMessage := json.RawMessage(jsonData) - response, err := c.SubmitRequest(method, path, rawMessage) - if err != nil { - return false, err - } - - exists, err := parseDatasourceExistenceQueryResponse(response) - if err != nil { - return false, errors.Wrap(err, "Failed to parse response of datasource existence request") - } - - if err := closeResponse(response); err != nil { - return exists, err - } - return exists, nil -} - -func (c *Client) SubmitRequest(method, path string, opts interface{}) (*druidgo.Response, error) { - res, err := c.NewRequest(method, path, opts) - if err != nil { - return nil, errors.Wrap(err, "failed to submit API request") - } - http := retryablehttp.NewClient() - - var b []byte - buf := bytes.NewBuffer(b) - http.Logger = log.New(buf, "", 0) - resp, err := http.Do(res) + var result []map[string]interface{} + _, err = c.ExecuteRequest(method, path, rawMessage, &result) if err != nil { - return nil, err - } - response := &druidgo.Response{Response: resp} - return response, nil -} - -func parseDatasourceExistenceQueryResponse(res *druidgo.Response) (bool, error) { - var responseBody []map[string]interface{} - if err := json.NewDecoder(res.Body).Decode(&responseBody); err != nil { - return false, errors.Wrap(err, "failed to deserialize the response") + klog.Error("Failed to execute request", err) + return false, err } - return len(responseBody) != 0, nil -} -func closeResponse(response *druidgo.Response) error { - err := response.Body.Close() - if err != nil { - return errors.Wrap(err, "Failed to close the response body") - } - return nil + return len(result) > 0, nil } // CheckDBReadWriteAccess checks read and write access in the DB @@ -238,41 +195,25 @@ func (c *Client) GetData() (string, error) { func (c *Client) runSelectQuery() (string, error) { method := "POST" path := "druid/v2/sql" - data := map[string]interface{}{ "query": "SELECT * FROM \"kubedb-datasource\"", } + jsonData, err := json.Marshal(data) if err != nil { return "", errors.Wrap(err, "failed to marshal query json data") } rawMessage := json.RawMessage(jsonData) - response, err := c.SubmitRequest(method, path, rawMessage) - if err != nil { - return "", err - } - if response == nil { - return "", errors.New("response body is empty") - } - id, err := parseSelectQueryResponse(response, "id") + var result []map[string]interface{} + _, err = c.ExecuteRequest(method, path, rawMessage, &result) if err != nil { - return "", errors.Wrap(err, "failed to parse the response body") - } - - if err := closeResponse(response); err != nil { + klog.Error("Failed to execute POST query request", err) return "", err } - return id.(string), nil -} + id := result[0]["id"] -func parseSelectQueryResponse(res *druidgo.Response, key string) (interface{}, error) { - var responseBody []map[string]interface{} - if err := json.NewDecoder(res.Body).Decode(&responseBody); err != nil { - return "", errors.Wrap(err, "failed to deserialize the response") - } - value := responseBody[0][key] - return value, nil + return id.(string), nil } func (c *Client) updateCoordinatorsWaitBeforeDeletingConfig(value int32) error { @@ -296,11 +237,9 @@ func (c *Client) updateCoordinatorDynamicConfig(data map[string]interface{}) err } rawMessage := json.RawMessage(jsonData) - response, err := c.SubmitRequest(method, path, rawMessage) + _, err = c.ExecuteRequest(method, path, rawMessage, nil) if err != nil { - return err - } - if err := closeResponse(response); err != nil { + klog.Error("Failed to execute coordinator config update request", err) return err } return nil @@ -336,33 +275,19 @@ func (c *Client) submitTask(taskType DruidTaskType, dataSource string, data stri } else { task = GetKillTaskDefinition() } - rawMessage := json.RawMessage(task) method := "POST" path := "druid/indexer/v1/task" - response, err := c.SubmitRequest(method, path, rawMessage) - if err != nil { - return "", err - } - - taskID, err := GetValueFromClusterResponse(response, "task") + var result map[string]interface{} + _, err := c.ExecuteRequest(method, path, rawMessage, &result) if err != nil { - return "", errors.Wrap(err, "failed to parse response of task api request") - } - if err = closeResponse(response); err != nil { + klog.Error("Failed to execute POST ingestion or kill task request", err) return "", err } - return fmt.Sprintf("%v", taskID), nil -} -func GetValueFromClusterResponse(res *druidgo.Response, key string) (interface{}, error) { - responseBody := make(map[string]interface{}) - if err := json.NewDecoder(res.Body).Decode(&responseBody); err != nil { - return "", errors.Wrap(err, "failed to deserialize the response") - } - value := responseBody[key] - return value, nil + taskID := result["task"] + return taskID.(string), nil } func GetIngestionTaskDefinition(dataSource string, data string) string { @@ -419,21 +344,18 @@ func GetKillTaskDefinition() string { func (c *Client) CheckTaskStatus(taskID string) (bool, error) { method := "GET" path := fmt.Sprintf("druid/indexer/v1/task/%s/status", taskID) - response, err := c.SubmitRequest(method, path, nil) - if err != nil { - return false, errors.Wrap(err, "failed to check task status") - } - statusRes, err := GetValueFromClusterResponse(response, "status") + var result map[string]interface{} + _, err := c.ExecuteRequest(method, path, nil, &result) if err != nil { - return false, errors.Wrap(err, "failed to parse respons of task ingestion request") + klog.Error("Failed to execute GET task status request", err) + return false, err } + + statusRes := result["status"] statusMap := statusRes.(map[string]interface{}) status := statusMap["status"].(string) - if err = closeResponse(response); err != nil { - return false, err - } return status == "SUCCESS", nil } diff --git a/druid/kubedb_client_builder.go b/druid/kubedb_client_builder.go index d4998010..547c0623 100644 --- a/druid/kubedb_client_builder.go +++ b/druid/kubedb_client_builder.go @@ -18,8 +18,11 @@ package druid import ( "context" + "crypto/tls" + "crypto/x509" "errors" "fmt" + "net/http" druidgo "github.com/grafadruid/go-druid" _ "github.com/lib/pq" @@ -27,6 +30,7 @@ import ( kerr "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" "k8s.io/klog/v2" + dbapi "kubedb.dev/apimachinery/apis/kubedb/v1" olddbapi "kubedb.dev/apimachinery/apis/kubedb/v1alpha2" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -74,28 +78,24 @@ func (o *KubeDBClientBuilder) WithNodeRole(nodeRole olddbapi.DruidNodeRoleType) func (o *KubeDBClientBuilder) GetDruidClient() (*Client, error) { var druidOpts []druidgo.ClientOption - if !*o.db.Spec.DisableSecurity { - if o.db.Spec.AuthSecret == nil { - klog.Error("AuthSecret not set") - return nil, errors.New("auth-secret is not set") + // Add druid auth credential to the client + if !o.db.Spec.DisableSecurity { + authOpts, err := o.getClientAuthOpts() + if err != nil { + klog.Error(err, "failed to get client auth options") + return nil, err } + druidOpts = append(druidOpts, *authOpts) + } - authSecret := &core.Secret{} - err := o.kc.Get(o.ctx, types.NamespacedName{ - Namespace: o.db.Namespace, - Name: o.db.Spec.AuthSecret.Name, - }, authSecret) + // Add druid ssl configs to the client + if o.db.Spec.EnableSSL { + sslOpts, err := o.getClientSSLConfig() if err != nil { - if kerr.IsNotFound(err) { - klog.Error(err, "AuthSecret not found") - return nil, errors.New("auth-secret not found") - } + klog.Error(err, "failed to get client ssl options") return nil, err } - userName := string(authSecret.Data[core.BasicAuthUsernameKey]) - password := string(authSecret.Data[core.BasicAuthPasswordKey]) - - druidOpts = append(druidOpts, druidgo.WithBasicAuth(userName, password)) + druidOpts = append(druidOpts, *sslOpts) } druidClient, err := druidgo.NewClient(o.url, druidOpts...) @@ -107,8 +107,82 @@ func (o *KubeDBClientBuilder) GetDruidClient() (*Client, error) { }, nil } +func (o *KubeDBClientBuilder) getClientAuthOpts() (*druidgo.ClientOption, error) { + if o.db.Spec.AuthSecret == nil { + klog.Error("AuthSecret not set") + return nil, errors.New("auth-secret is not set") + } + + authSecret := &core.Secret{} + err := o.kc.Get(o.ctx, types.NamespacedName{ + Namespace: o.db.Namespace, + Name: o.db.Spec.AuthSecret.Name, + }, authSecret) + if err != nil { + if kerr.IsNotFound(err) { + klog.Error(err, "AuthSecret not found") + return nil, errors.New("auth-secret not found") + } + return nil, err + } + userName := string(authSecret.Data[core.BasicAuthUsernameKey]) + password := string(authSecret.Data[core.BasicAuthPasswordKey]) + + druidAuthOpts := druidgo.WithBasicAuth(userName, password) + return &druidAuthOpts, nil +} + +func (o *KubeDBClientBuilder) getClientSSLConfig() (*druidgo.ClientOption, error) { + certSecret := &core.Secret{} + err := o.kc.Get(o.ctx, types.NamespacedName{ + Namespace: o.db.Namespace, + Name: o.db.GetCertSecretName(olddbapi.DruidClientCert), + }, certSecret) + if err != nil { + if kerr.IsNotFound(err) { + klog.Error(err, "Client certificate secret not found") + return nil, errors.New("client certificate secret is not found") + } + klog.Error(err, "Failed to get client certificate Secret") + return nil, err + } + + // get tls cert, clientCA and rootCA for tls config + clientCA := x509.NewCertPool() + rootCA := x509.NewCertPool() + + crt, err := tls.X509KeyPair(certSecret.Data[core.TLSCertKey], certSecret.Data[core.TLSPrivateKeyKey]) + if err != nil { + klog.Error(err, "Failed to parse private key pair") + return nil, err + } + clientCA.AppendCertsFromPEM(certSecret.Data[dbapi.TLSCACertFileName]) + rootCA.AppendCertsFromPEM(certSecret.Data[dbapi.TLSCACertFileName]) + + httpClient := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + Certificates: []tls.Certificate{crt}, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: clientCA, + RootCAs: rootCA, + MaxVersion: tls.VersionTLS12, + }, + }, + } + tlsOpts := druidgo.WithHTTPClient(httpClient) + return &tlsOpts, nil +} + // GetNodesAddress returns DNS for the nodes based on type of the node func (o *KubeDBClientBuilder) GetNodesAddress() string { - baseUrl := fmt.Sprintf("http://%s-0.%s.%s.svc.cluster.local:%d", o.db.PetSetName(o.nodeRole), o.db.GoverningServiceName(), o.db.Namespace, o.db.DruidNodeContainerPort(o.nodeRole)) + var scheme string + if o.db.Spec.EnableSSL { + scheme = "https" + } else { + scheme = "http" + } + + baseUrl := fmt.Sprintf("%s://%s-0.%s.%s.svc.cluster.local:%d", scheme, o.db.PetSetName(o.nodeRole), o.db.GoverningServiceName(), o.db.Namespace, o.db.DruidNodeContainerPort(o.nodeRole)) return baseUrl } diff --git a/go.mod b/go.mod index 619a3738..57fb598b 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,6 @@ require ( github.com/go-sql-driver/mysql v1.8.1 github.com/gocql/gocql v1.6.0 github.com/grafadruid/go-druid v0.0.6 - github.com/hashicorp/go-retryablehttp v0.7.7 github.com/lib/pq v1.10.7 github.com/michaelklishin/rabbit-hole/v2 v2.16.0 github.com/microsoft/go-mssqldb v1.6.0 @@ -79,6 +78,7 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect @@ -162,3 +162,5 @@ replace sigs.k8s.io/controller-runtime => github.com/kmodules/controller-runtime replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.6 replace k8s.io/apiserver => github.com/kmodules/apiserver v0.30.2-0.20240519082755-d7b8c2d9e699 + +replace kubedb.dev/apimachinery => ../apimachinery diff --git a/go.sum b/go.sum index 4526e7be..ef72552f 100644 --- a/go.sum +++ b/go.sum @@ -804,8 +804,6 @@ kmodules.xyz/monitoring-agent-api v0.30.1 h1:OdYucfl7OblBqVhCyEcOC3HvUrOKtDh8lcM kmodules.xyz/monitoring-agent-api v0.30.1/go.mod h1:oR3tk5O4koYar4cD9N3AjbBFr9XTwBU3sw9qD2NdNQc= kmodules.xyz/offshoot-api v0.30.1 h1:TrulAYO+oBsXe9sZZGTmNWIuI8qD2izMpgcTSPvgAmI= kmodules.xyz/offshoot-api v0.30.1/go.mod h1:T3mpjR6fui0QzOcmQvIuANytW48fe9ytmy/1cgx6D4g= -kubedb.dev/apimachinery v0.48.0 h1:gMGqkBRs81wbmGPQIqMGY/MztKg4MYjZ39d9F656V2c= -kubedb.dev/apimachinery v0.48.0/go.mod h1:TeZW+vt9OLf0Jyb/AZktvOOzf3NV+rFhHDN/zTh1EjA= kubeops.dev/petset v0.0.7 h1:F77BTRfUqRVO7kNc8q2oFSSviDmYBqni/osXqu0kgJ4= kubeops.dev/petset v0.0.7/go.mod h1:lt0SZV4ohRy7RiwLNUnMoauG4lCbcRbSqhMg20rdUQg= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= diff --git a/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/openapi_generated.go b/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/openapi_generated.go index e0624fc7..e9fd58cf 100644 --- a/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/openapi_generated.go +++ b/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/openapi_generated.go @@ -31699,11 +31699,17 @@ func schema_apimachinery_apis_catalog_v1alpha1_SolrVersionSpec(ref common.Refere Format: "", }, }, - "securityContext": { + "updateConstraints": { SchemaProps: spec.SchemaProps{ - Description: "SecurityContext is for the additional security information for the Solr container", + Description: "SecurityContext is for the additional security information for the Solr container update constraints", Default: map[string]interface{}{}, - Ref: ref("kubedb.dev/apimachinery/apis/catalog/v1alpha1.SecurityContext"), + Ref: ref("kubedb.dev/apimachinery/apis/catalog/v1alpha1.UpdateConstraints"), + }, + }, + "securityContext": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("kubedb.dev/apimachinery/apis/catalog/v1alpha1.SecurityContext"), }, }, }, @@ -31711,7 +31717,7 @@ func schema_apimachinery_apis_catalog_v1alpha1_SolrVersionSpec(ref common.Refere }, }, Dependencies: []string{ - "kubedb.dev/apimachinery/apis/catalog/v1alpha1.SecurityContext", "kubedb.dev/apimachinery/apis/catalog/v1alpha1.SolrInitContainer", "kubedb.dev/apimachinery/apis/catalog/v1alpha1.SolrVersionDatabase"}, + "kubedb.dev/apimachinery/apis/catalog/v1alpha1.SecurityContext", "kubedb.dev/apimachinery/apis/catalog/v1alpha1.SolrInitContainer", "kubedb.dev/apimachinery/apis/catalog/v1alpha1.SolrVersionDatabase", "kubedb.dev/apimachinery/apis/catalog/v1alpha1.UpdateConstraints"}, } } diff --git a/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/solr_version_types.go b/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/solr_version_types.go index 96848d0d..460e1f5e 100644 --- a/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/solr_version_types.go +++ b/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/solr_version_types.go @@ -59,6 +59,8 @@ type SolrVersionSpec struct { // +optional Deprecated bool `json:"deprecated,omitempty"` // SecurityContext is for the additional security information for the Solr container + // update constraints + UpdateConstraints UpdateConstraints `json:"updateConstraints,omitempty"` // +optional SecurityContext SecurityContext `json:"securityContext"` } diff --git a/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/zz_generated.deepcopy.go b/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/zz_generated.deepcopy.go index 8368d286..56c3f13b 100644 --- a/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/kubedb.dev/apimachinery/apis/catalog/v1alpha1/zz_generated.deepcopy.go @@ -3713,6 +3713,7 @@ func (in *SolrVersionSpec) DeepCopyInto(out *SolrVersionSpec) { *out = *in out.DB = in.DB out.InitContainer = in.InitContainer + in.UpdateConstraints.DeepCopyInto(&out.UpdateConstraints) in.SecurityContext.DeepCopyInto(&out.SecurityContext) return } diff --git a/vendor/kubedb.dev/apimachinery/apis/kubedb/constants.go b/vendor/kubedb.dev/apimachinery/apis/kubedb/constants.go index 19bfafa5..2041bed8 100644 --- a/vendor/kubedb.dev/apimachinery/apis/kubedb/constants.go +++ b/vendor/kubedb.dev/apimachinery/apis/kubedb/constants.go @@ -1000,14 +1000,23 @@ const ( EnvDruidCoordinatorAsOverlord = "DRUID_COORDINATOR_AS_OVERLORD" EnvDruidMetadataTLSEnable = "DRUID_METADATA_TLS_ENABLE" EnvDruidMetadataStorageType = "DRUID_METADATA_STORAGE_TYPE" + EnvDruidKeyStorePassword = "DRUID_KEY_STORE_PASSWORD" - DruidPortCoordinators = 8081 - DruidPortOverlords = 8090 - DruidPortHistoricals = 8083 - DruidPortMiddleManagers = 8091 - DruidPortBrokers = 8082 - DruidPortRouters = 8888 - DruidExporterPort = 9104 + DruidPlainTextPortCoordinators = 8081 + DruidPlainTextPortOverlords = 8090 + DruidPlainTextPortHistoricals = 8083 + DruidPlainTextPortMiddleManagers = 8091 + DruidPlainTextPortBrokers = 8082 + DruidPlainTextPortRouters = 8888 + + DruidTLSPortCoordinators = 8281 + DruidTLSPortOverlords = 8290 + DruidTLSPortHistoricals = 8283 + DruidTLSPortMiddleManagers = 8291 + DruidTLSPortBrokers = 8282 + DruidTLSPortRouters = 9088 + + DruidExporterPort = 9104 DruidMetadataStorageTypePostgres = "Postgres" @@ -1030,6 +1039,33 @@ const ( DruidMetadataStorageConnectorPasswordEnvConfig = "{\"type\": \"environment\", \"variable\": \"DRUID_METADATA_STORAGE_PASSWORD\"}" DruidMetadataStorageCreateTables = "druid.metadata.storage.connector.createTables" + // Druid TLS + DruidKeystorePasswordKey = "keystore_password" + DruidTrustStorePasswordKey = "truststore_password" + DruidKeystoreSecretKey = "keystore-cred" + + DruidEnablePlaintextPort = "druid.enablePlaintextPort" + DruidEnableTLSPort = "druid.enableTlsPort" + DruidKeyStorePath = "druid.server.https.keyStorePath" + DruidKeyStoreType = "druid.server.https.keyStoreType" + DruidCertAlias = "druid.server.https.certAlias" + DruidKeyStorePassword = "druid.server.https.keyStorePassword" + DruidRequireClientCertificate = "druid.server.https.requireClientCertificate" + DruidTrustStoreType = "druid.server.https.trustStoreType" + + DruidTrustStorePassword = "druid.client.https.trustStorePassword" + DruidTrustStorePath = "druid.client.https.trustStorePath" + DruidClientTrustStoreType = "druid.client.https.trustStoreType" + DruidClientValidateHostNames = "druid.client.https.validateHostnames" + + DruidKeyStoreTypeJKS = "jks" + DruidKeyStorePasswordEnvConfig = "{\"type\": \"environment\", \"variable\": \"DRUID_KEY_STORE_PASSWORD\"}" + + DruidValueTrue = "true" + DruidValueFalse = "false" + + DruidCertDir = "/opt/druid/ssl" + // MySQL TLS DruidMetadataMySQLUseSSL = "druid.metadata.mysql.ssl.useSSL" DruidMetadataMySQLClientCertKeyStoreURL = "druid.metadata.mysql.ssl.clientCertificateKeyStoreUrl" @@ -1102,6 +1138,7 @@ const ( DruidExtensionBasicSecurity = "druid-basic-security" DruidExtensionMultiStageQuery = "druid-multi-stage-query" DruidExtensionPrometheusEmitter = "prometheus-emitter" + DruidExtensionSSLContext = "simple-client-sslcontext" DruidService = "druid.service" // Monitoring Configurations @@ -1122,6 +1159,9 @@ const ( DruidMonitoringTaskCountStatsMonitor = "org.apache.druid.server.metrics.TaskCountStatsMonitor" DruidMonitoringSysMonitor = "org.apache.druid.java.util.metrics.SysMonitor" + DruidDimensionMapDir = "/opt/druid/conf/metrics.json" + DruidEmitterPrometheusStrategyValue = "exporter" + /// Coordinators Configurations DruidCoordinatorStartDelay = "druid.coordinator.startDelay" DruidCoordinatorPeriod = "druid.coordinator.period" diff --git a/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/druid_helpers.go b/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/druid_helpers.go index 45fd8c66..79875da3 100644 --- a/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/druid_helpers.go +++ b/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/druid_helpers.go @@ -19,6 +19,7 @@ package v1alpha2 import ( "context" "fmt" + "path/filepath" "strconv" "strings" @@ -125,14 +126,18 @@ func (d *Druid) ServiceLabels(alias ServiceAlias, extraLabels ...map[string]stri return d.offShootLabels(meta_util.OverwriteKeys(d.OffShootSelectors(), extraLabels...), svcTemplate.Labels) } -func (r *Druid) Finalizer() string { - return fmt.Sprintf("%s/%s", apis.Finalizer, r.ResourceSingular()) +func (d *Druid) Finalizer() string { + return fmt.Sprintf("%s/%s", apis.Finalizer, d.ResourceSingular()) } func (d *Druid) DefaultUserCredSecretName(username string) string { return meta_util.NameWithSuffix(d.Name, strings.ReplaceAll(fmt.Sprintf("%s-cred", username), "_", "-")) } +func (d *Druid) DruidSecretName(suffix string) string { + return strings.Join([]string{d.Name, suffix}, "-") +} + type DruidStatsService struct { *Druid } @@ -204,21 +209,23 @@ func (d *Druid) PodControllerLabels(nodeType DruidNodeRoleType, extraLabels ...m } func (d *Druid) GetNodeSpec(nodeType DruidNodeRoleType) (*DruidNode, *DruidDataNode) { - if nodeType == DruidNodeRoleCoordinators { + switch nodeType { + case DruidNodeRoleCoordinators: return d.Spec.Topology.Coordinators, nil - } else if nodeType == DruidNodeRoleOverlords { + case DruidNodeRoleOverlords: return d.Spec.Topology.Overlords, nil - } else if nodeType == DruidNodeRoleMiddleManagers { + case DruidNodeRoleMiddleManagers: return nil, d.Spec.Topology.MiddleManagers - } else if nodeType == DruidNodeRoleHistoricals { + case DruidNodeRoleHistoricals: return nil, d.Spec.Topology.Historicals - } else if nodeType == DruidNodeRoleBrokers { + case DruidNodeRoleBrokers: return d.Spec.Topology.Brokers, nil - } else if nodeType == DruidNodeRoleRouters { + case DruidNodeRoleRouters: return d.Spec.Topology.Routers, nil + default: + klog.Errorf("unknown druid node role %s\n", nodeType) + return nil, nil } - - panic("Node role name does not match any known types") } func (d *Druid) ServiceAccountName() string { @@ -235,19 +242,42 @@ func (d *Druid) DruidNodeRoleStringSingular(nodeRole DruidNodeRoleType) string { } func (d *Druid) DruidNodeContainerPort(nodeRole DruidNodeRoleType) int32 { - if nodeRole == DruidNodeRoleCoordinators { - return kubedb.DruidPortCoordinators - } else if nodeRole == DruidNodeRoleOverlords { - return kubedb.DruidPortOverlords - } else if nodeRole == DruidNodeRoleMiddleManagers { - return kubedb.DruidPortMiddleManagers - } else if nodeRole == DruidNodeRoleHistoricals { - return kubedb.DruidPortHistoricals - } else if nodeRole == DruidNodeRoleBrokers { - return kubedb.DruidPortBrokers + if !d.Spec.EnableSSL { + switch nodeRole { + case DruidNodeRoleCoordinators: + return kubedb.DruidPlainTextPortCoordinators + case DruidNodeRoleOverlords: + return kubedb.DruidPlainTextPortOverlords + case DruidNodeRoleMiddleManagers: + return kubedb.DruidPlainTextPortMiddleManagers + case DruidNodeRoleHistoricals: + return kubedb.DruidPlainTextPortHistoricals + case DruidNodeRoleBrokers: + return kubedb.DruidPlainTextPortBrokers + case DruidNodeRoleRouters: + return kubedb.DruidPlainTextPortRouters + default: + klog.Errorf("unknown druid node role %s\n", nodeRole) + } + } else { + switch nodeRole { + case DruidNodeRoleCoordinators: + return kubedb.DruidTLSPortCoordinators + case DruidNodeRoleOverlords: + return kubedb.DruidTLSPortOverlords + case DruidNodeRoleMiddleManagers: + return kubedb.DruidTLSPortMiddleManagers + case DruidNodeRoleHistoricals: + return kubedb.DruidTLSPortHistoricals + case DruidNodeRoleBrokers: + return kubedb.DruidTLSPortBrokers + case DruidNodeRoleRouters: + return kubedb.DruidTLSPortRouters + default: + klog.Errorf("unknown node role %s\n", nodeRole) + } } - // Routers - return kubedb.DruidPortRouters + return -1 } func (d *Druid) SetHealthCheckerDefaults() { @@ -320,7 +350,8 @@ func (d *Druid) GetMetadataStorageType(metadataStorage string) DruidMetadataStor metadataStorage == kubedb.DruidMetadataStorageTypePostgres || metadataStorage == strings.ToLower(string(kubedb.DruidMetadataStorageTypePostgres)) { return DruidMetadataStoragePostgreSQL } else { - panic(fmt.Sprintf("Unknown metadata storage type: %s", metadataStorage)) + klog.Errorf("Unknown metadata storage type: %s", metadataStorage) + return "" } } @@ -365,13 +396,30 @@ func (d *Druid) OffshootSelectors(extraSelectors ...map[string]string) map[strin return meta_util.OverwriteKeys(selector, extraSelectors...) } -func (d Druid) OffshootLabels() map[string]string { +func (d *Druid) OffshootLabels() map[string]string { return d.offshootLabels(d.OffshootSelectors(), nil) } -func (e Druid) offshootLabels(selector, override map[string]string) map[string]string { +func (d *Druid) offshootLabels(selector, override map[string]string) map[string]string { selector[meta_util.ComponentLabelKey] = kubedb.ComponentDatabase - return meta_util.FilterKeys(kubedb.GroupName, selector, meta_util.OverwriteKeys(nil, e.Labels, override)) + return meta_util.FilterKeys(kubedb.GroupName, selector, meta_util.OverwriteKeys(nil, d.Labels, override)) +} + +// CertificateName returns the default certificate name and/or certificate secret name for a certificate alias +func (d *Druid) CertificateName(alias DruidCertificateAlias) string { + return meta_util.NameWithSuffix(d.Name, fmt.Sprintf("%s-cert", string(alias))) +} + +// GetCertSecretName returns the secret name for a certificate alias if any, +// otherwise returns default certificate secret name for the given alias. +func (d *Druid) GetCertSecretName(alias DruidCertificateAlias) string { + if d.Spec.TLS != nil { + name, ok := kmapi.GetCertificateSecretName(d.Spec.TLS.Certificates, string(alias)) + if ok { + return name + } + } + return d.CertificateName(alias) } func (d *Druid) SetDefaults() { @@ -379,11 +427,7 @@ func (d *Druid) SetDefaults() { d.Spec.DeletionPolicy = TerminationPolicyDelete } - if d.Spec.DisableSecurity == nil { - d.Spec.DisableSecurity = pointer.BoolP(false) - } - - if !*d.Spec.DisableSecurity { + if !d.Spec.DisableSecurity { if d.Spec.AuthSecret == nil { d.Spec.AuthSecret = &v1.LocalObjectReference{ Name: d.DefaultUserCredSecretName(kubedb.DruidUserAdmin), @@ -391,6 +435,16 @@ func (d *Druid) SetDefaults() { } } + if d.Spec.EnableSSL { + if d.Spec.KeystoreCredSecret == nil { + d.Spec.KeystoreCredSecret = &SecretReference{ + LocalObjectReference: core.LocalObjectReference{ + Name: d.DruidSecretName(kubedb.DruidKeystoreSecretKey), + }, + } + } + } + var druidVersion catalog.DruidVersion err := DefaultClient.Get(context.TODO(), types.NamespacedName{ Name: d.Spec.Version, @@ -523,6 +577,18 @@ func (d *Druid) SetDefaults() { } d.Spec.Monitor.SetDefaults() } + + if d.Spec.EnableSSL { + d.SetTLSDefaults() + } +} + +func (d *Druid) SetTLSDefaults() { + if d.Spec.TLS == nil || d.Spec.TLS.IssuerRef == nil { + return + } + d.Spec.TLS.Certificates = kmapi.SetMissingSecretNameForCertificate(d.Spec.TLS.Certificates, string(DruidServerCert), d.CertificateName(DruidServerCert)) + d.Spec.TLS.Certificates = kmapi.SetMissingSecretNameForCertificate(d.Spec.TLS.Certificates, string(DruidClientCert), d.CertificateName(DruidClientCert)) } func (d *Druid) SetDefaultsToMetadataStorage() { @@ -725,3 +791,16 @@ func (d *Druid) GetZooKeeperName() string { func (d *Druid) GetInitConfigMapName() string { return d.OffShootName() + "-init-script" } + +// CertSecretVolumeName returns the CertSecretVolumeName +// Values will be like: client-certs, server-certs etc. +func (d *Druid) CertSecretVolumeName(alias DruidCertificateAlias) string { + return string(alias) + "-certs" +} + +// CertSecretVolumeMountPath returns the CertSecretVolumeMountPath +// if configDir is "/var/druid/ssl", +// mountPath will be, "/var/druid/ssl/". +func (d *Druid) CertSecretVolumeMountPath(configDir string, cert string) string { + return filepath.Join(configDir, cert) +} diff --git a/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/druid_types.go b/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/druid_types.go index ef34f62e..1a40e8fb 100644 --- a/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/druid_types.go +++ b/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/druid_types.go @@ -64,7 +64,7 @@ type DruidSpec struct { // disable security. It disables authentication security of user. // If unset, default is false // +optional - DisableSecurity *bool `json:"disableSecurity,omitempty"` + DisableSecurity bool `json:"disableSecurity,omitempty"` // Database authentication secret // +optional @@ -79,9 +79,16 @@ type DruidSpec struct { // +optional ConfigSecret *core.LocalObjectReference `json:"configSecret,omitempty"` - //// TLS contains tls configurations - //// +optional - //TLS *kmapi.TLSConfig `json:"tls,omitempty"` + // To enable ssl for http layer + EnableSSL bool `json:"enableSSL,omitempty"` + + // Keystore encryption secret + // +optional + KeystoreCredSecret *SecretReference `json:"keystoreCredSecret,omitempty"` + + // TLS contains tls configurations + // +optional + TLS *kmapi.TLSConfig `json:"tls,omitempty"` // MetadataStorage contains information for Druid to connect to external dependency metadata storage // +optional @@ -274,3 +281,11 @@ const ( DruidDeepStorageAzure DruidDeepStorageType = "azure" DruidDeepStorageHDFS DruidDeepStorageType = "hdfs" ) + +// +kubebuilder:validation:Enum=server;client;metrics-exporter +type DruidCertificateAlias string + +const ( + DruidServerCert DruidCertificateAlias = "server" + DruidClientCert DruidCertificateAlias = "client" +) diff --git a/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/openapi_generated.go b/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/openapi_generated.go index 2428653d..de1434d0 100644 --- a/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/openapi_generated.go +++ b/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/openapi_generated.go @@ -26944,6 +26944,25 @@ func schema_apimachinery_apis_kubedb_v1alpha2_DruidSpec(ref common.ReferenceCall Ref: ref("k8s.io/api/core/v1.LocalObjectReference"), }, }, + "enableSSL": { + SchemaProps: spec.SchemaProps{ + Description: "To enable ssl for http layer", + Type: []string{"boolean"}, + Format: "", + }, + }, + "keystoreCredSecret": { + SchemaProps: spec.SchemaProps{ + Description: "Keystore encryption secret", + Ref: ref("kubedb.dev/apimachinery/apis/kubedb/v1alpha2.SecretReference"), + }, + }, + "tls": { + SchemaProps: spec.SchemaProps{ + Description: "TLS contains tls configurations", + Ref: ref("kmodules.xyz/client-go/api/v1.TLSConfig"), + }, + }, "metadataStorage": { SchemaProps: spec.SchemaProps{ Description: "MetadataStorage contains information for Druid to connect to external dependency metadata storage", @@ -27008,7 +27027,7 @@ func schema_apimachinery_apis_kubedb_v1alpha2_DruidSpec(ref common.ReferenceCall }, }, Dependencies: []string{ - "k8s.io/api/core/v1.LocalObjectReference", "kmodules.xyz/client-go/api/v1.HealthCheckSpec", "kmodules.xyz/monitoring-agent-api/api/v1.AgentSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.DeepStorageSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.DruidClusterTopology", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.InitSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.MetadataStorage", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.NamedServiceTemplateSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.ZookeeperRef"}, + "k8s.io/api/core/v1.LocalObjectReference", "kmodules.xyz/client-go/api/v1.HealthCheckSpec", "kmodules.xyz/client-go/api/v1.TLSConfig", "kmodules.xyz/monitoring-agent-api/api/v1.AgentSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.DeepStorageSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.DruidClusterTopology", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.InitSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.MetadataStorage", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.NamedServiceTemplateSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.SecretReference", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.ZookeeperRef"}, } } diff --git a/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/zz_generated.deepcopy.go b/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/zz_generated.deepcopy.go index 7e98f2fd..ca330600 100644 --- a/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/zz_generated.deepcopy.go +++ b/vendor/kubedb.dev/apimachinery/apis/kubedb/v1alpha2/zz_generated.deepcopy.go @@ -989,11 +989,6 @@ func (in *DruidSpec) DeepCopyInto(out *DruidSpec) { *out = new(DruidClusterTopology) (*in).DeepCopyInto(*out) } - if in.DisableSecurity != nil { - in, out := &in.DisableSecurity, &out.DisableSecurity - *out = new(bool) - **out = **in - } if in.AuthSecret != nil { in, out := &in.AuthSecret, &out.AuthSecret *out = new(corev1.LocalObjectReference) @@ -1009,6 +1004,16 @@ func (in *DruidSpec) DeepCopyInto(out *DruidSpec) { *out = new(corev1.LocalObjectReference) **out = **in } + if in.KeystoreCredSecret != nil { + in, out := &in.KeystoreCredSecret, &out.KeystoreCredSecret + *out = new(SecretReference) + **out = **in + } + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = new(apiv1.TLSConfig) + (*in).DeepCopyInto(*out) + } if in.MetadataStorage != nil { in, out := &in.MetadataStorage, &out.MetadataStorage *out = new(MetadataStorage) diff --git a/vendor/kubedb.dev/apimachinery/crds/catalog.kubedb.com_solrversions.yaml b/vendor/kubedb.dev/apimachinery/crds/catalog.kubedb.com_solrversions.yaml index 16bc33b5..0149f607 100644 --- a/vendor/kubedb.dev/apimachinery/crds/catalog.kubedb.com_solrversions.yaml +++ b/vendor/kubedb.dev/apimachinery/crds/catalog.kubedb.com_solrversions.yaml @@ -67,6 +67,17 @@ spec: format: int64 type: integer type: object + updateConstraints: + properties: + allowlist: + items: + type: string + type: array + denylist: + items: + type: string + type: array + type: object version: type: string required: diff --git a/vendor/kubedb.dev/apimachinery/crds/kubedb.com_druids.yaml b/vendor/kubedb.dev/apimachinery/crds/kubedb.com_druids.yaml index e665f732..5925af93 100644 --- a/vendor/kubedb.dev/apimachinery/crds/kubedb.com_druids.yaml +++ b/vendor/kubedb.dev/apimachinery/crds/kubedb.com_druids.yaml @@ -88,6 +88,8 @@ spec: type: string disableSecurity: type: boolean + enableSSL: + type: boolean halted: type: boolean healthChecker: @@ -1117,6 +1119,15 @@ spec: waitForInitialRestore: type: boolean type: object + keystoreCredSecret: + properties: + externallyManaged: + type: boolean + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic metadataStorage: properties: createTables: @@ -1411,6 +1422,107 @@ spec: - alias type: object type: array + tls: + properties: + certificates: + items: + properties: + alias: + type: string + dnsNames: + items: + type: string + type: array + duration: + type: string + emailAddresses: + items: + type: string + type: array + ipAddresses: + items: + type: string + type: array + issuerRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + privateKey: + properties: + encoding: + enum: + - PKCS1 + - PKCS8 + type: string + type: object + renewBefore: + type: string + secretName: + type: string + subject: + properties: + countries: + items: + type: string + type: array + localities: + items: + type: string + type: array + organizationalUnits: + items: + type: string + type: array + organizations: + items: + type: string + type: array + postalCodes: + items: + type: string + type: array + provinces: + items: + type: string + type: array + serialNumber: + type: string + streetAddresses: + items: + type: string + type: array + type: object + uris: + items: + type: string + type: array + required: + - alias + type: object + type: array + issuerRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + type: object topology: properties: brokers: diff --git a/vendor/kubedb.dev/apimachinery/crds/ops.kubedb.com_druidopsrequests.yaml b/vendor/kubedb.dev/apimachinery/crds/ops.kubedb.com_druidopsrequests.yaml index e76cea9f..2ab0c325 100644 --- a/vendor/kubedb.dev/apimachinery/crds/ops.kubedb.com_druidopsrequests.yaml +++ b/vendor/kubedb.dev/apimachinery/crds/ops.kubedb.com_druidopsrequests.yaml @@ -48,6 +48,22 @@ spec: - IfReady - Always type: string + configuration: + properties: + applyConfig: + additionalProperties: + type: string + type: object + configSecret: + properties: + name: + default: "" + type: string + type: object + x-kubernetes-map-type: atomic + removeCustomConfig: + type: boolean + type: object databaseRef: properties: name: @@ -55,16 +71,154 @@ spec: type: string type: object x-kubernetes-map-type: atomic + horizontalScaling: + properties: + topology: + properties: + brokers: + format: int32 + type: integer + coordinators: + format: int32 + type: integer + historicals: + format: int32 + type: integer + middleManagers: + format: int32 + type: integer + overlords: + format: int32 + type: integer + routers: + format: int32 + type: integer + type: object + type: object restart: type: object timeout: type: string + tls: + properties: + certificates: + items: + properties: + alias: + type: string + dnsNames: + items: + type: string + type: array + duration: + type: string + emailAddresses: + items: + type: string + type: array + ipAddresses: + items: + type: string + type: array + issuerRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + privateKey: + properties: + encoding: + enum: + - PKCS1 + - PKCS8 + type: string + type: object + renewBefore: + type: string + secretName: + type: string + subject: + properties: + countries: + items: + type: string + type: array + localities: + items: + type: string + type: array + organizationalUnits: + items: + type: string + type: array + organizations: + items: + type: string + type: array + postalCodes: + items: + type: string + type: array + provinces: + items: + type: string + type: array + serialNumber: + type: string + streetAddresses: + items: + type: string + type: array + type: object + uris: + items: + type: string + type: array + required: + - alias + type: object + type: array + issuerRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + remove: + type: boolean + rotateCertificates: + type: boolean + type: object type: enum: + - UpdateVersion + - HorizontalScaling - VerticalScaling - VolumeExpansion - Restart + - Reconfigure + - ReconfigureTLS type: string + updateVersion: + properties: + targetVersion: + type: string + type: object verticalScaling: properties: brokers: diff --git a/vendor/modules.txt b/vendor/modules.txt index dc6a2180..b76db862 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1564,7 +1564,7 @@ kmodules.xyz/offshoot-api/api/v1 kmodules.xyz/offshoot-api/api/v1/conversion kmodules.xyz/offshoot-api/api/v2 kmodules.xyz/offshoot-api/util -# kubedb.dev/apimachinery v0.48.0 +# kubedb.dev/apimachinery v0.48.0 => ../apimachinery ## explicit; go 1.22.1 kubedb.dev/apimachinery/apis kubedb.dev/apimachinery/apis/catalog @@ -1672,3 +1672,4 @@ xorm.io/xorm/tags # sigs.k8s.io/controller-runtime => github.com/kmodules/controller-runtime v0.18.4-0.20240603164526-fa88ec2314fe # github.com/imdario/mergo => github.com/imdario/mergo v0.3.6 # k8s.io/apiserver => github.com/kmodules/apiserver v0.30.2-0.20240519082755-d7b8c2d9e699 +# kubedb.dev/apimachinery => ../apimachinery