diff --git a/api/v1/aerospikecluster_mutating_webhook.go b/api/v1/aerospikecluster_mutating_webhook.go index 7e6203ab9..10c7222c4 100644 --- a/api/v1/aerospikecluster_mutating_webhook.go +++ b/api/v1/aerospikecluster_mutating_webhook.go @@ -31,6 +31,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook/admission" "github.com/aerospike/aerospike-kubernetes-operator/pkg/merge" + lib "github.com/aerospike/aerospike-management-lib" ) //nolint:lll // for readability @@ -248,21 +249,19 @@ func (c *AerospikeCluster) updateRacksAerospikeConfigFromGlobal(asLog logr.Logge for idx := range c.Spec.RackConfig.Racks { rack := &c.Spec.RackConfig.Racks[idx] - var ( - m map[string]interface{} - err error - ) + var m map[string]interface{} if rack.InputAerospikeConfig != nil { // Merge this rack's and global config. - m, err = merge.Merge( + merged, err := merge.Merge( c.Spec.AerospikeConfig.Value, rack.InputAerospikeConfig.Value, ) - if err != nil { return err } + m = lib.DeepCopy(merged).(map[string]interface{}) + asLog.V(1).Info( "Merged rack config from global aerospikeConfig", "rack id", rack.ID, "rackAerospikeConfig", m, "globalAerospikeConfig", diff --git a/api/v1/aerospikecluster_types.go b/api/v1/aerospikecluster_types.go index 27627f043..699a08726 100644 --- a/api/v1/aerospikecluster_types.go +++ b/api/v1/aerospikecluster_types.go @@ -659,6 +659,11 @@ type AerospikeClusterStatusSpec struct { //nolint:govet // for readability // +kubebuilder:pruning:PreserveUnknownFields // +nullable AerospikeConfig *AerospikeConfigSpec `json:"aerospikeConfig,omitempty"` + // EnableDynamicConfigUpdate enables dynamic config update flow of the operator. + // If enabled, operator will try to update the Aerospike config dynamically. + // In case of inconsistent state during dynamic config update, operator falls back to rolling restart. + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Enable Dynamic Config Update" + EnableDynamicConfigUpdate *bool `json:"enableDynamicConfigUpdate,omitempty"` // Define resources requests and limits for Aerospike Server Container. // Please contact aerospike for proper sizing exercise // Only Memory and Cpu resources can be given @@ -994,6 +999,14 @@ func CopySpecToStatus(spec *AerospikeClusterSpec) (*AerospikeClusterStatusSpec, status.OperatorClientCertSpec = clientCertSpec } + if spec.EnableDynamicConfigUpdate != nil { + enableDynamicConfigUpdate := lib.DeepCopy( + spec.EnableDynamicConfigUpdate, + ).(*bool) + + status.EnableDynamicConfigUpdate = enableDynamicConfigUpdate + } + // Storage statusPodSpec := lib.DeepCopy(&spec.PodSpec).(*AerospikePodSpec) status.PodSpec = *statusPodSpec @@ -1083,6 +1096,14 @@ func CopyStatusToSpec(status *AerospikeClusterStatusSpec) (*AerospikeClusterSpec spec.OperatorClientCertSpec = clientCertSpec } + if status.EnableDynamicConfigUpdate != nil { + enableDynamicConfigUpdate := lib.DeepCopy( + status.EnableDynamicConfigUpdate, + ).(*bool) + + spec.EnableDynamicConfigUpdate = enableDynamicConfigUpdate + } + // Storage specPodSpec := lib.DeepCopy(&status.PodSpec).(*AerospikePodSpec) diff --git a/api/v1/aerospikecluster_validating_webhook.go b/api/v1/aerospikecluster_validating_webhook.go index 19813a150..7cca9aa7a 100644 --- a/api/v1/aerospikecluster_validating_webhook.go +++ b/api/v1/aerospikecluster_validating_webhook.go @@ -1358,7 +1358,7 @@ func validateAerospikeConfigUpdate( } } - return validateNsConfUpdate(incomingSpec, outgoingSpec, currentStatus, incomingVersion) + return validateNsConfUpdate(incomingSpec, outgoingSpec, currentStatus) } func validateTLSUpdate(oldConf, newConf map[string]interface{}) error { @@ -1516,7 +1516,7 @@ func validateNetworkPolicyUpdate(oldPolicy, newPolicy *AerospikeNetworkPolicy) e return nil } -func validateNsConfUpdate(newConfSpec, oldConfSpec, currentStatus *AerospikeConfigSpec, incomingVersion string) error { +func validateNsConfUpdate(newConfSpec, oldConfSpec, currentStatus *AerospikeConfigSpec) error { newConf := newConfSpec.Value oldConf := oldConfSpec.Value @@ -1550,13 +1550,8 @@ func validateNsConfUpdate(newConfSpec, oldConfSpec, currentStatus *AerospikeConf } if singleConf["name"] == oldSingleConf["name"] { - val, err := lib.CompareVersions(incomingVersion, Version6) - if err != nil { - return fmt.Errorf("failed to check image version: %v", err) - } - - // For versions 6.0 and later, replication-factor is dynamic for AP namespaces (non strong-consistency). - if (IsNSSCEnabled(singleConf) || val < 0) && isValueUpdated( + // replication-factor update not allowed + if isValueUpdated( oldSingleConf, singleConf, "replication-factor", ) { return fmt.Errorf( diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index fad9aac52..d21f9c6b9 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -256,6 +256,11 @@ func (in *AerospikeClusterStatusSpec) DeepCopyInto(out *AerospikeClusterStatusSp in, out := &in.AerospikeConfig, &out.AerospikeConfig *out = (*in).DeepCopy() } + if in.EnableDynamicConfigUpdate != nil { + in, out := &in.EnableDynamicConfigUpdate, &out.EnableDynamicConfigUpdate + *out = new(bool) + **out = **in + } if in.Resources != nil { in, out := &in.Resources, &out.Resources *out = new(corev1.ResourceRequirements) diff --git a/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml b/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml index bef8aea20..6676d4989 100644 --- a/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml +++ b/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml @@ -9601,6 +9601,12 @@ spec: - customInterface type: string type: object + enableDynamicConfigUpdate: + description: EnableDynamicConfigUpdate enables dynamic config update + flow of the operator. If enabled, operator will try to update the + Aerospike config dynamically. In case of inconsistent state during + dynamic config update, operator falls back to rolling restart. + type: boolean image: description: Aerospike server image type: string diff --git a/config/manifests/bases/aerospike-kubernetes-operator.clusterserviceversion.yaml b/config/manifests/bases/aerospike-kubernetes-operator.clusterserviceversion.yaml index cd2b711bb..92a168efd 100644 --- a/config/manifests/bases/aerospike-kubernetes-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/aerospike-kubernetes-operator.clusterserviceversion.yaml @@ -47,12 +47,12 @@ spec: the Aerospike cluster. displayName: Aerospike Network Policy path: aerospikeNetworkPolicy - - description: EnableDynamicUpdate enables dynamic config update flow of the - operator. If enabled, operator will try to update the Aerospike config dynamically. - In case of inconsistent state during dynamic config update, operator falls - back to rolling restart. - displayName: EnableDynamicUpdate - path: enableDynamicUpdate + - description: EnableDynamicConfigUpdate enables dynamic config update flow + of the operator. If enabled, operator will try to update the Aerospike config + dynamically. In case of inconsistent state during dynamic config update, + operator falls back to rolling restart. + displayName: Enable Dynamic Config Update + path: enableDynamicConfigUpdate - description: Aerospike server image displayName: Server Image path: image diff --git a/config/samples/secrets/server-cert.pem b/config/samples/secrets/server-cert.pem index ebdbde86c..11ee59b1a 100644 --- a/config/samples/secrets/server-cert.pem +++ b/config/samples/secrets/server-cert.pem @@ -2,78 +2,84 @@ Certificate: Data: Version: 3 (0x2) Serial Number: - bc:b2:59:97:0d:d4:37:b7 - Signature Algorithm: sha256WithRSAEncryption + 1a:b3:73:28:82:32:20:ca:f1:b2:72:57:4f:42:62:51:ad:d3:ec:df + Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=CA, L=Mountain View, O=Aerospike, Inc., OU=Engineering Test, CN=Root CA - IssuerFile: ca-cert2.pem Validity - Not Before: Apr 21 07:40:04 2023 GMT - Not After : Apr 20 07:40:04 2024 GMT - Subject: C=US, ST=CA, L=Mountain View, O=Aerospike, Inc., OU=Cluster Name Test, CN=aerospike-a-0.test-runner + Not Before: Apr 22 08:57:01 2024 GMT + Not After : Aug 24 08:57:01 3023 GMT + Subject: C=US, ST=CA, O=Aerospike, OU=Engineering Test, CN=aerospike-a-0.test-runner Subject Public Key Info: Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) + Public-Key: (2048 bit) Modulus: - 00:ea:38:e7:cc:6d:27:61:a8:a4:42:f2:d1:88:f5: - a9:4f:bb:27:25:5b:c9:fd:6c:68:09:72:e0:b8:b5: - 1f:76:ac:3b:49:8d:29:9f:fb:da:15:9f:b3:a8:14: - 71:6a:dd:e5:ec:7f:e4:7e:ee:38:7b:81:d7:4d:e2: - 4a:e7:40:e7:f9:d5:f7:e2:f6:18:c1:47:06:96:84: - 6a:da:89:d8:28:ee:ba:9a:4d:79:fc:3b:41:a6:c7: - fe:57:dd:4f:d6:33:4e:54:c2:8c:b6:53:69:11:a5: - f2:16:45:3e:4f:15:5c:93:f2:88:ed:6c:5d:cd:87: - 98:ca:d7:ae:87:b3:45:7a:45:ca:3a:9a:b3:6b:86: - 53:4d:03:07:51:6f:bc:45:18:36:4b:79:66:78:79: - 4a:68:39:fc:25:5f:88:b2:c8:fa:f5:cb:5b:a5:d0: - 8a:6e:92:c4:6a:3c:13:63:91:65:d8:d5:f3:dc:85: - e0:7c:da:d7:cb:97:2b:35:15:f0:2e:d8:84:df:b9: - c7:8f:a4:1a:7c:d5:20:3e:fc:6d:fe:e8:c0:2a:1f: - 52:da:d4:85:5d:d2:22:04:ff:fd:10:37:23:a7:ce: - 32:10:89:68:80:6b:2f:c5:23:76:d0:61:5a:0d:4b: - c2:00:a9:a4:db:b5:4e:30:d2:f4:2c:0a:9e:98:12: - 4f:67 + 00:a0:f1:9e:06:10:10:f9:75:00:bd:fc:94:05:1c: + 16:41:bf:25:dc:2f:05:6a:51:28:83:ba:9b:f2:16: + c1:a7:58:b2:c7:5f:c8:50:43:5d:21:b8:a6:0c:6c: + 8a:2c:40:57:86:e8:40:4e:2f:b3:08:7f:e8:69:6f: + 35:c9:a5:ee:24:7a:65:79:62:9c:41:f2:aa:62:fd: + 8d:ad:f1:da:fb:fe:96:83:30:e9:e4:c9:6e:34:04: + aa:eb:b0:dd:06:5a:ca:67:35:f2:02:ea:12:46:8f: + ca:56:cf:7a:3f:80:17:ca:c7:49:0f:cc:3c:dd:6f: + 36:ff:66:94:6f:ec:f4:dd:5a:bb:c2:48:e3:8f:84: + d9:df:14:d5:29:06:72:a0:40:ee:f5:95:be:8a:cf: + b6:80:54:e2:15:59:25:c4:5e:ab:8f:b3:01:c1:84: + e8:71:55:69:85:ab:a2:6b:98:5b:7d:a9:9b:27:fb: + e9:47:87:80:06:06:c9:23:b4:54:12:2e:32:36:f6: + a7:f2:59:5b:64:41:21:9f:10:e6:db:af:dd:40:f9: + 1e:49:d5:74:ff:58:88:e1:85:47:e7:b8:8f:d1:e6: + b8:da:09:ae:61:e7:89:65:07:d5:81:36:e4:71:e1: + 70:8f:66:76:77:e6:3c:ef:d4:71:48:11:fa:bf:7b: + e0:bd Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: DNS:aerospike-a-0.test-runner, DNS:aerospike-a-1.test-runner, DNS:aerospike-a-2.test-runner, DNS:aerospike-a-3.test-runner, DNS:aerospike-a-4.test-runner, DNS:aerospike-a-5.test-runner + X509v3 Subject Key Identifier: + E7:A1:BF:11:DB:27:49:B9:59:75:B8:0A:C9:01:48:9C:85:31:F7:7E + X509v3 Authority Key Identifier: + CB:DD:69:7B:6D:3D:C7:6F:36:C0:EB:AF:4C:26:4D:3E:E0:97:53:61 Signature Algorithm: sha256WithRSAEncryption - 08:63:53:34:d1:8e:e9:96:5d:45:fb:13:61:63:83:25:ef:9d: - 45:fd:30:0f:12:ab:d5:ac:6e:cd:76:73:c6:96:02:b5:1d:33: - e9:ee:32:84:8b:39:0d:ab:a4:03:7f:f2:c5:0a:24:3e:59:75: - 37:28:ef:d4:6c:4c:2a:c0:45:bf:02:4a:5d:e5:7d:44:bb:f8: - 63:3a:28:f6:ff:f6:8d:ed:c4:50:e8:48:cd:86:67:ab:1d:43: - 86:f9:f7:cb:e5:db:85:9e:ed:c1:fe:97:ef:04:54:2d:ff:ab: - fd:ad:e9:85:2e:c2:ce:b2:0c:af:bb:4a:80:3a:5c:f8:c9:04: - 5f:10:2e:18:3b:7a:35:42:86:da:d7:a5:74:dd:2d:58:81:96: - a7:ab:01:98:c4:36:eb:d3:62:70:2d:5b:24:f7:db:c0:43:42: - 46:37:a1:57:25:7c:d5:43:a3:f9:75:35:46:f2:00:3b:8b:e1: - 59:af:58:cf:84:1d:97:0f:72:9b:b6:c4:82:8e:15:37:d1:25: - 34:7a:2e:ae:23:03:27:e9:8a:43:c8:0e:34:15:f1:15:62:e2: - f1:8b:e1:1b:f2:1a:50:d0:97:cb:bf:96:61:d9:f0:ca:75:b5: - 09:49:22:c6:d2:59:c9:c2:23:36:f3:c4:ab:8d:4a:fd:df:08: - 2e:1f:7d:90 + Signature Value: + 4b:2c:dc:65:27:63:a5:20:f3:e5:d4:42:66:d1:87:2a:74:48: + e1:63:89:1e:5a:43:41:e3:45:28:5d:fe:65:d4:9a:f7:20:0c: + c6:51:86:12:e0:59:12:e0:f7:5a:fc:9e:04:ab:ee:b7:c6:f5: + 84:53:46:33:a4:2f:af:35:2a:08:33:31:eb:5c:d3:e5:2c:2b: + c3:fd:27:49:98:67:60:e1:ba:79:d3:be:c9:df:6d:2f:a7:59: + 69:7b:6d:18:ec:7a:71:17:ab:9e:4a:dd:09:86:04:73:fe:35: + 11:64:70:1a:08:45:73:7d:d4:0d:d7:39:55:c9:86:e0:f2:79: + 1c:f6:6e:ac:af:fa:79:9d:02:f3:20:dd:2f:19:34:92:9c:b4: + 50:1d:cb:45:fb:6f:41:d0:52:10:28:c0:a6:45:06:b9:c4:50: + d0:6b:83:3a:31:eb:07:b6:64:5b:a6:01:8b:b2:2f:33:84:1e: + 9d:a5:a2:eb:e6:fa:85:51:67:a3:e1:fb:89:9f:22:15:41:c0: + d7:54:c2:36:b2:49:f8:fb:94:c7:44:04:5d:0f:70:b8:8e:f5: + 31:da:27:d8:8f:21:22:87:a7:df:32:2b:61:46:c2:de:e6:5d: + 96:f0:40:f5:b9:9e:ef:da:f4:90:94:7e:55:16:d7:9e:37:a4: + 13:56:61:5d + -----BEGIN CERTIFICATE----- -MIIEMTCCAxmgAwIBAgIJALyyWZcN1De3MA0GCSqGSIb3DQEBCwUAMHkxCzAJBgNV -BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEYMBYG -A1UECgwPQWVyb3NwaWtlLCBJbmMuMRkwFwYDVQQLDBBFbmdpbmVlcmluZyBUZXN0 -MRAwDgYDVQQDDAdSb290IENBMB4XDTIzMDQyMTA3NDAwNFoXDTI0MDQyMDA3NDAw -NFowgYAxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRh -aW4gVmlldzEYMBYGA1UECgwPQWVyb3NwaWtlLCBJbmMuMRowGAYDVQQLDBFDbHVz -dGVyIE5hbWUgVGVzdDEWMBQGA1UEAwwNYm9iLWNsdXN0ZXItYTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAOo458xtJ2GopELy0Yj1qU+7JyVbyf1saAly -4Li1H3asO0mNKZ/72hWfs6gUcWrd5ex/5H7uOHuB103iSudA5/nV9+L2GMFHBpaE -atqJ2CjuuppNefw7QabH/lfdT9YzTlTCjLZTaRGl8hZFPk8VXJPyiO1sXc2HmMrX -roezRXpFyjqas2uGU00DB1FvvEUYNkt5Znh5Smg5/CVfiLLI+vXLW6XQim6SxGo8 -E2ORZdjV89yF4Hza18uXKzUV8C7YhN+5x4+kGnzVID78bf7owCofUtrUhV3SIgT/ -/RA3I6fOMhCJaIBrL8UjdtBhWg1LwgCppNu1TjDS9CwKnpgST2cCAwEAAaOBszCB -sDCBrQYDVR0RBIGlMIGighlhZXJvc3Bpa2UtYS0wLnRlc3QtcnVubmVyghlhZXJv -c3Bpa2UtYS0xLnRlc3QtcnVubmVyghlhZXJvc3Bpa2UtYS0yLnRlc3QtcnVubmVy -ghlhZXJvc3Bpa2UtYS0zLnRlc3QtcnVubmVyghlhZXJvc3Bpa2UtYS00LnRlc3Qt -cnVubmVyghlhZXJvc3Bpa2UtYS01LnRlc3QtcnVubmVyMA0GCSqGSIb3DQEBCwUA -A4IBAQAIY1M00Y7pll1F+xNhY4Ml751F/TAPEqvVrG7NdnPGlgK1HTPp7jKEizkN -q6QDf/LFCiQ+WXU3KO/UbEwqwEW/Akpd5X1Eu/hjOij2//aN7cRQ6EjNhmerHUOG -+ffL5duFnu3B/pfvBFQt/6v9remFLsLOsgyvu0qAOlz4yQRfEC4YO3o1Qoba16V0 -3S1YgZanqwGYxDbr02JwLVsk99vAQ0JGN6FXJXzVQ6P5dTVG8gA7i+FZr1jPhB2X -D3KbtsSCjhU30SU0ei6uIwMn6YpDyA40FfEVYuLxi+Eb8hpQ0JfLv5Zh2fDKdbUJ -SSLG0lnJwiM288SrjUr93wguH32Q +MIIEajCCA1KgAwIBAgIUGrNzKIIyIMrxsnJXT0JiUa3T7N8wDQYJKoZIhvcNAQEL +BQAweTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFp +biBWaWV3MRgwFgYDVQQKDA9BZXJvc3Bpa2UsIEluYy4xGTAXBgNVBAsMEEVuZ2lu +ZWVyaW5nIFRlc3QxEDAOBgNVBAMMB1Jvb3QgQ0EwIBcNMjQwNDIyMDg1NzAxWhgP +MzAyMzA4MjQwODU3MDFaMG0xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAG +A1UECgwJQWVyb3NwaWtlMRkwFwYDVQQLDBBFbmdpbmVlcmluZyBUZXN0MSIwIAYD +VQQDDBlhZXJvc3Bpa2UtYS0wLnRlc3QtcnVubmVyMIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAoPGeBhAQ+XUAvfyUBRwWQb8l3C8FalEog7qb8hbBp1iy +x1/IUENdIbimDGyKLEBXhuhATi+zCH/oaW81yaXuJHpleWKcQfKqYv2NrfHa+/6W +gzDp5MluNASq67DdBlrKZzXyAuoSRo/KVs96P4AXysdJD8w83W82/2aUb+z03Vq7 +wkjjj4TZ3xTVKQZyoEDu9ZW+is+2gFTiFVklxF6rj7MBwYTocVVphauia5hbfamb +J/vpR4eABgbJI7RUEi4yNvan8llbZEEhnxDm26/dQPkeSdV0/1iI4YVH57iP0ea4 +2gmuYeeJZQfVgTbkceFwj2Z2d+Y879RxSBH6v3vgvQIDAQABo4HzMIHwMIGtBgNV +HREEgaUwgaKCGWFlcm9zcGlrZS1hLTAudGVzdC1ydW5uZXKCGWFlcm9zcGlrZS1h +LTEudGVzdC1ydW5uZXKCGWFlcm9zcGlrZS1hLTIudGVzdC1ydW5uZXKCGWFlcm9z +cGlrZS1hLTMudGVzdC1ydW5uZXKCGWFlcm9zcGlrZS1hLTQudGVzdC1ydW5uZXKC +GWFlcm9zcGlrZS1hLTUudGVzdC1ydW5uZXIwHQYDVR0OBBYEFOehvxHbJ0m5WXW4 +CskBSJyFMfd+MB8GA1UdIwQYMBaAFMvdaXttPcdvNsDrr0wmTT7gl1NhMA0GCSqG +SIb3DQEBCwUAA4IBAQBLLNxlJ2OlIPPl1EJm0YcqdEjhY4keWkNB40UoXf5l1Jr3 +IAzGUYYS4FkS4Pda/J4Eq+63xvWEU0YzpC+vNSoIMzHrXNPlLCvD/SdJmGdg4bp5 +077J320vp1lpe20Y7HpxF6ueSt0JhgRz/jURZHAaCEVzfdQN1zlVyYbg8nkc9m6s +r/p5nQLzIN0vGTSSnLRQHctF+29B0FIQKMCmRQa5xFDQa4M6MesHtmRbpgGLsi8z +hB6dpaLr5vqFUWej4fuJnyIVQcDXVMI2skn4+5THRARdD3C4jvUx2ifYjyEih6ff +MithRsLe5l2W8ED1uZ7v2vSQlH5VFteeN6QTVmFd -----END CERTIFICATE----- \ No newline at end of file diff --git a/config/samples/secrets/server_key.pem b/config/samples/secrets/server_key.pem index 1675d69bf..495afb7a8 100644 --- a/config/samples/secrets/server_key.pem +++ b/config/samples/secrets/server_key.pem @@ -1,28 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDqOOfMbSdhqKRC -8tGI9alPuyclW8n9bGgJcuC4tR92rDtJjSmf+9oVn7OoFHFq3eXsf+R+7jh7gddN -4krnQOf51ffi9hjBRwaWhGraidgo7rqaTXn8O0Gmx/5X3U/WM05Uwoy2U2kRpfIW -RT5PFVyT8ojtbF3Nh5jK166Hs0V6Rco6mrNrhlNNAwdRb7xFGDZLeWZ4eUpoOfwl -X4iyyPr1y1ul0IpuksRqPBNjkWXY1fPcheB82tfLlys1FfAu2ITfucePpBp81SA+ -/G3+6MAqH1La1IVd0iIE//0QNyOnzjIQiWiAay/FI3bQYVoNS8IAqaTbtU4w0vQs -Cp6YEk9nAgMBAAECggEBAIAvUpTrrCDjZbqKH6jgIaBUIdFtUbeTS8DYESqlXana -CrxvODepYypwc6dqQMQm2v265Lee8mSNo+KpFStIt2xg8MBSxSuKDo3zvHML+7Qz -KwblnfwwBfcb/xPhOB9XhugWbWIfdiJFep87mCU54KfLlaqyowenzTQ+I/N6ZmzK -lu+mQcdhOQmZ0YlwmRWIh8fUIt2yVMtaIrE76TxzcwgM2Vr2v4L7fcvrdQhTFneS -kNPOw7yztmFQQCmfn4Yl98oLr1ZkqR9uH5czcu3pLyfAmvo9Uz8ttS3gzidoavDZ -dfyEMJRAKbQAUZi/F4d52oZzRZseCYPkxgDqW/0Nb9kCgYEA/oF8h3M8zq5mjFN9 -o7iscuLcdZOlQpWSmcEaGmdyjoIw2j+EdjH0Eta38qOkNUpvSTqWNondc9RCFeDn -S9fyf5R5OqLXAzhPLQA15tIRpcBc9PqSgRn6q9aLJXJIoz4J+5UB8bJ8V6gsiwCP -p7Q+m+fccTpd1cSgfuOnUcZgS2sCgYEA65ju/0GTJwbtMnzT5Lq+9nI6UxmCMiLY -DCAeRXGjuesQfDDJaOkgKXf8LG2dwhWy6dM82D1SzduMfPkcBr7aNzpIcRpAq+tY -hvBTwaSQQ2H5VZj+v+Q4nU4RhFBZrO9R8zgV+jsYb0Mr2wYjOBCCqtvmHkPWCr3R -u1M4UaB45vUCgYBkr0dbsqxAu+AX7cPLrHiUrsk2vqVndRLdPvabsYcxd7Hp9azq -sZJ0jXuSQ0joSD1EhCf/BYWVmEhYrXPznkfyTwOyvc9AF9vC2s14Nm0C3NoplKO2 -7Vcs+iBsPQ0df6KlY+qz+r+UUhTlHOC4IOeP+CdOqB+NPU+dQ2TjRg68ZwKBgDpn -7H/9SrS3I+CLT6B5p1PDV7A4N62kM7k10StYE8XIf4q6MYQ/nwiIxUxiVGTEKlmL -U58r/LYqAncM7qTBdamRWlonrvav3n99XtY3rMf3pu9QgX8i3eIpc3BA1ypnHgLU -2aXyNomGtn2S1PJWLX6cCz1fhdWd3zu4UtLxnGdtAoGAUQXOWpmFzeH7EdSmpHre -i6dds3fnKTLCQaIzImjeE9ITqX0lmj/3Y+qlB9ZUfA+UAfv7JAd44xnSO6gY51c1 -7DJ4BUA4JVjgzHpJMT2kOJh5s6PyHjyoNbBEHHUeXqEJVQouOxVyOKTQyM2UeHWn -tOnGqfMs8rsMBM96VSui+W0= +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCg8Z4GEBD5dQC9 +/JQFHBZBvyXcLwVqUSiDupvyFsGnWLLHX8hQQ10huKYMbIosQFeG6EBOL7MIf+hp +bzXJpe4kemV5YpxB8qpi/Y2t8dr7/paDMOnkyW40BKrrsN0GWspnNfIC6hJGj8pW +z3o/gBfKx0kPzDzdbzb/ZpRv7PTdWrvCSOOPhNnfFNUpBnKgQO71lb6Kz7aAVOIV +WSXEXquPswHBhOhxVWmFq6JrmFt9qZsn++lHh4AGBskjtFQSLjI29qfyWVtkQSGf +EObbr91A+R5J1XT/WIjhhUfnuI/R5rjaCa5h54llB9WBNuRx4XCPZnZ35jzv1HFI +Efq/e+C9AgMBAAECggEASAwhq6EhmCqSjHo3YRoztHb3YdwC1pdCRcYR7YvWYS3J +yorMR3IAjQn1+3XTXP/ortHlh5q+0L1Bs4E/WOfY9ad9KZvFS5hwQiQzenzchRZx +FoWdDvhFRzAXu67PIvsdxJpXnopeaAwSjk4O8cJL5FDWGiZZ0N7qhebL6FbxPu2b +LJy8A+Q6GpCGOJsDgEl0bJy77IqNGMF8Sg/OcYJo7QZhq3sQvoe0kkc0EWC/tbOF +gZSwKCyCSHJ+jPy8RsCMHNC0UuRJzjN3tZsCT+EAjaYGWB2OF/KWtzKKHO3ZbrVH ++MH30i9U0KaHn6pFU2na/J0ZsNqw0btHKQ8cSPVVWQKBgQDYGBjap20GRFhzLJrf +cDNwLvSgpNROb/pHknb42ge+LYSi+BAI9yi0rJX1XFDbxMkvSvmm40TqKIfPQEXF +r1CoGv2i6jznwgFVfJf9oCq1m46jR9ZGyEsXuo0Eh4SAk91zyXGnsXdq1PKMTkwQ +0sM36jxOquoIKe4pRRLEWmi5iwKBgQC+qkaTtmfgvRxBhA/h5rrAC4Ba6oPvUjY5 +lo0BpBa36o4oLnp5F1vZ/ElvWFw0ZXs5tvrPSin0/IkxtCTPuucCHPpRj6vP2Dvf +HOGoRO7AcrsgDEbaZgbW5d0dP5Gh/Uiu/yj5uKFXk/IZzFYy4EXMY0QahTPlyFwA +zjhs04fH1wKBgQCHF9F56I9tCo8tOaZ8pz1RFdnTEBi2DKUv123PNyb+CqDP7TrB +EBr/kKGTKapXKhgIG9wlLBGqPbpho7G621YWMgF8tulqjcudsO2oHlh0/pHWnBNm +XtMrO3HrcfkxFL+uIjKOfpDEVepoMo61Ob3Xl/UpzQnQHr6ISGlqHYc47wKBgQCP +YvKsx3KbetyzEKP5GVG8d2nR9ae+5S7OZEAqycIkEgtSgJGuWzjCWI7JY8QDy4W+ +Q7OfDIE9MmXisT0107NCzZQanldxeYadJdU2fJCovh+n3FO0jyH5nuiIxHO7RQXS +RSYFlyoO+L4LVLZGkI8tREHFSANdfS5jlLKudO4aBQKBgQCovGs+sztwOa+uUCXI +lDRSV/Bf3SBiLq4MSjjsTdvJL1BdsVQEA+OpK8TO7jzBlFOdFnI6bfO4etdo+jNO +DKo3jyPINLRNmlwaOp6ImiYcv6PWCIH2aD3eNkcDt/VCFKQtbbykWv+K7BfJmiiT +Nwb6dVlKYQNRBohBgcxC8Zi8cA== -----END PRIVATE KEY----- \ No newline at end of file diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index e7537a7eb..f7fbb4446 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -338,7 +338,7 @@ func (r *SingleClusterReconciler) setDynamicConfig( for _, host := range selectedHostConns { podName := podIPNameMap[host.ASConn.AerospikeHostName] - asConfCmds, err := asconfig.CreateSetConfigCmdList(dynamicConfDiffPerPod[podName], + asConfCmds, err := asconfig.CreateSetConfigCmdList(r.Log, dynamicConfDiffPerPod[podName], host.ASConn, r.getClientPolicy()) if err != nil { diff --git a/go.mod b/go.mod index e0b0469e8..cccac1c6b 100644 --- a/go.mod +++ b/go.mod @@ -5,15 +5,15 @@ go 1.21 toolchain go1.21.8 require ( - github.com/aerospike/aerospike-management-lib v1.3.1-0.20240412130613-2bc07a8654c3 + github.com/aerospike/aerospike-management-lib v1.3.1-0.20240423071640-92c4d186a795 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/evanphx/json-patch v4.12.0+incompatible - github.com/go-logr/logr v1.3.0 + github.com/go-logr/logr v1.4.1 github.com/onsi/ginkgo/v2 v2.13.0 github.com/onsi/gomega v1.29.0 - github.com/stretchr/testify v1.8.4 - golang.org/x/oauth2 v0.11.0 // indirect - golang.org/x/term v0.18.0 // indirect + github.com/stretchr/testify v1.9.0 + golang.org/x/oauth2 v0.17.0 // indirect + golang.org/x/term v0.19.0 // indirect k8s.io/api v0.29.0 k8s.io/apimachinery v0.29.0 k8s.io/client-go v0.29.0 @@ -25,8 +25,8 @@ require ( github.com/aerospike/aerospike-client-go/v7 v7.1.0 github.com/deckarep/golang-set/v2 v2.3.1 github.com/sirupsen/logrus v1.9.0 - golang.org/x/crypto v0.21.0 - golang.org/x/net v0.21.0 + golang.org/x/crypto v0.22.0 + golang.org/x/net v0.24.0 gomodules.xyz/jsonpatch/v2 v2.3.0 k8s.io/utils v0.0.0-20230726121419-3b25d923346b ) @@ -45,12 +45,12 @@ require ( github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect - github.com/google/uuid v1.3.1 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -77,13 +77,13 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.14.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 // indirect - google.golang.org/grpc v1.59.0 // indirect + google.golang.org/appengine v1.6.8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/grpc v1.63.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 8130ff961..3c738906d 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/aerospike/aerospike-client-go/v7 v7.1.0 h1:yvCTKdbpqZxHvv7sWsFHV1j49jZcC8yXRooWsDFqKtA= github.com/aerospike/aerospike-client-go/v7 v7.1.0/go.mod h1:AkHiKvCbqa1c16gCNGju3c5X/yzwLVvblNczqjxNwNk= -github.com/aerospike/aerospike-management-lib v1.3.1-0.20240412130613-2bc07a8654c3 h1:buzjr9iDYSuI0jy/A8366pfPXalBP3Gke3MN+rO/Vzo= -github.com/aerospike/aerospike-management-lib v1.3.1-0.20240412130613-2bc07a8654c3/go.mod h1:E4dk798IikCp9a8fugpYoeQVIXuvdxogHvt6sKhaORQ= +github.com/aerospike/aerospike-management-lib v1.3.1-0.20240423071640-92c4d186a795 h1:6YxT+4mYhnGtUu42RSVZaCT8DW9Npx0DUJB68tnXm8w= +github.com/aerospike/aerospike-management-lib v1.3.1-0.20240423071640-92c4d186a795/go.mod h1:3JKrmC/mLSV8SygbrPQPNV8T7bFaTMjB8wfnX25gB+4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= @@ -30,8 +30,9 @@ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2Vvl github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= @@ -47,10 +48,10 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -62,8 +63,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -132,8 +133,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -144,6 +145,7 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -162,30 +164,34 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= -golang.org/x/oauth2 v0.11.0/go.mod h1:LdF7O/8bLR/qWK9DrpXmbHLTouvRHK0SgJl0GmDBchk= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -195,15 +201,20 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -214,6 +225,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -222,12 +234,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4 h1:DC7wcm+i+P1rN3Ff07vL+OndGg5OhNddHyTA+ocPqYE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231127180814-3a041ad873d4/go.mod h1:eJVxU6o+4G1PSczBr85xmyvSNYAKvAYgkub40YGomFM= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= +google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= diff --git a/helm-charts/aerospike-kubernetes-operator/crds/customresourcedefinition_aerospikeclusters.asdb.aerospike.com.yaml b/helm-charts/aerospike-kubernetes-operator/crds/customresourcedefinition_aerospikeclusters.asdb.aerospike.com.yaml index bef8aea20..6676d4989 100644 --- a/helm-charts/aerospike-kubernetes-operator/crds/customresourcedefinition_aerospikeclusters.asdb.aerospike.com.yaml +++ b/helm-charts/aerospike-kubernetes-operator/crds/customresourcedefinition_aerospikeclusters.asdb.aerospike.com.yaml @@ -9601,6 +9601,12 @@ spec: - customInterface type: string type: object + enableDynamicConfigUpdate: + description: EnableDynamicConfigUpdate enables dynamic config update + flow of the operator. If enabled, operator will try to update the + Aerospike config dynamically. In case of inconsistent state during + dynamic config update, operator falls back to rolling restart. + type: boolean image: description: Aerospike server image type: string diff --git a/test/cluster_helper.go b/test/cluster_helper.go index 241eae04e..49a52b655 100644 --- a/test/cluster_helper.go +++ b/test/cluster_helper.go @@ -1554,6 +1554,23 @@ func getSCNamespaceConfig(name, path string) map[string]interface{} { } } +func getSCNamespaceConfigWithSet(name, path string) map[string]interface{} { + return map[string]interface{}{ + "name": name, + "replication-factor": 2, + "strong-consistency": true, + "storage-engine": map[string]interface{}{ + "type": "device", + "devices": []interface{}{path}, + }, + "sets": []map[string]interface{}{ + { + "name": "testset", + }, + }, + } +} + func getNonSCInMemoryNamespaceConfig(name string) map[string]interface{} { return map[string]interface{}{ "name": name, diff --git a/test/cluster_test.go b/test/cluster_test.go index 28cd1ef25..84da35a98 100644 --- a/test/cluster_test.go +++ b/test/cluster_test.go @@ -979,22 +979,6 @@ func UpdateClusterTest(ctx goctx.Context) { ) Expect(err).ToNot(HaveOccurred()) - By("UpdateReplicationFactor: should update namespace replication-factor on non-SC namespace") - - aeroCluster, err := getCluster( - k8sClient, ctx, - clusterNamespacedName, - ) - Expect(err).ToNot(HaveOccurred()) - nsList := aeroCluster.Spec.AerospikeConfig.Value["namespaces"].([]interface{}) - namespaceConfig := nsList[len(nsList)-1].(map[string]interface{}) - // aeroCluster.Spec.AerospikeConfig.Value["namespaces"].([]interface{})[0].(map[string]interface{}) - namespaceConfig["replication-factor"] = 3 - aeroCluster.Spec.AerospikeConfig.Value["namespaces"].([]interface{})[len(nsList)-1] = namespaceConfig - - err = updateCluster(k8sClient, ctx, aeroCluster) - Expect(err).ToNot(HaveOccurred()) - By("Scaling up along with modifying Namespace storage Dynamically") err = scaleUpClusterTestWithNSDeviceHandling( @@ -1162,6 +1146,35 @@ func UpdateClusterTest(ctx goctx.Context) { Expect(err).Should(HaveOccurred()) }, ) + + It( + "UpdateReplicationFactor: should fail for updating namespace"+ + "replication-factor on non-SC namespace. Cannot be updated", + func() { + By("RollingRestart By Adding Namespace Dynamically") + + err := rollingRestartClusterByAddingNamespaceDynamicallyTest( + k8sClient, ctx, dynamicNs, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + aeroCluster, err := getCluster( + k8sClient, ctx, + clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + nsList := aeroCluster.Spec.AerospikeConfig.Value["namespaces"].([]interface{}) + namespaceConfig := nsList[len(nsList)-1].(map[string]interface{}) + namespaceConfig["replication-factor"] = 3 + aeroCluster.Spec.AerospikeConfig.Value["namespaces"].([]interface{})[len(nsList)-1] = namespaceConfig + + err = k8sClient.Update( + ctx, aeroCluster, + ) + Expect(err).Should(HaveOccurred()) + }, + ) }, ) diff --git a/test/dynamic_config_test.go b/test/dynamic_config_test.go index df87c5681..1ef4913f5 100644 --- a/test/dynamic_config_test.go +++ b/test/dynamic_config_test.go @@ -3,13 +3,23 @@ package test import ( goctx "context" "fmt" + "os" + "strings" + "time" + mapset "github.com/deckarep/golang-set/v2" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "golang.org/x/net/context" + "k8s.io/utils/ptr" + ctrl "sigs.k8s.io/controller-runtime" asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" + "github.com/aerospike/aerospike-kubernetes-operator/pkg/configschema" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" + lib "github.com/aerospike/aerospike-management-lib" + "github.com/aerospike/aerospike-management-lib/asconfig" + "github.com/aerospike/aerospike-management-lib/info" ) type podID struct { @@ -17,6 +27,14 @@ type podID struct { asdPID string } +const clName = "dynamic-config-test" + +var clusterNamespacedName = getNamespacedName( + clName, namespace, +) + +var configWithMaxDefaultVal = mapset.NewSet("info-max-ms", "flush-max-ms") + var _ = Describe( "DynamicConfig", func() { @@ -25,10 +43,6 @@ var _ = Describe( Context( "When doing valid operations", func() { - clusterName := "dynamic-config-test" - clusterNamespacedName := getNamespacedName( - clusterName, namespace, - ) BeforeEach( func() { // Create a 2 node cluster @@ -53,6 +67,7 @@ var _ = Describe( }, }, } + aeroCluster.Spec.EnableDynamicConfigUpdate = ptr.To(true) err := deployCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) }, @@ -71,6 +86,7 @@ var _ = Describe( "Should update config dynamically", func() { By("Modify dynamic config by adding fields") + aeroCluster, err := getCluster( k8sClient, ctx, clusterNamespacedName, ) @@ -84,22 +100,44 @@ var _ = Describe( } aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = 18000 - aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["log"] = log + dc := map[string]interface{}{ + "name": "dc2", + "auth-mode": "internal", + "auth-user": "admin", + "node-address-ports": []string{ + "aeroclusterdst-0-0 3000", + }, + "auth-password-file": "/etc/aerospike/secret/password_DC1.txt", + "namespaces": []map[string]interface{}{ + { + "name": "test", + }, + }, + } + + aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"] = append( + aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"].([]interface{}), dc) + err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) + By("Fetch and verify dynamic configs") + pod := aeroCluster.Status.Pods["dynamic-config-test-0-0"] + // Fetch and verify service section config conf, err := getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, "service", &pod) Expect(err).ToNot(HaveOccurred()) + cv, ok := conf["proto-fd-max"] Expect(ok).ToNot(BeFalse()) Expect(cv).To(Equal(int64(18000))) + // Fetch and verify security section config conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, "security", &pod) Expect(err).ToNot(HaveOccurred()) @@ -109,10 +147,19 @@ var _ = Describe( Expect(reportDataOp).To(Equal("test")) + // Fetch and verify xdr section config + conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, + "xdr", &pod) + Expect(err).ToNot(HaveOccurred()) + + Expect(conf["dcs"]).To(HaveLen(2)) + By("Verify no warm/cold restarts in Pods") + validateServerRestart(ctx, aeroCluster, podPIDMap, false) By("Modify dynamic config by removing fields") + aeroCluster, err = getCluster( k8sClient, ctx, clusterNamespacedName, ) @@ -124,11 +171,17 @@ var _ = Describe( delete(aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{}), "proto-fd-max") delete(aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{}), "log") + aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"] = + aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"].([]interface{})[:1] + err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) + By("Fetch and verify dynamic configs") + pod = aeroCluster.Status.Pods["dynamic-config-test-0-0"] + // Fetch and verify service section config conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, "service", &pod) Expect(err).ToNot(HaveOccurred()) @@ -137,6 +190,7 @@ var _ = Describe( Expect(cv).To(Equal(int64(15000))) + // Fetch and verify security section config conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, "security", &pod) Expect(err).ToNot(HaveOccurred()) @@ -144,9 +198,16 @@ var _ = Describe( _, ok = conf["log.report-data-op[0]"].(string) Expect(ok).ToNot(BeTrue()) + // Fetch and verify xdr section config + conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, + "xdr", &pod) + Expect(err).ToNot(HaveOccurred()) + + Expect(conf["dcs"]).To(HaveLen(1)) + By("Verify no warm/cold restarts in Pods") - validateServerRestart(ctx, aeroCluster, podPIDMap, false) + validateServerRestart(ctx, aeroCluster, podPIDMap, false) }, ) @@ -164,6 +225,167 @@ var _ = Describe( Expect(err).ToNot(HaveOccurred()) aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = true + + err = updateCluster(k8sClient, ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + By("Fetch and verify static configs") + + pod := aeroCluster.Status.Pods["dynamic-config-test-0-0"] + + conf, err := getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, + "security", &pod) + Expect(err).ToNot(HaveOccurred()) + + enableQuotas, ok := conf["enable-quotas"].(bool) + Expect(ok).ToNot(BeFalse()) + + Expect(enableQuotas).To(BeTrue()) + + By("Verify warm restarts in Pods") + + validateServerRestart(ctx, aeroCluster, podPIDMap, true) + }, + ) + + It( + "Should update config statically by disabling dynamic update feature", func() { + + By("Modify dynamic config statically") + + aeroCluster, err := getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + podPIDMap, err := getPodIDs(ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + // Disable dynamic config update and set config + aeroCluster.Spec.EnableDynamicConfigUpdate = ptr.To(false) + aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = 19000 + + err = updateCluster(k8sClient, ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + By("Fetch and verify static configs") + + pod := aeroCluster.Status.Pods["dynamic-config-test-0-0"] + + conf, err := getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, + "service", &pod) + Expect(err).ToNot(HaveOccurred()) + + cv, ok := conf["proto-fd-max"] + Expect(ok).ToNot(BeFalse()) + + Expect(cv).To(Equal(int64(19000))) + + By("Verify warm restarts in Pods") + validateServerRestart(ctx, aeroCluster, podPIDMap, true) + }, + ) + }, + ) + + Context( + "When doing invalid operations", func() { + + BeforeEach( + func() { + // Create a 2 node cluster + aeroCluster := createDummyAerospikeCluster( + clusterNamespacedName, 2, + ) + aeroCluster.Spec.AerospikeConfig.Value["xdr"] = map[string]interface{}{ + "dcs": []map[string]interface{}{ + { + "name": "dc1", + "auth-mode": "internal", + "auth-user": "admin", + "node-address-ports": []string{ + "aeroclusterdst-0-0 3000", + }, + "auth-password-file": "/etc/aerospike/secret/password_DC1.txt", + "namespaces": []map[string]interface{}{ + { + "name": "test", + }, + }, + }, + }, + } + aeroCluster.Spec.EnableDynamicConfigUpdate = ptr.To(true) + err := deployCluster(k8sClient, ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + }, + ) + + AfterEach( + func() { + aeroCluster, err := getCluster(k8sClient, ctx, clusterNamespacedName) + Expect(err).ToNot(HaveOccurred()) + + _ = deleteCluster(k8sClient, ctx, aeroCluster) + }, + ) + + It( + "Should fail dynamic config update fully for invalid config", func() { + aeroCluster, err := getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + podPIDMap, err := getPodIDs(ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + // Failure: + // Update invalid config value + // This change will lead to dynamic config update failure. + // In case of full failure, will not fall back to rolling restart + aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = 9999999 + + err = updateClusterWithTO(k8sClient, ctx, aeroCluster, time.Minute*1) + Expect(err).To(HaveOccurred()) + + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + // Recovery: + // Update valid config value + // This change will lead to dynamic config update success. + aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = 15000 + + err = updateCluster(k8sClient, ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + // As there was no full config update failure, + // expectation is that pods will not be restarted. + By("Verify cold restarts in Pods") + validateServerRestart(ctx, aeroCluster, podPIDMap, false) + }, + ) + + It( + "Should fail dynamic config update partially for invalid config", func() { + aeroCluster, err := getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + podPIDMap, err := getPodIDs(ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + // Failure: + // Update multiple invalid config values + // This change will lead to dynamic config update failure. + // Assuming it will fall back to rolling restart in case of partial failure. + // Which leads to pod failures. + aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = 9999999 + dc := map[string]interface{}{ "name": "dc2", "auth-mode": "internal", @@ -182,28 +404,183 @@ var _ = Describe( aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"] = append( aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"].([]interface{}), dc) + err = updateClusterWithTO(k8sClient, ctx, aeroCluster, time.Minute*1) + Expect(err).To(HaveOccurred()) + + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + // Recovery: + // Update valid config value + // This change will lead to static config update success. + aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = 15000 + err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) - pod := aeroCluster.Status.Pods["dynamic-config-test-0-0"] + // As pods were failed, expectation is that pods will be cold restarted. + By("Verify cold restarts in Pods") + validateServerRestart(ctx, aeroCluster, podPIDMap, true) - conf, err := getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, - "security", &pod) + }, + ) + }, + ) + + Context( + "When doing complete dynamic config change", func() { + + BeforeEach( + func() { + // Create a 2 node cluster + aeroCluster := createDummyAerospikeCluster( + clusterNamespacedName, 2, + ) + aeroCluster.Spec.AerospikeConfig.Value["xdr"] = map[string]interface{}{ + "dcs": []map[string]interface{}{ + { + "name": "dc1", + "auth-mode": "internal", + "auth-user": "admin", + "node-address-ports": []string{ + "aeroclusterdst-0-0 3000", + }, + "auth-password-file": "/etc/aerospike/secret/password_DC1.txt", + "namespaces": []map[string]interface{}{ + { + "name": "test", + }, + }, + }, + }, + } + + aeroCluster.Spec.AerospikeConfig.Value["namespaces"] = []interface{}{ + getSCNamespaceConfigWithSet("test", "/test/dev/xvdf"), + } + + aeroCluster.Spec.AerospikeConfig.Value["security"] = map[string]interface{}{ + "log": map[string]interface{}{ + "report-data-op-role": []string{"read"}, + "report-data-op-user": []string{"admin2"}, + }, + } + + aeroCluster.Spec.EnableDynamicConfigUpdate = ptr.To(true) + + admin2 := asdbv1.AerospikeUserSpec{ + Name: "admin2", + SecretName: authSecretName, + Roles: []string{ + "sys-admin", + "user-admin", + "read-write", + }, + } + + aeroCluster.Spec.AerospikeAccessControl.Users = append(aeroCluster.Spec.AerospikeAccessControl.Users, admin2) + + err := deployCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) + }, + ) - enableQuotas, ok := conf["enable-quotas"].(bool) - Expect(ok).ToNot(BeFalse()) + AfterEach( + func() { + aeroCluster, err := getCluster(k8sClient, ctx, clusterNamespacedName) + Expect(err).ToNot(HaveOccurred()) - Expect(enableQuotas).To(BeTrue()) + _ = deleteCluster(k8sClient, ctx, aeroCluster) + }, + ) - conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, - "xdr", &pod) + It( + "Should update config dynamically", func() { + + By("Modify all dynamic config fields") + aeroCluster, err := getCluster( + k8sClient, ctx, clusterNamespacedName, + ) Expect(err).ToNot(HaveOccurred()) - Expect(conf["dcs"]).To(HaveLen(2)) + schemaMap, err := configschema.NewSchemaMap() + if err != nil { + os.Exit(1) + } - By("Verify warm restarts in Pods") - validateServerRestart(ctx, aeroCluster, podPIDMap, true) + schemaMapLogger := ctrl.Log.WithName("schema-map") + asconfig.InitFromMap(schemaMapLogger, schemaMap) + + podPIDMap, err := getPodIDs(ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + dynamic, err := asconfig.GetDynamic("7.0.0") + Expect(err).ToNot(HaveOccurred()) + + flatServer, flatSpec, err := getAerospikeConfigFromNodeAndSpec(aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + By("Verify Service Context configs dynamically") + err = validateServiceContextDynamically(ctx, flatServer, flatSpec, aeroCluster, dynamic) + Expect(err).ToNot(HaveOccurred()) + + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + By("Verify no warm/cold restarts in Pods") + validateServerRestart(ctx, aeroCluster, podPIDMap, false) + + By("Verify Network Context configs dynamically") + err = validateNetworkContextDynamically(ctx, flatServer, flatSpec, aeroCluster, dynamic) + Expect(err).ToNot(HaveOccurred()) + + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + By("Verify no warm/cold restarts in Pods") + validateServerRestart(ctx, aeroCluster, podPIDMap, false) + + By("Verify Namespace Context configs dynamically") + err = validateNamespaceContextDynamically(ctx, flatServer, flatSpec, aeroCluster, dynamic) + Expect(err).ToNot(HaveOccurred()) + + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + By("Verify no warm/cold restarts in Pods") + validateServerRestart(ctx, aeroCluster, podPIDMap, false) + + By("Verify Security Context configs dynamically") + err = validateSecurityContextDynamically(ctx, flatServer, flatSpec, aeroCluster, dynamic) + Expect(err).ToNot(HaveOccurred()) + + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + By("Verify no warm/cold restarts in Pods") + validateServerRestart(ctx, aeroCluster, podPIDMap, false) + + By("Verify XDR Context configs dynamically") + err = validateXDRContextDynamically(ctx, flatServer, flatSpec, aeroCluster, dynamic) + Expect(err).ToNot(HaveOccurred()) + + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + By("Verify no warm/cold restarts in Pods") + validateServerRestart(ctx, aeroCluster, podPIDMap, false) }, ) }, @@ -263,3 +640,331 @@ func getPodIDs(ctx context.Context, aeroCluster *asdbv1.AerospikeCluster) (map[s return pidMap, nil } + +func updateValue(val interface{}, confKey string) (interface{}, error) { + switch val2 := val.(type) { + case []string: + if v, ok := sliceConfTypeVal[confKey]; ok { + return v, nil + } + case string: + if v, ok := stringConfTypeVal[confKey]; ok { + return v, nil + } + case bool: + return !val2, nil + case int: + return val2 + 1, nil + case uint64: + return val2 + 1, nil + case int64: + return val2 + 1, nil + case float64: + return val2 + 1, nil + + case lib.Stats: + pkgLog.Info("got lib.stats type key", confKey) + default: + return nil, fmt.Errorf("format not supported") + } + + return nil, nil +} + +var stringConfTypeVal = map[string]string{ + "network.heartbeat.protocol": "v3", + "namespaces._.storage-engine.compression": "snappy", +} + +var sliceConfTypeVal = map[string][]string{ + "security.log.report-data-op": {"test"}, + "security.log.report-data-op-role": {"sys-admin"}, + "security.log.report-data-op-user": {"admin"}, + "xdr.dcs._.namespaces._.ship-sets": {"testset"}, + "xdr.dcs._.namespaces._.ignore-sets": {"testset"}, + "xdr.dcs._.namespaces._.ship-bins": {"testbin"}, + "xdr.dcs._.namespaces._.ignore-bins": {"testbin"}, +} + +func validateServiceContextDynamically( + ctx goctx.Context, flatServer, flatSpec *asconfig.Conf, + aeroCluster *asdbv1.AerospikeCluster, dynamic mapset.Set[string], +) error { + newSpec := *flatSpec + ignoredConf := mapset.NewSet("cluster-name", "microsecond-histograms") + + for confKey, val := range *flatServer { + if asconfig.ContextKey(confKey) != "service" { + continue + } + + tokens := strings.Split(confKey, ".") + + if dynamic.Contains(asconfig.GetFlatKey(tokens)) && !ignoredConf.Contains(asconfig.BaseKey(confKey)) { + v, err := updateValue(val, asconfig.GetFlatKey(tokens)) + if err != nil { + return err + } + + if v != nil { + if configWithMaxDefaultVal.Contains(asconfig.BaseKey(confKey)) { + v = v.(uint64) - 1 + } + + if asconfig.BaseKey(confKey) == "proto-fd-idle-ms" { + v = 70000 + } + + newSpec[confKey] = v + } + } + } + + newConf := asconfig.New(logger, &newSpec) + newMap := *newConf.ToMap() + + aeroCluster.Spec.AerospikeConfig.Value["service"] = lib.DeepCopy(newMap["service"]) + + return updateCluster(k8sClient, ctx, aeroCluster) +} + +func validateNetworkContextDynamically( + ctx goctx.Context, flatServer, flatSpec *asconfig.Conf, + aeroCluster *asdbv1.AerospikeCluster, dynamic mapset.Set[string], +) error { + newSpec := *flatSpec + ignoredConf := mapset.NewSet("connect-timeout-ms") + + for confKey, val := range *flatServer { + if asconfig.ContextKey(confKey) != "network" { + continue + } + + tokens := strings.Split(confKey, ".") + + if dynamic.Contains(asconfig.GetFlatKey(tokens)) && !ignoredConf.Contains(asconfig.BaseKey(confKey)) { + v, err := updateValue(val, asconfig.GetFlatKey(tokens)) + if err != nil { + return err + } + + if v != nil { + newSpec[confKey] = v + } + } + } + + newConf := asconfig.New(logger, &newSpec) + newMap := *newConf.ToMap() + + aeroCluster.Spec.AerospikeConfig.Value["network"] = lib.DeepCopy(newMap["network"]) + + return updateCluster(k8sClient, ctx, aeroCluster) +} + +func validateNamespaceContextDynamically( + ctx goctx.Context, flatServer, flatSpec *asconfig.Conf, + aeroCluster *asdbv1.AerospikeCluster, dynamic mapset.Set[string], +) error { + newSpec := *flatSpec + ignoredConf := mapset.NewSet("rack-id", "default-ttl", "disable-write-dup-res", + "disallow-expunge", "conflict-resolution-policy") + + for confKey, val := range *flatServer { + if asconfig.ContextKey(confKey) != "namespaces" { + continue + } + + tokens := strings.Split(confKey, ".") + if dynamic.Contains(asconfig.GetFlatKey(tokens)) && !ignoredConf.Contains(asconfig.BaseKey(confKey)) { + v, err := updateValue(val, asconfig.GetFlatKey(tokens)) + if err != nil { + return err + } + + if v != nil { + if configWithMaxDefaultVal.Contains(asconfig.BaseKey(confKey)) { + v = v.(int64) - 1 + } + + newSpec[confKey] = v + } + } + } + + newConf := asconfig.New(logger, &newSpec) + newMap := *newConf.ToMap() + + aeroCluster.Spec.AerospikeConfig.Value["namespaces"] = lib.DeepCopy(newMap["namespaces"]) + + return updateCluster(k8sClient, ctx, aeroCluster) +} + +func validateSecurityContextDynamically( + ctx goctx.Context, flatServer, flatSpec *asconfig.Conf, + aeroCluster *asdbv1.AerospikeCluster, dynamic mapset.Set[string], +) error { + newSpec := *flatSpec + + for confKey, val := range *flatServer { + if asconfig.ContextKey(confKey) != "security" { + continue + } + + tokens := strings.Split(confKey, ".") + if dynamic.Contains(asconfig.GetFlatKey(tokens)) { + v, err := updateValue(val, asconfig.GetFlatKey(tokens)) + if err != nil { + return err + } + + if v != nil { + newSpec[confKey] = v + } + } + } + + newConf := asconfig.New(logger, &newSpec) + newMap := *newConf.ToMap() + + aeroCluster.Spec.AerospikeConfig.Value["security"] = lib.DeepCopy(newMap["security"]) + + return updateCluster(k8sClient, ctx, aeroCluster) +} + +func validateXDRContextDynamically( + ctx goctx.Context, flatServer, flatSpec *asconfig.Conf, + aeroCluster *asdbv1.AerospikeCluster, dynamic mapset.Set[string], +) error { + xdrNSFields := make(asconfig.Conf) + dcFields := make(asconfig.Conf) + + for confKey, val := range *flatServer { + if asconfig.ContextKey(confKey) != "xdr" { + continue + } + + tokens := strings.Split(confKey, ".") + if dynamic.Contains(asconfig.GetFlatKey(tokens)) { + if len(tokens) < 3 || tokens[len(tokens)-3] == "namespaces" { + xdrNSFields[confKey] = val + } else { + dcFields[confKey] = val + } + } + } + + if err := validateXDRDCFieldsDynamically(ctx, &dcFields, flatSpec, aeroCluster); err != nil { + return err + } + + aeroCluster, err := getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + if err != nil { + return err + } + + return validateXDRNSFieldsDynamically(ctx, &xdrNSFields, flatSpec, aeroCluster) +} + +func validateXDRNSFieldsDynamically(ctx goctx.Context, flatServer, flatSpec *asconfig.Conf, + aeroCluster *asdbv1.AerospikeCluster) error { + newSpec := *flatSpec + ignoredConf := mapset.NewSet("ship-bin-luts") + + for confKey, val := range *flatServer { + tokens := strings.Split(confKey, ".") + if !ignoredConf.Contains(asconfig.BaseKey(confKey)) { + v, err := updateValue(val, asconfig.GetFlatKey(tokens)) + if err != nil { + return err + } + + if v != nil { + switch asconfig.BaseKey(confKey) { + case "max-throughput": + v = v.(int64) + 99 + case "transaction-queue-limit": + v = (v.(int64) - 1) * 2 + } + + newSpec[confKey] = v + } + } + } + + newConf := asconfig.New(logger, &newSpec) + newMap := *newConf.ToMap() + + aeroCluster.Spec.AerospikeConfig.Value["xdr"] = lib.DeepCopy(newMap["xdr"]) + + return updateCluster(k8sClient, ctx, aeroCluster) +} + +func validateXDRDCFieldsDynamically(ctx goctx.Context, flatServer, flatSpec *asconfig.Conf, + aeroCluster *asdbv1.AerospikeCluster) error { + newSpec := *flatSpec + ignoredConf := mapset.NewSet("connector") + + for confKey, val := range *flatServer { + tokens := strings.Split(confKey, ".") + if !ignoredConf.Contains(asconfig.BaseKey(confKey)) { + v, err := updateValue(val, asconfig.GetFlatKey(tokens)) + if err != nil { + return err + } + + if v != nil { + newSpec[confKey] = v + } + } + } + + newConf := asconfig.New(logger, &newSpec) + newMap := *newConf.ToMap() + + aeroCluster.Spec.AerospikeConfig.Value["xdr"] = lib.DeepCopy(newMap["xdr"]) + dcs := aeroCluster.Spec.AerospikeConfig.Value["xdr"].(lib.Stats)["dcs"].([]lib.Stats) + delete(dcs[0], "namespaces") + delete(dcs[0], "node-address-ports") + aeroCluster.Spec.AerospikeConfig.Value["xdr"].(lib.Stats)["dcs"] = dcs + + return updateCluster(k8sClient, ctx, aeroCluster) +} + +func getAerospikeConfigFromNodeAndSpec(aeroCluster *asdbv1.AerospikeCluster) (flatServer, flatSpec *asconfig.Conf, + err error) { + pods, err := getPodList(aeroCluster, k8sClient) + if err != nil { + return nil, nil, err + } + + pod := aeroCluster.Status.Pods[pods.Items[0].Name] + + host, err := createHost(&pod) + if err != nil { + return nil, nil, err + } + + asinfo := info.NewAsInfo( + logger, host, getClientPolicy(aeroCluster, k8sClient), + ) + + serverConf, err := asconfig.GenerateConf(logger, asinfo, false) + if err != nil { + return nil, nil, err + } + + server, err := asconfig.NewMapAsConfig(logger, serverConf.Conf) + if err != nil { + return nil, nil, err + } + + spec, err := asconfig.NewMapAsConfig(logger, aeroCluster.Spec.AerospikeConfig.Value) + if err != nil { + return nil, nil, err + } + + return server.GetFlatMap(), spec.GetFlatMap(), nil +}