From 495db95169538b4a34774783bfa86524915e88da Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Mon, 11 Dec 2023 15:03:31 +0530 Subject: [PATCH 01/20] Adding support for dynamic config change. --- api/v1/access_control_validate.go | 7 +- api/v1/aerospikecluster_mutating_webhook.go | 48 +--- api/v1/aerospikecluster_types.go | 144 +++++----- api/v1/aerospikecluster_validating_webhook.go | 13 +- api/v1/aerospikeconfig.go | 2 +- api/v1/utils.go | 4 +- api/v1beta1/aerospikeconfig.go | 7 +- controllers/aero_info_calls.go | 36 +++ controllers/configmap.go | 7 +- controllers/pod.go | 257 ++++++++++++++++-- controllers/rack.go | 115 ++++++-- controllers/reconciler.go | 13 +- controllers/statefulset.go | 17 +- go.mod | 7 +- go.sum | 9 +- test/cluster_helper.go | 14 +- test/services_test.go | 5 +- 17 files changed, 491 insertions(+), 214 deletions(-) diff --git a/api/v1/access_control_validate.go b/api/v1/access_control_validate.go index 1ef0531a1..cb7358db6 100644 --- a/api/v1/access_control_validate.go +++ b/api/v1/access_control_validate.go @@ -33,6 +33,9 @@ const ( // DefaultAdminPassword si default admin user password. DefaultAdminPassword = "admin" + + // Version6 server version 6 tag + Version6 = "6.0.0.0" ) // roleNameForbiddenChars are characters forbidden in role name. @@ -213,7 +216,7 @@ func isRoleSpecValid( _, ok := PredefinedRoles[roleSpec.Name] if ok { - cmp, err := asconfig.CompareVersions(version, "6.0.0.0") + cmp, err := asconfig.CompareVersions(version, Version6) if err != nil { return false, err } @@ -319,7 +322,7 @@ func isPrivilegeValid( } // Check if new privileges are used in an older version. - cmp, err := asconfig.CompareVersions(version, "6.0.0.0") + cmp, err := asconfig.CompareVersions(version, Version6) if err != nil { return false, err } diff --git a/api/v1/aerospikecluster_mutating_webhook.go b/api/v1/aerospikecluster_mutating_webhook.go index 4dc2f371c..552d6409d 100644 --- a/api/v1/aerospikecluster_mutating_webhook.go +++ b/api/v1/aerospikecluster_mutating_webhook.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2023. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,6 +30,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 @@ -88,9 +89,7 @@ func (c *AerospikeCluster) setDefaults(asLog logr.Logger) error { // Set common aerospikeConfig defaults // Update configMap - if err := c.setDefaultAerospikeConfigs( - asLog, *c.Spec.AerospikeConfig, - ); err != nil { + if err := c.setDefaultAerospikeConfigs(asLog, *c.Spec.AerospikeConfig, DefaultRackID); err != nil { return err } @@ -254,18 +253,18 @@ func (c *AerospikeCluster) updateRacksAerospikeConfigFromGlobal(asLog logr.Logge c.Spec.AerospikeConfig.Value, rack.InputAerospikeConfig.Value, ) + if err != nil { + return err + } + asLog.V(1).Info( "Merged rack config from global aerospikeConfig", "rack id", rack.ID, "rackAerospikeConfig", m, "globalAerospikeConfig", c.Spec.AerospikeConfig, ) - - if err != nil { - return err - } } else { // Use the global config. - m = c.Spec.AerospikeConfig.Value + m = lib.DeepCopy(c.Spec.AerospikeConfig.Value).(map[string]interface{}) } asLog.V(1).Info( @@ -275,9 +274,7 @@ func (c *AerospikeCluster) updateRacksAerospikeConfigFromGlobal(asLog logr.Logge // Set defaults in updated rack config // Above merge function may have overwritten defaults. - if err := c.setDefaultAerospikeConfigs( - asLog, AerospikeConfigSpec{Value: m}, - ); err != nil { + if err := c.setDefaultAerospikeConfigs(asLog, AerospikeConfigSpec{Value: m}, rack.ID); err != nil { return err } @@ -287,15 +284,12 @@ func (c *AerospikeCluster) updateRacksAerospikeConfigFromGlobal(asLog logr.Logge return nil } -func (c *AerospikeCluster) setDefaultAerospikeConfigs( - asLog logr.Logger, configSpec AerospikeConfigSpec, -) error { +func (c *AerospikeCluster) setDefaultAerospikeConfigs(asLog logr.Logger, + configSpec AerospikeConfigSpec, rackID int) error { config := configSpec.Value // namespace conf - if err := setDefaultNsConf( - asLog, configSpec, c.Spec.RackConfig.Namespaces, - ); err != nil { + if err := setDefaultNsConf(asLog, configSpec, c.Spec.RackConfig.Namespaces, rackID); err != nil { return err } @@ -362,10 +356,7 @@ func (n *AerospikeNetworkPolicy) setNetworkNamespace(namespace string) { // Helper // ***************************************************************************** -func setDefaultNsConf( - asLog logr.Logger, configSpec AerospikeConfigSpec, - rackEnabledNsList []string, -) error { +func setDefaultNsConf(asLog logr.Logger, configSpec AerospikeConfigSpec, rackEnabledNsList []string, rackID int) error { config := configSpec.Value // namespace conf nsConf, ok := config["namespaces"] @@ -399,21 +390,10 @@ func setDefaultNsConf( ) } - // Add dummy rack-id only for rackEnabled namespaces - defaultConfs := map[string]interface{}{"rack-id": DefaultRackID} - if nsName, ok := nsMap["name"]; ok { if _, ok := nsName.(string); ok { if isNameExist(rackEnabledNsList, nsName.(string)) { - // Add dummy rack-id, should be replaced with actual rack-id by init-container script - if err := setDefaultsInConfigMap( - asLog, nsMap, defaultConfs, - ); err != nil { - return fmt.Errorf( - "failed to set default aerospikeConfig.namespaces rack config: %v", - err, - ) - } + nsMap["rack-id"] = rackID } else { // User may have added this key or may have patched object with new smaller rackEnabledNamespace list // but left namespace defaults. This key should be removed then only controller will detect diff --git a/api/v1/aerospikecluster_types.go b/api/v1/aerospikecluster_types.go index 9346610f5..f496a5ea7 100644 --- a/api/v1/aerospikecluster_types.go +++ b/api/v1/aerospikecluster_types.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2023. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -864,87 +864,78 @@ func init() { } // CopySpecToStatus copy spec in status. Spec to Status DeepCopy doesn't work. It fails in reflect lib. -func CopySpecToStatus(spec *AerospikeClusterSpec) (*AerospikeClusterStatusSpec, error) { //nolint:dupl // not duplicate +func CopySpecToStatus(spec *AerospikeClusterSpec) (*AerospikeClusterStatusSpec, error) { status := AerospikeClusterStatusSpec{} status.Size = spec.Size status.Image = spec.Image // Storage - statusStorage := AerospikeStorageSpec{} - lib.DeepCopy(&statusStorage, &spec.Storage) + statusStorage := lib.DeepCopy(spec.Storage).(AerospikeStorageSpec) status.Storage = statusStorage if spec.AerospikeAccessControl != nil { // AerospikeAccessControl - statusAerospikeAccessControl := &AerospikeAccessControlSpec{} - lib.DeepCopy( - statusAerospikeAccessControl, spec.AerospikeAccessControl, - ) + statusAerospikeAccessControl := lib.DeepCopy( + *spec.AerospikeAccessControl, + ).(AerospikeAccessControlSpec) - status.AerospikeAccessControl = statusAerospikeAccessControl + status.AerospikeAccessControl = &statusAerospikeAccessControl } - // AerospikeConfig - statusAerospikeConfig := &AerospikeConfigSpec{} - lib.DeepCopy( - statusAerospikeConfig, spec.AerospikeConfig, - ) + if spec.AerospikeConfig != nil { + // AerospikeConfig + statusAerospikeConfig := lib.DeepCopy( + *spec.AerospikeConfig, + ).(AerospikeConfigSpec) - status.AerospikeConfig = statusAerospikeConfig + status.AerospikeConfig = &statusAerospikeConfig + } if spec.ValidationPolicy != nil { // ValidationPolicy - statusValidationPolicy := &ValidationPolicySpec{} - lib.DeepCopy( - statusValidationPolicy, spec.ValidationPolicy, - ) + statusValidationPolicy := lib.DeepCopy( + *spec.ValidationPolicy, + ).(ValidationPolicySpec) - status.ValidationPolicy = statusValidationPolicy + status.ValidationPolicy = &statusValidationPolicy } // RackConfig - statusRackConfig := RackConfig{} - lib.DeepCopy(&statusRackConfig, &spec.RackConfig) + statusRackConfig := lib.DeepCopy(spec.RackConfig).(RackConfig) status.RackConfig = statusRackConfig // AerospikeNetworkPolicy - statusAerospikeNetworkPolicy := AerospikeNetworkPolicy{} - lib.DeepCopy( - &statusAerospikeNetworkPolicy, &spec.AerospikeNetworkPolicy, - ) + statusAerospikeNetworkPolicy := lib.DeepCopy( + spec.AerospikeNetworkPolicy, + ).(AerospikeNetworkPolicy) status.AerospikeNetworkPolicy = statusAerospikeNetworkPolicy if spec.OperatorClientCertSpec != nil { - clientCertSpec := &AerospikeOperatorClientCertSpec{} - lib.DeepCopy( - clientCertSpec, spec.OperatorClientCertSpec, - ) + clientCertSpec := lib.DeepCopy( + *spec.OperatorClientCertSpec, + ).(AerospikeOperatorClientCertSpec) - status.OperatorClientCertSpec = clientCertSpec + status.OperatorClientCertSpec = &clientCertSpec } // Storage - statusPodSpec := AerospikePodSpec{} - lib.DeepCopy(&statusPodSpec, &spec.PodSpec) + statusPodSpec := lib.DeepCopy(spec.PodSpec).(AerospikePodSpec) status.PodSpec = statusPodSpec - seedsFinderServices := SeedsFinderServices{} - lib.DeepCopy( - &seedsFinderServices, &spec.SeedsFinderServices, - ) + seedsFinderServices := lib.DeepCopy( + spec.SeedsFinderServices, + ).(SeedsFinderServices) status.SeedsFinderServices = seedsFinderServices // RosterNodeBlockList if len(spec.RosterNodeBlockList) != 0 { - var rosterNodeBlockList []string - - lib.DeepCopy( - &rosterNodeBlockList, &spec.RosterNodeBlockList, - ) + rosterNodeBlockList := lib.DeepCopy( + spec.RosterNodeBlockList, + ).([]string) status.RosterNodeBlockList = rosterNodeBlockList } @@ -953,88 +944,79 @@ func CopySpecToStatus(spec *AerospikeClusterSpec) (*AerospikeClusterStatusSpec, } // CopyStatusToSpec copy status in spec. Status to Spec DeepCopy doesn't work. It fails in reflect lib. -func CopyStatusToSpec(status *AerospikeClusterStatusSpec) (*AerospikeClusterSpec, error) { //nolint:dupl // no need +func CopyStatusToSpec(status *AerospikeClusterStatusSpec) (*AerospikeClusterSpec, error) { spec := AerospikeClusterSpec{} spec.Size = status.Size spec.Image = status.Image // Storage - specStorage := AerospikeStorageSpec{} - lib.DeepCopy(&specStorage, &status.Storage) + specStorage := lib.DeepCopy(status.Storage).(AerospikeStorageSpec) spec.Storage = specStorage if status.AerospikeAccessControl != nil { // AerospikeAccessControl - specAerospikeAccessControl := &AerospikeAccessControlSpec{} - lib.DeepCopy( - specAerospikeAccessControl, status.AerospikeAccessControl, - ) + specAerospikeAccessControl := lib.DeepCopy( + status.AerospikeAccessControl, + ).(*AerospikeAccessControlSpec) spec.AerospikeAccessControl = specAerospikeAccessControl } // AerospikeConfig - specAerospikeConfig := &AerospikeConfigSpec{} - lib.DeepCopy( - specAerospikeConfig, status.AerospikeConfig, - ) + if status.AerospikeConfig != nil { + specAerospikeConfig := lib.DeepCopy( + status.AerospikeConfig, + ).(*AerospikeConfigSpec) - spec.AerospikeConfig = specAerospikeConfig + spec.AerospikeConfig = specAerospikeConfig + } if status.ValidationPolicy != nil { // ValidationPolicy - specValidationPolicy := &ValidationPolicySpec{} - lib.DeepCopy( - specValidationPolicy, status.ValidationPolicy, - ) + specValidationPolicy := lib.DeepCopy( + *status.ValidationPolicy, + ).(ValidationPolicySpec) - spec.ValidationPolicy = specValidationPolicy + spec.ValidationPolicy = &specValidationPolicy } // RackConfig - specRackConfig := RackConfig{} - lib.DeepCopy(&specRackConfig, &status.RackConfig) + specRackConfig := lib.DeepCopy(status.RackConfig).(RackConfig) spec.RackConfig = specRackConfig // AerospikeNetworkPolicy - specAerospikeNetworkPolicy := AerospikeNetworkPolicy{} - lib.DeepCopy( - &specAerospikeNetworkPolicy, &status.AerospikeNetworkPolicy, - ) + specAerospikeNetworkPolicy := lib.DeepCopy( + status.AerospikeNetworkPolicy, + ).(AerospikeNetworkPolicy) spec.AerospikeNetworkPolicy = specAerospikeNetworkPolicy if status.OperatorClientCertSpec != nil { - clientCertSpec := &AerospikeOperatorClientCertSpec{} - lib.DeepCopy( - clientCertSpec, status.OperatorClientCertSpec, - ) + clientCertSpec := lib.DeepCopy( + *status.OperatorClientCertSpec, + ).(AerospikeOperatorClientCertSpec) - spec.OperatorClientCertSpec = clientCertSpec + spec.OperatorClientCertSpec = &clientCertSpec } // Storage - specPodSpec := AerospikePodSpec{} - lib.DeepCopy(&specPodSpec, &status.PodSpec) + specPodSpec := lib.DeepCopy(status.PodSpec).(AerospikePodSpec) spec.PodSpec = specPodSpec - seedsFinderServices := SeedsFinderServices{} - lib.DeepCopy( - &seedsFinderServices, &status.SeedsFinderServices, - ) + seedsFinderServices := lib.DeepCopy( + status.SeedsFinderServices, + ).(SeedsFinderServices) spec.SeedsFinderServices = seedsFinderServices // RosterNodeBlockList if len(status.RosterNodeBlockList) != 0 { - var rosterNodeBlockList []string - - lib.DeepCopy( - &rosterNodeBlockList, &status.RosterNodeBlockList, - ) + rosterNodeBlockList := lib.DeepCopy( + status.RosterNodeBlockList, + ).([]string) spec.RosterNodeBlockList = rosterNodeBlockList } diff --git a/api/v1/aerospikecluster_validating_webhook.go b/api/v1/aerospikecluster_validating_webhook.go index 96d8e9454..021d7c074 100644 --- a/api/v1/aerospikecluster_validating_webhook.go +++ b/api/v1/aerospikecluster_validating_webhook.go @@ -1,5 +1,5 @@ /* -Copyright 2021. +Copyright 2023. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -1384,7 +1384,7 @@ func validateAerospikeConfigUpdate( } } - return validateNsConfUpdate(incomingSpec, outgoingSpec, currentStatus) + return validateNsConfUpdate(incomingSpec, outgoingSpec, currentStatus, incomingVersion) } func validateTLSUpdate(oldConf, newConf map[string]interface{}) error { @@ -1542,7 +1542,7 @@ func validateNetworkPolicyUpdate(oldPolicy, newPolicy *AerospikeNetworkPolicy) e return nil } -func validateNsConfUpdate(newConfSpec, oldConfSpec, currentStatus *AerospikeConfigSpec) error { +func validateNsConfUpdate(newConfSpec, oldConfSpec, currentStatus *AerospikeConfigSpec, incomingVersion string) error { newConf := newConfSpec.Value oldConf := oldConfSpec.Value @@ -1577,7 +1577,12 @@ func validateNsConfUpdate(newConfSpec, oldConfSpec, currentStatus *AerospikeConf if singleConf["name"] == oldSingleConf["name"] { // replication-factor update not allowed - if isValueUpdated( + val, err := asconfig.CompareVersions(incomingVersion, Version6) + if err != nil { + return fmt.Errorf("failed to check image version: %v", err) + } + + if (IsNSSCEnabled(singleConf) || val < 0) && isValueUpdated( oldSingleConf, singleConf, "replication-factor", ) { return fmt.Errorf( diff --git a/api/v1/aerospikeconfig.go b/api/v1/aerospikeconfig.go index 824b75a40..d2e37db70 100644 --- a/api/v1/aerospikeconfig.go +++ b/api/v1/aerospikeconfig.go @@ -27,7 +27,7 @@ func (c *AerospikeConfigSpec) DeepCopy() *AerospikeConfigSpec { dst := &AerospikeConfigSpec{ Value: map[string]interface{}{}, } - lib.DeepCopy(dst, c) + dst.Value = lib.DeepCopy(c.Value).(map[string]interface{}) return dst } diff --git a/api/v1/utils.go b/api/v1/utils.go index fe1a28e3a..d613db5d4 100644 --- a/api/v1/utils.go +++ b/api/v1/utils.go @@ -61,8 +61,8 @@ const ( AerospikeInitContainerName = "aerospike-init" AerospikeInitContainerRegistryEnvVar = "AEROSPIKE_KUBERNETES_INIT_REGISTRY" AerospikeInitContainerDefaultRegistry = "docker.io" - AerospikeInitContainerDefaultRegistryNamespace = "aerospike" - AerospikeInitContainerDefaultRepoAndTag = "aerospike-kubernetes-init:2.1.0" + AerospikeInitContainerDefaultRegistryNamespace = "tanmayj10" + AerospikeInitContainerDefaultRepoAndTag = "aerospike-kubernetes-init:2.1.0-dev" AerospikeAppLabel = "app" AerospikeCustomResourceLabel = "aerospike.com/cr" AerospikeRackIDLabel = "aerospike.com/rack-id" diff --git a/api/v1beta1/aerospikeconfig.go b/api/v1beta1/aerospikeconfig.go index 7d7ae431c..5b94577ed 100644 --- a/api/v1beta1/aerospikeconfig.go +++ b/api/v1beta1/aerospikeconfig.go @@ -24,11 +24,10 @@ func (c *AerospikeConfigSpec) UnmarshalJSON(b []byte) error { } func (c *AerospikeConfigSpec) DeepCopy() *AerospikeConfigSpec { - src := *c - dst := AerospikeConfigSpec{ + dst := &AerospikeConfigSpec{ Value: map[string]interface{}{}, } - lib.DeepCopy(dst.Value, src.Value) + dst.Value = lib.DeepCopy(c.Value).(map[string]interface{}) - return &dst + return dst } diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index 093da495b..818378076 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -296,3 +296,39 @@ func (r *SingleClusterReconciler) setMigrateFillDelay( return reconcileSuccess() } + +func (r *SingleClusterReconciler) setDynamicConfig( + policy *as.ClientPolicy, + cmds []string, pods []*corev1.Pod, ignorablePodNames sets.Set[string], +) reconcileResult { + // This doesn't make actual connection, only objects having connection info are created + allHostConns, err := r.newAllHostConnWithOption(ignorablePodNames) + if err != nil { + return reconcileError( + fmt.Errorf( + "failed to get hostConn for aerospike cluster nodes: %v", err, + ), + ) + } + + podList := make([]corev1.Pod, 0, len(pods)) + + for idx := range pods { + podList = append(podList, *pods[idx]) + } + + selectedHostConns, err := r.newPodsHostConnWithOption(podList, ignorablePodNames) + if err != nil { + return reconcileError( + fmt.Errorf( + "failed to get hostConn for aerospike cluster nodes: %v", err, + ), + ) + } + + if err := deployment.SetConfigCommandsOnHosts(r.Log, policy, allHostConns, selectedHostConns, cmds); err != nil { + return reconcileError(err) + } + + return reconcileSuccess() +} diff --git a/controllers/configmap.go b/controllers/configmap.go index 102ef5911..a94bbd78e 100644 --- a/controllers/configmap.go +++ b/controllers/configmap.go @@ -167,10 +167,9 @@ func (r *SingleClusterReconciler) createConfigMapData(rack *asdbv1.Rack) ( func createPodSpecForRack( aeroCluster *asdbv1.AerospikeCluster, rack *asdbv1.Rack, ) *asdbv1.AerospikePodSpec { - rackFullPodSpec := asdbv1.AerospikePodSpec{} - lib.DeepCopy( - &rackFullPodSpec, &aeroCluster.Spec.PodSpec, - ) + rackFullPodSpec := lib.DeepCopy( + aeroCluster.Spec.PodSpec, + ).(asdbv1.AerospikePodSpec) rackFullPodSpec.Affinity = rack.PodSpec.Affinity rackFullPodSpec.Tolerations = rack.PodSpec.Tolerations diff --git a/controllers/pod.go b/controllers/pod.go index 1244e6f3e..9bf04c06c 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -20,6 +20,7 @@ import ( asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" "github.com/aerospike/aerospike-kubernetes-operator/pkg/jsonpatch" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" + "github.com/aerospike/aerospike-management-lib/asconfig" ) // RestartType is the type of pod restart to use. @@ -29,6 +30,9 @@ const ( // noRestart needed. noRestart RestartType = iota + // noRestartUpdateConf indicates that restart is not needed but conf file has to be updated. + noRestartUpdateConf + // podRestart indicates that restart requires a restart of the pod. podRestart @@ -37,7 +41,7 @@ const ( ) // mergeRestartType generates the updated restart type based on precedence. -// podRestart > quickRestart > noRestart +// podRestart > quickRestart > noRestartUpdateConf > noRestart func mergeRestartType(current, incoming RestartType) RestartType { if current == podRestart || incoming == podRestart { return podRestart @@ -47,20 +51,31 @@ func mergeRestartType(current, incoming RestartType) RestartType { return quickRestart } + if current == noRestartUpdateConf || incoming == noRestartUpdateConf { + return noRestartUpdateConf + } + return noRestart } // Fetching RestartType of all pods, based on the operation being performed. -func (r *SingleClusterReconciler) getRollingRestartTypeMap( - rackState *RackState, pods []*corev1.Pod, ignorablePodNames sets.Set[string], -) (map[string]RestartType, error) { - var addedNSDevices []string +func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, ignorablePodNames sets.Set[string]) ( + restartTypeMap map[string]RestartType, dynamicCmds []string, err error) { + var ( + addedNSDevices []string + onlyDynamicConfigChange bool + ) - restartTypeMap := make(map[string]RestartType) + restartTypeMap = make(map[string]RestartType) + + pods, err := r.getOrderedRackPodList(rackState.Rack.ID) + if err != nil { + return nil, nil, fmt.Errorf("failed to list pods: %v", err) + } confMap, err := r.getConfigMap(rackState.Rack.ID) if err != nil { - return nil, err + return nil, nil, err } requiredConfHash := confMap.Data[aerospikeConfHashFileName] @@ -71,24 +86,39 @@ func (r *SingleClusterReconciler) getRollingRestartTypeMap( } podStatus := r.aeroCluster.Status.Pods[pods[idx].Name] - if addedNSDevices == nil && podStatus.AerospikeConfigHash != requiredConfHash { - // Fetching all block devices that have been added in namespaces. - addedNSDevices, err = r.getNSAddedDevices(rackState) - if err != nil { - return nil, err + if podStatus.AerospikeConfigHash != requiredConfHash { + if addedNSDevices == nil { + // Fetching all block devices that have been added in namespaces. + addedNSDevices, err = r.getNSAddedDevices(rackState) + if err != nil { + return nil, nil, err + } + } + + if dynamicCmds == nil { + // Fetching all dynamic config commands. + dynamicCmds, err = r.handleDynamicConfigChange(rackState) + if err != nil { + return nil, nil, err + } } } - restartType := r.getRollingRestartTypePod(rackState, pods[idx], confMap, addedNSDevices) + if len(dynamicCmds) > 0 { + onlyDynamicConfigChange = true + } + + restartType := r.getRollingRestartTypePod(rackState, pods[idx], confMap, addedNSDevices, onlyDynamicConfigChange) restartTypeMap[pods[idx].Name] = restartType } - return restartTypeMap, nil + return restartTypeMap, dynamicCmds, nil } func (r *SingleClusterReconciler) getRollingRestartTypePod( - rackState *RackState, pod *corev1.Pod, confMap *corev1.ConfigMap, addedNSDevices []string, + rackState *RackState, pod *corev1.Pod, confMap *corev1.ConfigMap, + addedNSDevices []string, onlyDynamicConfigChange bool, ) RestartType { restartType := noRestart @@ -105,9 +135,14 @@ func (r *SingleClusterReconciler) getRollingRestartTypePod( // Check if aerospikeConfig is updated if podStatus.AerospikeConfigHash != requiredConfHash { + podRestartType := quickRestart // checking if volumes added in namespace is part of dirtyVolumes. // if yes, then podRestart is needed. - podRestartType := r.handleNSOrDeviceAddition(addedNSDevices, pod.Name) + if len(addedNSDevices) > 0 { + podRestartType = r.handleNSOrDeviceAddition(addedNSDevices, pod.Name) + } else if onlyDynamicConfigChange { + podRestartType = noRestartUpdateConf + } restartType = mergeRestartType(restartType, podRestartType) @@ -180,14 +215,25 @@ func (r *SingleClusterReconciler) rollingRestartPods( return reconcileSuccess() } -func (r *SingleClusterReconciler) restartASDInPod( - rackState *RackState, pod *corev1.Pod, -) error { +func (r *SingleClusterReconciler) restartOrUpdateAerospikeServer(rackState *RackState, + pod *corev1.Pod, operation RestartType) error { cmName := getNamespacedNameForSTSConfigMap(r.aeroCluster, rackState.Rack.ID) initBinary := "/etc/aerospike/akoinit" + + var subCommand string + + switch operation { + case noRestart, podRestart: + return fmt.Errorf("invalid operation for akoinit") + case quickRestart: + subCommand = "quick-restart" + case noRestartUpdateConf: + subCommand = "update-conf" + } + cmd := []string{ initBinary, - "quick-restart", + subCommand, "--cm-name", cmName.Name, "--cm-namespace", @@ -226,7 +272,7 @@ func (r *SingleClusterReconciler) restartASDInPod( } } else { r.Log.V(1).Info( - "Failed warm restart", "err", err, "podName", pod.Name, "stdout", + "Failed to perform", "operation", subCommand, "err", err, "podName", pod.Name, "stdout", stdout, "stderr", stderr, ) @@ -234,11 +280,19 @@ func (r *SingleClusterReconciler) restartASDInPod( } } - r.Recorder.Eventf( - r.aeroCluster, corev1.EventTypeNormal, "PodWarmRestarted", - "[rack-%d] Restarted Pod %s", rackState.Rack.ID, pod.Name, - ) - r.Log.V(1).Info("Pod warm restarted", "podName", pod.Name) + if subCommand == "quick-restart" { + r.Recorder.Eventf( + r.aeroCluster, corev1.EventTypeNormal, "PodWarmRestarted", + "[rack-%d] Restarted Pod %s", rackState.Rack.ID, pod.Name, + ) + r.Log.V(1).Info("Pod warm restarted", "podName", pod.Name) + } else { + r.Recorder.Eventf( + r.aeroCluster, corev1.EventTypeNormal, "PodConfUpdated", + "[rack-%d] Updated Pod %s", rackState.Rack.ID, pod.Name, + ) + r.Log.V(1).Info("Pod conf updated", "podName", pod.Name) + } return nil } @@ -261,7 +315,7 @@ func (r *SingleClusterReconciler) restartPods( if restartType == quickRestart { // If ASD restart fails then go ahead and restart the pod - if err := r.restartASDInPod(rackState, pod); err == nil { + if err := r.restartOrUpdateAerospikeServer(rackState, pod, quickRestart); err == nil { continue } } @@ -283,6 +337,44 @@ func (r *SingleClusterReconciler) restartPods( return reconcileSuccess() } +func (r *SingleClusterReconciler) updatePods( + rackState *RackState, podsToUpdate []*corev1.Pod, +) reconcileResult { + restartedPods := make([]*corev1.Pod, 0, len(podsToUpdate)) + + for idx := range podsToUpdate { + pod := podsToUpdate[idx] + + r.Log.Info("updating pod", "pod", pod.Name) + // If update Conf fails then go ahead and restart the asd + var err error + if err = r.restartOrUpdateAerospikeServer(rackState, pod, noRestartUpdateConf); err == nil { + continue + } + + r.Log.Info("Restarting pod as updating failed", "pod", pod.Name, "err", err) + // If ASD restart fails then go ahead and restart the pod + if err := r.restartOrUpdateAerospikeServer(rackState, pod, quickRestart); err == nil { + continue + } + + if err := r.Client.Delete(context.TODO(), pod); err != nil { + r.Log.Error(err, "Failed to delete pod") + return reconcileError(err) + } + + restartedPods = append(restartedPods, pod) + + r.Log.V(1).Info("Pod deleted", "podName", pod.Name) + } + + if len(restartedPods) > 0 { + return r.ensurePodsRunningAndReady(restartedPods) + } + + return reconcileSuccess() +} + func (r *SingleClusterReconciler) ensurePodsRunningAndReady(podsToCheck []*corev1.Pod) reconcileResult { podNames := getPodNames(podsToCheck) readyPods := map[string]bool{} @@ -641,8 +733,10 @@ func (r *SingleClusterReconciler) cleanupDanglingPodsRack(sts *appsv1.StatefulSe } } - if err := r.cleanupPods(danglingPods, rackState); err != nil { - return fmt.Errorf("failed dangling pod cleanup: %v", err) + if len(danglingPods) > 0 { + if err := r.cleanupPods(danglingPods, rackState); err != nil { + return fmt.Errorf("failed dangling pod cleanup: %v", err) + } } return nil @@ -1012,7 +1106,7 @@ func (r *SingleClusterReconciler) handleNSOrDeviceRemoval(rackState *RackState, } func (r *SingleClusterReconciler) handleNSOrDeviceRemovalPerPod( - removedDevices []string, removedFiles []string, pod *corev1.Pod, + removedDevices, removedFiles []string, pod *corev1.Pod, ) error { podStatus := r.aeroCluster.Status.Pods[pod.Name] @@ -1212,3 +1306,106 @@ func (r *SingleClusterReconciler) getConfigMap(rackID int) (*corev1.ConfigMap, e return confMap, nil } + +func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState) ([]string, error) { + var rackStatus asdbv1.Rack + + asConfCmds := make([]string, 0) + + for idx := range r.aeroCluster.Status.RackConfig.Racks { + if r.aeroCluster.Status.RackConfig.Racks[idx].ID == rackState.Rack.ID { + rackStatus = r.aeroCluster.Status.RackConfig.Racks[idx] + } + } + + version := strings.Split(r.aeroCluster.Spec.Image, ":") + + asConfStatus, err := asconfig.NewMapAsConfig(r.Log, version[1], rackStatus.AerospikeConfig.Value) + if err != nil { + return asConfCmds, fmt.Errorf("failed to load config map by lib: %v", err) + } + + asConfSpec, err := asconfig.NewMapAsConfig(r.Log, version[1], rackState.Rack.AerospikeConfig.Value) + if err != nil { + return asConfCmds, fmt.Errorf("failed to load config map by lib: %v", err) + } + + flatStatusConf := *asConfStatus.GetFlatMap() + flatSpecConf := *asConfSpec.GetFlatMap() + + specToStatusDiffs := asconfig.ConfDiff(r.Log, flatSpecConf, flatStatusConf, true, false, true, version[1]) + r.Log.Info("print diff", "difference", fmt.Sprintf("%v", specToStatusDiffs)) + + if len(specToStatusDiffs) > 1 { + r.Log.V(1).Info("Multiple config change in single go is not supported,"+ + "falling back to rolling restart if needed", "diff", fmt.Sprintf("%v", specToStatusDiffs)) + + return asConfCmds, nil + } + + dynamic, _ := asconfig.GetDynamic("6.4.0") + r.Log.Info("printing dynamic values", "dynamic", dynamic) + + for diff, value := range specToStatusDiffs { + isDynamic := isFieldDynamic(dynamic, diff) + r.Log.Info("isDynamic", "isDynamic", isDynamic) + + if !isDynamic { + r.Log.Info("Static field has been changed, cannot change config dynamically", "key", diff) + return asConfCmds, nil + } + + if fmt.Sprintf("%T", value) == "[]string" { + if statusValue, ok := flatStatusConf[diff]; ok { + statusSet := sets.NewString(statusValue.([]string)...) + diffSet := sets.NewString(value.([]string)...) + + if len(statusSet.Difference(diffSet)) > 0 { + r.Log.Info("Can not remove value from list dynamically", "key", diff, + "statusset", fmt.Sprint(statusSet.List()), "diffSet", fmt.Sprint(diffSet.List())) + return asConfCmds, nil + } + } + } + } + + for diff, value := range specToStatusDiffs { + r.Log.Info("creating command", "diff", diff, "value", value) + + cmds, err := asconfig.CreateASConfCommand(diff, value) + if err != nil { + return asConfCmds, fmt.Errorf("failed to create asconfig command: %v", err) + } + + asConfCmds = append(asConfCmds, cmds...) + } + + r.Log.Info("printing commands", "asConfCmds", fmt.Sprintf("%v", asConfCmds)) + // run asinfo command list in server + + return asConfCmds, nil +} + +func isFieldDynamic(dynamic map[string]bool, diff string) bool { + var key string + + tokens := strings.Split(diff, ".") + for _, token := range tokens { + if token[0] == '{' && token[len(token)-1] == '}' { + key += "_." + } else { + key = key + token + "." + } + } + + key = strings.TrimSuffix(key, ".") + if strings.Contains(key, "replication-factor") { + return true + } + + if strings.Contains(key, "rack-id") { + return false + } + + return dynamic[key] +} diff --git a/controllers/rack.go b/controllers/rack.go index 66e269349..df9cc9c22 100644 --- a/controllers/rack.go +++ b/controllers/rack.go @@ -392,7 +392,8 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat return found, res } } else { - var needRollingRestartRack, restartTypeMap, nErr = r.needRollingRestartRack(rackState, ignorablePodNames) + var needRollingRestartRack, needDynamicUpdateRack, restartTypeMap, + dynamicCmds, nErr = r.needRollingRestartRack(rackState, ignorablePodNames) if nErr != nil { return found, reconcileError(nErr) } @@ -417,6 +418,27 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat return found, res } } + + if needDynamicUpdateRack { + res = r.updateDynamicConfig(rackState, ignorablePodNames, restartTypeMap, failedPods, dynamicCmds) + if !res.isSuccess { + if res.err != nil { + r.Log.Error( + res.err, "Failed to do dynamic update", "stsName", + found.Name, + ) + + r.Recorder.Eventf( + r.aeroCluster, corev1.EventTypeWarning, + "RackRollingRestartFailed", + "[rack-%d] Failed to do rolling restart {STS: %s/%s}", + rackState.Rack.ID, found.Namespace, found.Name, + ) + } + + return found, res + } + } } if r.aeroCluster.Spec.RackConfig.MaxIgnorablePods != nil { @@ -428,6 +450,69 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat return found, reconcileSuccess() } +func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, + ignorablePodNames sets.Set[string], restartTypeMap map[string]RestartType, + failedPods []*corev1.Pod, dynamicCmds []string) reconcileResult { + r.Log.Info("Update dynamic config in Aerospike pods") + + r.Recorder.Eventf( + r.aeroCluster, corev1.EventTypeNormal, "RackDynamicUpdate", + "[rack-%d] Started Dynamic update", rackState.Rack.ID, + ) + + var ( + err error + podList []*corev1.Pod + ) + + failedPodNames := sets.Set[string]{} + + for idx := range failedPods { + sets.Insert(failedPodNames, failedPods[idx].Name) + } + + // List the pods for this aeroCluster's statefulset + podList, err = r.getOrderedRackPodList(rackState.Rack.ID) + if err != nil { + return reconcileError(fmt.Errorf("failed to list pods: %v", err)) + } + + // Find pods which needs restart + podsToUpdate := make([]*corev1.Pod, 0, len(podList)) + + for idx := range podList { + pod := podList[idx] + + restartType := restartTypeMap[pod.Name] + if restartType != noRestartUpdateConf || failedPodNames.Has(pod.Name) { + r.Log.Info("This Pod doesn't need any update, Skip this", "pod", pod.Name) + continue + } + + podsToUpdate = append(podsToUpdate, pod) + } + + podNames := getPodNames(podsToUpdate) + if err = r.createOrUpdatePodServiceIfNeeded(podNames); err != nil { + return reconcileError(err) + } + + if res := r.setDynamicConfig(r.getClientPolicy(), dynamicCmds, podsToUpdate, ignorablePodNames); !res.isSuccess { + return res + } + + if res := r.updatePods(rackState, podsToUpdate); !res.isSuccess { + return res + } + + r.Recorder.Eventf( + r.aeroCluster, corev1.EventTypeNormal, "RackDynamicUpdate", + "[rack-%d] Finished Dynamic update", rackState.Rack.ID, + ) + + return reconcileSuccess() +} + func (r *SingleClusterReconciler) handleNSOrDeviceRemovalForIgnorablePods( rackState *RackState, ignorablePodNames sets.Set[string], ) reconcileResult { @@ -997,7 +1082,7 @@ func (r *SingleClusterReconciler) rollingRestartRack(found *appsv1.StatefulSet, } restartType := restartTypeMap[pod.Name] - if restartType == noRestart { + if restartType == noRestart || restartType == noRestartUpdateConf { r.Log.Info("This Pod doesn't need rolling restart, Skip this", "pod", pod.Name) continue } @@ -1062,25 +1147,25 @@ func (r *SingleClusterReconciler) rollingRestartRack(found *appsv1.StatefulSet, } func (r *SingleClusterReconciler) needRollingRestartRack(rackState *RackState, ignorablePodNames sets.Set[string]) ( - needRestart bool, restartTypeMap map[string]RestartType, err error, + needRestart, needUpdateConf bool, restartTypeMap map[string]RestartType, dynamicCmds []string, err error, ) { - podList, err := r.getOrderedRackPodList(rackState.Rack.ID) + restartTypeMap, dynamicCmds, err = r.getRollingRestartTypeMap(rackState, ignorablePodNames) if err != nil { - return false, nil, fmt.Errorf("failed to list pods: %v", err) - } - - restartTypeMap, err = r.getRollingRestartTypeMap(rackState, podList, ignorablePodNames) - if err != nil { - return false, nil, err + return needRestart, needUpdateConf, nil, nil, err } for _, restartType := range restartTypeMap { - if restartType != noRestart { - return true, restartTypeMap, nil + switch restartType { + case noRestart: + // Do nothing + case noRestartUpdateConf: + needUpdateConf = true + case podRestart, quickRestart: + needRestart = true } } - return false, nil, nil + return needRestart, needUpdateConf, restartTypeMap, dynamicCmds, nil } func (r *SingleClusterReconciler) isRackUpgradeNeeded(rackID int, ignorablePodNames sets.Set[string]) ( @@ -1213,9 +1298,7 @@ func (r *SingleClusterReconciler) isStorageVolumeSourceUpdated(volume *asdbv1.Vo return true } - var volumeCopy asdbv1.VolumeSpec - - lib.DeepCopy(&volumeCopy, volume) + volumeCopy := lib.DeepCopy(*volume).(asdbv1.VolumeSpec) if volumeCopy.Source.Secret != nil { setDefaultsSecretVolumeSource(volumeCopy.Source.Secret) diff --git a/controllers/reconciler.go b/controllers/reconciler.go index 58b4417bb..d6fcb915a 100644 --- a/controllers/reconciler.go +++ b/controllers/reconciler.go @@ -384,18 +384,17 @@ func (r *SingleClusterReconciler) updateAccessControlStatus() error { } // AerospikeAccessControl - statusAerospikeAccessControl := &asdbv1.AerospikeAccessControlSpec{} - lib.DeepCopy( - statusAerospikeAccessControl, r.aeroCluster.Spec.AerospikeAccessControl, - ) + statusAerospikeAccessControl := lib.DeepCopy( + *r.aeroCluster.Spec.AerospikeAccessControl, + ).(asdbv1.AerospikeAccessControlSpec) - newAeroCluster.Status.AerospikeClusterStatusSpec.AerospikeAccessControl = statusAerospikeAccessControl + newAeroCluster.Status.AerospikeClusterStatusSpec.AerospikeAccessControl = &statusAerospikeAccessControl if err := r.patchStatus(newAeroCluster); err != nil { return fmt.Errorf("error updating status: %w", err) } - r.aeroCluster.Status.AerospikeClusterStatusSpec.AerospikeAccessControl = statusAerospikeAccessControl + r.aeroCluster.Status.AerospikeClusterStatusSpec.AerospikeAccessControl = &statusAerospikeAccessControl r.Log.Info("Updated access control status", "status", newAeroCluster.Status) @@ -539,7 +538,7 @@ func (r *SingleClusterReconciler) patchStatus(newAeroCluster *asdbv1.AerospikeCl // Seems like a bug in encoding/json/Unmarshall. // // Workaround by force copying new object's status to old object's status. - lib.DeepCopy(&oldAeroCluster.Status, &newAeroCluster.Status) + oldAeroCluster.Status = lib.DeepCopy(newAeroCluster.Status).(asdbv1.AerospikeClusterStatus) return nil } diff --git a/controllers/statefulset.go b/controllers/statefulset.go index 1d36c7596..26412718a 100644 --- a/controllers/statefulset.go +++ b/controllers/statefulset.go @@ -133,7 +133,7 @@ func (r *SingleClusterReconciler) createSTS( { Name: asdbv1.AerospikeInitContainerName, Image: asdbv1.GetAerospikeInitContainerImage(r.aeroCluster), - ImagePullPolicy: corev1.PullIfNotPresent, + ImagePullPolicy: corev1.PullAlways, VolumeMounts: getDefaultAerospikeInitContainerVolumeMounts(), Env: append( envVarList, []corev1.EnvVar{ @@ -790,13 +790,13 @@ func (r *SingleClusterReconciler) updateSTSNonPVStorage( func (r *SingleClusterReconciler) updateSTSSchedulingPolicy( st *appsv1.StatefulSet, rackState *RackState, ) { - affinity := &corev1.Affinity{} + var affinity corev1.Affinity // Use rack affinity, if given if rackState.Rack.PodSpec.Affinity != nil { - lib.DeepCopy(affinity, rackState.Rack.PodSpec.Affinity) + affinity = lib.DeepCopy(*rackState.Rack.PodSpec.Affinity).(corev1.Affinity) } else if r.aeroCluster.Spec.PodSpec.Affinity != nil { - lib.DeepCopy(affinity, r.aeroCluster.Spec.PodSpec.Affinity) + affinity = lib.DeepCopy(*r.aeroCluster.Spec.PodSpec.Affinity).(corev1.Affinity) } // Set our rules in PodAntiAffinity @@ -896,7 +896,7 @@ func (r *SingleClusterReconciler) updateSTSSchedulingPolicy( } } - st.Spec.Template.Spec.Affinity = affinity + st.Spec.Template.Spec.Affinity = &affinity // Use rack nodeSelector, if given if len(rackState.Rack.PodSpec.NodeSelector) != 0 { @@ -961,8 +961,7 @@ func updateSTSContainers( // Create a copy because updating stateful sets defaults // on the sidecar container object which mutates original aeroCluster object. - specContainerCopy := &corev1.Container{} - lib.DeepCopy(specContainerCopy, specContainer) + specContainerCopy := lib.DeepCopy(*specContainer).(corev1.Container) for stsIdx := range stsContainers { if specContainer.Name != stsContainers[stsIdx].Name { @@ -972,7 +971,7 @@ func updateSTSContainers( // Retain volume mounts and devices to make sure external storage will not lose. specContainerCopy.VolumeMounts = stsContainers[stsIdx].VolumeMounts specContainerCopy.VolumeDevices = stsContainers[stsIdx].VolumeDevices - stsContainers[stsIdx] = *specContainerCopy + stsContainers[stsIdx] = specContainerCopy found = true break @@ -980,7 +979,7 @@ func updateSTSContainers( if !found { // Add to stateful set containers. - stsContainers = append(stsContainers, *specContainerCopy) + stsContainers = append(stsContainers, specContainerCopy) } } diff --git a/go.mod b/go.mod index 87eff97ac..10e7d55c7 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v0.0.0-20231129055344-b6aff63f1dbb + github.com/aerospike/aerospike-management-lib v0.0.0-20231208095128-a898bdce6a13 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/evanphx/json-patch v4.12.0+incompatible github.com/go-logr/logr v1.2.4 @@ -68,7 +68,6 @@ require ( github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect - github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect @@ -78,7 +77,7 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/net v0.10.0 // indirect + golang.org/x/net v0.17.0 // indirect golang.org/x/sync v0.2.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect @@ -87,7 +86,7 @@ require ( google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect google.golang.org/grpc v1.54.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index abd92dab8..a222b152f 100644 --- a/go.sum +++ b/go.sum @@ -598,8 +598,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/aerospike/aerospike-client-go/v6 v6.14.0 h1:Z3FcGWJda1sagzdc6Akz4EJ13Pq55Uyn6qtFLrVUDd0= github.com/aerospike/aerospike-client-go/v6 v6.14.0/go.mod h1:/0Wm81GhMqem+9flWcpazPKoRfjFeG6WrQdXGiMNi0A= -github.com/aerospike/aerospike-management-lib v0.0.0-20231129055344-b6aff63f1dbb h1:ykX3ElBNT/VOUhw/+5+jiFnWw3LSbPfl6eRrhQzBBFk= -github.com/aerospike/aerospike-management-lib v0.0.0-20231129055344-b6aff63f1dbb/go.mod h1:LPOsGG8okRSH4hN9Y8VXFzsfIpBDj2WKEsI/f6wxwaw= +github.com/aerospike/aerospike-management-lib v0.0.0-20231208095128-a898bdce6a13 h1:T8KB2wrwTEPfiyeWzQMXmUI/cm6HmVAdI1QZx952ed8= +github.com/aerospike/aerospike-management-lib v0.0.0-20231208095128-a898bdce6a13/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -878,8 +878,6 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= -github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc= -github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -1457,8 +1455,9 @@ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/test/cluster_helper.go b/test/cluster_helper.go index b1263a8c7..f165f4abd 100644 --- a/test/cluster_helper.go +++ b/test/cluster_helper.go @@ -298,7 +298,7 @@ func rollingRestartClusterTest( aeroCluster.Spec.AerospikeConfig.Value["service"] = map[string]interface{}{} } - aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = defaultProtofdmax + 1 + aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["indent-allocations"] = true err = updateCluster(k8sClient, ctx, aeroCluster) if err != nil { @@ -307,7 +307,7 @@ func rollingRestartClusterTest( // Verify that the change has been applied on the cluster. return validateAerospikeConfigServiceClusterUpdate( - log, k8sClient, ctx, clusterNamespacedName, []string{"proto-fd-max"}, + log, k8sClient, ctx, clusterNamespacedName, []string{"indent-allocations"}, ) } @@ -1363,16 +1363,14 @@ func aerospikeClusterCreateUpdateWithTO( // Apply the update. if desired.Spec.AerospikeAccessControl != nil { - current.Spec.AerospikeAccessControl = &asdbv1.AerospikeAccessControlSpec{} - lib.DeepCopy(¤t.Spec, &desired.Spec) + current.Spec = lib.DeepCopy(desired.Spec).(asdbv1.AerospikeClusterSpec) } else { current.Spec.AerospikeAccessControl = nil } - lib.DeepCopy( - ¤t.Spec.AerospikeConfig.Value, - &desired.Spec.AerospikeConfig.Value, - ) + current.Spec.AerospikeConfig.Value = lib.DeepCopy( + desired.Spec.AerospikeConfig.Value, + ).(map[string]interface{}) if err := k8sClient.Update(ctx, current); err != nil { return err diff --git a/test/services_test.go b/test/services_test.go index b7e49e8d8..8ea26485d 100644 --- a/test/services_test.go +++ b/test/services_test.go @@ -129,10 +129,9 @@ func createLoadBalancer() *asdbv1.LoadBalancerSpec { ), ) - result := &asdbv1.LoadBalancerSpec{} - lib.DeepCopy(result, lb) + result := lib.DeepCopy(lb).(asdbv1.LoadBalancerSpec) - return result + return &result } func loadBalancerName(aeroCluster *asdbv1.AerospikeCluster) types.NamespacedName { From 3751956668eae737953aa5d598e3f95e0a23bdb3 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Thu, 14 Dec 2023 14:47:08 +0530 Subject: [PATCH 02/20] Code structure change --- controllers/aero_info_calls.go | 12 ++++++++-- controllers/pod.go | 44 +++++++++++----------------------- controllers/rack.go | 15 ++++++------ go.mod | 2 +- go.sum | 10 ++++++++ 5 files changed, 43 insertions(+), 40 deletions(-) diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index 818378076..5b95b2e8d 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -24,6 +24,7 @@ import ( asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" "github.com/aerospike/aerospike-management-lib/deployment" + "github.com/aerospike/aerospike-management-lib/info" ) // ------------------------------------------------------------------------------------ @@ -299,7 +300,7 @@ func (r *SingleClusterReconciler) setMigrateFillDelay( func (r *SingleClusterReconciler) setDynamicConfig( policy *as.ClientPolicy, - cmds []string, pods []*corev1.Pod, ignorablePodNames sets.Set[string], + diffs map[string]interface{}, pods []*corev1.Pod, ignorablePodNames sets.Set[string], ) reconcileResult { // This doesn't make actual connection, only objects having connection info are created allHostConns, err := r.newAllHostConnWithOption(ignorablePodNames) @@ -326,7 +327,14 @@ func (r *SingleClusterReconciler) setDynamicConfig( ) } - if err := deployment.SetConfigCommandsOnHosts(r.Log, policy, allHostConns, selectedHostConns, cmds); err != nil { + asConfCmds, err := info.CreateConfigSetCmdList(diffs) + if err != nil { + return reconcileError(err) + } + + r.Log.Info("printing commands", "asConfCmds", fmt.Sprintf("%v", asConfCmds)) + + if err := deployment.SetConfigCommandsOnHosts(r.Log, policy, allHostConns, selectedHostConns, asConfCmds); err != nil { return reconcileError(err) } diff --git a/controllers/pod.go b/controllers/pod.go index 9bf04c06c..d2123b0b8 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -60,7 +60,7 @@ func mergeRestartType(current, incoming RestartType) RestartType { // Fetching RestartType of all pods, based on the operation being performed. func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, ignorablePodNames sets.Set[string]) ( - restartTypeMap map[string]RestartType, dynamicCmds []string, err error) { + restartTypeMap map[string]RestartType, dynamicDiffs map[string]interface{}, err error) { var ( addedNSDevices []string onlyDynamicConfigChange bool @@ -95,16 +95,16 @@ func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, } } - if dynamicCmds == nil { - // Fetching all dynamic config commands. - dynamicCmds, err = r.handleDynamicConfigChange(rackState) + if dynamicDiffs == nil { + // Fetching all dynamic diffs. + dynamicDiffs, err = r.handleDynamicConfigChange(rackState) if err != nil { return nil, nil, err } } } - if len(dynamicCmds) > 0 { + if len(dynamicDiffs) > 0 { onlyDynamicConfigChange = true } @@ -113,7 +113,7 @@ func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, restartTypeMap[pods[idx].Name] = restartType } - return restartTypeMap, dynamicCmds, nil + return restartTypeMap, dynamicDiffs, nil } func (r *SingleClusterReconciler) getRollingRestartTypePod( @@ -1307,11 +1307,9 @@ func (r *SingleClusterReconciler) getConfigMap(rackID int) (*corev1.ConfigMap, e return confMap, nil } -func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState) ([]string, error) { +func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState) (map[string]interface{}, error) { var rackStatus asdbv1.Rack - asConfCmds := make([]string, 0) - for idx := range r.aeroCluster.Status.RackConfig.Racks { if r.aeroCluster.Status.RackConfig.Racks[idx].ID == rackState.Rack.ID { rackStatus = r.aeroCluster.Status.RackConfig.Racks[idx] @@ -1322,12 +1320,12 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState asConfStatus, err := asconfig.NewMapAsConfig(r.Log, version[1], rackStatus.AerospikeConfig.Value) if err != nil { - return asConfCmds, fmt.Errorf("failed to load config map by lib: %v", err) + return nil, fmt.Errorf("failed to load config map by lib: %v", err) } asConfSpec, err := asconfig.NewMapAsConfig(r.Log, version[1], rackState.Rack.AerospikeConfig.Value) if err != nil { - return asConfCmds, fmt.Errorf("failed to load config map by lib: %v", err) + return nil, fmt.Errorf("failed to load config map by lib: %v", err) } flatStatusConf := *asConfStatus.GetFlatMap() @@ -1340,10 +1338,10 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState r.Log.V(1).Info("Multiple config change in single go is not supported,"+ "falling back to rolling restart if needed", "diff", fmt.Sprintf("%v", specToStatusDiffs)) - return asConfCmds, nil + return nil, nil } - dynamic, _ := asconfig.GetDynamic("6.4.0") + dynamic, _ := asconfig.GetDynamic("7.0.0") r.Log.Info("printing dynamic values", "dynamic", dynamic) for diff, value := range specToStatusDiffs { @@ -1352,7 +1350,7 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState if !isDynamic { r.Log.Info("Static field has been changed, cannot change config dynamically", "key", diff) - return asConfCmds, nil + return nil, nil } if fmt.Sprintf("%T", value) == "[]string" { @@ -1363,27 +1361,13 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState if len(statusSet.Difference(diffSet)) > 0 { r.Log.Info("Can not remove value from list dynamically", "key", diff, "statusset", fmt.Sprint(statusSet.List()), "diffSet", fmt.Sprint(diffSet.List())) - return asConfCmds, nil + return nil, nil } } } } - for diff, value := range specToStatusDiffs { - r.Log.Info("creating command", "diff", diff, "value", value) - - cmds, err := asconfig.CreateASConfCommand(diff, value) - if err != nil { - return asConfCmds, fmt.Errorf("failed to create asconfig command: %v", err) - } - - asConfCmds = append(asConfCmds, cmds...) - } - - r.Log.Info("printing commands", "asConfCmds", fmt.Sprintf("%v", asConfCmds)) - // run asinfo command list in server - - return asConfCmds, nil + return specToStatusDiffs, nil } func isFieldDynamic(dynamic map[string]bool, diff string) bool { diff --git a/controllers/rack.go b/controllers/rack.go index df9cc9c22..b43aa15f5 100644 --- a/controllers/rack.go +++ b/controllers/rack.go @@ -393,7 +393,7 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat } } else { var needRollingRestartRack, needDynamicUpdateRack, restartTypeMap, - dynamicCmds, nErr = r.needRollingRestartRack(rackState, ignorablePodNames) + dynamicDiffs, nErr = r.needRollingRestartRack(rackState, ignorablePodNames) if nErr != nil { return found, reconcileError(nErr) } @@ -420,7 +420,7 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat } if needDynamicUpdateRack { - res = r.updateDynamicConfig(rackState, ignorablePodNames, restartTypeMap, failedPods, dynamicCmds) + res = r.updateDynamicConfig(rackState, ignorablePodNames, restartTypeMap, failedPods, dynamicDiffs) if !res.isSuccess { if res.err != nil { r.Log.Error( @@ -452,7 +452,7 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, ignorablePodNames sets.Set[string], restartTypeMap map[string]RestartType, - failedPods []*corev1.Pod, dynamicCmds []string) reconcileResult { + failedPods []*corev1.Pod, dynamicDiffs map[string]interface{}) reconcileResult { r.Log.Info("Update dynamic config in Aerospike pods") r.Recorder.Eventf( @@ -497,7 +497,7 @@ func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, return reconcileError(err) } - if res := r.setDynamicConfig(r.getClientPolicy(), dynamicCmds, podsToUpdate, ignorablePodNames); !res.isSuccess { + if res := r.setDynamicConfig(r.getClientPolicy(), dynamicDiffs, podsToUpdate, ignorablePodNames); !res.isSuccess { return res } @@ -1147,9 +1147,10 @@ func (r *SingleClusterReconciler) rollingRestartRack(found *appsv1.StatefulSet, } func (r *SingleClusterReconciler) needRollingRestartRack(rackState *RackState, ignorablePodNames sets.Set[string]) ( - needRestart, needUpdateConf bool, restartTypeMap map[string]RestartType, dynamicCmds []string, err error, + needRestart, needUpdateConf bool, restartTypeMap map[string]RestartType, + dynamicDiffs map[string]interface{}, err error, ) { - restartTypeMap, dynamicCmds, err = r.getRollingRestartTypeMap(rackState, ignorablePodNames) + restartTypeMap, dynamicDiffs, err = r.getRollingRestartTypeMap(rackState, ignorablePodNames) if err != nil { return needRestart, needUpdateConf, nil, nil, err } @@ -1165,7 +1166,7 @@ func (r *SingleClusterReconciler) needRollingRestartRack(rackState *RackState, i } } - return needRestart, needUpdateConf, restartTypeMap, dynamicCmds, nil + return needRestart, needUpdateConf, restartTypeMap, dynamicDiffs, nil } func (r *SingleClusterReconciler) isRackUpgradeNeeded(rackID int, ignorablePodNames sets.Set[string]) ( diff --git a/go.mod b/go.mod index 10e7d55c7..05c220a3b 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v0.0.0-20231208095128-a898bdce6a13 + github.com/aerospike/aerospike-management-lib v0.0.0-20231214090640-f5839c8a0c7c github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/evanphx/json-patch v4.12.0+incompatible github.com/go-logr/logr v1.2.4 diff --git a/go.sum b/go.sum index a222b152f..4ad795a94 100644 --- a/go.sum +++ b/go.sum @@ -600,6 +600,12 @@ github.com/aerospike/aerospike-client-go/v6 v6.14.0 h1:Z3FcGWJda1sagzdc6Akz4EJ13 github.com/aerospike/aerospike-client-go/v6 v6.14.0/go.mod h1:/0Wm81GhMqem+9flWcpazPKoRfjFeG6WrQdXGiMNi0A= github.com/aerospike/aerospike-management-lib v0.0.0-20231208095128-a898bdce6a13 h1:T8KB2wrwTEPfiyeWzQMXmUI/cm6HmVAdI1QZx952ed8= github.com/aerospike/aerospike-management-lib v0.0.0-20231208095128-a898bdce6a13/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= +github.com/aerospike/aerospike-management-lib v0.0.0-20231213115658-c5ab043aa10f h1:AGi7jFUBXl5o9Nx+Z/HfQ0E9T8YSDcFxAf7sMN6iYKI= +github.com/aerospike/aerospike-management-lib v0.0.0-20231213115658-c5ab043aa10f/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= +github.com/aerospike/aerospike-management-lib v0.0.0-20231213145135-5a70e4609127 h1:xQBiVdymv2MJMFih7KjBhQy//O8hHQnNP/PyEBC5r38= +github.com/aerospike/aerospike-management-lib v0.0.0-20231213145135-5a70e4609127/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= +github.com/aerospike/aerospike-management-lib v0.0.0-20231214090640-f5839c8a0c7c h1:txL0afFeA436KmPHmPCn8TdYCKAK2vMWULyOKK52ZaM= +github.com/aerospike/aerospike-management-lib v0.0.0-20231214090640-f5839c8a0c7c/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -671,6 +677,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -808,10 +815,12 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -851,6 +860,7 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= From 7de7c95dc57ad026507fe3b48503a2ef5b9b9487 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Wed, 20 Dec 2023 16:04:35 +0530 Subject: [PATCH 03/20] Supporting logging dynamic changes. --- controllers/aero_info_calls.go | 9 +++++++-- controllers/pod.go | 13 +++++++++---- go.mod | 2 +- go.sum | 10 ++-------- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index 5b95b2e8d..e27057ec4 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -24,7 +24,6 @@ import ( asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" "github.com/aerospike/aerospike-management-lib/deployment" - "github.com/aerospike/aerospike-management-lib/info" ) // ------------------------------------------------------------------------------------ @@ -327,7 +326,13 @@ func (r *SingleClusterReconciler) setDynamicConfig( ) } - asConfCmds, err := info.CreateConfigSetCmdList(diffs) + if len(selectedHostConns) == 0 { + r.Log.Info("No pods selected for dynamic config change") + + return reconcileSuccess() + } + + asConfCmds, err := deployment.CreateConfigSetCmdList(diffs, selectedHostConns[0].ASConn, r.getClientPolicy()) if err != nil { return reconcileError(err) } diff --git a/controllers/pod.go b/controllers/pod.go index d2123b0b8..6be93e85f 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -1331,8 +1331,8 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState flatStatusConf := *asConfStatus.GetFlatMap() flatSpecConf := *asConfSpec.GetFlatMap() - specToStatusDiffs := asconfig.ConfDiff(r.Log, flatSpecConf, flatStatusConf, true, false, true, version[1]) - r.Log.Info("print diff", "difference", fmt.Sprintf("%v", specToStatusDiffs)) + specToStatusDiffs := asconfig.ConfDiff(r.Log, flatSpecConf, flatStatusConf, true, false, true, "7.0.0") + r.Log.Info("print diff outside", "difference", fmt.Sprintf("%v", specToStatusDiffs)) if len(specToStatusDiffs) > 1 { r.Log.V(1).Info("Multiple config change in single go is not supported,"+ @@ -1387,8 +1387,13 @@ func isFieldDynamic(dynamic map[string]bool, diff string) bool { return true } - if strings.Contains(key, "rack-id") { - return false + // Marking these fields as static as corresponding set-config commands are not straight forward. + staticFields := []string{"rack-id", "report-data-op"} + + for _, field := range staticFields { + if strings.Contains(key, field) { + return false + } } return dynamic[key] diff --git a/go.mod b/go.mod index 05c220a3b..2c9ad1797 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v0.0.0-20231214090640-f5839c8a0c7c + github.com/aerospike/aerospike-management-lib v0.0.0-20231220090750-e26636a42694 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/evanphx/json-patch v4.12.0+incompatible github.com/go-logr/logr v1.2.4 diff --git a/go.sum b/go.sum index 4ad795a94..41439000a 100644 --- a/go.sum +++ b/go.sum @@ -598,14 +598,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/aerospike/aerospike-client-go/v6 v6.14.0 h1:Z3FcGWJda1sagzdc6Akz4EJ13Pq55Uyn6qtFLrVUDd0= github.com/aerospike/aerospike-client-go/v6 v6.14.0/go.mod h1:/0Wm81GhMqem+9flWcpazPKoRfjFeG6WrQdXGiMNi0A= -github.com/aerospike/aerospike-management-lib v0.0.0-20231208095128-a898bdce6a13 h1:T8KB2wrwTEPfiyeWzQMXmUI/cm6HmVAdI1QZx952ed8= -github.com/aerospike/aerospike-management-lib v0.0.0-20231208095128-a898bdce6a13/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= -github.com/aerospike/aerospike-management-lib v0.0.0-20231213115658-c5ab043aa10f h1:AGi7jFUBXl5o9Nx+Z/HfQ0E9T8YSDcFxAf7sMN6iYKI= -github.com/aerospike/aerospike-management-lib v0.0.0-20231213115658-c5ab043aa10f/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= -github.com/aerospike/aerospike-management-lib v0.0.0-20231213145135-5a70e4609127 h1:xQBiVdymv2MJMFih7KjBhQy//O8hHQnNP/PyEBC5r38= -github.com/aerospike/aerospike-management-lib v0.0.0-20231213145135-5a70e4609127/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= -github.com/aerospike/aerospike-management-lib v0.0.0-20231214090640-f5839c8a0c7c h1:txL0afFeA436KmPHmPCn8TdYCKAK2vMWULyOKK52ZaM= -github.com/aerospike/aerospike-management-lib v0.0.0-20231214090640-f5839c8a0c7c/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= +github.com/aerospike/aerospike-management-lib v0.0.0-20231220090750-e26636a42694 h1:ge+2XpHQRkxjsGHwouVC3JNv2YuN93w69A85jWPsaig= +github.com/aerospike/aerospike-management-lib v0.0.0-20231220090750-e26636a42694/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= From f62c38f0be19f6a343cc1d4c410c0b2d0e4f194d Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Fri, 22 Dec 2023 14:58:20 +0530 Subject: [PATCH 04/20] Moving dynamic field validation in management lib. --- controllers/pod.go | 44 +++++--------------------------------------- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 8 insertions(+), 42 deletions(-) diff --git a/controllers/pod.go b/controllers/pod.go index 6be93e85f..bf5bb20f4 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -1341,18 +1341,13 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState return nil, nil } - dynamic, _ := asconfig.GetDynamic("7.0.0") - r.Log.Info("printing dynamic values", "dynamic", dynamic) + isDynamic := asconfig.IsAllDynamicConfig(specToStatusDiffs, "7.0.0") + if !isDynamic { + r.Log.Info("Static field has been changed, cannot change config dynamically") + return nil, nil + } for diff, value := range specToStatusDiffs { - isDynamic := isFieldDynamic(dynamic, diff) - r.Log.Info("isDynamic", "isDynamic", isDynamic) - - if !isDynamic { - r.Log.Info("Static field has been changed, cannot change config dynamically", "key", diff) - return nil, nil - } - if fmt.Sprintf("%T", value) == "[]string" { if statusValue, ok := flatStatusConf[diff]; ok { statusSet := sets.NewString(statusValue.([]string)...) @@ -1369,32 +1364,3 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState return specToStatusDiffs, nil } - -func isFieldDynamic(dynamic map[string]bool, diff string) bool { - var key string - - tokens := strings.Split(diff, ".") - for _, token := range tokens { - if token[0] == '{' && token[len(token)-1] == '}' { - key += "_." - } else { - key = key + token + "." - } - } - - key = strings.TrimSuffix(key, ".") - if strings.Contains(key, "replication-factor") { - return true - } - - // Marking these fields as static as corresponding set-config commands are not straight forward. - staticFields := []string{"rack-id", "report-data-op"} - - for _, field := range staticFields { - if strings.Contains(key, field) { - return false - } - } - - return dynamic[key] -} diff --git a/go.mod b/go.mod index 2c9ad1797..08aeca674 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v0.0.0-20231220090750-e26636a42694 + github.com/aerospike/aerospike-management-lib v0.0.0-20231221135621-91f78d86f1ee github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/evanphx/json-patch v4.12.0+incompatible github.com/go-logr/logr v1.2.4 diff --git a/go.sum b/go.sum index 41439000a..8c812d4c5 100644 --- a/go.sum +++ b/go.sum @@ -598,8 +598,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/aerospike/aerospike-client-go/v6 v6.14.0 h1:Z3FcGWJda1sagzdc6Akz4EJ13Pq55Uyn6qtFLrVUDd0= github.com/aerospike/aerospike-client-go/v6 v6.14.0/go.mod h1:/0Wm81GhMqem+9flWcpazPKoRfjFeG6WrQdXGiMNi0A= -github.com/aerospike/aerospike-management-lib v0.0.0-20231220090750-e26636a42694 h1:ge+2XpHQRkxjsGHwouVC3JNv2YuN93w69A85jWPsaig= -github.com/aerospike/aerospike-management-lib v0.0.0-20231220090750-e26636a42694/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= +github.com/aerospike/aerospike-management-lib v0.0.0-20231221135621-91f78d86f1ee h1:QXe1i/k2kidL/nH8h9SEbteOYVKzpvbIK94oHBAEUvk= +github.com/aerospike/aerospike-management-lib v0.0.0-20231221135621-91f78d86f1ee/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= From 4a31423b91e73eb618c1e8b566da104a672d91b8 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Wed, 27 Dec 2023 20:37:24 +0530 Subject: [PATCH 05/20] version 2, handing diff in more detailed way --- controllers/aero_info_calls.go | 2 +- controllers/pod.go | 24 +++++------------------- controllers/rack.go | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- 5 files changed, 11 insertions(+), 25 deletions(-) diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index e27057ec4..aa648118a 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -299,7 +299,7 @@ func (r *SingleClusterReconciler) setMigrateFillDelay( func (r *SingleClusterReconciler) setDynamicConfig( policy *as.ClientPolicy, - diffs map[string]interface{}, pods []*corev1.Pod, ignorablePodNames sets.Set[string], + diffs map[string]map[string]interface{}, pods []*corev1.Pod, ignorablePodNames sets.Set[string], ) reconcileResult { // This doesn't make actual connection, only objects having connection info are created allHostConns, err := r.newAllHostConnWithOption(ignorablePodNames) diff --git a/controllers/pod.go b/controllers/pod.go index bf5bb20f4..e054e7dfa 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -60,7 +60,7 @@ func mergeRestartType(current, incoming RestartType) RestartType { // Fetching RestartType of all pods, based on the operation being performed. func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, ignorablePodNames sets.Set[string]) ( - restartTypeMap map[string]RestartType, dynamicDiffs map[string]interface{}, err error) { + restartTypeMap map[string]RestartType, dynamicDiffs map[string]map[string]interface{}, err error) { var ( addedNSDevices []string onlyDynamicConfigChange bool @@ -1307,7 +1307,8 @@ func (r *SingleClusterReconciler) getConfigMap(rackID int) (*corev1.ConfigMap, e return confMap, nil } -func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState) (map[string]interface{}, error) { +func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState) ( + map[string]map[string]interface{}, error) { var rackStatus asdbv1.Rack for idx := range r.aeroCluster.Status.RackConfig.Racks { @@ -1331,7 +1332,7 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState flatStatusConf := *asConfStatus.GetFlatMap() flatSpecConf := *asConfSpec.GetFlatMap() - specToStatusDiffs := asconfig.ConfDiff(r.Log, flatSpecConf, flatStatusConf, true, false, true, "7.0.0") + specToStatusDiffs := asconfig.ConfDiff(r.Log, flatSpecConf, flatStatusConf, true, "7.0.0") r.Log.Info("print diff outside", "difference", fmt.Sprintf("%v", specToStatusDiffs)) if len(specToStatusDiffs) > 1 { @@ -1343,24 +1344,9 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState isDynamic := asconfig.IsAllDynamicConfig(specToStatusDiffs, "7.0.0") if !isDynamic { - r.Log.Info("Static field has been changed, cannot change config dynamically") + r.Log.Info("Static field has been modified, cannot change config dynamically") return nil, nil } - for diff, value := range specToStatusDiffs { - if fmt.Sprintf("%T", value) == "[]string" { - if statusValue, ok := flatStatusConf[diff]; ok { - statusSet := sets.NewString(statusValue.([]string)...) - diffSet := sets.NewString(value.([]string)...) - - if len(statusSet.Difference(diffSet)) > 0 { - r.Log.Info("Can not remove value from list dynamically", "key", diff, - "statusset", fmt.Sprint(statusSet.List()), "diffSet", fmt.Sprint(diffSet.List())) - return nil, nil - } - } - } - } - return specToStatusDiffs, nil } diff --git a/controllers/rack.go b/controllers/rack.go index b43aa15f5..82cb125df 100644 --- a/controllers/rack.go +++ b/controllers/rack.go @@ -452,7 +452,7 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, ignorablePodNames sets.Set[string], restartTypeMap map[string]RestartType, - failedPods []*corev1.Pod, dynamicDiffs map[string]interface{}) reconcileResult { + failedPods []*corev1.Pod, dynamicDiffs map[string]map[string]interface{}) reconcileResult { r.Log.Info("Update dynamic config in Aerospike pods") r.Recorder.Eventf( @@ -1148,7 +1148,7 @@ func (r *SingleClusterReconciler) rollingRestartRack(found *appsv1.StatefulSet, func (r *SingleClusterReconciler) needRollingRestartRack(rackState *RackState, ignorablePodNames sets.Set[string]) ( needRestart, needUpdateConf bool, restartTypeMap map[string]RestartType, - dynamicDiffs map[string]interface{}, err error, + dynamicDiffs map[string]map[string]interface{}, err error, ) { restartTypeMap, dynamicDiffs, err = r.getRollingRestartTypeMap(rackState, ignorablePodNames) if err != nil { diff --git a/go.mod b/go.mod index 08aeca674..093b9b386 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v0.0.0-20231221135621-91f78d86f1ee + github.com/aerospike/aerospike-management-lib v0.0.0-20231227142907-e308f15df328 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/evanphx/json-patch v4.12.0+incompatible github.com/go-logr/logr v1.2.4 diff --git a/go.sum b/go.sum index 8c812d4c5..2560947ac 100644 --- a/go.sum +++ b/go.sum @@ -598,8 +598,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/aerospike/aerospike-client-go/v6 v6.14.0 h1:Z3FcGWJda1sagzdc6Akz4EJ13Pq55Uyn6qtFLrVUDd0= github.com/aerospike/aerospike-client-go/v6 v6.14.0/go.mod h1:/0Wm81GhMqem+9flWcpazPKoRfjFeG6WrQdXGiMNi0A= -github.com/aerospike/aerospike-management-lib v0.0.0-20231221135621-91f78d86f1ee h1:QXe1i/k2kidL/nH8h9SEbteOYVKzpvbIK94oHBAEUvk= -github.com/aerospike/aerospike-management-lib v0.0.0-20231221135621-91f78d86f1ee/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= +github.com/aerospike/aerospike-management-lib v0.0.0-20231227142907-e308f15df328 h1:caUEqo6A/BZzPuobq++veNUynPpmum6FRlGgrW6Q2ZE= +github.com/aerospike/aerospike-management-lib v0.0.0-20231227142907-e308f15df328/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= From 0eac6fab8ec96c07cbb1d2ec5c22acd4f79003da Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Tue, 9 Jan 2024 16:44:05 +0530 Subject: [PATCH 06/20] Disallow DC and Namespace addition/removal dynamically from xdr. --- api/v1/aerospikecluster_validating_webhook.go | 2 +- controllers/aero_info_calls.go | 21 ++- controllers/pod.go | 140 +++++++++--------- controllers/rack.go | 4 - go.mod | 3 +- go.sum | 92 +++++++++++- pkg/utils/pod.go | 11 +- pkg/utils/utils.go | 10 ++ test/storage_init_test.go | 8 +- test/warm_restart_test.go | 8 +- 10 files changed, 205 insertions(+), 94 deletions(-) diff --git a/api/v1/aerospikecluster_validating_webhook.go b/api/v1/aerospikecluster_validating_webhook.go index a3e6688f8..deb19a19b 100644 --- a/api/v1/aerospikecluster_validating_webhook.go +++ b/api/v1/aerospikecluster_validating_webhook.go @@ -1578,7 +1578,7 @@ func validateNsConfUpdate(newConfSpec, oldConfSpec, currentStatus *AerospikeConf if singleConf["name"] == oldSingleConf["name"] { // replication-factor update not allowed - val, err := asconfig.CompareVersions(incomingVersion, Version6) + val, err := lib.CompareVersions(incomingVersion, Version6) if err != nil { return fmt.Errorf("failed to check image version: %v", err) } diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index aa648118a..e515b7f4e 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -15,10 +15,12 @@ package controllers import ( "fmt" + "strings" "time" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/sets" + "sigs.k8s.io/controller-runtime/pkg/reconcile" as "github.com/aerospike/aerospike-client-go/v6" asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" @@ -312,8 +314,10 @@ func (r *SingleClusterReconciler) setDynamicConfig( } podList := make([]corev1.Pod, 0, len(pods)) + podIPNameMap := make(map[string]string, len(pods)) for idx := range pods { + podIPNameMap[pods[idx].Status.PodIP] = pods[idx].Name podList = append(podList, *pods[idx]) } @@ -332,15 +336,26 @@ func (r *SingleClusterReconciler) setDynamicConfig( return reconcileSuccess() } - asConfCmds, err := deployment.CreateConfigSetCmdList(diffs, selectedHostConns[0].ASConn, r.getClientPolicy()) + asConfCmds, err := deployment.CreateConfigSetCmdList(r.Log, diffs, selectedHostConns[0].ASConn, r.getClientPolicy()) if err != nil { + // Assuming error returned here will not be a server error. return reconcileError(err) } r.Log.Info("printing commands", "asConfCmds", fmt.Sprintf("%v", asConfCmds)) - if err := deployment.SetConfigCommandsOnHosts(r.Log, policy, allHostConns, selectedHostConns, asConfCmds); err != nil { - return reconcileError(err) + for _, host := range selectedHostConns { + if err := deployment.SetConfigCommandsOnHost(r.Log, policy, allHostConns, host, asConfCmds); err != nil { + if strings.HasPrefix(err.Error(), "ServerError:") { + return reconcileError(reconcile.TerminalError(err)) + } + + return reconcileError(err) + } + + if err := r.updatePod(podIPNameMap[host.ASConn.AerospikeHostName]); err != nil { + return reconcileError(err) + } } return reconcileSuccess() diff --git a/controllers/pod.go b/controllers/pod.go index e054e7dfa..96dce6ec1 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -215,9 +215,21 @@ func (r *SingleClusterReconciler) rollingRestartPods( return reconcileSuccess() } -func (r *SingleClusterReconciler) restartOrUpdateAerospikeServer(rackState *RackState, - pod *corev1.Pod, operation RestartType) error { - cmName := getNamespacedNameForSTSConfigMap(r.aeroCluster, rackState.Rack.ID) +func (r *SingleClusterReconciler) restartOrUpdateAerospikeServer(podName string, + operation RestartType) error { + rackID, err := utils.GetRackIDFromPodName(podName) + if err != nil { + return fmt.Errorf( + "failed to get rackID for the pod %s", podName, + ) + } + + podNamespacedName := types.NamespacedName{ + Name: podName, + Namespace: r.aeroCluster.Namespace, + } + + cmName := getNamespacedNameForSTSConfigMap(r.aeroCluster, *rackID) initBinary := "/etc/aerospike/akoinit" var subCommand string @@ -243,7 +255,7 @@ func (r *SingleClusterReconciler) restartOrUpdateAerospikeServer(rackState *Rack // Quick restart attempt should not take significant time. // Therefore, it's ok to block the operator on the quick restart attempt. stdout, stderr, err := utils.Exec( - pod, asdbv1.AerospikeServerContainerName, cmd, r.KubeClient, + podNamespacedName, asdbv1.AerospikeServerContainerName, cmd, r.KubeClient, r.KubeConfig, ) if err != nil { @@ -258,13 +270,13 @@ func (r *SingleClusterReconciler) restartOrUpdateAerospikeServer(rackState *Rack // Quick restart attempt should not take significant time. // Therefore, it's ok to block the operator on the quick restart attempt. stdout, stderr, err = utils.Exec( - pod, asdbv1.AerospikeServerContainerName, cmd, r.KubeClient, + podNamespacedName, asdbv1.AerospikeServerContainerName, cmd, r.KubeClient, r.KubeConfig, ) if err != nil { r.Log.V(1).Info( - "Failed warm restart", "err", err, "podName", pod.Name, "stdout", + "Failed warm restart", "err", err, "podName", podNamespacedName.Name, "stdout", stdout, "stderr", stderr, ) @@ -272,7 +284,7 @@ func (r *SingleClusterReconciler) restartOrUpdateAerospikeServer(rackState *Rack } } else { r.Log.V(1).Info( - "Failed to perform", "operation", subCommand, "err", err, "podName", pod.Name, "stdout", + "Failed to perform", "operation", subCommand, "err", err, "podName", podNamespacedName.Name, "stdout", stdout, "stderr", stderr, ) @@ -283,15 +295,15 @@ func (r *SingleClusterReconciler) restartOrUpdateAerospikeServer(rackState *Rack if subCommand == "quick-restart" { r.Recorder.Eventf( r.aeroCluster, corev1.EventTypeNormal, "PodWarmRestarted", - "[rack-%d] Restarted Pod %s", rackState.Rack.ID, pod.Name, + "[rack-%d] Restarted Pod %s", *rackID, podNamespacedName.Name, ) - r.Log.V(1).Info("Pod warm restarted", "podName", pod.Name) + r.Log.V(1).Info("Pod warm restarted", "podName", podNamespacedName.Name) } else { r.Recorder.Eventf( r.aeroCluster, corev1.EventTypeNormal, "PodConfUpdated", - "[rack-%d] Updated Pod %s", rackState.Rack.ID, pod.Name, + "[rack-%d] Updated Pod %s", *rackID, podNamespacedName.Name, ) - r.Log.V(1).Info("Pod conf updated", "podName", pod.Name) + r.Log.V(1).Info("Pod conf updated", "podName", podNamespacedName.Name) } return nil @@ -315,7 +327,7 @@ func (r *SingleClusterReconciler) restartPods( if restartType == quickRestart { // If ASD restart fails then go ahead and restart the pod - if err := r.restartOrUpdateAerospikeServer(rackState, pod, quickRestart); err == nil { + if err := r.restartOrUpdateAerospikeServer(pod.Name, quickRestart); err == nil { continue } } @@ -337,42 +349,16 @@ func (r *SingleClusterReconciler) restartPods( return reconcileSuccess() } -func (r *SingleClusterReconciler) updatePods( - rackState *RackState, podsToUpdate []*corev1.Pod, -) reconcileResult { - restartedPods := make([]*corev1.Pod, 0, len(podsToUpdate)) - - for idx := range podsToUpdate { - pod := podsToUpdate[idx] - - r.Log.Info("updating pod", "pod", pod.Name) - // If update Conf fails then go ahead and restart the asd - var err error - if err = r.restartOrUpdateAerospikeServer(rackState, pod, noRestartUpdateConf); err == nil { - continue - } - - r.Log.Info("Restarting pod as updating failed", "pod", pod.Name, "err", err) - // If ASD restart fails then go ahead and restart the pod - if err := r.restartOrUpdateAerospikeServer(rackState, pod, quickRestart); err == nil { - continue - } - - if err := r.Client.Delete(context.TODO(), pod); err != nil { - r.Log.Error(err, "Failed to delete pod") - return reconcileError(err) - } - - restartedPods = append(restartedPods, pod) +func (r *SingleClusterReconciler) updatePod(podName string) error { + r.Log.Info("updating pod", "pod", podName) - r.Log.V(1).Info("Pod deleted", "podName", pod.Name) + if err := r.restartOrUpdateAerospikeServer(podName, noRestartUpdateConf); err != nil { + return err } - if len(restartedPods) > 0 { - return r.ensurePodsRunningAndReady(restartedPods) - } + r.Log.V(1).Info("Pod Updated", "podName", podName) - return reconcileSuccess() + return nil } func (r *SingleClusterReconciler) ensurePodsRunningAndReady(podsToCheck []*corev1.Pod) reconcileResult { @@ -1096,7 +1082,7 @@ func (r *SingleClusterReconciler) handleNSOrDeviceRemoval(rackState *RackState, } for _, pod := range podsToRestart { - err := r.handleNSOrDeviceRemovalPerPod(removedDevices, removedFiles, pod) + err := r.handleNSOrDeviceRemovalPerPod(removedDevices, removedFiles, pod.Name) if err != nil { return err } @@ -1106,12 +1092,12 @@ func (r *SingleClusterReconciler) handleNSOrDeviceRemoval(rackState *RackState, } func (r *SingleClusterReconciler) handleNSOrDeviceRemovalPerPod( - removedDevices, removedFiles []string, pod *corev1.Pod, + removedDevices, removedFiles []string, podName string, ) error { - podStatus := r.aeroCluster.Status.Pods[pod.Name] + podStatus := r.aeroCluster.Status.Pods[podName] for _, file := range removedFiles { - err := r.deleteFileStorage(pod, file) + err := r.deleteFileStorage(podName, file) if err != nil { return err } @@ -1126,7 +1112,7 @@ func (r *SingleClusterReconciler) handleNSOrDeviceRemovalPerPod( patch1 := jsonpatch.PatchOperation{ Operation: "replace", - Path: "/status/pods/" + pod.Name + "/dirtyVolumes", + Path: "/status/pods/" + podName + "/dirtyVolumes", Value: sets.List(dirtyVolumes), } patches = append(patches, patch1) @@ -1271,7 +1257,7 @@ func getVolumeNameFromDevicePath(volumes []asdbv1.VolumeSpec, s string) string { return "" } -func (r *SingleClusterReconciler) deleteFileStorage(pod *corev1.Pod, fileName string) error { +func (r *SingleClusterReconciler) deleteFileStorage(podName, fileName string) error { cmd := []string{ "bash", "-c", fmt.Sprintf( "rm -rf %s", @@ -1279,14 +1265,17 @@ func (r *SingleClusterReconciler) deleteFileStorage(pod *corev1.Pod, fileName st ), } r.Log.Info( - "Deleting file", "file", fileName, "cmd", cmd, "podname", pod.Name, + "Deleting file", "file", fileName, "cmd", cmd, "podname", podName, ) - stdout, stderr, err := utils.Exec(pod, asdbv1.AerospikeServerContainerName, cmd, r.KubeClient, r.KubeConfig) + podNamespacedName := types.NamespacedName{Name: podName, Namespace: r.aeroCluster.Namespace} + + stdout, stderr, err := utils.Exec(podNamespacedName, asdbv1.AerospikeServerContainerName, + cmd, r.KubeClient, r.KubeConfig) if err != nil { r.Log.V(1).Info( - "File deletion failed", "err", err, "podName", pod.Name, "stdout", + "File deletion failed", "err", err, "podName", podName, "stdout", stdout, "stderr", stderr, ) @@ -1329,24 +1318,43 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState return nil, fmt.Errorf("failed to load config map by lib: %v", err) } - flatStatusConf := *asConfStatus.GetFlatMap() - flatSpecConf := *asConfSpec.GetFlatMap() + specToStatusDiffs, err := asconfig.ConfDiff(r.Log, *asConfSpec.GetFlatMap(), *asConfStatus.GetFlatMap(), + true, "7.0.0") + if err != nil { + r.Log.Info("failed to get config diff, fallback to rolling restart: %v", err) + return nil, nil + } - specToStatusDiffs := asconfig.ConfDiff(r.Log, flatSpecConf, flatStatusConf, true, "7.0.0") - r.Log.Info("print diff outside", "difference", fmt.Sprintf("%v", specToStatusDiffs)) + if len(specToStatusDiffs) > 0 { + r.Log.Info("print diff outside", "difference", fmt.Sprintf("%v", specToStatusDiffs)) - if len(specToStatusDiffs) > 1 { - r.Log.V(1).Info("Multiple config change in single go is not supported,"+ - "falling back to rolling restart if needed", "diff", fmt.Sprintf("%v", specToStatusDiffs)) + if checkXDRDCOrNamespaceAdded(specToStatusDiffs) { + r.Log.Info("XDR DC or Namespace added, not supported dynamically") + return nil, nil + } - return nil, nil - } + isDynamic, err := asconfig.IsAllDynamicConfig(r.Log, specToStatusDiffs, "7.0.0") + if err != nil { + r.Log.Info("failed to check if all config is dynamic, fallback to rolling restart: %v", err) + return nil, nil + } - isDynamic := asconfig.IsAllDynamicConfig(specToStatusDiffs, "7.0.0") - if !isDynamic { - r.Log.Info("Static field has been modified, cannot change config dynamically") - return nil, nil + if !isDynamic { + r.Log.Info("Static field has been modified, cannot change config dynamically") + return nil, nil + } } return specToStatusDiffs, nil } + +func checkXDRDCOrNamespaceAdded(diffs map[string]map[string]interface{}) bool { + for k := range diffs { + tokens := strings.Split(k, ".") + if tokens[0] == "xdr" && tokens[len(tokens)-1] == "name" { + return true + } + } + + return false +} diff --git a/controllers/rack.go b/controllers/rack.go index 82cb125df..6fb335efa 100644 --- a/controllers/rack.go +++ b/controllers/rack.go @@ -501,10 +501,6 @@ func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, return res } - if res := r.updatePods(rackState, podsToUpdate); !res.isSuccess { - return res - } - r.Recorder.Eventf( r.aeroCluster, corev1.EventTypeNormal, "RackDynamicUpdate", "[rack-%d] Finished Dynamic update", rackState.Rack.ID, diff --git a/go.mod b/go.mod index 8e526fc68..40aba8380 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v0.0.0-20240103175849-7fd218327d01 + github.com/aerospike/aerospike-management-lib v0.0.0-20240109070650-a9a5815dd8e7 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/evanphx/json-patch v4.12.0+incompatible github.com/go-logr/logr v1.2.4 @@ -68,7 +68,6 @@ require ( github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.9.0 // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect diff --git a/go.sum b/go.sum index bde47c79e..c744bf54d 100644 --- a/go.sum +++ b/go.sum @@ -598,9 +598,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/aerospike/aerospike-client-go/v6 v6.14.0 h1:Z3FcGWJda1sagzdc6Akz4EJ13Pq55Uyn6qtFLrVUDd0= github.com/aerospike/aerospike-client-go/v6 v6.14.0/go.mod h1:/0Wm81GhMqem+9flWcpazPKoRfjFeG6WrQdXGiMNi0A= -github.com/aerospike/aerospike-management-lib v0.0.0-20231227142907-e308f15df328/go.mod h1:qoBjUWFlcE7s7PBSyeEXeEJVypgr0/w5lXGKy7MvKVo= -github.com/aerospike/aerospike-management-lib v0.0.0-20240103175849-7fd218327d01 h1:yDY4/cAuIRP4Qh/Ikbpke7TqehoRec3uM+RVHHs8oAg= -github.com/aerospike/aerospike-management-lib v0.0.0-20240103175849-7fd218327d01/go.mod h1:PGPGJ+AHknx8j215Xo7ffYvqpCXhEUiYhPTz5ECC+P0= +github.com/aerospike/aerospike-management-lib v0.0.0-20240109070650-a9a5815dd8e7 h1:x/cAEeyhqpZD0qnYolWXPREfqmBx7iWkLINUVccM56s= +github.com/aerospike/aerospike-management-lib v0.0.0-20240109070650-a9a5815dd8e7/go.mod h1:PGPGJ+AHknx8j215Xo7ffYvqpCXhEUiYhPTz5ECC+P0= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -610,8 +609,12 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -619,6 +622,7 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -633,10 +637,13 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A= github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/go-control-plane v0.10.3/go.mod h1:fJJn/j26vwOu972OllsvAgJJM//w9BV6Fxbg2LuVd34= @@ -645,10 +652,13 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo= github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= @@ -665,12 +675,17 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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= github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -682,6 +697,7 @@ github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -708,12 +724,14 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +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/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -729,8 +747,10 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -751,9 +771,11 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= @@ -782,10 +804,13 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -803,26 +828,36 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/onsi/gomega v1.27.7/go.mod h1:1p8OOlwo2iUUDsHnOrjE5UKYJ+e3W8eQ3qSlRahPmr4= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= @@ -830,30 +865,37 @@ github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= +github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -869,10 +911,14 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ 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.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +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/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= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -881,6 +927,7 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64 h1:5mLPGnFdSsevFRFc9q3yYbBkB6tsm4aCwwQV/j1JQAQ= github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= @@ -895,9 +942,14 @@ go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -907,6 +959,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -964,6 +1017,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -991,6 +1046,7 @@ golang.org/x/oauth2 v0.0.0-20221006150949-b44042a4b9c1/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= +golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1007,6 +1063,7 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1078,9 +1135,11 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.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.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1098,6 +1157,7 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +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.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1105,6 +1165,7 @@ golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1168,6 +1229,7 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1177,6 +1239,7 @@ golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= gomodules.xyz/jsonpatch/v2 v2.3.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= @@ -1248,6 +1311,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1380,7 +1444,9 @@ google.golang.org/genproto v0.0.0-20230320184635-7606e756e683/go.mod h1:NWraEVix google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= +google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -1400,10 +1466,12 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -1412,9 +1480,11 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1424,15 +1494,23 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo= k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4= +k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo= k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ= k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg= k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= +k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE= k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ= +k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo= k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo= +k8s.io/klog/v2 v2.90.1 h1:m4bYOKall2MmOiRaR1J+We67Do7vm9KiQVlT96lnHUw= k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= +k8s.io/kubectl v0.27.2 h1:sSBM2j94MHBFRWfHIWtEXWCicViQzZsb177rNsKBhZg= k8s.io/kubectl v0.27.2/go.mod h1:GCOODtxPcrjh+EC611MqREkU8RjYBh10ldQCQ6zpFKw= +k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= @@ -1472,7 +1550,11 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/controller-runtime v0.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU= sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE= sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/utils/pod.go b/pkg/utils/pod.go index b7c687dd8..0ac64fe3e 100644 --- a/pkg/utils/pod.go +++ b/pkg/utils/pod.go @@ -9,6 +9,7 @@ import ( "strings" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/remotecommand" @@ -148,17 +149,15 @@ func GetRackIDFromPodName(podName string) (*int, error) { } // Exec executes a non interactive command on a pod. -func Exec( - pod *corev1.Pod, container string, cmd []string, - kubeClient *kubernetes.Clientset, kubeConfig *rest.Config, -) (stdoutStr, stderrStr string, err error) { +func Exec(podNamespacedName types.NamespacedName, container string, cmd []string, kubeClient *kubernetes.Clientset, + kubeConfig *rest.Config) (stdoutStr, stderrStr string, err error) { request := kubeClient. CoreV1(). RESTClient(). Post(). Resource("pods"). - Namespace(pod.Namespace). - Name(pod.Name). + Namespace(podNamespacedName.Namespace). + Name(podNamespacedName.Name). SubResource("exec"). VersionedParams( &corev1.PodExecOptions{ diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index eb6a9c607..48179096a 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -10,6 +10,7 @@ import ( //nolint:staticcheck // this ripemd160 legacy hash is only used for diff comparison not for security purpose "golang.org/x/crypto/ripemd160" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" ) @@ -37,6 +38,15 @@ func NamespacedName(namespace, name string) string { return fmt.Sprintf("%s/%s", namespace, name) } +func GetNamespacedNameForPod( + pod *corev1.Pod, +) types.NamespacedName { + return types.NamespacedName{ + Name: pod.Name, + Namespace: pod.Namespace, + } +} + // IsImageEqual returns true if image name image1 is equal to image name image2. func IsImageEqual(image1, image2 string) bool { desiredImageWithVersion := strings.TrimPrefix(image1, DockerHubImagePrefix) diff --git a/test/storage_init_test.go b/test/storage_init_test.go index bc00d7a24..692ca7825 100644 --- a/test/storage_init_test.go +++ b/test/storage_init_test.go @@ -708,7 +708,7 @@ func writeDataToVolumeBlock( magicBytes, path, ), } - _, _, err := utils.Exec(pod, cName, cmd, k8sClientset, cfg) + _, _, err := utils.Exec(utils.GetNamespacedNameForPod(pod), cName, cmd, k8sClientset, cfg) if err != nil { return fmt.Errorf("error creating file %v", err) @@ -725,7 +725,7 @@ func writeDataToVolumeFileSystem( cmd := []string{ "bash", "-c", fmt.Sprintf("echo %s > %s/magic.txt", magicBytes, path), } - _, _, err := utils.Exec(pod, cName, cmd, k8sClientset, cfg) + _, _, err := utils.Exec(utils.GetNamespacedNameForPod(pod), cName, cmd, k8sClientset, cfg) if err != nil { return fmt.Errorf("error creating file %v", err) @@ -740,7 +740,7 @@ func hasDataBlock(pod *corev1.Pod, volume *asdbv1.VolumeSpec) bool { cmd := []string{ "bash", "-c", fmt.Sprintf("dd if=%s count=1 status=none", path), } - stdout, _, _ := utils.Exec(pod, cName, cmd, k8sClientset, cfg) + stdout, _, _ := utils.Exec(utils.GetNamespacedNameForPod(pod), cName, cmd, k8sClientset, cfg) return strings.HasPrefix(stdout, magicBytes) } @@ -749,7 +749,7 @@ func hasDataFilesystem(pod *corev1.Pod, volume *asdbv1.VolumeSpec) bool { cName, path := getContainerNameAndPath(volume) cmd := []string{"bash", "-c", fmt.Sprintf("cat %s/magic.txt", path)} - stdout, _, _ := utils.Exec(pod, cName, cmd, k8sClientset, cfg) + stdout, _, _ := utils.Exec(utils.GetNamespacedNameForPod(pod), cName, cmd, k8sClientset, cfg) return strings.HasPrefix(stdout, magicBytes) } diff --git a/test/warm_restart_test.go b/test/warm_restart_test.go index 6f91a8268..f41ebe930 100644 --- a/test/warm_restart_test.go +++ b/test/warm_restart_test.go @@ -108,6 +108,7 @@ func createMarkerFile( } for podIndex := range podList.Items { + pod := &podList.Items[podIndex] cmd := []string{ "bash", "-c", @@ -115,13 +116,13 @@ func createMarkerFile( } _, _, err := utils.Exec( - &podList.Items[podIndex], asdbv1.AerospikeServerContainerName, cmd, k8sClientset, + utils.GetNamespacedNameForPod(pod), asdbv1.AerospikeServerContainerName, cmd, k8sClientset, cfg, ) if err != nil { return fmt.Errorf( - "error reading ASD Pid from pod %s - %v", podList.Items[podIndex].Name, err, + "error reading ASD Pid from pod %s - %v", pod.Name, err, ) } } @@ -141,6 +142,7 @@ func isMarkerPresent( podToMarkerPresent := make(map[string]bool) for podIndex := range podList.Items { + pod := &podList.Items[podIndex] cmd := []string{ "bash", "-c", @@ -148,7 +150,7 @@ func isMarkerPresent( } _, _, err := utils.Exec( - &podList.Items[podIndex], asdbv1.AerospikeServerContainerName, cmd, k8sClientset, + utils.GetNamespacedNameForPod(pod), asdbv1.AerospikeServerContainerName, cmd, k8sClientset, cfg, ) From 7ec3d6368d44e6b77848c2584fc34b5c1fd68022 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Tue, 30 Jan 2024 12:53:46 +0530 Subject: [PATCH 07/20] storing status in annotation of pod for error handling --- api/v1/aerospikecluster_types.go | 2 + api/v1/aerospikecluster_validating_webhook.go | 2 +- .../asdb.aerospike.com_aerospikeclusters.yaml | 2 + controllers/aero_info_calls.go | 44 ++-- controllers/configmap.go | 4 +- controllers/pod.go | 227 ++++++++++++------ controllers/rack.go | 15 +- controllers/reconciler.go | 21 +- go.mod | 14 +- go.sum | 18 +- 10 files changed, 221 insertions(+), 128 deletions(-) diff --git a/api/v1/aerospikecluster_types.go b/api/v1/aerospikecluster_types.go index f496a5ea7..a282d98b7 100644 --- a/api/v1/aerospikecluster_types.go +++ b/api/v1/aerospikecluster_types.go @@ -827,6 +827,8 @@ type AerospikePodStatus struct { //nolint:govet // for readability // PodSpecHash is ripemd160 hash of PodSpec used by this pod PodSpecHash string `json:"podSpecHash"` + + DynamicConfigFailed bool `json:"dynamicConfigFailed,omitempty"` } // +kubebuilder:object:root=true diff --git a/api/v1/aerospikecluster_validating_webhook.go b/api/v1/aerospikecluster_validating_webhook.go index deb19a19b..eeba1d2d6 100644 --- a/api/v1/aerospikecluster_validating_webhook.go +++ b/api/v1/aerospikecluster_validating_webhook.go @@ -1706,7 +1706,7 @@ func validateAerospikeConfigSchema( ) error { config := configSpec.Value - asConf, err := asconfig.NewMapAsConfig(aslog, version, config) + asConf, err := asconfig.NewMapAsConfig(aslog, config) if err != nil { return fmt.Errorf("failed to load config map by lib: %v", err) } diff --git a/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml b/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml index 266989bf2..ff4f532e4 100644 --- a/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml +++ b/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml @@ -13292,6 +13292,8 @@ spec: items: type: string type: array + dynamicConfigFailed: + type: boolean hostExternalIP: description: HostExternalIP of the K8s host this pod is scheduled on. diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index e515b7f4e..23b13d26a 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -14,17 +14,18 @@ limitations under the License. package controllers import ( + "context" "fmt" - "strings" "time" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/sets" - "sigs.k8s.io/controller-runtime/pkg/reconcile" as "github.com/aerospike/aerospike-client-go/v6" asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" + "github.com/aerospike/aerospike-kubernetes-operator/pkg/jsonpatch" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" + libcommons "github.com/aerospike/aerospike-management-lib/commons" "github.com/aerospike/aerospike-management-lib/deployment" ) @@ -300,8 +301,7 @@ func (r *SingleClusterReconciler) setMigrateFillDelay( } func (r *SingleClusterReconciler) setDynamicConfig( - policy *as.ClientPolicy, - diffs map[string]map[string]interface{}, pods []*corev1.Pod, ignorablePodNames sets.Set[string], + dynamicConfDiffPerPod map[string]libcommons.DynamicConfigMap, pods []*corev1.Pod, ignorablePodNames sets.Set[string], ) reconcileResult { // This doesn't make actual connection, only objects having connection info are created allHostConns, err := r.newAllHostConnWithOption(ignorablePodNames) @@ -336,24 +336,38 @@ func (r *SingleClusterReconciler) setDynamicConfig( return reconcileSuccess() } - asConfCmds, err := deployment.CreateConfigSetCmdList(r.Log, diffs, selectedHostConns[0].ASConn, r.getClientPolicy()) - if err != nil { - // Assuming error returned here will not be a server error. - return reconcileError(err) - } + for _, host := range selectedHostConns { + podName := podIPNameMap[host.ASConn.AerospikeHostName] + asConfCmds, err := deployment.CreateConfigSetCmdList(r.Log, dynamicConfDiffPerPod[podName], + host.ASConn, r.getClientPolicy()) - r.Log.Info("printing commands", "asConfCmds", fmt.Sprintf("%v", asConfCmds)) + if err != nil { + // Assuming error returned here will not be a server error. + return reconcileError(err) + } - for _, host := range selectedHostConns { - if err := deployment.SetConfigCommandsOnHost(r.Log, policy, allHostConns, host, asConfCmds); err != nil { - if strings.HasPrefix(err.Error(), "ServerError:") { - return reconcileError(reconcile.TerminalError(err)) + r.Log.Info("printing commands", "asConfCmds", fmt.Sprintf("%v", asConfCmds)) + + if err := deployment.SetConfigCommandsOnHost(r.Log, r.getClientPolicy(), allHostConns, host, asConfCmds); err != nil { + var patches []jsonpatch.PatchOperation + + patch := jsonpatch.PatchOperation{ + Operation: "replace", + Path: "/status/pods/" + podName + "/dynamicConfigFailed", + Value: true, + } + patches = append(patches, patch) + + if patchErr := r.patchPodStatus( + context.TODO(), patches, + ); patchErr != nil { + return reconcileError(fmt.Errorf("error updating status: %v", patchErr)) } return reconcileError(err) } - if err := r.updatePod(podIPNameMap[host.ASConn.AerospikeHostName]); err != nil { + if err := r.updatePod(podName); err != nil { return reconcileError(err) } } diff --git a/controllers/configmap.go b/controllers/configmap.go index a94bbd78e..5b3a6f560 100644 --- a/controllers/configmap.go +++ b/controllers/configmap.go @@ -185,15 +185,13 @@ func (r *SingleClusterReconciler) buildConfigTemplate(rack *asdbv1.Rack) ( "aerospikecluster", utils.ClusterNamespacedName(r.aeroCluster), ) - version := strings.Split(r.aeroCluster.Spec.Image, ":") - configMap := rack.AerospikeConfig.Value log.V(1).Info( "AerospikeConfig", "config", configMap, "image", r.aeroCluster.Spec.Image, ) - asConf, err := asconfig.NewMapAsConfig(r.Log, version[1], configMap) + asConf, err := asconfig.NewMapAsConfig(r.Log, configMap) if err != nil { return "", fmt.Errorf("failed to load config map by lib: %v", err) } diff --git a/controllers/pod.go b/controllers/pod.go index 96dce6ec1..09b62a0bd 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -15,12 +15,15 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/util/retry" "sigs.k8s.io/controller-runtime/pkg/client" asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" "github.com/aerospike/aerospike-kubernetes-operator/pkg/jsonpatch" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" + lib "github.com/aerospike/aerospike-management-lib" "github.com/aerospike/aerospike-management-lib/asconfig" + libcommons "github.com/aerospike/aerospike-management-lib/commons" ) // RestartType is the type of pod restart to use. @@ -60,13 +63,11 @@ func mergeRestartType(current, incoming RestartType) RestartType { // Fetching RestartType of all pods, based on the operation being performed. func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, ignorablePodNames sets.Set[string]) ( - restartTypeMap map[string]RestartType, dynamicDiffs map[string]map[string]interface{}, err error) { - var ( - addedNSDevices []string - onlyDynamicConfigChange bool - ) + restartTypeMap map[string]RestartType, dynamicConfDiffPerPod map[string]libcommons.DynamicConfigMap, err error) { + var addedNSDevices []string restartTypeMap = make(map[string]RestartType) + dynamicConfDiffPerPod = make(map[string]libcommons.DynamicConfigMap) pods, err := r.getOrderedRackPodList(rackState.Rack.ID) if err != nil { @@ -95,25 +96,25 @@ func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, } } - if dynamicDiffs == nil { - // Fetching all dynamic diffs. - dynamicDiffs, err = r.handleDynamicConfigChange(rackState) + // If dynamic commands have failed in previous retry, then we should not try to update config dynamically. + if !podStatus.DynamicConfigFailed { + // Fetching all dynamic config change. + dynamicConfDiffPerPod[pods[idx].Name], err = r.handleDynamicConfigChange(rackState, pods[idx]) if err != nil { return nil, nil, err } } } - if len(dynamicDiffs) > 0 { - onlyDynamicConfigChange = true - } - - restartType := r.getRollingRestartTypePod(rackState, pods[idx], confMap, addedNSDevices, onlyDynamicConfigChange) + restartTypeMap[pods[idx].Name] = r.getRollingRestartTypePod(rackState, pods[idx], confMap, addedNSDevices, + len(dynamicConfDiffPerPod[pods[idx].Name]) > 0) - restartTypeMap[pods[idx].Name] = restartType + if podStatus.DynamicConfigFailed { + restartTypeMap[pods[idx].Name] = mergeRestartType(restartTypeMap[pods[idx].Name], quickRestart) + } } - return restartTypeMap, dynamicDiffs, nil + return restartTypeMap, dynamicConfDiffPerPod, nil } func (r *SingleClusterReconciler) getRollingRestartTypePod( @@ -141,13 +142,14 @@ func (r *SingleClusterReconciler) getRollingRestartTypePod( if len(addedNSDevices) > 0 { podRestartType = r.handleNSOrDeviceAddition(addedNSDevices, pod.Name) } else if onlyDynamicConfigChange { + // If only dynamic config change is there, then we can update config dynamically. podRestartType = noRestartUpdateConf } restartType = mergeRestartType(restartType, podRestartType) r.Log.Info( - "AerospikeConfig changed. Need rolling restart", + "AerospikeConfig changed. Need rolling restart or update config dynamically", "requiredHash", requiredConfHash, "currentHash", podStatus.AerospikeConfigHash, ) @@ -328,6 +330,19 @@ func (r *SingleClusterReconciler) restartPods( if restartType == quickRestart { // If ASD restart fails then go ahead and restart the pod if err := r.restartOrUpdateAerospikeServer(pod.Name, quickRestart); err == nil { + var patches []jsonpatch.PatchOperation + + patch := jsonpatch.PatchOperation{ + Operation: "replace", + Path: "/status/pods/" + pod.Name + "/dynamicConfigFailed", + Value: false, + } + patches = append(patches, patch) + + if err := r.patchPodStatus(context.TODO(), patches); err != nil { + return reconcileError(err) + } + continue } } @@ -671,22 +686,7 @@ func (r *SingleClusterReconciler) removePodStatus(podNames []string) error { patches = append(patches, patch) } - jsonPatchJSON, err := json.Marshal(patches) - if err != nil { - return fmt.Errorf("error creating json-patch : %v", err) - } - - constantPatch := client.RawPatch(types.JSONPatchType, jsonPatchJSON) - - // Since the pod status is updated from pod init container, - // set the field owner to "pod" for pod status updates. - if err = r.Client.Status().Patch( - context.TODO(), r.aeroCluster, constantPatch, client.FieldOwner("pod"), - ); err != nil { - return fmt.Errorf("error updating status: %v", err) - } - - return nil + return r.patchPodStatus(context.TODO(), patches) } func (r *SingleClusterReconciler) cleanupDanglingPodsRack(sts *appsv1.StatefulSet, rackState *RackState) error { @@ -1117,20 +1117,9 @@ func (r *SingleClusterReconciler) handleNSOrDeviceRemovalPerPod( } patches = append(patches, patch1) - jsonPatchJSON, err := json.Marshal(patches) - if err != nil { + if err := r.patchPodStatus(context.TODO(), patches); err != nil { return err } - - constantPatch := client.RawPatch(types.JSONPatchType, jsonPatchJSON) - - // Since the pod status is updated from pod init container, - // set the field owner to "pod" for pod status updates. - if err = r.Client.Status().Patch( - context.TODO(), r.aeroCluster, constantPatch, client.FieldOwner("pod"), - ); err != nil { - return fmt.Errorf("error updating status: %v", err) - } } return nil @@ -1296,29 +1285,26 @@ func (r *SingleClusterReconciler) getConfigMap(rackID int) (*corev1.ConfigMap, e return confMap, nil } -func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState) ( - map[string]map[string]interface{}, error) { - var rackStatus asdbv1.Rack +func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState, pod *corev1.Pod) ( + libcommons.DynamicConfigMap, error) { + statusFromAnnotation := pod.Annotations["aerospikeConf"] - for idx := range r.aeroCluster.Status.RackConfig.Racks { - if r.aeroCluster.Status.RackConfig.Racks[idx].ID == rackState.Rack.ID { - rackStatus = r.aeroCluster.Status.RackConfig.Racks[idx] - } + asConfStatus, err := getFlatConfig(r.Log, statusFromAnnotation) + if err != nil { + return nil, fmt.Errorf("failed to load config map by lib: %v", err) } - version := strings.Split(r.aeroCluster.Spec.Image, ":") - - asConfStatus, err := asconfig.NewMapAsConfig(r.Log, version[1], rackStatus.AerospikeConfig.Value) + asConf, err := asconfig.NewMapAsConfig(r.Log, rackState.Rack.AerospikeConfig.Value) if err != nil { return nil, fmt.Errorf("failed to load config map by lib: %v", err) } - asConfSpec, err := asconfig.NewMapAsConfig(r.Log, version[1], rackState.Rack.AerospikeConfig.Value) + asConfSpec, err := getFlatConfig(r.Log, asConf.ToConfFile()) if err != nil { return nil, fmt.Errorf("failed to load config map by lib: %v", err) } - specToStatusDiffs, err := asconfig.ConfDiff(r.Log, *asConfSpec.GetFlatMap(), *asConfStatus.GetFlatMap(), + specToStatusDiffs, err := asconfig.ConfDiff(r.Log, *asConfSpec, *asConfStatus, true, "7.0.0") if err != nil { r.Log.Info("failed to get config diff, fallback to rolling restart: %v", err) @@ -1328,11 +1314,6 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState if len(specToStatusDiffs) > 0 { r.Log.Info("print diff outside", "difference", fmt.Sprintf("%v", specToStatusDiffs)) - if checkXDRDCOrNamespaceAdded(specToStatusDiffs) { - r.Log.Info("XDR DC or Namespace added, not supported dynamically") - return nil, nil - } - isDynamic, err := asconfig.IsAllDynamicConfig(r.Log, specToStatusDiffs, "7.0.0") if err != nil { r.Log.Info("failed to check if all config is dynamic, fallback to rolling restart: %v", err) @@ -1348,13 +1329,125 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState return specToStatusDiffs, nil } -func checkXDRDCOrNamespaceAdded(diffs map[string]map[string]interface{}) bool { - for k := range diffs { - tokens := strings.Split(k, ".") - if tokens[0] == "xdr" && tokens[len(tokens)-1] == "name" { - return true +func toPlural(k string, v any, m configMap) { + // convert asconfig fields/contexts that need to be plural + // in order to create valid asconfig yaml. + if plural := asconfig.PluralOf(k); plural != k { + // if the config item can be plural or singular and is not a slice + // then the item should not be converted to the plural form. + // If the management lib ever parses list entries as anything other + // than []string this might have to change. + if isListOrString(k) { + if _, ok := v.([]string); !ok { + return + } + + if len(v.([]string)) == 1 { + // the management lib parses all config fields + // that are in singularToPlural as lists. If these + // fields are actually scalars then overwrite the list + // with the single value + m[k] = v.([]string)[0] + return + } } + + delete(m, k) + m[plural] = v } +} - return false +// isListOrString returns true for special config fields that may be a +// single string value or a list with multiple strings in the schema files +// NOTE: any time the schema changes to make a value +// a string or a list (array) that value needs to be added here +func isListOrString(name string) bool { + switch name { + case "feature-key-file", "tls-authenticate-client": + return true + default: + return false + } +} + +type configMap = lib.Stats + +// mapping functions get mapped to each key value pair in a management lib Stats map +// m is the map that k and v came from +type mapping func(k string, v any, m configMap) + +// mutateMap maps functions to each key value pair in the management lib's Stats map +// the functions are applied sequentially to each k,v pair. +func mutateMap(in configMap, funcs []mapping) { + for k, v := range in { + switch v := v.(type) { + case configMap: + mutateMap(v, funcs) + case []configMap: + for _, lv := range v { + mutateMap(lv, funcs) + } + } + + for _, f := range funcs { + f(k, in[k], in) + } + } +} + +func getFlatConfig(log logger, confStr string) (*asconfig.Conf, error) { + asConf, err := asconfig.FromConfFile(log, "", strings.NewReader(confStr)) + if err != nil { + return nil, fmt.Errorf("failed to load config map by lib: %v", err) + } + + cmap := *asConf.ToMap() + + mutateMap(cmap, []mapping{ + toPlural, + }) + + asConf, err = asconfig.NewMapAsConfig( + log, + cmap, + ) + + if err != nil { + return nil, err + } + + return asConf.GetFlatMap(), nil +} + +func (r *SingleClusterReconciler) patchPodStatus(ctx context.Context, patches []jsonpatch.PatchOperation) error { + if len(patches) == 0 { + return nil + } + + jsonPatchJSON, err := json.Marshal(patches) + if err != nil { + return err + } + + constantPatch := client.RawPatch(types.JSONPatchType, jsonPatchJSON) + + // Since the pod status is updated from pod init container, + // set the field owner to "pod" for pod status updates. + + err = retry.OnError(retry.DefaultBackoff, func(err error) bool { + // Customize the error check for retrying, return true to retry, false to stop retrying + return true + }, func() error { + // Patch the resource + if err = r.Client.Status().Patch( + ctx, r.aeroCluster, constantPatch, client.FieldOwner("pod"), + ); err != nil { + return fmt.Errorf("error updating status: %v", err) + } + + r.Log.Info("Pod status patched successfully") + return nil + }) + + return nil } diff --git a/controllers/rack.go b/controllers/rack.go index 6fb335efa..6f6af2f84 100644 --- a/controllers/rack.go +++ b/controllers/rack.go @@ -18,6 +18,7 @@ import ( asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" lib "github.com/aerospike/aerospike-management-lib" + "github.com/aerospike/aerospike-management-lib/commons" ) type scaledDownRack struct { @@ -393,7 +394,7 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat } } else { var needRollingRestartRack, needDynamicUpdateRack, restartTypeMap, - dynamicDiffs, nErr = r.needRollingRestartRack(rackState, ignorablePodNames) + dynamicConfDiffPerPod, nErr = r.needRollingRestartRack(rackState, ignorablePodNames) if nErr != nil { return found, reconcileError(nErr) } @@ -420,7 +421,7 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat } if needDynamicUpdateRack { - res = r.updateDynamicConfig(rackState, ignorablePodNames, restartTypeMap, failedPods, dynamicDiffs) + res = r.updateDynamicConfig(rackState, ignorablePodNames, restartTypeMap, failedPods, dynamicConfDiffPerPod) if !res.isSuccess { if res.err != nil { r.Log.Error( @@ -452,7 +453,7 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, ignorablePodNames sets.Set[string], restartTypeMap map[string]RestartType, - failedPods []*corev1.Pod, dynamicDiffs map[string]map[string]interface{}) reconcileResult { + failedPods []*corev1.Pod, dynamicConfDiffPerPod map[string]commons.DynamicConfigMap) reconcileResult { r.Log.Info("Update dynamic config in Aerospike pods") r.Recorder.Eventf( @@ -497,7 +498,7 @@ func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, return reconcileError(err) } - if res := r.setDynamicConfig(r.getClientPolicy(), dynamicDiffs, podsToUpdate, ignorablePodNames); !res.isSuccess { + if res := r.setDynamicConfig(dynamicConfDiffPerPod, podsToUpdate, ignorablePodNames); !res.isSuccess { return res } @@ -1144,9 +1145,9 @@ func (r *SingleClusterReconciler) rollingRestartRack(found *appsv1.StatefulSet, func (r *SingleClusterReconciler) needRollingRestartRack(rackState *RackState, ignorablePodNames sets.Set[string]) ( needRestart, needUpdateConf bool, restartTypeMap map[string]RestartType, - dynamicDiffs map[string]map[string]interface{}, err error, + dynamicConfDiffPerPod map[string]commons.DynamicConfigMap, err error, ) { - restartTypeMap, dynamicDiffs, err = r.getRollingRestartTypeMap(rackState, ignorablePodNames) + restartTypeMap, dynamicConfDiffPerPod, err = r.getRollingRestartTypeMap(rackState, ignorablePodNames) if err != nil { return needRestart, needUpdateConf, nil, nil, err } @@ -1162,7 +1163,7 @@ func (r *SingleClusterReconciler) needRollingRestartRack(rackState *RackState, i } } - return needRestart, needUpdateConf, restartTypeMap, dynamicDiffs, nil + return needRestart, needUpdateConf, restartTypeMap, dynamicConfDiffPerPod, nil } func (r *SingleClusterReconciler) isRackUpgradeNeeded(rackID int, ignorablePodNames sets.Set[string]) ( diff --git a/controllers/reconciler.go b/controllers/reconciler.go index d6fcb915a..97ad34e55 100644 --- a/controllers/reconciler.go +++ b/controllers/reconciler.go @@ -864,28 +864,9 @@ func (r *SingleClusterReconciler) migrateInitialisedVolumeNames(ctx context.Cont } } - if len(patches) == 0 { - return nil - } - - jsonPatchJSON, err := json.Marshal(patches) - if err != nil { - return err - } - - constantPatch := client.RawPatch(types.JSONPatchType, jsonPatchJSON) - - // Since the pod status is updated from pod init container, - // set the field owner to "pod" for pod status updates. r.Log.Info("Patching status with updated initialised volumes") - if err = r.Client.Status().Patch( - ctx, r.aeroCluster, constantPatch, client.FieldOwner("pod"), - ); err != nil { - return fmt.Errorf("error updating status: %v", err) - } - - return nil + return r.patchPodStatus(ctx, patches) } func (r *SingleClusterReconciler) getPVCUid(ctx context.Context, pod *corev1.Pod, volName string) (string, error) { diff --git a/go.mod b/go.mod index 40aba8380..4bd155426 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v0.0.0-20240109070650-a9a5815dd8e7 + github.com/aerospike/aerospike-management-lib v1.2.1-0.20240129073609-fa537ce5d006 github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/evanphx/json-patch v4.12.0+incompatible github.com/go-logr/logr v1.2.4 @@ -25,6 +25,7 @@ require ( github.com/sirupsen/logrus v1.9.0 golang.org/x/crypto v0.17.0 gomodules.xyz/jsonpatch/v2 v2.3.0 + gopkg.in/yaml.v2 v2.4.0 ) // Pinned this dependcy to fix vulnerbaility in `golang.org/x/net` pkg @@ -76,18 +77,17 @@ require ( go.uber.org/atomic v1.7.0 // indirect go.uber.org/multierr v1.6.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.15.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.9.1 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/grpc v1.54.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/grpc v1.58.3 // indirect + google.golang.org/protobuf v1.32.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apiextensions-apiserver v0.27.2 // indirect k8s.io/component-base v0.27.2 // indirect diff --git a/go.sum b/go.sum index c744bf54d..950908a88 100644 --- a/go.sum +++ b/go.sum @@ -598,8 +598,10 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/aerospike/aerospike-client-go/v6 v6.14.0 h1:Z3FcGWJda1sagzdc6Akz4EJ13Pq55Uyn6qtFLrVUDd0= github.com/aerospike/aerospike-client-go/v6 v6.14.0/go.mod h1:/0Wm81GhMqem+9flWcpazPKoRfjFeG6WrQdXGiMNi0A= -github.com/aerospike/aerospike-management-lib v0.0.0-20240109070650-a9a5815dd8e7 h1:x/cAEeyhqpZD0qnYolWXPREfqmBx7iWkLINUVccM56s= -github.com/aerospike/aerospike-management-lib v0.0.0-20240109070650-a9a5815dd8e7/go.mod h1:PGPGJ+AHknx8j215Xo7ffYvqpCXhEUiYhPTz5ECC+P0= +github.com/aerospike/aerospike-management-lib v1.1.1-0.20240122164802-8ad7cb9b7599 h1:OwAZz/mIFsy08+hwIumLsFCQeXJUT/iKeQMtcDQIkJM= +github.com/aerospike/aerospike-management-lib v1.1.1-0.20240122164802-8ad7cb9b7599/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240129073609-fa537ce5d006 h1:IR/JdXyh/CebyOHYFOicJ7R3TDTcOyT9hLPE5Cj1i24= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240129073609-fa537ce5d006/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -1063,8 +1065,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1135,8 +1137,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.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.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= @@ -1466,8 +1468,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From a18475d1eaf79eea787b37c79bbd648d904298e1 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Fri, 2 Feb 2024 15:09:25 +0530 Subject: [PATCH 08/20] Giving pod update permission in cluster role and adding testcases. --- .../manifests/rbac/aerospikecluster_role.yaml | 11 +- controllers/pod.go | 6 +- .../aerospikecluster-clusterrole.yaml | 9 +- test/cluster_test.go | 2 +- test/dynamic_config_test.go | 217 ++++++++++++++++++ test/large_reconcile_test.go | 15 +- 6 files changed, 244 insertions(+), 16 deletions(-) create mode 100644 test/dynamic_config_test.go diff --git a/config/manifests/rbac/aerospikecluster_role.yaml b/config/manifests/rbac/aerospikecluster_role.yaml index 12283773a..b3c8f36bc 100644 --- a/config/manifests/rbac/aerospikecluster_role.yaml +++ b/config/manifests/rbac/aerospikecluster_role.yaml @@ -6,7 +6,6 @@ rules: - apiGroups: - "" resources: - - pods - nodes - services - configmaps @@ -19,4 +18,12 @@ rules: resources: - '*' verbs: - - '*' \ No newline at end of file + - '*' +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - update \ No newline at end of file diff --git a/controllers/pod.go b/controllers/pod.go index 09b62a0bd..4d7050cd9 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -1434,12 +1434,12 @@ func (r *SingleClusterReconciler) patchPodStatus(ctx context.Context, patches [] // Since the pod status is updated from pod init container, // set the field owner to "pod" for pod status updates. - err = retry.OnError(retry.DefaultBackoff, func(err error) bool { + return retry.OnError(retry.DefaultBackoff, func(err error) bool { // Customize the error check for retrying, return true to retry, false to stop retrying return true }, func() error { // Patch the resource - if err = r.Client.Status().Patch( + if err := r.Client.Status().Patch( ctx, r.aeroCluster, constantPatch, client.FieldOwner("pod"), ); err != nil { return fmt.Errorf("error updating status: %v", err) @@ -1448,6 +1448,4 @@ func (r *SingleClusterReconciler) patchPodStatus(ctx context.Context, patches [] r.Log.Info("Pod status patched successfully") return nil }) - - return nil } diff --git a/helm-charts/aerospike-kubernetes-operator/templates/aerospikecluster-clusterrole.yaml b/helm-charts/aerospike-kubernetes-operator/templates/aerospikecluster-clusterrole.yaml index 262c13c03..1c5d7596d 100644 --- a/helm-charts/aerospike-kubernetes-operator/templates/aerospikecluster-clusterrole.yaml +++ b/helm-charts/aerospike-kubernetes-operator/templates/aerospikecluster-clusterrole.yaml @@ -10,7 +10,6 @@ rules: - apiGroups: - "" resources: - - pods - nodes - services - configmaps @@ -24,3 +23,11 @@ rules: - '*' verbs: - '*' +- apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - update diff --git a/test/cluster_test.go b/test/cluster_test.go index 697256638..abdaaf26e 100644 --- a/test/cluster_test.go +++ b/test/cluster_test.go @@ -177,7 +177,7 @@ func clusterWithMaxIgnorablePod(ctx goctx.Context) { Expect(err).ToNot(HaveOccurred()) val := intstr.FromInt(1) aeroCluster.Spec.RackConfig.MaxIgnorablePods = &val - aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = int64(18000) + aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = false err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) diff --git a/test/dynamic_config_test.go b/test/dynamic_config_test.go new file mode 100644 index 000000000..7ce50f735 --- /dev/null +++ b/test/dynamic_config_test.go @@ -0,0 +1,217 @@ +package test + +import ( + goctx "context" + "fmt" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "golang.org/x/net/context" + + asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" + "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" +) + +type podID struct { + podUID string + asdPID string +} + +var _ = Describe( + "DynamicConfig", func() { + + ctx := goctx.Background() + + Context( + "When doing valid operations", func() { + + clusterName := "dynamic-config-test" + clusterNamespacedName := getNamespacedName( + clusterName, namespace, + ) + 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", + }, + }, + }, + }, + } + 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 update config dynamically", func() { + + By("Modify dynamic config by adding fields") + aeroCluster, err := getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + podPIDMap, err := getPodIDs(ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = 18000 + log := map[string]interface{}{ + "report-data-op": []string{"test"}, + } + + 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("Verify no warm/cold restarts in Pods") + noRestart, err := verifyNoRestart(ctx, aeroCluster, podPIDMap) + Expect(err).ToNot(HaveOccurred()) + Expect(noRestart).To(Equal(false)) + + By("Modify dynamic config by removing fields") + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + podPIDMap, err = getPodIDs(ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + 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("Verify no warm/cold restarts in Pods") + noRestart, err = verifyNoRestart(ctx, aeroCluster, podPIDMap) + Expect(err).ToNot(HaveOccurred()) + Expect(noRestart).To(Equal(false)) + }, + ) + + It( + "Should update config statically", func() { + + By("Modify static config") + + aeroCluster, err := getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + podPIDMap, err := getPodIDs(ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = false + + err = updateCluster(k8sClient, ctx, aeroCluster) + Expect(err).ToNot(HaveOccurred()) + + By("Verify warm restarts in Pods") + noRestart, err := verifyNoRestart(ctx, aeroCluster, podPIDMap) + Expect(err).ToNot(HaveOccurred()) + Expect(noRestart).To(Equal(true)) + }, + ) + }, + ) + + }, +) + +func verifyNoRestart(ctx goctx.Context, cluster *asdbv1.AerospikeCluster, pidMap map[string]podID) (bool, error) { + newPodPidMap, err := getPodIDs(ctx, cluster) + if err != nil { + return false, err + } + + for podName, pid := range pidMap { + if newPodPidMap[podName].podUID != pid.podUID || newPodPidMap[podName].asdPID != pid.asdPID { + return true, nil + } + } + + return false, nil +} + +func getPodIDs(ctx context.Context, aeroCluster *asdbv1.AerospikeCluster) (map[string]podID, error) { + podList, err := getClusterPodList(k8sClient, ctx, aeroCluster) + if err != nil { + return nil, err + } + + pidMap := make(map[string]podID) + + for podIndex := range podList.Items { + pod := &podList.Items[podIndex] + cmd := []string{ + "bash", + "-c", + "ps -A -o pid,cmd|grep \"asd\" | grep -v grep | grep -v tini |head -n 1 | awk '{print $1}'", + } + + stdout, _, execErr := utils.Exec( + utils.GetNamespacedNameForPod(pod), asdbv1.AerospikeServerContainerName, cmd, k8sClientset, + cfg, + ) + + if execErr != nil { + return nil, fmt.Errorf( + "error reading ASD Pid from pod %s - %v", pod.Name, execErr, + ) + } + + pidMap[pod.Name] = podID{ + podUID: string(pod.UID), + asdPID: stdout, + } + } + + return pidMap, nil +} diff --git a/test/large_reconcile_test.go b/test/large_reconcile_test.go index 2944e7f44..e60e0fdf5 100644 --- a/test/large_reconcile_test.go +++ b/test/large_reconcile_test.go @@ -102,9 +102,8 @@ var _ = Describe( ) Expect(err).ToNot(HaveOccurred()) - // oldService := aeroCluster.Spec.AerospikeConfig.Value["service"] - tempConf := 18000 - aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = tempConf + tempConf := true + aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = tempConf err = k8sClient.Update(goctx.TODO(), aeroCluster) Expect(err).ToNot(HaveOccurred()) @@ -114,7 +113,7 @@ var _ = Describe( ) Expect(err).ToNot(HaveOccurred()) - aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = defaultProtofdmax + aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = false err = k8sClient.Update(goctx.TODO(), aeroCluster) Expect(err).ToNot(HaveOccurred()) @@ -325,7 +324,7 @@ func waitForClusterScaleDown( func waitForClusterRollingRestart( k8sClient client.Client, aeroCluster *asdbv1.AerospikeCluster, - replicas int, tempConf int, retryInterval, timeout time.Duration, + replicas int, tempConf bool, retryInterval, timeout time.Duration, ) error { err := wait.PollUntilContextTimeout(goctx.TODO(), retryInterval, timeout, true, func(ctx goctx.Context) (done bool, err error) { @@ -343,10 +342,10 @@ func waitForClusterRollingRestart( return false, err } - protofdmax := newCluster.Status.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"].(float64) - if int(protofdmax) == tempConf { + enableQuotas := newCluster.Status.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"].(bool) + if enableQuotas == tempConf { err := fmt.Errorf( - "cluster status can not be updated with intermediate conf value %d,"+ + "cluster status can not be updated with intermediate conf value %v,"+ " it should have only final value, as this is the new reconcile flow", tempConf, ) From 05ffaefdb6aaeb39d88d5897a4213ea97223ef56 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Mon, 12 Feb 2024 23:52:29 +0530 Subject: [PATCH 09/20] adressing comments --- api/v1/aerospikecluster_mutating_webhook.go | 2 +- api/v1/aerospikecluster_types.go | 1 + api/v1/aerospikecluster_validating_webhook.go | 7 ++-- .../asdb.aerospike.com_aerospikeclusters.yaml | 2 + controllers/aero_info_calls.go | 6 ++- controllers/configmap.go | 12 +----- controllers/pod.go | 39 +++++++------------ controllers/rack.go | 25 +++++------- controllers/reconciler.go | 2 +- controllers/statefulset.go | 19 +++------ go.mod | 2 +- go.sum | 6 +++ ..._aerospikeclusters.asdb.aerospike.com.yaml | 4 ++ pkg/utils/utils.go | 16 ++++++-- test/dynamic_config_test.go | 27 ++++++++++++- test/rack_utils.go | 16 ++------ test/storage_init_test.go | 8 ++-- test/warm_restart_test.go | 4 +- 18 files changed, 102 insertions(+), 96 deletions(-) diff --git a/api/v1/aerospikecluster_mutating_webhook.go b/api/v1/aerospikecluster_mutating_webhook.go index 552d6409d..eccfbeea1 100644 --- a/api/v1/aerospikecluster_mutating_webhook.go +++ b/api/v1/aerospikecluster_mutating_webhook.go @@ -1,5 +1,5 @@ /* -Copyright 2023. +Copyright 2024. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/api/v1/aerospikecluster_types.go b/api/v1/aerospikecluster_types.go index a282d98b7..6060be3ba 100644 --- a/api/v1/aerospikecluster_types.go +++ b/api/v1/aerospikecluster_types.go @@ -828,6 +828,7 @@ type AerospikePodStatus struct { //nolint:govet // for readability // PodSpecHash is ripemd160 hash of PodSpec used by this pod PodSpecHash string `json:"podSpecHash"` + // DynamicConfigFailed is true if aerospike config change failed to apply dynamically. DynamicConfigFailed bool `json:"dynamicConfigFailed,omitempty"` } diff --git a/api/v1/aerospikecluster_validating_webhook.go b/api/v1/aerospikecluster_validating_webhook.go index b67293821..d22a7f782 100644 --- a/api/v1/aerospikecluster_validating_webhook.go +++ b/api/v1/aerospikecluster_validating_webhook.go @@ -1,5 +1,5 @@ /* -Copyright 2023. +Copyright 2024. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -40,7 +40,6 @@ import ( internalerrors "github.com/aerospike/aerospike-kubernetes-operator/errors" "github.com/aerospike/aerospike-management-lib/asconfig" - "github.com/aerospike/aerospike-management-lib/deployment" ) var networkConnectionTypes = []string{"service", "heartbeat", "fabric"} @@ -92,7 +91,7 @@ func (c *AerospikeCluster) ValidateUpdate(oldObj runtime.Object) (admission.Warn return nil, err } - if err := deployment.IsValidUpgrade( + if err := asconfig.IsValidUpgrade( outgoingVersion, incomingVersion, ); err != nil { return nil, fmt.Errorf("failed to start upgrade: %v", err) @@ -1557,12 +1556,12 @@ func validateNsConfUpdate(newConfSpec, oldConfSpec, currentStatus *AerospikeConf } if singleConf["name"] == oldSingleConf["name"] { - // replication-factor update not allowed 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( oldSingleConf, singleConf, "replication-factor", ) { diff --git a/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml b/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml index 720f8141f..599bdfa75 100644 --- a/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml +++ b/config/crd/bases/asdb.aerospike.com_aerospikeclusters.yaml @@ -14177,6 +14177,8 @@ spec: type: string type: array dynamicConfigFailed: + description: DynamicConfigFailed is true if aerospike config + change failed to apply dynamically. type: boolean hostExternalIP: description: HostExternalIP of the K8s host this pod is scheduled diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index 23b13d26a..56ae1f185 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -25,6 +25,7 @@ import ( asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" "github.com/aerospike/aerospike-kubernetes-operator/pkg/jsonpatch" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" + "github.com/aerospike/aerospike-management-lib/asconfig" libcommons "github.com/aerospike/aerospike-management-lib/commons" "github.com/aerospike/aerospike-management-lib/deployment" ) @@ -338,7 +339,7 @@ func (r *SingleClusterReconciler) setDynamicConfig( for _, host := range selectedHostConns { podName := podIPNameMap[host.ASConn.AerospikeHostName] - asConfCmds, err := deployment.CreateConfigSetCmdList(r.Log, dynamicConfDiffPerPod[podName], + asConfCmds, err := asconfig.CreateSetConfigCmdList(r.Log, dynamicConfDiffPerPod[podName], host.ASConn, r.getClientPolicy()) if err != nil { @@ -348,7 +349,8 @@ func (r *SingleClusterReconciler) setDynamicConfig( r.Log.Info("printing commands", "asConfCmds", fmt.Sprintf("%v", asConfCmds)) - if err := deployment.SetConfigCommandsOnHost(r.Log, r.getClientPolicy(), allHostConns, host, asConfCmds); err != nil { + if err := deployment.SetConfigCommandsOnHosts(r.Log, r.getClientPolicy(), allHostConns, + []*deployment.HostConn{host}, asConfCmds); err != nil { var patches []jsonpatch.PatchOperation patch := jsonpatch.PatchOperation{ diff --git a/controllers/configmap.go b/controllers/configmap.go index 5b3a6f560..863e366ba 100644 --- a/controllers/configmap.go +++ b/controllers/configmap.go @@ -8,7 +8,6 @@ import ( "fmt" "io/fs" "path/filepath" - "strconv" "strings" "text/template" @@ -89,15 +88,6 @@ func init() { } } -func getNamespacedNameForSTSConfigMap( - aeroCluster *asdbv1.AerospikeCluster, rackID int, -) types.NamespacedName { - return types.NamespacedName{ - Name: aeroCluster.Name + "-" + strconv.Itoa(rackID), - Namespace: aeroCluster.Namespace, - } -} - // createConfigMapData create configMap data func (r *SingleClusterReconciler) createConfigMapData(rack *asdbv1.Rack) ( map[string]string, error, @@ -310,7 +300,7 @@ func (r *SingleClusterReconciler) getFQDNsForCluster() ([]string, error) { for idx := range rackStateList { rackState := &rackStateList[idx] size := rackState.Size - stsName := getNamespacedNameForSTS(r.aeroCluster, rackState.Rack.ID) + stsName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, rackState.Rack.ID) for i := 0; i < size; i++ { fqdn := getFQDNForPod(r.aeroCluster, getSTSPodName(stsName.Name, int32(i))) diff --git a/controllers/pod.go b/controllers/pod.go index 4d7050cd9..172e33116 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -217,7 +217,7 @@ func (r *SingleClusterReconciler) rollingRestartPods( return reconcileSuccess() } -func (r *SingleClusterReconciler) restartOrUpdateAerospikeServer(podName string, +func (r *SingleClusterReconciler) restartASDOrUpdateAerospikeConf(podName string, operation RestartType) error { rackID, err := utils.GetRackIDFromPodName(podName) if err != nil { @@ -231,7 +231,7 @@ func (r *SingleClusterReconciler) restartOrUpdateAerospikeServer(podName string, Namespace: r.aeroCluster.Namespace, } - cmName := getNamespacedNameForSTSConfigMap(r.aeroCluster, *rackID) + cmName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, *rackID) initBinary := "/etc/aerospike/akoinit" var subCommand string @@ -329,20 +329,7 @@ func (r *SingleClusterReconciler) restartPods( if restartType == quickRestart { // If ASD restart fails then go ahead and restart the pod - if err := r.restartOrUpdateAerospikeServer(pod.Name, quickRestart); err == nil { - var patches []jsonpatch.PatchOperation - - patch := jsonpatch.PatchOperation{ - Operation: "replace", - Path: "/status/pods/" + pod.Name + "/dynamicConfigFailed", - Value: false, - } - patches = append(patches, patch) - - if err := r.patchPodStatus(context.TODO(), patches); err != nil { - return reconcileError(err) - } - + if err := r.restartASDOrUpdateAerospikeConf(pod.Name, quickRestart); err == nil { continue } } @@ -367,7 +354,7 @@ func (r *SingleClusterReconciler) restartPods( func (r *SingleClusterReconciler) updatePod(podName string) error { r.Log.Info("updating pod", "pod", podName) - if err := r.restartOrUpdateAerospikeServer(podName, noRestartUpdateConf); err != nil { + if err := r.restartASDOrUpdateAerospikeConf(podName, noRestartUpdateConf); err != nil { return err } @@ -1275,7 +1262,7 @@ func (r *SingleClusterReconciler) deleteFileStorage(podName, fileName string) er } func (r *SingleClusterReconciler) getConfigMap(rackID int) (*corev1.ConfigMap, error) { - cmName := getNamespacedNameForSTSConfigMap(r.aeroCluster, rackID) + cmName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, rackID) confMap := &corev1.ConfigMap{} if err := r.Client.Get(context.TODO(), cmName, confMap); err != nil { @@ -1304,8 +1291,13 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState return nil, fmt.Errorf("failed to load config map by lib: %v", err) } + version, err := asdbv1.GetImageVersion(r.aeroCluster.Spec.Image) + if err != nil { + return nil, err + } + specToStatusDiffs, err := asconfig.ConfDiff(r.Log, *asConfSpec, *asConfStatus, - true, "7.0.0") + true, version) if err != nil { r.Log.Info("failed to get config diff, fallback to rolling restart: %v", err) return nil, nil @@ -1314,7 +1306,7 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState if len(specToStatusDiffs) > 0 { r.Log.Info("print diff outside", "difference", fmt.Sprintf("%v", specToStatusDiffs)) - isDynamic, err := asconfig.IsAllDynamicConfig(r.Log, specToStatusDiffs, "7.0.0") + isDynamic, err := asconfig.IsAllDynamicConfig(r.Log, specToStatusDiffs, version) if err != nil { r.Log.Info("failed to check if all config is dynamic, fallback to rolling restart: %v", err) return nil, nil @@ -1396,7 +1388,7 @@ func mutateMap(in configMap, funcs []mapping) { } func getFlatConfig(log logger, confStr string) (*asconfig.Conf, error) { - asConf, err := asconfig.FromConfFile(log, "", strings.NewReader(confStr)) + asConf, err := asconfig.FromConfFile(log, strings.NewReader(confStr)) if err != nil { return nil, fmt.Errorf("failed to load config map by lib: %v", err) } @@ -1431,14 +1423,13 @@ func (r *SingleClusterReconciler) patchPodStatus(ctx context.Context, patches [] constantPatch := client.RawPatch(types.JSONPatchType, jsonPatchJSON) - // Since the pod status is updated from pod init container, - // set the field owner to "pod" for pod status updates. - return retry.OnError(retry.DefaultBackoff, func(err error) bool { // Customize the error check for retrying, return true to retry, false to stop retrying return true }, func() error { // Patch the resource + // Since the pod status is updated from pod init container, + // set the field owner to "pod" for pod status updates. if err := r.Client.Status().Patch( ctx, r.aeroCluster, constantPatch, client.FieldOwner("pod"), ); err != nil { diff --git a/controllers/rack.go b/controllers/rack.go index 6f6af2f84..72c4349a5 100644 --- a/controllers/rack.go +++ b/controllers/rack.go @@ -62,7 +62,7 @@ func (r *SingleClusterReconciler) reconcileRacks() reconcileResult { state := &rackStateList[idx] found := &appsv1.StatefulSet{} - stsName := getNamespacedNameForSTS(r.aeroCluster, state.Rack.ID) + stsName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, state.Rack.ID) if err = r.Client.Get(context.TODO(), stsName, found); err != nil { if !errors.IsNotFound(err) { @@ -124,7 +124,7 @@ func (r *SingleClusterReconciler) reconcileRacks() reconcileResult { for idx := range rackStateList { state := &rackStateList[idx] found := &appsv1.StatefulSet{} - stsName := getNamespacedNameForSTS(r.aeroCluster, state.Rack.ID) + stsName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, state.Rack.ID) if err = r.Client.Get(context.TODO(), stsName, found); err != nil { if !errors.IsNotFound(err) { @@ -184,7 +184,7 @@ func (r *SingleClusterReconciler) reconcileRacks() reconcileResult { for idx := range rackStateList { state := &rackStateList[idx] found := &appsv1.StatefulSet{} - stsName := getNamespacedNameForSTS(r.aeroCluster, state.Rack.ID) + stsName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, state.Rack.ID) if err := r.Client.Get(context.TODO(), stsName, found); err != nil { if !errors.IsNotFound(err) { @@ -230,13 +230,13 @@ func (r *SingleClusterReconciler) createEmptyRack(rackState *RackState) ( r.Log.Info("AerospikeCluster", "Spec", r.aeroCluster.Spec) // Bad config should not come here. It should be validated in validation hook - cmName := getNamespacedNameForSTSConfigMap(r.aeroCluster, rackState.Rack.ID) + cmName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, rackState.Rack.ID) if err := r.buildSTSConfigMap(cmName, rackState.Rack); err != nil { r.Log.Error(err, "Failed to create configMap from AerospikeConfig") return nil, reconcileError(err) } - stsName := getNamespacedNameForSTS(r.aeroCluster, rackState.Rack.ID) + stsName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, rackState.Rack.ID) found, err := r.createSTS(stsName, rackState) if err != nil { @@ -293,7 +293,7 @@ func (r *SingleClusterReconciler) deleteRacks( for idx := range racksToDelete { rack := &racksToDelete[idx] found := &appsv1.StatefulSet{} - stsName := getNamespacedNameForSTS(r.aeroCluster, rack.ID) + stsName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, rack.ID) err := r.Client.Get(context.TODO(), stsName, found) if err != nil { @@ -325,7 +325,7 @@ func (r *SingleClusterReconciler) deleteRacks( } // Delete configMap - cmName := getNamespacedNameForSTSConfigMap(r.aeroCluster, rack.ID) + cmName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, rack.ID) if err = r.deleteRackConfigMap(cmName); err != nil { return reconcileError(err) } @@ -355,7 +355,7 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat // So a check based on spec and status will skip configMap update. // Hence, a rolling restart of pod will never bring pod to desired config if err := r.updateSTSConfigMap( - getNamespacedNameForSTSConfigMap( + utils.GetNamespacedNameForSTSOrConfigMap( r.aeroCluster, rackState.Rack.ID, ), rackState.Rack, ); err != nil { @@ -431,8 +431,8 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat r.Recorder.Eventf( r.aeroCluster, corev1.EventTypeWarning, - "RackRollingRestartFailed", - "[rack-%d] Failed to do rolling restart {STS: %s/%s}", + "RackDynamicConfigUpdateFailed", + "[rack-%d] Failed to update aerospike config dynamically {STS: %s/%s}", rackState.Rack.ID, found.Namespace, found.Name, ) } @@ -493,11 +493,6 @@ func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, podsToUpdate = append(podsToUpdate, pod) } - podNames := getPodNames(podsToUpdate) - if err = r.createOrUpdatePodServiceIfNeeded(podNames); err != nil { - return reconcileError(err) - } - if res := r.setDynamicConfig(dynamicConfDiffPerPod, podsToUpdate, ignorablePodNames); !res.isSuccess { return res } diff --git a/controllers/reconciler.go b/controllers/reconciler.go index 97ad34e55..c6ef1438c 100644 --- a/controllers/reconciler.go +++ b/controllers/reconciler.go @@ -69,7 +69,7 @@ func (r *SingleClusterReconciler) Reconcile() (ctrl.Result, error) { return reconcile.Result{}, nil } - // The cluster is not being deleted, add finalizer in not added already + // The cluster is not being deleted, add finalizer if not added already if err := r.addFinalizer(finalizerName); err != nil { r.Log.Error(err, "Failed to add finalizer") return reconcile.Result{}, err diff --git a/controllers/statefulset.go b/controllers/statefulset.go index c7e0880af..ecfb466d4 100644 --- a/controllers/statefulset.go +++ b/controllers/statefulset.go @@ -133,7 +133,7 @@ func (r *SingleClusterReconciler) createSTS( { Name: asdbv1.AerospikeInitContainerName, Image: asdbv1.GetAerospikeInitContainerImage(r.aeroCluster), - ImagePullPolicy: corev1.PullAlways, + ImagePullPolicy: corev1.PullIfNotPresent, VolumeMounts: getDefaultAerospikeInitContainerVolumeMounts(), Env: append( envVarList, []corev1.EnvVar{ @@ -145,7 +145,7 @@ func (r *SingleClusterReconciler) createSTS( // TODO: Do we need this var? { Name: "CONFIG_MAP_NAME", - Value: getNamespacedNameForSTSConfigMap( + Value: utils.GetNamespacedNameForSTSOrConfigMap( r.aeroCluster, rackState.Rack.ID, ).Name, }, @@ -333,7 +333,7 @@ func (r *SingleClusterReconciler) getSTS(rackState *RackState) (*appsv1.Stateful found := &appsv1.StatefulSet{} if err := r.Client.Get( context.TODO(), - getNamespacedNameForSTS(r.aeroCluster, rackState.Rack.ID), + utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, rackState.Rack.ID), found, ); err != nil { return nil, err @@ -1025,7 +1025,7 @@ func (r *SingleClusterReconciler) waitForAllSTSToBeReady(ignorablePodNames sets. for rackID := range allRackIDs { st := &appsv1.StatefulSet{} - stsName := getNamespacedNameForSTS(r.aeroCluster, rackID) + stsName := utils.GetNamespacedNameForSTSOrConfigMap(r.aeroCluster, rackID) if err := r.Client.Get(context.TODO(), stsName, st); err != nil { if !errors.IsNotFound(err) { @@ -1206,7 +1206,7 @@ func getDefaultSTSVolumes( VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{ - Name: getNamespacedNameForSTSConfigMap( + Name: utils.GetNamespacedNameForSTSOrConfigMap( aeroCluster, rackState.Rack.ID, ).Name, }, @@ -1491,15 +1491,6 @@ func getSTSContainerPort( return ports } -func getNamespacedNameForSTS( - aeroCluster *asdbv1.AerospikeCluster, rackID int, -) types.NamespacedName { - return types.NamespacedName{ - Name: aeroCluster.Name + "-" + strconv.Itoa(rackID), - Namespace: aeroCluster.Namespace, - } -} - func getSTSPodOrdinal(podName string) (*int32, error) { parts := strings.Split(podName, "-") ordinalStr := parts[len(parts)-1] diff --git a/go.mod b/go.mod index 085f50665..731ba75bf 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v1.2.1-0.20240129073609-fa537ce5d006 + github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212090410-ceae9d0d0462 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 diff --git a/go.sum b/go.sum index a406fd6f7..0aafbdc39 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/aerospike/aerospike-client-go/v6 v6.14.0 h1:Z3FcGWJda1sagzdc6Akz4EJ13 github.com/aerospike/aerospike-client-go/v6 v6.14.0/go.mod h1:/0Wm81GhMqem+9flWcpazPKoRfjFeG6WrQdXGiMNi0A= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240129073609-fa537ce5d006 h1:IR/JdXyh/CebyOHYFOicJ7R3TDTcOyT9hLPE5Cj1i24= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240129073609-fa537ce5d006/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212090410-ceae9d0d0462 h1:ANVS9H64iUL70GEYS7VB1LGKRPwMUumk9xsooHfvw2I= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212090410-ceae9d0d0462/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= @@ -28,6 +30,7 @@ github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJ github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= 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-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 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= @@ -72,8 +75,10 @@ github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -96,6 +101,7 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/onsi/ginkgo/v2 v2.13.0 h1:0jY9lJquiL8fcf3M4LAXN5aMlS/b2BV86HFFPCPMgE4= 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 723aa4f7a..599bdfa75 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 @@ -14176,6 +14176,10 @@ spec: items: type: string type: array + dynamicConfigFailed: + description: DynamicConfigFailed is true if aerospike config + change failed to apply dynamically. + type: boolean hostExternalIP: description: HostExternalIP of the K8s host this pod is scheduled on. diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 48179096a..f87e44d5d 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -10,6 +10,7 @@ import ( //nolint:staticcheck // this ripemd160 legacy hash is only used for diff comparison not for security purpose "golang.org/x/crypto/ripemd160" corev1 "k8s.io/api/core/v1" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" @@ -38,12 +39,19 @@ func NamespacedName(namespace, name string) string { return fmt.Sprintf("%s/%s", namespace, name) } -func GetNamespacedNameForPod( - pod *corev1.Pod, +func GetNamespacedName(obj meta.Object) types.NamespacedName { + return types.NamespacedName{ + Namespace: obj.GetNamespace(), + Name: obj.GetName(), + } +} + +func GetNamespacedNameForSTSOrConfigMap( + aeroCluster *asdbv1.AerospikeCluster, rackID int, ) types.NamespacedName { return types.NamespacedName{ - Name: pod.Name, - Namespace: pod.Namespace, + Name: aeroCluster.Name + "-" + strconv.Itoa(rackID), + Namespace: aeroCluster.Namespace, } } diff --git a/test/dynamic_config_test.go b/test/dynamic_config_test.go index 7ce50f735..65f85e4a5 100644 --- a/test/dynamic_config_test.go +++ b/test/dynamic_config_test.go @@ -106,6 +106,15 @@ var _ = Describe( err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + Expect(aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"]).To(Equal(float64(18000))) + Expect(aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["log"].(map[string]interface{})["report-data-op"].([]interface{})[0]).To(Equal("test")) + Expect(aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"]).To(HaveLen(2)) + By("Verify no warm/cold restarts in Pods") noRestart, err := verifyNoRestart(ctx, aeroCluster, podPIDMap) Expect(err).ToNot(HaveOccurred()) @@ -128,6 +137,15 @@ var _ = Describe( err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + Expect(aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"]).To(BeNil()) + Expect(aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["log"]).To(BeNil()) + Expect(aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"]).To(HaveLen(1)) + By("Verify no warm/cold restarts in Pods") noRestart, err = verifyNoRestart(ctx, aeroCluster, podPIDMap) Expect(err).ToNot(HaveOccurred()) @@ -153,6 +171,13 @@ var _ = Describe( err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) + aeroCluster, err = getCluster( + k8sClient, ctx, clusterNamespacedName, + ) + Expect(err).ToNot(HaveOccurred()) + + Expect(aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"]).To(Equal(false)) + By("Verify warm restarts in Pods") noRestart, err := verifyNoRestart(ctx, aeroCluster, podPIDMap) Expect(err).ToNot(HaveOccurred()) @@ -197,7 +222,7 @@ func getPodIDs(ctx context.Context, aeroCluster *asdbv1.AerospikeCluster) (map[s } stdout, _, execErr := utils.Exec( - utils.GetNamespacedNameForPod(pod), asdbv1.AerospikeServerContainerName, cmd, k8sClientset, + utils.GetNamespacedName(pod), asdbv1.AerospikeServerContainerName, cmd, k8sClientset, cfg, ) diff --git a/test/rack_utils.go b/test/rack_utils.go index d54bda2ab..f00dfbd76 100644 --- a/test/rack_utils.go +++ b/test/rack_utils.go @@ -16,6 +16,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" + "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" lib "github.com/aerospike/aerospike-management-lib" "github.com/aerospike/aerospike-management-lib/info" ) @@ -195,7 +196,7 @@ func getPodSpecAnnotations( for rackStateIndex := range rackStateList { found := &appsv1.StatefulSet{} - stsName := getNamespacedNameForStatefulSet(aeroCluster, rackStateList[rackStateIndex].Rack.ID) + stsName := utils.GetNamespacedNameForSTSOrConfigMap(aeroCluster, rackStateList[rackStateIndex].Rack.ID) err := k8sClient.Get(ctx, stsName, found) if errors.IsNotFound(err) { @@ -222,7 +223,7 @@ func getPodSpecLabels( rackStateList := getConfiguredRackStateList(aeroCluster) for rackStateIndex := range rackStateList { found := &appsv1.StatefulSet{} - stsName := getNamespacedNameForStatefulSet(aeroCluster, rackStateList[rackStateIndex].Rack.ID) + stsName := utils.GetNamespacedNameForSTSOrConfigMap(aeroCluster, rackStateList[rackStateIndex].Rack.ID) err := k8sClient.Get(ctx, stsName, found) if errors.IsNotFound(err) { @@ -248,7 +249,7 @@ func validateRackEnabledCluster( rackStateList := getConfiguredRackStateList(aeroCluster) for rackStateIndex := range rackStateList { found := &appsv1.StatefulSet{} - stsName := getNamespacedNameForStatefulSet( + stsName := utils.GetNamespacedNameForSTSOrConfigMap( aeroCluster, rackStateList[rackStateIndex].Rack.ID, ) @@ -456,15 +457,6 @@ func splitRacks(nodeCount, rackCount int) []int { return topology } -func getNamespacedNameForStatefulSet( - aeroCluster *asdbv1.AerospikeCluster, rackID int, -) types.NamespacedName { - return types.NamespacedName{ - Name: aeroCluster.Name + "-" + strconv.Itoa(rackID), - Namespace: aeroCluster.Namespace, - } -} - func getNamespacedName(name, namespace string) types.NamespacedName { return types.NamespacedName{ Name: name, diff --git a/test/storage_init_test.go b/test/storage_init_test.go index 692ca7825..95728b334 100644 --- a/test/storage_init_test.go +++ b/test/storage_init_test.go @@ -708,7 +708,7 @@ func writeDataToVolumeBlock( magicBytes, path, ), } - _, _, err := utils.Exec(utils.GetNamespacedNameForPod(pod), cName, cmd, k8sClientset, cfg) + _, _, err := utils.Exec(utils.GetNamespacedName(pod), cName, cmd, k8sClientset, cfg) if err != nil { return fmt.Errorf("error creating file %v", err) @@ -725,7 +725,7 @@ func writeDataToVolumeFileSystem( cmd := []string{ "bash", "-c", fmt.Sprintf("echo %s > %s/magic.txt", magicBytes, path), } - _, _, err := utils.Exec(utils.GetNamespacedNameForPod(pod), cName, cmd, k8sClientset, cfg) + _, _, err := utils.Exec(utils.GetNamespacedName(pod), cName, cmd, k8sClientset, cfg) if err != nil { return fmt.Errorf("error creating file %v", err) @@ -740,7 +740,7 @@ func hasDataBlock(pod *corev1.Pod, volume *asdbv1.VolumeSpec) bool { cmd := []string{ "bash", "-c", fmt.Sprintf("dd if=%s count=1 status=none", path), } - stdout, _, _ := utils.Exec(utils.GetNamespacedNameForPod(pod), cName, cmd, k8sClientset, cfg) + stdout, _, _ := utils.Exec(utils.GetNamespacedName(pod), cName, cmd, k8sClientset, cfg) return strings.HasPrefix(stdout, magicBytes) } @@ -749,7 +749,7 @@ func hasDataFilesystem(pod *corev1.Pod, volume *asdbv1.VolumeSpec) bool { cName, path := getContainerNameAndPath(volume) cmd := []string{"bash", "-c", fmt.Sprintf("cat %s/magic.txt", path)} - stdout, _, _ := utils.Exec(utils.GetNamespacedNameForPod(pod), cName, cmd, k8sClientset, cfg) + stdout, _, _ := utils.Exec(utils.GetNamespacedName(pod), cName, cmd, k8sClientset, cfg) return strings.HasPrefix(stdout, magicBytes) } diff --git a/test/warm_restart_test.go b/test/warm_restart_test.go index f41ebe930..f1fe64aa3 100644 --- a/test/warm_restart_test.go +++ b/test/warm_restart_test.go @@ -116,7 +116,7 @@ func createMarkerFile( } _, _, err := utils.Exec( - utils.GetNamespacedNameForPod(pod), asdbv1.AerospikeServerContainerName, cmd, k8sClientset, + utils.GetNamespacedName(pod), asdbv1.AerospikeServerContainerName, cmd, k8sClientset, cfg, ) @@ -150,7 +150,7 @@ func isMarkerPresent( } _, _, err := utils.Exec( - utils.GetNamespacedNameForPod(pod), asdbv1.AerospikeServerContainerName, cmd, k8sClientset, + utils.GetNamespacedName(pod), asdbv1.AerospikeServerContainerName, cmd, k8sClientset, cfg, ) From 5ebb6f2856c3778afd4ba582f486a711787d7be1 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Tue, 13 Feb 2024 00:44:47 +0530 Subject: [PATCH 10/20] fixing lint --- controllers/pod.go | 54 ++++--------------------------------- go.mod | 2 +- go.sum | 2 ++ test/dynamic_config_test.go | 9 ++++--- 4 files changed, 14 insertions(+), 53 deletions(-) diff --git a/controllers/pod.go b/controllers/pod.go index 172e33116..ec09eb9b9 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -21,7 +21,6 @@ import ( asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" "github.com/aerospike/aerospike-kubernetes-operator/pkg/jsonpatch" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" - lib "github.com/aerospike/aerospike-management-lib" "github.com/aerospike/aerospike-management-lib/asconfig" libcommons "github.com/aerospike/aerospike-management-lib/commons" ) @@ -1321,61 +1320,18 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState return specToStatusDiffs, nil } -func toPlural(k string, v any, m configMap) { - // convert asconfig fields/contexts that need to be plural - // in order to create valid asconfig yaml. - if plural := asconfig.PluralOf(k); plural != k { - // if the config item can be plural or singular and is not a slice - // then the item should not be converted to the plural form. - // If the management lib ever parses list entries as anything other - // than []string this might have to change. - if isListOrString(k) { - if _, ok := v.([]string); !ok { - return - } - - if len(v.([]string)) == 1 { - // the management lib parses all config fields - // that are in singularToPlural as lists. If these - // fields are actually scalars then overwrite the list - // with the single value - m[k] = v.([]string)[0] - return - } - } - - delete(m, k) - m[plural] = v - } -} - -// isListOrString returns true for special config fields that may be a -// single string value or a list with multiple strings in the schema files -// NOTE: any time the schema changes to make a value -// a string or a list (array) that value needs to be added here -func isListOrString(name string) bool { - switch name { - case "feature-key-file", "tls-authenticate-client": - return true - default: - return false - } -} - -type configMap = lib.Stats - // mapping functions get mapped to each key value pair in a management lib Stats map // m is the map that k and v came from -type mapping func(k string, v any, m configMap) +type mapping func(k string, v any, m asconfig.Conf) // mutateMap maps functions to each key value pair in the management lib's Stats map // the functions are applied sequentially to each k,v pair. -func mutateMap(in configMap, funcs []mapping) { +func mutateMap(in asconfig.Conf, funcs []mapping) { for k, v := range in { switch v := v.(type) { - case configMap: + case asconfig.Conf: mutateMap(v, funcs) - case []configMap: + case []asconfig.Conf: for _, lv := range v { mutateMap(lv, funcs) } @@ -1396,7 +1352,7 @@ func getFlatConfig(log logger, confStr string) (*asconfig.Conf, error) { cmap := *asConf.ToMap() mutateMap(cmap, []mapping{ - toPlural, + asconfig.ToPlural, }) asConf, err = asconfig.NewMapAsConfig( diff --git a/go.mod b/go.mod index 731ba75bf..b5c96c706 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212090410-ceae9d0d0462 + github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212190343-4526f5f309b2 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 diff --git a/go.sum b/go.sum index 0aafbdc39..d230ccc70 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/aerospike/aerospike-management-lib v1.2.1-0.20240129073609-fa537ce5d0 github.com/aerospike/aerospike-management-lib v1.2.1-0.20240129073609-fa537ce5d006/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212090410-ceae9d0d0462 h1:ANVS9H64iUL70GEYS7VB1LGKRPwMUumk9xsooHfvw2I= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212090410-ceae9d0d0462/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212190343-4526f5f309b2 h1:75mpNdTAZW0hUgY4wg176Y1+87qTFyUmsscl+c7gOOI= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212190343-4526f5f309b2/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= diff --git a/test/dynamic_config_test.go b/test/dynamic_config_test.go index 65f85e4a5..3f87ddabc 100644 --- a/test/dynamic_config_test.go +++ b/test/dynamic_config_test.go @@ -111,8 +111,10 @@ var _ = Describe( ) Expect(err).ToNot(HaveOccurred()) - Expect(aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"]).To(Equal(float64(18000))) - Expect(aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["log"].(map[string]interface{})["report-data-op"].([]interface{})[0]).To(Equal("test")) + logs := aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["log"] + Expect(aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"]). + To(Equal(float64(18000))) + Expect(logs.(map[string]interface{})["report-data-op"].([]interface{})[0]).To(Equal("test")) Expect(aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"]).To(HaveLen(2)) By("Verify no warm/cold restarts in Pods") @@ -176,7 +178,8 @@ var _ = Describe( ) Expect(err).ToNot(HaveOccurred()) - Expect(aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"]).To(Equal(false)) + Expect(aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"]). + To(Equal(false)) By("Verify warm restarts in Pods") noRestart, err := verifyNoRestart(ctx, aeroCluster, podPIDMap) From b73f541ab5aa6daf3dbeeef2189e6e5711032c9d Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Wed, 14 Feb 2024 17:28:31 +0530 Subject: [PATCH 11/20] addressing comments --- api/v1/aerospikecluster_mutating_webhook.go | 3 +- api/v1/aerospikecluster_types.go | 102 ++++++++++---------- api/v1/aerospikeconfig.go | 7 +- api/v1beta1/aerospikeconfig.go | 7 +- controllers/aero_info_calls.go | 3 +- controllers/configmap.go | 6 +- controllers/pod.go | 44 ++++++--- controllers/rack.go | 8 +- controllers/reconciler.go | 11 ++- controllers/statefulset.go | 14 +-- go.mod | 2 +- go.sum | 2 + test/cluster_helper.go | 7 +- test/services_test.go | 4 +- 14 files changed, 113 insertions(+), 107 deletions(-) diff --git a/api/v1/aerospikecluster_mutating_webhook.go b/api/v1/aerospikecluster_mutating_webhook.go index eccfbeea1..3daa89263 100644 --- a/api/v1/aerospikecluster_mutating_webhook.go +++ b/api/v1/aerospikecluster_mutating_webhook.go @@ -30,7 +30,6 @@ 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 @@ -264,7 +263,7 @@ func (c *AerospikeCluster) updateRacksAerospikeConfigFromGlobal(asLog logr.Logge ) } else { // Use the global config. - m = lib.DeepCopy(c.Spec.AerospikeConfig.Value).(map[string]interface{}) + m = c.Spec.AerospikeConfig.DeepCopy().Value } asLog.V(1).Info( diff --git a/api/v1/aerospikecluster_types.go b/api/v1/aerospikecluster_types.go index 6060be3ba..c5f60cabb 100644 --- a/api/v1/aerospikecluster_types.go +++ b/api/v1/aerospikecluster_types.go @@ -1,5 +1,5 @@ /* -Copyright 2023. +Copyright 2024. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -867,6 +867,8 @@ func init() { } // CopySpecToStatus copy spec in status. Spec to Status DeepCopy doesn't work. It fails in reflect lib. +// +//nolint:dupl // not duplicate func CopySpecToStatus(spec *AerospikeClusterSpec) (*AerospikeClusterStatusSpec, error) { status := AerospikeClusterStatusSpec{} @@ -874,79 +876,81 @@ func CopySpecToStatus(spec *AerospikeClusterSpec) (*AerospikeClusterStatusSpec, status.Image = spec.Image // Storage - statusStorage := lib.DeepCopy(spec.Storage).(AerospikeStorageSpec) + statusStorage := lib.DeepCopy(&spec.Storage).(*AerospikeStorageSpec) - status.Storage = statusStorage + status.Storage = *statusStorage if spec.AerospikeAccessControl != nil { // AerospikeAccessControl statusAerospikeAccessControl := lib.DeepCopy( - *spec.AerospikeAccessControl, - ).(AerospikeAccessControlSpec) + spec.AerospikeAccessControl, + ).(*AerospikeAccessControlSpec) - status.AerospikeAccessControl = &statusAerospikeAccessControl + status.AerospikeAccessControl = statusAerospikeAccessControl } if spec.AerospikeConfig != nil { // AerospikeConfig statusAerospikeConfig := lib.DeepCopy( - *spec.AerospikeConfig, - ).(AerospikeConfigSpec) + spec.AerospikeConfig, + ).(*AerospikeConfigSpec) - status.AerospikeConfig = &statusAerospikeConfig + status.AerospikeConfig = statusAerospikeConfig } if spec.ValidationPolicy != nil { // ValidationPolicy statusValidationPolicy := lib.DeepCopy( - *spec.ValidationPolicy, - ).(ValidationPolicySpec) + spec.ValidationPolicy, + ).(*ValidationPolicySpec) - status.ValidationPolicy = &statusValidationPolicy + status.ValidationPolicy = statusValidationPolicy } // RackConfig - statusRackConfig := lib.DeepCopy(spec.RackConfig).(RackConfig) - status.RackConfig = statusRackConfig + statusRackConfig := lib.DeepCopy(&spec.RackConfig).(*RackConfig) + status.RackConfig = *statusRackConfig // AerospikeNetworkPolicy statusAerospikeNetworkPolicy := lib.DeepCopy( - spec.AerospikeNetworkPolicy, - ).(AerospikeNetworkPolicy) + &spec.AerospikeNetworkPolicy, + ).(*AerospikeNetworkPolicy) - status.AerospikeNetworkPolicy = statusAerospikeNetworkPolicy + status.AerospikeNetworkPolicy = *statusAerospikeNetworkPolicy if spec.OperatorClientCertSpec != nil { clientCertSpec := lib.DeepCopy( - *spec.OperatorClientCertSpec, - ).(AerospikeOperatorClientCertSpec) + spec.OperatorClientCertSpec, + ).(*AerospikeOperatorClientCertSpec) - status.OperatorClientCertSpec = &clientCertSpec + status.OperatorClientCertSpec = clientCertSpec } // Storage - statusPodSpec := lib.DeepCopy(spec.PodSpec).(AerospikePodSpec) - status.PodSpec = statusPodSpec + statusPodSpec := lib.DeepCopy(&spec.PodSpec).(*AerospikePodSpec) + status.PodSpec = *statusPodSpec seedsFinderServices := lib.DeepCopy( - spec.SeedsFinderServices, - ).(SeedsFinderServices) + &spec.SeedsFinderServices, + ).(*SeedsFinderServices) - status.SeedsFinderServices = seedsFinderServices + status.SeedsFinderServices = *seedsFinderServices // RosterNodeBlockList if len(spec.RosterNodeBlockList) != 0 { rosterNodeBlockList := lib.DeepCopy( - spec.RosterNodeBlockList, - ).([]string) + &spec.RosterNodeBlockList, + ).(*[]string) - status.RosterNodeBlockList = rosterNodeBlockList + status.RosterNodeBlockList = *rosterNodeBlockList } return &status, nil } // CopyStatusToSpec copy status in spec. Status to Spec DeepCopy doesn't work. It fails in reflect lib. +// +//nolint:dupl // not duplicate func CopyStatusToSpec(status *AerospikeClusterStatusSpec) (*AerospikeClusterSpec, error) { spec := AerospikeClusterSpec{} @@ -954,8 +958,8 @@ func CopyStatusToSpec(status *AerospikeClusterStatusSpec) (*AerospikeClusterSpec spec.Image = status.Image // Storage - specStorage := lib.DeepCopy(status.Storage).(AerospikeStorageSpec) - spec.Storage = specStorage + specStorage := lib.DeepCopy(&status.Storage).(*AerospikeStorageSpec) + spec.Storage = *specStorage if status.AerospikeAccessControl != nil { // AerospikeAccessControl @@ -978,50 +982,50 @@ func CopyStatusToSpec(status *AerospikeClusterStatusSpec) (*AerospikeClusterSpec if status.ValidationPolicy != nil { // ValidationPolicy specValidationPolicy := lib.DeepCopy( - *status.ValidationPolicy, - ).(ValidationPolicySpec) + status.ValidationPolicy, + ).(*ValidationPolicySpec) - spec.ValidationPolicy = &specValidationPolicy + spec.ValidationPolicy = specValidationPolicy } // RackConfig - specRackConfig := lib.DeepCopy(status.RackConfig).(RackConfig) + specRackConfig := lib.DeepCopy(&status.RackConfig).(*RackConfig) - spec.RackConfig = specRackConfig + spec.RackConfig = *specRackConfig // AerospikeNetworkPolicy specAerospikeNetworkPolicy := lib.DeepCopy( - status.AerospikeNetworkPolicy, - ).(AerospikeNetworkPolicy) + &status.AerospikeNetworkPolicy, + ).(*AerospikeNetworkPolicy) - spec.AerospikeNetworkPolicy = specAerospikeNetworkPolicy + spec.AerospikeNetworkPolicy = *specAerospikeNetworkPolicy if status.OperatorClientCertSpec != nil { clientCertSpec := lib.DeepCopy( - *status.OperatorClientCertSpec, - ).(AerospikeOperatorClientCertSpec) + status.OperatorClientCertSpec, + ).(*AerospikeOperatorClientCertSpec) - spec.OperatorClientCertSpec = &clientCertSpec + spec.OperatorClientCertSpec = clientCertSpec } // Storage - specPodSpec := lib.DeepCopy(status.PodSpec).(AerospikePodSpec) + specPodSpec := lib.DeepCopy(&status.PodSpec).(*AerospikePodSpec) - spec.PodSpec = specPodSpec + spec.PodSpec = *specPodSpec seedsFinderServices := lib.DeepCopy( - status.SeedsFinderServices, - ).(SeedsFinderServices) + &status.SeedsFinderServices, + ).(*SeedsFinderServices) - spec.SeedsFinderServices = seedsFinderServices + spec.SeedsFinderServices = *seedsFinderServices // RosterNodeBlockList if len(status.RosterNodeBlockList) != 0 { rosterNodeBlockList := lib.DeepCopy( - status.RosterNodeBlockList, - ).([]string) + &status.RosterNodeBlockList, + ).(*[]string) - spec.RosterNodeBlockList = rosterNodeBlockList + spec.RosterNodeBlockList = *rosterNodeBlockList } return &spec, nil diff --git a/api/v1/aerospikeconfig.go b/api/v1/aerospikeconfig.go index d2e37db70..d54137182 100644 --- a/api/v1/aerospikeconfig.go +++ b/api/v1/aerospikeconfig.go @@ -24,10 +24,5 @@ func (c *AerospikeConfigSpec) UnmarshalJSON(b []byte) error { } func (c *AerospikeConfigSpec) DeepCopy() *AerospikeConfigSpec { - dst := &AerospikeConfigSpec{ - Value: map[string]interface{}{}, - } - dst.Value = lib.DeepCopy(c.Value).(map[string]interface{}) - - return dst + return lib.DeepCopy(c).(*AerospikeConfigSpec) } diff --git a/api/v1beta1/aerospikeconfig.go b/api/v1beta1/aerospikeconfig.go index 5b94577ed..5d4f83fa5 100644 --- a/api/v1beta1/aerospikeconfig.go +++ b/api/v1beta1/aerospikeconfig.go @@ -24,10 +24,5 @@ func (c *AerospikeConfigSpec) UnmarshalJSON(b []byte) error { } func (c *AerospikeConfigSpec) DeepCopy() *AerospikeConfigSpec { - dst := &AerospikeConfigSpec{ - Value: map[string]interface{}{}, - } - dst.Value = lib.DeepCopy(c.Value).(map[string]interface{}) - - return dst + return lib.DeepCopy(c).(*AerospikeConfigSpec) } diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index 56ae1f185..2dccc4c7c 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -26,7 +26,6 @@ import ( "github.com/aerospike/aerospike-kubernetes-operator/pkg/jsonpatch" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" "github.com/aerospike/aerospike-management-lib/asconfig" - libcommons "github.com/aerospike/aerospike-management-lib/commons" "github.com/aerospike/aerospike-management-lib/deployment" ) @@ -302,7 +301,7 @@ func (r *SingleClusterReconciler) setMigrateFillDelay( } func (r *SingleClusterReconciler) setDynamicConfig( - dynamicConfDiffPerPod map[string]libcommons.DynamicConfigMap, pods []*corev1.Pod, ignorablePodNames sets.Set[string], + dynamicConfDiffPerPod map[string]asconfig.DynamicConfigMap, pods []*corev1.Pod, ignorablePodNames sets.Set[string], ) reconcileResult { // This doesn't make actual connection, only objects having connection info are created allHostConns, err := r.newAllHostConnWithOption(ignorablePodNames) diff --git a/controllers/configmap.go b/controllers/configmap.go index 863e366ba..c356d20e9 100644 --- a/controllers/configmap.go +++ b/controllers/configmap.go @@ -158,14 +158,14 @@ func createPodSpecForRack( aeroCluster *asdbv1.AerospikeCluster, rack *asdbv1.Rack, ) *asdbv1.AerospikePodSpec { rackFullPodSpec := lib.DeepCopy( - aeroCluster.Spec.PodSpec, - ).(asdbv1.AerospikePodSpec) + &aeroCluster.Spec.PodSpec, + ).(*asdbv1.AerospikePodSpec) rackFullPodSpec.Affinity = rack.PodSpec.Affinity rackFullPodSpec.Tolerations = rack.PodSpec.Tolerations rackFullPodSpec.NodeSelector = rack.PodSpec.NodeSelector - return &rackFullPodSpec + return rackFullPodSpec } func (r *SingleClusterReconciler) buildConfigTemplate(rack *asdbv1.Rack) ( diff --git a/controllers/pod.go b/controllers/pod.go index ec09eb9b9..ab95df5e9 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -21,8 +21,8 @@ import ( asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" "github.com/aerospike/aerospike-kubernetes-operator/pkg/jsonpatch" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" + lib "github.com/aerospike/aerospike-management-lib" "github.com/aerospike/aerospike-management-lib/asconfig" - libcommons "github.com/aerospike/aerospike-management-lib/commons" ) // RestartType is the type of pod restart to use. @@ -62,11 +62,11 @@ func mergeRestartType(current, incoming RestartType) RestartType { // Fetching RestartType of all pods, based on the operation being performed. func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, ignorablePodNames sets.Set[string]) ( - restartTypeMap map[string]RestartType, dynamicConfDiffPerPod map[string]libcommons.DynamicConfigMap, err error) { + restartTypeMap map[string]RestartType, dynamicConfDiffPerPod map[string]asconfig.DynamicConfigMap, err error) { var addedNSDevices []string restartTypeMap = make(map[string]RestartType) - dynamicConfDiffPerPod = make(map[string]libcommons.DynamicConfigMap) + dynamicConfDiffPerPod = make(map[string]asconfig.DynamicConfigMap) pods, err := r.getOrderedRackPodList(rackState.Rack.ID) if err != nil { @@ -95,13 +95,30 @@ func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, } } - // If dynamic commands have failed in previous retry, then we should not try to update config dynamically. - if !podStatus.DynamicConfigFailed { - // Fetching all dynamic config change. - dynamicConfDiffPerPod[pods[idx].Name], err = r.handleDynamicConfigChange(rackState, pods[idx]) - if err != nil { - return nil, nil, err + serverContainer := getContainer(pods[idx].Spec.Containers, asdbv1.AerospikeServerContainerName) + + version, err := asdbv1.GetImageVersion(serverContainer.Image) + if err != nil { + return nil, nil, err + } + + v, err := lib.CompareVersions(version, "7.0.0") + if err != nil { + return nil, nil, err + } + + // If version >= 7.0.0, then we can update config dynamically. + if v >= 0 { + // If dynamic commands have failed in previous retry, then we should not try to update config dynamically. + if !podStatus.DynamicConfigFailed { + // Fetching all dynamic config change. + dynamicConfDiffPerPod[pods[idx].Name], err = r.handleDynamicConfigChange(rackState, pods[idx], version) + if err != nil { + return nil, nil, err + } } + } else { + r.Log.Info("Dynamic config change not supported for version < 7.0.0", "currentVersion", version) } } @@ -1271,8 +1288,8 @@ func (r *SingleClusterReconciler) getConfigMap(rackID int) (*corev1.ConfigMap, e return confMap, nil } -func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState, pod *corev1.Pod) ( - libcommons.DynamicConfigMap, error) { +func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState, pod *corev1.Pod, version string) ( + asconfig.DynamicConfigMap, error) { statusFromAnnotation := pod.Annotations["aerospikeConf"] asConfStatus, err := getFlatConfig(r.Log, statusFromAnnotation) @@ -1290,11 +1307,6 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState return nil, fmt.Errorf("failed to load config map by lib: %v", err) } - version, err := asdbv1.GetImageVersion(r.aeroCluster.Spec.Image) - if err != nil { - return nil, err - } - specToStatusDiffs, err := asconfig.ConfDiff(r.Log, *asConfSpec, *asConfStatus, true, version) if err != nil { diff --git a/controllers/rack.go b/controllers/rack.go index 72c4349a5..f8aa6ea67 100644 --- a/controllers/rack.go +++ b/controllers/rack.go @@ -18,7 +18,7 @@ import ( asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" lib "github.com/aerospike/aerospike-management-lib" - "github.com/aerospike/aerospike-management-lib/commons" + "github.com/aerospike/aerospike-management-lib/asconfig" ) type scaledDownRack struct { @@ -453,7 +453,7 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, ignorablePodNames sets.Set[string], restartTypeMap map[string]RestartType, - failedPods []*corev1.Pod, dynamicConfDiffPerPod map[string]commons.DynamicConfigMap) reconcileResult { + failedPods []*corev1.Pod, dynamicConfDiffPerPod map[string]asconfig.DynamicConfigMap) reconcileResult { r.Log.Info("Update dynamic config in Aerospike pods") r.Recorder.Eventf( @@ -1140,7 +1140,7 @@ func (r *SingleClusterReconciler) rollingRestartRack(found *appsv1.StatefulSet, func (r *SingleClusterReconciler) needRollingRestartRack(rackState *RackState, ignorablePodNames sets.Set[string]) ( needRestart, needUpdateConf bool, restartTypeMap map[string]RestartType, - dynamicConfDiffPerPod map[string]commons.DynamicConfigMap, err error, + dynamicConfDiffPerPod map[string]asconfig.DynamicConfigMap, err error, ) { restartTypeMap, dynamicConfDiffPerPod, err = r.getRollingRestartTypeMap(rackState, ignorablePodNames) if err != nil { @@ -1291,7 +1291,7 @@ func (r *SingleClusterReconciler) isStorageVolumeSourceUpdated(volume *asdbv1.Vo return true } - volumeCopy := lib.DeepCopy(*volume).(asdbv1.VolumeSpec) + volumeCopy := lib.DeepCopy(volume).(*asdbv1.VolumeSpec) if volumeCopy.Source.Secret != nil { setDefaultsSecretVolumeSource(volumeCopy.Source.Secret) diff --git a/controllers/reconciler.go b/controllers/reconciler.go index c6ef1438c..fbbe8f1e8 100644 --- a/controllers/reconciler.go +++ b/controllers/reconciler.go @@ -385,16 +385,16 @@ func (r *SingleClusterReconciler) updateAccessControlStatus() error { // AerospikeAccessControl statusAerospikeAccessControl := lib.DeepCopy( - *r.aeroCluster.Spec.AerospikeAccessControl, - ).(asdbv1.AerospikeAccessControlSpec) + r.aeroCluster.Spec.AerospikeAccessControl, + ).(*asdbv1.AerospikeAccessControlSpec) - newAeroCluster.Status.AerospikeClusterStatusSpec.AerospikeAccessControl = &statusAerospikeAccessControl + newAeroCluster.Status.AerospikeClusterStatusSpec.AerospikeAccessControl = statusAerospikeAccessControl if err := r.patchStatus(newAeroCluster); err != nil { return fmt.Errorf("error updating status: %w", err) } - r.aeroCluster.Status.AerospikeClusterStatusSpec.AerospikeAccessControl = &statusAerospikeAccessControl + r.aeroCluster.Status.AerospikeClusterStatusSpec.AerospikeAccessControl = statusAerospikeAccessControl r.Log.Info("Updated access control status", "status", newAeroCluster.Status) @@ -538,7 +538,8 @@ func (r *SingleClusterReconciler) patchStatus(newAeroCluster *asdbv1.AerospikeCl // Seems like a bug in encoding/json/Unmarshall. // // Workaround by force copying new object's status to old object's status. - oldAeroCluster.Status = lib.DeepCopy(newAeroCluster.Status).(asdbv1.AerospikeClusterStatus) + aeroclusterStatus := lib.DeepCopy(&newAeroCluster.Status).(*asdbv1.AerospikeClusterStatus) + oldAeroCluster.Status = *aeroclusterStatus return nil } diff --git a/controllers/statefulset.go b/controllers/statefulset.go index ecfb466d4..9e4a5edc6 100644 --- a/controllers/statefulset.go +++ b/controllers/statefulset.go @@ -790,13 +790,13 @@ func (r *SingleClusterReconciler) updateSTSNonPVStorage( func (r *SingleClusterReconciler) updateSTSSchedulingPolicy( st *appsv1.StatefulSet, rackState *RackState, ) { - var affinity corev1.Affinity + affinity := &corev1.Affinity{} // Use rack affinity, if given if rackState.Rack.PodSpec.Affinity != nil { - affinity = lib.DeepCopy(*rackState.Rack.PodSpec.Affinity).(corev1.Affinity) + affinity = lib.DeepCopy(rackState.Rack.PodSpec.Affinity).(*corev1.Affinity) } else if r.aeroCluster.Spec.PodSpec.Affinity != nil { - affinity = lib.DeepCopy(*r.aeroCluster.Spec.PodSpec.Affinity).(corev1.Affinity) + affinity = lib.DeepCopy(r.aeroCluster.Spec.PodSpec.Affinity).(*corev1.Affinity) } // Set our rules in PodAntiAffinity @@ -896,7 +896,7 @@ func (r *SingleClusterReconciler) updateSTSSchedulingPolicy( } } - st.Spec.Template.Spec.Affinity = &affinity + st.Spec.Template.Spec.Affinity = affinity // Use rack nodeSelector, if given if len(rackState.Rack.PodSpec.NodeSelector) != 0 { @@ -961,7 +961,7 @@ func updateSTSContainers( // Create a copy because updating stateful sets defaults // on the sidecar container object which mutates original aeroCluster object. - specContainerCopy := lib.DeepCopy(*specContainer).(corev1.Container) + specContainerCopy := lib.DeepCopy(specContainer).(*corev1.Container) for stsIdx := range stsContainers { if specContainer.Name != stsContainers[stsIdx].Name { @@ -971,7 +971,7 @@ func updateSTSContainers( // Retain volume mounts and devices to make sure external storage will not lose. specContainerCopy.VolumeMounts = stsContainers[stsIdx].VolumeMounts specContainerCopy.VolumeDevices = stsContainers[stsIdx].VolumeDevices - stsContainers[stsIdx] = specContainerCopy + stsContainers[stsIdx] = *specContainerCopy found = true break @@ -979,7 +979,7 @@ func updateSTSContainers( if !found { // Add to stateful set containers. - stsContainers = append(stsContainers, specContainerCopy) + stsContainers = append(stsContainers, *specContainerCopy) } } diff --git a/go.mod b/go.mod index b5c96c706..1ba86737a 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212190343-4526f5f309b2 + github.com/aerospike/aerospike-management-lib v1.2.1-0.20240214064425-a46a75c0a939 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 diff --git a/go.sum b/go.sum index d230ccc70..75cebfe2c 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212090410-ceae9d0d04 github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212090410-ceae9d0d0462/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212190343-4526f5f309b2 h1:75mpNdTAZW0hUgY4wg176Y1+87qTFyUmsscl+c7gOOI= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212190343-4526f5f309b2/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240214064425-a46a75c0a939 h1:s3W8hj8EI6M2BsjMk4CW1qhIafdWBcpWLwAFqPEsJdU= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240214064425-a46a75c0a939/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= diff --git a/test/cluster_helper.go b/test/cluster_helper.go index 834ec9a71..89aa45cbc 100644 --- a/test/cluster_helper.go +++ b/test/cluster_helper.go @@ -1362,14 +1362,13 @@ func aerospikeClusterCreateUpdateWithTO( // Apply the update. if desired.Spec.AerospikeAccessControl != nil { - current.Spec = lib.DeepCopy(desired.Spec).(asdbv1.AerospikeClusterSpec) + current.Spec.AerospikeAccessControl = &asdbv1.AerospikeAccessControlSpec{} + current.Spec = *lib.DeepCopy(&desired.Spec).(*asdbv1.AerospikeClusterSpec) } else { current.Spec.AerospikeAccessControl = nil } - current.Spec.AerospikeConfig.Value = lib.DeepCopy( - desired.Spec.AerospikeConfig.Value, - ).(map[string]interface{}) + current.Spec.AerospikeConfig.Value = desired.Spec.AerospikeConfig.DeepCopy().Value if err := k8sClient.Update(ctx, current); err != nil { return err diff --git a/test/services_test.go b/test/services_test.go index 8dcaf5188..c28b0192c 100644 --- a/test/services_test.go +++ b/test/services_test.go @@ -129,9 +129,9 @@ func createLoadBalancer() *asdbv1.LoadBalancerSpec { ), ) - result := lib.DeepCopy(lb).(asdbv1.LoadBalancerSpec) + result := lib.DeepCopy(&lb).(*asdbv1.LoadBalancerSpec) - return &result + return result } func loadBalancerName(aeroCluster *asdbv1.AerospikeCluster) types.NamespacedName { From 2573a3873db41a899153e67447f7d0da71b92f05 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Thu, 15 Feb 2024 19:54:56 +0530 Subject: [PATCH 12/20] addressing comments --- go.mod | 2 +- go.sum | 2 ++ test/dynamic_config_test.go | 25 ++++++++++--------------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index 1ba86737a..7c0ced485 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v1.2.1-0.20240214064425-a46a75c0a939 + github.com/aerospike/aerospike-management-lib v1.2.1-0.20240215140954-26c9ef4857c0 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 diff --git a/go.sum b/go.sum index 75cebfe2c..7aba9d5d2 100644 --- a/go.sum +++ b/go.sum @@ -8,6 +8,8 @@ github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212190343-4526f5f309 github.com/aerospike/aerospike-management-lib v1.2.1-0.20240212190343-4526f5f309b2/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240214064425-a46a75c0a939 h1:s3W8hj8EI6M2BsjMk4CW1qhIafdWBcpWLwAFqPEsJdU= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240214064425-a46a75c0a939/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240215140954-26c9ef4857c0 h1:hQz0rqqvR/E/2QLnCi5B5BNx4qokIOkvYaeGmIwM8+c= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240215140954-26c9ef4857c0/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= diff --git a/test/dynamic_config_test.go b/test/dynamic_config_test.go index 3f87ddabc..a7e5e54db 100644 --- a/test/dynamic_config_test.go +++ b/test/dynamic_config_test.go @@ -118,9 +118,7 @@ var _ = Describe( Expect(aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"]).To(HaveLen(2)) By("Verify no warm/cold restarts in Pods") - noRestart, err := verifyNoRestart(ctx, aeroCluster, podPIDMap) - Expect(err).ToNot(HaveOccurred()) - Expect(noRestart).To(Equal(false)) + validateServerRestart(ctx, aeroCluster, podPIDMap, false) By("Modify dynamic config by removing fields") aeroCluster, err = getCluster( @@ -149,9 +147,7 @@ var _ = Describe( Expect(aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"]).To(HaveLen(1)) By("Verify no warm/cold restarts in Pods") - noRestart, err = verifyNoRestart(ctx, aeroCluster, podPIDMap) - Expect(err).ToNot(HaveOccurred()) - Expect(noRestart).To(Equal(false)) + validateServerRestart(ctx, aeroCluster, podPIDMap, false) }, ) @@ -182,9 +178,7 @@ var _ = Describe( To(Equal(false)) By("Verify warm restarts in Pods") - noRestart, err := verifyNoRestart(ctx, aeroCluster, podPIDMap) - Expect(err).ToNot(HaveOccurred()) - Expect(noRestart).To(Equal(true)) + validateServerRestart(ctx, aeroCluster, podPIDMap, true) }, ) }, @@ -193,19 +187,20 @@ var _ = Describe( }, ) -func verifyNoRestart(ctx goctx.Context, cluster *asdbv1.AerospikeCluster, pidMap map[string]podID) (bool, error) { +func validateServerRestart(ctx goctx.Context, cluster *asdbv1.AerospikeCluster, pidMap map[string]podID, + shouldRestart bool) { + restarted := false + newPodPidMap, err := getPodIDs(ctx, cluster) - if err != nil { - return false, err - } + Expect(err).ToNot(HaveOccurred()) for podName, pid := range pidMap { if newPodPidMap[podName].podUID != pid.podUID || newPodPidMap[podName].asdPID != pid.asdPID { - return true, nil + restarted = true } } - return false, nil + Expect(restarted).To(Equal(shouldRestart)) } func getPodIDs(ctx context.Context, aeroCluster *asdbv1.AerospikeCluster) (map[string]podID, error) { From ea10a6f7752a8dac38b8d46e6d06ce8b7d8d9eef Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Sat, 17 Feb 2024 17:30:24 +0530 Subject: [PATCH 13/20] fixing tests --- controllers/aero_info_calls.go | 2 +- controllers/pod.go | 8 ++-- go.mod | 2 +- go.sum | 2 + test/dynamic_config_test.go | 74 ++++++++++++++++++++++++---------- test/rack_utils.go | 13 +----- test/utils.go | 28 +++++++++++++ 7 files changed, 89 insertions(+), 40 deletions(-) diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index 2dccc4c7c..94b1d892b 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -346,7 +346,7 @@ func (r *SingleClusterReconciler) setDynamicConfig( return reconcileError(err) } - r.Log.Info("printing commands", "asConfCmds", fmt.Sprintf("%v", asConfCmds)) + r.Log.Info("Generated dynamic commands", "commands", fmt.Sprintf("%v", asConfCmds), "pod", podName) if err := deployment.SetConfigCommandsOnHosts(r.Log, r.getClientPolicy(), allHostConns, []*deployment.HostConn{host}, asConfCmds); err != nil { diff --git a/controllers/pod.go b/controllers/pod.go index ab95df5e9..b7b9de073 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -368,7 +368,7 @@ func (r *SingleClusterReconciler) restartPods( } func (r *SingleClusterReconciler) updatePod(podName string) error { - r.Log.Info("updating pod", "pod", podName) + r.Log.Info("Updating pod", "pod", podName) if err := r.restartASDOrUpdateAerospikeConf(podName, noRestartUpdateConf); err != nil { return err @@ -1310,16 +1310,14 @@ func (r *SingleClusterReconciler) handleDynamicConfigChange(rackState *RackState specToStatusDiffs, err := asconfig.ConfDiff(r.Log, *asConfSpec, *asConfStatus, true, version) if err != nil { - r.Log.Info("failed to get config diff, fallback to rolling restart: %v", err) + r.Log.Info("Failed to get config diff to change config dynamically, fallback to rolling restart: %v", err) return nil, nil } if len(specToStatusDiffs) > 0 { - r.Log.Info("print diff outside", "difference", fmt.Sprintf("%v", specToStatusDiffs)) - isDynamic, err := asconfig.IsAllDynamicConfig(r.Log, specToStatusDiffs, version) if err != nil { - r.Log.Info("failed to check if all config is dynamic, fallback to rolling restart: %v", err) + r.Log.Info("Failed to check if all config is dynamic, fallback to rolling restart: %v", err) return nil, nil } diff --git a/go.mod b/go.mod index 7c0ced485..c98da191a 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/aerospike/aerospike-client-go/v6 v6.14.0 - github.com/aerospike/aerospike-management-lib v1.2.1-0.20240215140954-26c9ef4857c0 + github.com/aerospike/aerospike-management-lib v1.2.1-0.20240217101322-63da5d036614 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 diff --git a/go.sum b/go.sum index 7aba9d5d2..4c3e2c66d 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/aerospike/aerospike-management-lib v1.2.1-0.20240214064425-a46a75c0a9 github.com/aerospike/aerospike-management-lib v1.2.1-0.20240214064425-a46a75c0a939/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240215140954-26c9ef4857c0 h1:hQz0rqqvR/E/2QLnCi5B5BNx4qokIOkvYaeGmIwM8+c= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240215140954-26c9ef4857c0/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240217101322-63da5d036614 h1:tdpAQb+7k4eTNR8/UWiLna9lGVpzhmhxMKmsfYjBFhY= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240217101322-63da5d036614/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= diff --git a/test/dynamic_config_test.go b/test/dynamic_config_test.go index a7e5e54db..d3e131271 100644 --- a/test/dynamic_config_test.go +++ b/test/dynamic_config_test.go @@ -79,11 +79,12 @@ var _ = Describe( podPIDMap, err := getPodIDs(ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) - aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"] = 18000 log := map[string]interface{}{ "report-data-op": []string{"test"}, } + 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", @@ -106,16 +107,30 @@ var _ = Describe( err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) - aeroCluster, err = getCluster( - k8sClient, ctx, clusterNamespacedName, - ) + 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(18000))) + + conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, + "security", &pod) + Expect(err).ToNot(HaveOccurred()) + + reportDataOp, ok := conf["log.report-data-op[0]"].(string) + Expect(ok).ToNot(BeFalse()) + + Expect(reportDataOp).To(Equal("test")) + + conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, + "xdr", &pod) Expect(err).ToNot(HaveOccurred()) - logs := aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["log"] - Expect(aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"]). - To(Equal(float64(18000))) - Expect(logs.(map[string]interface{})["report-data-op"].([]interface{})[0]).To(Equal("test")) - Expect(aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"]).To(HaveLen(2)) + Expect(conf["dcs"]).To(HaveLen(2)) By("Verify no warm/cold restarts in Pods") validateServerRestart(ctx, aeroCluster, podPIDMap, false) @@ -137,17 +152,32 @@ var _ = Describe( err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) - aeroCluster, err = getCluster( - k8sClient, ctx, clusterNamespacedName, - ) + 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(15000))) + + conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, + "security", &pod) + Expect(err).ToNot(HaveOccurred()) + + _, ok = conf["log.report-data-op[0]"].(string) + Expect(ok).ToNot(BeTrue()) + + conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, + "xdr", &pod) Expect(err).ToNot(HaveOccurred()) - Expect(aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["proto-fd-max"]).To(BeNil()) - Expect(aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["log"]).To(BeNil()) - Expect(aeroCluster.Spec.AerospikeConfig.Value["xdr"].(map[string]interface{})["dcs"]).To(HaveLen(1)) + Expect(conf["dcs"]).To(HaveLen(1)) By("Verify no warm/cold restarts in Pods") validateServerRestart(ctx, aeroCluster, podPIDMap, false) + }, ) @@ -169,13 +199,16 @@ var _ = Describe( err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) - aeroCluster, err = getCluster( - k8sClient, ctx, clusterNamespacedName, - ) + pod := aeroCluster.Status.Pods["dynamic-config-test-0-0"] + + conf, err := getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, + "security", &pod) Expect(err).ToNot(HaveOccurred()) - Expect(aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"]). - To(Equal(false)) + enableQuotas, ok := conf["enable-quotas"].(bool) + Expect(ok).ToNot(BeFalse()) + + Expect(enableQuotas).To(BeFalse()) By("Verify warm restarts in Pods") validateServerRestart(ctx, aeroCluster, podPIDMap, true) @@ -183,7 +216,6 @@ var _ = Describe( ) }, ) - }, ) diff --git a/test/rack_utils.go b/test/rack_utils.go index f00dfbd76..098dde03f 100644 --- a/test/rack_utils.go +++ b/test/rack_utils.go @@ -92,22 +92,11 @@ func validateAerospikeConfigServiceUpdate( // TODO: // We may need to check for all keys in aerospikeConfig in rack // but we know that we are changing for service only for now - host, err := createHost(&pod) + svcConfs, err := getAerospikeConfigFromNode(log, k8sClient, ctx, clusterNamespacedName, "service", &pod) if err != nil { return err } - asinfo := info.NewAsInfo( - log, host, getClientPolicy(aeroCluster, k8sClient), - ) - - confs, err := getAsConfig(asinfo, "service") - if err != nil { - return err - } - - svcConfs := confs["service"].(lib.Stats) - for k, v := range rack.InputAerospikeConfig.Value["service"].(map[string]interface{}) { if vint, ok := v.(int); ok { v = int64(vint) diff --git a/test/utils.go b/test/utils.go index 94da43766..f41db61c8 100644 --- a/test/utils.go +++ b/test/utils.go @@ -14,6 +14,7 @@ import ( "strings" "time" + "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" @@ -27,6 +28,7 @@ import ( asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1" operatorUtils "github.com/aerospike/aerospike-kubernetes-operator/pkg/utils" lib "github.com/aerospike/aerospike-management-lib" + "github.com/aerospike/aerospike-management-lib/info" ) var ( @@ -758,3 +760,29 @@ func getGitRepoRootPath() (string, error) { return strings.TrimSpace(string(path)), nil } + +func getAerospikeConfigFromNode(log logr.Logger, k8sClient client.Client, ctx goctx.Context, + clusterNamespacedName types.NamespacedName, configContext string, pod *asdbv1.AerospikePodStatus) (lib.Stats, error) { + aeroCluster, err := getCluster(k8sClient, ctx, clusterNamespacedName) + if err != nil { + return nil, err + } + + host, err := createHost(pod) + if err != nil { + return nil, err + } + + asinfo := info.NewAsInfo( + log, host, getClientPolicy(aeroCluster, k8sClient), + ) + + confs, err := getAsConfig(asinfo, configContext) + if err != nil { + return nil, err + } + + svcConfs := confs[configContext].(lib.Stats) + + return svcConfs, nil +} From afe0e132589e5211ee60c9b2e657dd403ba0d866 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Fri, 23 Feb 2024 11:31:29 +0530 Subject: [PATCH 14/20] fixing failed pod handling --- controllers/rack.go | 14 ++++---------- test/cluster_helper.go | 1 + test/large_reconcile_test.go | 12 ++++++------ 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/controllers/rack.go b/controllers/rack.go index f8aa6ea67..86a8c4566 100644 --- a/controllers/rack.go +++ b/controllers/rack.go @@ -420,8 +420,8 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat } } - if needDynamicUpdateRack { - res = r.updateDynamicConfig(rackState, ignorablePodNames, restartTypeMap, failedPods, dynamicConfDiffPerPod) + if len(failedPods) == 0 && needDynamicUpdateRack { + res = r.updateDynamicConfig(rackState, ignorablePodNames, restartTypeMap, dynamicConfDiffPerPod) if !res.isSuccess { if res.err != nil { r.Log.Error( @@ -453,7 +453,7 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, ignorablePodNames sets.Set[string], restartTypeMap map[string]RestartType, - failedPods []*corev1.Pod, dynamicConfDiffPerPod map[string]asconfig.DynamicConfigMap) reconcileResult { + dynamicConfDiffPerPod map[string]asconfig.DynamicConfigMap) reconcileResult { r.Log.Info("Update dynamic config in Aerospike pods") r.Recorder.Eventf( @@ -466,12 +466,6 @@ func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, podList []*corev1.Pod ) - failedPodNames := sets.Set[string]{} - - for idx := range failedPods { - sets.Insert(failedPodNames, failedPods[idx].Name) - } - // List the pods for this aeroCluster's statefulset podList, err = r.getOrderedRackPodList(rackState.Rack.ID) if err != nil { @@ -485,7 +479,7 @@ func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, pod := podList[idx] restartType := restartTypeMap[pod.Name] - if restartType != noRestartUpdateConf || failedPodNames.Has(pod.Name) { + if restartType != noRestartUpdateConf { r.Log.Info("This Pod doesn't need any update, Skip this", "pod", pod.Name) continue } diff --git a/test/cluster_helper.go b/test/cluster_helper.go index 89aa45cbc..409270516 100644 --- a/test/cluster_helper.go +++ b/test/cluster_helper.go @@ -1042,6 +1042,7 @@ func createDummyAerospikeCluster( "service": map[string]interface{}{ "feature-key-file": "/etc/aerospike/secret/features.conf", "proto-fd-max": defaultProtofdmax, + "auto-pin": "none", }, "security": map[string]interface{}{}, "network": getNetworkConfig(), diff --git a/test/large_reconcile_test.go b/test/large_reconcile_test.go index e60e0fdf5..5d3cd1c22 100644 --- a/test/large_reconcile_test.go +++ b/test/large_reconcile_test.go @@ -102,8 +102,8 @@ var _ = Describe( ) Expect(err).ToNot(HaveOccurred()) - tempConf := true - aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = tempConf + tempConf := "cpu" + aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["auto-pin"] = tempConf err = k8sClient.Update(goctx.TODO(), aeroCluster) Expect(err).ToNot(HaveOccurred()) @@ -113,7 +113,7 @@ var _ = Describe( ) Expect(err).ToNot(HaveOccurred()) - aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = false + aeroCluster.Spec.AerospikeConfig.Value["service"].(map[string]interface{})["auto-pin"] = "none" err = k8sClient.Update(goctx.TODO(), aeroCluster) Expect(err).ToNot(HaveOccurred()) @@ -324,7 +324,7 @@ func waitForClusterScaleDown( func waitForClusterRollingRestart( k8sClient client.Client, aeroCluster *asdbv1.AerospikeCluster, - replicas int, tempConf bool, retryInterval, timeout time.Duration, + replicas int, tempConf string, retryInterval, timeout time.Duration, ) error { err := wait.PollUntilContextTimeout(goctx.TODO(), retryInterval, timeout, true, func(ctx goctx.Context) (done bool, err error) { @@ -342,8 +342,8 @@ func waitForClusterRollingRestart( return false, err } - enableQuotas := newCluster.Status.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"].(bool) - if enableQuotas == tempConf { + autoPin := newCluster.Status.AerospikeConfig.Value["service"].(map[string]interface{})["auto-pin"].(string) + if autoPin == tempConf { err := fmt.Errorf( "cluster status can not be updated with intermediate conf value %v,"+ " it should have only final value, as this is the new reconcile flow", From dd8412fbb951640d61a1ee838bfc462bb0c81f60 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Tue, 26 Mar 2024 12:19:37 +0530 Subject: [PATCH 15/20] Using latest lib and disallowing dynamic config change in xdr --- api/v1/utils.go | 2 +- controllers/aero_info_calls.go | 4 ++-- go.mod | 3 +-- go.sum | 6 ++---- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/api/v1/utils.go b/api/v1/utils.go index befc499a0..39aa6dfc2 100644 --- a/api/v1/utils.go +++ b/api/v1/utils.go @@ -63,7 +63,7 @@ const ( AerospikeInitContainerRegistryEnvVar = "AEROSPIKE_KUBERNETES_INIT_REGISTRY" AerospikeInitContainerDefaultRegistry = "docker.io" AerospikeInitContainerDefaultRegistryNamespace = "tanmayj10" - AerospikeInitContainerDefaultRepoAndTag = "aerospike-kubernetes-init:2.1.0-dev" + AerospikeInitContainerDefaultRepoAndTag = "aerospike-kubernetes-init:2.1.0-dev1" AerospikeAppLabel = "app" AerospikeCustomResourceLabel = "aerospike.com/cr" AerospikeRackIDLabel = "aerospike.com/rack-id" diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index d8f42a09d..a261b5224 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -1,5 +1,5 @@ /* -Copyright 2018 The aerospike-operator Authors. +Copyright 2024 The aerospike-operator Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -338,7 +338,7 @@ func (r *SingleClusterReconciler) setDynamicConfig( for _, host := range selectedHostConns { podName := podIPNameMap[host.ASConn.AerospikeHostName] - asConfCmds, err := asconfig.CreateSetConfigCmdList(r.Log, dynamicConfDiffPerPod[podName], + asConfCmds, err := asconfig.CreateSetConfigCmdList(dynamicConfDiffPerPod[podName], host.ASConn, r.getClientPolicy()) if err != nil { diff --git a/go.mod b/go.mod index 1f7dc807c..3b6c6b3ff 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 toolchain go1.21.8 require ( - github.com/aerospike/aerospike-management-lib v1.2.1-0.20240217101322-63da5d036614 + github.com/aerospike/aerospike-management-lib v1.2.1-0.20240325134810-f8046fe9872e 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 @@ -32,7 +32,6 @@ require ( ) require ( - github.com/aerospike/aerospike-client-go/v6 v6.14.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index 3d266bb7d..d5e5f8101 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ -github.com/aerospike/aerospike-client-go/v6 v6.14.0 h1:Z3FcGWJda1sagzdc6Akz4EJ13Pq55Uyn6qtFLrVUDd0= -github.com/aerospike/aerospike-client-go/v6 v6.14.0/go.mod h1:/0Wm81GhMqem+9flWcpazPKoRfjFeG6WrQdXGiMNi0A= 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.2.1-0.20240217101322-63da5d036614 h1:tdpAQb+7k4eTNR8/UWiLna9lGVpzhmhxMKmsfYjBFhY= -github.com/aerospike/aerospike-management-lib v1.2.1-0.20240217101322-63da5d036614/go.mod h1:cSmDG+UbsNt6uTpjdHPfVYvxsHiDh0R+iA5D6vqcLeI= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240325134810-f8046fe9872e h1:Q/AfYe++0ouO5csLS8l99kCQqJJvDKlfHwhuWbECpaQ= +github.com/aerospike/aerospike-management-lib v1.2.1-0.20240325134810-f8046fe9872e/go.mod h1:E4dk798IikCp9a8fugpYoeQVIXuvdxogHvt6sKhaORQ= 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= From 5fdde7c9ef6f1a542c929ea91794273f9fe5f10a Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Tue, 26 Mar 2024 12:46:32 +0530 Subject: [PATCH 16/20] Modifying test case --- test/dynamic_config_test.go | 54 ++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/test/dynamic_config_test.go b/test/dynamic_config_test.go index d3e131271..29e3959b5 100644 --- a/test/dynamic_config_test.go +++ b/test/dynamic_config_test.go @@ -86,23 +86,6 @@ 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()) @@ -126,12 +109,6 @@ var _ = Describe( Expect(reportDataOp).To(Equal("test")) - 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) @@ -146,8 +123,6 @@ 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()) @@ -169,12 +144,6 @@ var _ = Describe( _, ok = conf["log.report-data-op[0]"].(string) Expect(ok).ToNot(BeTrue()) - 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) @@ -195,6 +164,23 @@ var _ = Describe( Expect(err).ToNot(HaveOccurred()) aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = false + 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()) @@ -210,6 +196,12 @@ var _ = Describe( Expect(enableQuotas).To(BeFalse()) + conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, + "xdr", &pod) + Expect(err).ToNot(HaveOccurred()) + + Expect(conf["dcs"]).To(HaveLen(2)) + By("Verify warm restarts in Pods") validateServerRestart(ctx, aeroCluster, podPIDMap, true) }, From 46ce1aebe99313c435dc3d48b1c78db371f198c6 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Thu, 28 Mar 2024 12:06:59 +0530 Subject: [PATCH 17/20] address comments --- test/cluster_test.go | 2 +- test/dynamic_config_test.go | 5 +++-- test/utils.go | 4 +--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/test/cluster_test.go b/test/cluster_test.go index 752437dbc..a612386e2 100644 --- a/test/cluster_test.go +++ b/test/cluster_test.go @@ -184,7 +184,7 @@ func clusterWithMaxIgnorablePod(ctx goctx.Context) { Expect(err).ToNot(HaveOccurred()) val := intstr.FromInt32(1) aeroCluster.Spec.RackConfig.MaxIgnorablePods = &val - aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = false + aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = true // As pod is in pending state, CR object will be won't reach the final phase. // So expectedPhases can be InProgress or Completed diff --git a/test/dynamic_config_test.go b/test/dynamic_config_test.go index 29e3959b5..df87c5681 100644 --- a/test/dynamic_config_test.go +++ b/test/dynamic_config_test.go @@ -163,7 +163,7 @@ var _ = Describe( podPIDMap, err := getPodIDs(ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) - aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = false + aeroCluster.Spec.AerospikeConfig.Value["security"].(map[string]interface{})["enable-quotas"] = true dc := map[string]interface{}{ "name": "dc2", "auth-mode": "internal", @@ -194,7 +194,7 @@ var _ = Describe( enableQuotas, ok := conf["enable-quotas"].(bool) Expect(ok).ToNot(BeFalse()) - Expect(enableQuotas).To(BeFalse()) + Expect(enableQuotas).To(BeTrue()) conf, err = getAerospikeConfigFromNode(logger, k8sClient, ctx, clusterNamespacedName, "xdr", &pod) @@ -221,6 +221,7 @@ func validateServerRestart(ctx goctx.Context, cluster *asdbv1.AerospikeCluster, for podName, pid := range pidMap { if newPodPidMap[podName].podUID != pid.podUID || newPodPidMap[podName].asdPID != pid.asdPID { restarted = true + break } } diff --git a/test/utils.go b/test/utils.go index 62eeac2ee..7db639344 100644 --- a/test/utils.go +++ b/test/utils.go @@ -791,7 +791,5 @@ func getAerospikeConfigFromNode(log logr.Logger, k8sClient client.Client, ctx go return nil, err } - svcConfs := confs[configContext].(lib.Stats) - - return svcConfs, nil + return confs[configContext].(lib.Stats), nil } From ce0523460ac2c94af1633156ab9abc15601da1c5 Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Wed, 3 Apr 2024 16:47:25 +0530 Subject: [PATCH 18/20] fixing testcases --- api/v1/aerospikecluster_types.go | 8 ++++---- test/cluster_test.go | 17 +++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/api/v1/aerospikecluster_types.go b/api/v1/aerospikecluster_types.go index 19a3ab478..5fa0f1356 100644 --- a/api/v1/aerospikecluster_types.go +++ b/api/v1/aerospikecluster_types.go @@ -996,9 +996,9 @@ func CopySpecToStatus(spec *AerospikeClusterSpec) (*AerospikeClusterStatusSpec, } if len(spec.K8sNodeBlockList) != 0 { - k8sNodeBlockList := lib.DeepCopy(&spec.K8sNodeBlockList).([]string) + k8sNodeBlockList := lib.DeepCopy(&spec.K8sNodeBlockList).(*[]string) - status.K8sNodeBlockList = k8sNodeBlockList + status.K8sNodeBlockList = *k8sNodeBlockList } return &status, nil @@ -1086,8 +1086,8 @@ func CopyStatusToSpec(status *AerospikeClusterStatusSpec) (*AerospikeClusterSpec } if len(status.K8sNodeBlockList) != 0 { - k8sNodeBlockList := lib.DeepCopy(&status.K8sNodeBlockList).([]string) - spec.K8sNodeBlockList = k8sNodeBlockList + k8sNodeBlockList := lib.DeepCopy(&status.K8sNodeBlockList).(*[]string) + spec.K8sNodeBlockList = *k8sNodeBlockList } return &spec, nil diff --git a/test/cluster_test.go b/test/cluster_test.go index a612386e2..2181b058a 100644 --- a/test/cluster_test.go +++ b/test/cluster_test.go @@ -192,14 +192,15 @@ func clusterWithMaxIgnorablePod(ctx goctx.Context) { }, 1*time.Minute).ShouldNot(HaveOccurred()) By("Upgrade version") - aeroCluster, err = getCluster(k8sClient, ctx, clusterNamespacedName) - Expect(err).ToNot(HaveOccurred()) - newImage := baseImage + ":7.0.0.0_2" - aeroCluster.Spec.Image = newImage - // As pod is in pending state, CR object will be won't reach the final phase. - // So expectedPhases can be InProgress or Completed - err = updateClusterWithExpectedPhases(k8sClient, ctx, aeroCluster, expectedPhases) - Expect(err).ToNot(HaveOccurred()) + Eventually(func() error { + aeroCluster, err = getCluster(k8sClient, ctx, clusterNamespacedName) + Expect(err).ToNot(HaveOccurred()) + newImage := baseImage + ":7.0.0.0_2" + aeroCluster.Spec.Image = newImage + // As pod is in pending state, CR object will be won't reach the final phase. + // So expectedPhases can be InProgress or Completed + return updateClusterWithExpectedPhases(k8sClient, ctx, aeroCluster, expectedPhases) + }, 1*time.Minute).ShouldNot(HaveOccurred()) By("Verify pending pod") podList, err = getPodList(aeroCluster, k8sClient) From d6122032734b4f2bc58cf8871607e216b694c8fd Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Wed, 10 Apr 2024 11:02:41 +0530 Subject: [PATCH 19/20] addressing comments and adding testcases --- api/v1/aerospikecluster_mutating_webhook.go | 29 +++++--- api/v1/utils.go | 2 +- controllers/aero_info_calls.go | 6 +- controllers/pod.go | 12 ++-- controllers/rack.go | 46 +++++++----- controllers/reconciler.go | 11 +-- go.mod | 2 +- go.sum | 2 + test/cluster_test.go | 80 ++++++++++++++++++++- test/services_test.go | 4 +- 10 files changed, 151 insertions(+), 43 deletions(-) diff --git a/api/v1/aerospikecluster_mutating_webhook.go b/api/v1/aerospikecluster_mutating_webhook.go index 7089f5d80..7e6203ab9 100644 --- a/api/v1/aerospikecluster_mutating_webhook.go +++ b/api/v1/aerospikecluster_mutating_webhook.go @@ -95,7 +95,7 @@ func (c *AerospikeCluster) setDefaults(asLog logr.Logger) error { // Set common aerospikeConfig defaults // Update configMap - if err := c.setDefaultAerospikeConfigs(asLog, *c.Spec.AerospikeConfig, DefaultRackID); err != nil { + if err := c.setDefaultAerospikeConfigs(asLog, *c.Spec.AerospikeConfig, nil); err != nil { return err } @@ -280,7 +280,7 @@ func (c *AerospikeCluster) updateRacksAerospikeConfigFromGlobal(asLog logr.Logge // Set defaults in updated rack config // Above merge function may have overwritten defaults. - if err := c.setDefaultAerospikeConfigs(asLog, AerospikeConfigSpec{Value: m}, rack.ID); err != nil { + if err := c.setDefaultAerospikeConfigs(asLog, AerospikeConfigSpec{Value: m}, &rack.ID); err != nil { return err } @@ -291,7 +291,7 @@ func (c *AerospikeCluster) updateRacksAerospikeConfigFromGlobal(asLog logr.Logge } func (c *AerospikeCluster) setDefaultAerospikeConfigs(asLog logr.Logger, - configSpec AerospikeConfigSpec, rackID int) error { + configSpec AerospikeConfigSpec, rackID *int) error { config := configSpec.Value // namespace conf @@ -362,7 +362,8 @@ func (n *AerospikeNetworkPolicy) setNetworkNamespace(namespace string) { // Helper // ***************************************************************************** -func setDefaultNsConf(asLog logr.Logger, configSpec AerospikeConfigSpec, rackEnabledNsList []string, rackID int) error { +func setDefaultNsConf(asLog logr.Logger, configSpec AerospikeConfigSpec, + rackEnabledNsList []string, rackID *int) error { config := configSpec.Value // namespace conf nsConf, ok := config["namespaces"] @@ -397,16 +398,28 @@ func setDefaultNsConf(asLog logr.Logger, configSpec AerospikeConfigSpec, rackEna } if nsName, ok := nsMap["name"]; ok { - if _, ok := nsName.(string); ok { - if isNameExist(rackEnabledNsList, nsName.(string)) { - nsMap["rack-id"] = rackID + if name, ok := nsName.(string); ok { + if isNameExist(rackEnabledNsList, name) { + // Add rack-id only for rackEnabled namespaces + if rackID != nil { + // Add rack-id only in rack specific config, not in global config + defaultConfs := map[string]interface{}{"rack-id": *rackID} + if err := setDefaultsInConfigMap( + asLog, nsMap, defaultConfs, + ); err != nil { + return fmt.Errorf( + "failed to set default aerospikeConfig.namespaces rack config: %v", + err, + ) + } + } } else { // User may have added this key or may have patched object with new smaller rackEnabledNamespace list // but left namespace defaults. This key should be removed then only controller will detect // that some namespace is removed from rackEnabledNamespace list and cluster needs rolling restart asLog.Info( "Name aerospikeConfig.namespaces.name not found in rackEnabled namespace list. "+ - "Namespace will not have defaultRackID", + "Namespace will not have any rackID", "nsName", nsName, "rackEnabledNamespaces", rackEnabledNsList, ) diff --git a/api/v1/utils.go b/api/v1/utils.go index 39aa6dfc2..be7a731b3 100644 --- a/api/v1/utils.go +++ b/api/v1/utils.go @@ -63,7 +63,7 @@ const ( AerospikeInitContainerRegistryEnvVar = "AEROSPIKE_KUBERNETES_INIT_REGISTRY" AerospikeInitContainerDefaultRegistry = "docker.io" AerospikeInitContainerDefaultRegistryNamespace = "tanmayj10" - AerospikeInitContainerDefaultRepoAndTag = "aerospike-kubernetes-init:2.1.0-dev1" + AerospikeInitContainerDefaultRepoAndTag = "aerospike-kubernetes-init:2.1.0-dev3" AerospikeAppLabel = "app" AerospikeCustomResourceLabel = "aerospike.com/cr" AerospikeRackIDLabel = "aerospike.com/rack-id" diff --git a/controllers/aero_info_calls.go b/controllers/aero_info_calls.go index a261b5224..df016e31a 100644 --- a/controllers/aero_info_calls.go +++ b/controllers/aero_info_calls.go @@ -346,7 +346,7 @@ func (r *SingleClusterReconciler) setDynamicConfig( return reconcileError(err) } - r.Log.Info("Generated dynamic commands", "commands", fmt.Sprintf("%v", asConfCmds), "pod", podName) + r.Log.Info("Generated dynamic config commands", "commands", fmt.Sprintf("%v", asConfCmds), "pod", podName) if err := deployment.SetConfigCommandsOnHosts(r.Log, r.getClientPolicy(), allHostConns, []*deployment.HostConn{host}, asConfCmds); err != nil { @@ -362,13 +362,13 @@ func (r *SingleClusterReconciler) setDynamicConfig( if patchErr := r.patchPodStatus( context.TODO(), patches, ); patchErr != nil { - return reconcileError(fmt.Errorf("error updating status: %v", patchErr)) + return reconcileError(fmt.Errorf("error updating status: %v, dynamic config command error: %v", patchErr, err)) } return reconcileError(err) } - if err := r.updatePod(podName); err != nil { + if err := r.updateAerospikeConfInPod(podName); err != nil { return reconcileError(err) } } diff --git a/controllers/pod.go b/controllers/pod.go index 698a4dc18..c2e0f9e33 100644 --- a/controllers/pod.go +++ b/controllers/pod.go @@ -112,12 +112,12 @@ func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, return nil, nil, err } - v, err := lib.CompareVersions(version, "7.0.0") + v, err := lib.CompareVersions(version, "6.0.0") if err != nil { return nil, nil, err } - // If version >= 7.0.0, then we can update config dynamically. + // If version >= 6.0.0, then we can update config dynamically. if v >= 0 { // If dynamic commands have failed in previous retry, then we should not try to update config dynamically. if !podStatus.DynamicConfigFailed { @@ -128,7 +128,7 @@ func (r *SingleClusterReconciler) getRollingRestartTypeMap(rackState *RackState, } } } else { - r.Log.Info("Dynamic config change not supported for version < 7.0.0", "currentVersion", version) + r.Log.Info("Dynamic config change not supported for version < 6.0.0", "currentVersion", version) } } @@ -394,14 +394,14 @@ func (r *SingleClusterReconciler) restartPods( return reconcileSuccess() } -func (r *SingleClusterReconciler) updatePod(podName string) error { - r.Log.Info("Updating pod", "pod", podName) +func (r *SingleClusterReconciler) updateAerospikeConfInPod(podName string) error { + r.Log.Info("Updating aerospike config file in pod", "pod", podName) if err := r.restartASDOrUpdateAerospikeConf(podName, noRestartUpdateConf); err != nil { return err } - r.Log.V(1).Info("Pod Updated", "podName", podName) + r.Log.V(1).Info("Updated aerospike config file in pod", "podName", podName) return nil } diff --git a/controllers/rack.go b/controllers/rack.go index 45cd633b0..c442a9c3b 100644 --- a/controllers/rack.go +++ b/controllers/rack.go @@ -397,14 +397,13 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat return found, res } } else { - var needRollingRestartRack, needDynamicUpdateRack, restartTypeMap, - dynamicConfDiffPerPod, nErr = r.needRollingRestartRack(rackState, ignorablePodNames) + var rollingRestartInfo, nErr = r.getRollingRestartInfo(rackState, ignorablePodNames) if nErr != nil { return found, reconcileError(nErr) } - if needRollingRestartRack { - found, res = r.rollingRestartRack(found, rackState, ignorablePodNames, restartTypeMap, failedPods) + if rollingRestartInfo.needRestart { + found, res = r.rollingRestartRack(found, rackState, ignorablePodNames, rollingRestartInfo.restartTypeMap, failedPods) if !res.isSuccess { if res.err != nil { r.Log.Error( @@ -424,8 +423,9 @@ func (r *SingleClusterReconciler) upgradeOrRollingRestartRack(found *appsv1.Stat } } - if len(failedPods) == 0 && needDynamicUpdateRack { - res = r.updateDynamicConfig(rackState, ignorablePodNames, restartTypeMap, dynamicConfDiffPerPod) + if len(failedPods) == 0 && rollingRestartInfo.needUpdateConf { + res = r.updateDynamicConfig(rackState, ignorablePodNames, + rollingRestartInfo.restartTypeMap, rollingRestartInfo.dynamicConfDiffPerPod) if !res.isSuccess { if res.err != nil { r.Log.Error( @@ -469,8 +469,8 @@ func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, r.Log.Info("Update dynamic config in Aerospike pods") r.Recorder.Eventf( - r.aeroCluster, corev1.EventTypeNormal, "RackDynamicUpdate", - "[rack-%d] Started Dynamic update", rackState.Rack.ID, + r.aeroCluster, corev1.EventTypeNormal, "DynamicConfigUpdate", + "[rack-%d] Started dynamic config update", rackState.Rack.ID, ) var ( @@ -504,8 +504,8 @@ func (r *SingleClusterReconciler) updateDynamicConfig(rackState *RackState, } r.Recorder.Eventf( - r.aeroCluster, corev1.EventTypeNormal, "RackDynamicUpdate", - "[rack-%d] Finished Dynamic update", rackState.Rack.ID, + r.aeroCluster, corev1.EventTypeNormal, "DynamicConfigUpdate", + "[rack-%d] Finished Dynamic config update", rackState.Rack.ID, ) return reconcileSuccess() @@ -1215,15 +1215,22 @@ func (r *SingleClusterReconciler) handleK8sNodeBlockListPods(statefulSet *appsv1 return statefulSet, reconcileSuccess() } -func (r *SingleClusterReconciler) needRollingRestartRack(rackState *RackState, ignorablePodNames sets.Set[string]) ( - needRestart, needUpdateConf bool, restartTypeMap map[string]RestartType, - dynamicConfDiffPerPod map[string]asconfig.DynamicConfigMap, err error, +type rollingRestartInfo struct { + restartTypeMap map[string]RestartType + dynamicConfDiffPerPod map[string]asconfig.DynamicConfigMap + needRestart, needUpdateConf bool +} + +func (r *SingleClusterReconciler) getRollingRestartInfo(rackState *RackState, ignorablePodNames sets.Set[string]) ( + info *rollingRestartInfo, err error, ) { - restartTypeMap, dynamicConfDiffPerPod, err = r.getRollingRestartTypeMap(rackState, ignorablePodNames) + restartTypeMap, dynamicConfDiffPerPod, err := r.getRollingRestartTypeMap(rackState, ignorablePodNames) if err != nil { - return needRestart, needUpdateConf, nil, nil, err + return nil, err } + needRestart, needUpdateConf := false, false + for _, restartType := range restartTypeMap { switch restartType { case noRestart: @@ -1235,7 +1242,14 @@ func (r *SingleClusterReconciler) needRollingRestartRack(rackState *RackState, i } } - return needRestart, needUpdateConf, restartTypeMap, dynamicConfDiffPerPod, nil + info = &rollingRestartInfo{ + needRestart: needRestart, + needUpdateConf: needUpdateConf, + restartTypeMap: restartTypeMap, + dynamicConfDiffPerPod: dynamicConfDiffPerPod, + } + + return info, nil } func (r *SingleClusterReconciler) isRackUpgradeNeeded(rackID int, ignorablePodNames sets.Set[string]) ( diff --git a/controllers/reconciler.go b/controllers/reconciler.go index ced438597..0ae486729 100644 --- a/controllers/reconciler.go +++ b/controllers/reconciler.go @@ -463,10 +463,13 @@ func (r *SingleClusterReconciler) updateAccessControlStatus() error { return err } - // AerospikeAccessControl - statusAerospikeAccessControl := lib.DeepCopy( - r.aeroCluster.Spec.AerospikeAccessControl, - ).(*asdbv1.AerospikeAccessControlSpec) + var statusAerospikeAccessControl *asdbv1.AerospikeAccessControlSpec + if r.aeroCluster.Spec.AerospikeAccessControl != nil { + // AerospikeAccessControl + statusAerospikeAccessControl = lib.DeepCopy( + r.aeroCluster.Spec.AerospikeAccessControl, + ).(*asdbv1.AerospikeAccessControlSpec) + } newAeroCluster.Status.AerospikeClusterStatusSpec.AerospikeAccessControl = statusAerospikeAccessControl diff --git a/go.mod b/go.mod index 3b6c6b3ff..df7b4e00c 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 toolchain go1.21.8 require ( - github.com/aerospike/aerospike-management-lib v1.2.1-0.20240325134810-f8046fe9872e + github.com/aerospike/aerospike-management-lib v1.3.1-0.20240404063536-2adfbedf9687 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 diff --git a/go.sum b/go.sum index d5e5f8101..947f1be32 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/aerospike/aerospike-client-go/v7 v7.1.0 h1:yvCTKdbpqZxHvv7sWsFHV1j49j github.com/aerospike/aerospike-client-go/v7 v7.1.0/go.mod h1:AkHiKvCbqa1c16gCNGju3c5X/yzwLVvblNczqjxNwNk= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240325134810-f8046fe9872e h1:Q/AfYe++0ouO5csLS8l99kCQqJJvDKlfHwhuWbECpaQ= github.com/aerospike/aerospike-management-lib v1.2.1-0.20240325134810-f8046fe9872e/go.mod h1:E4dk798IikCp9a8fugpYoeQVIXuvdxogHvt6sKhaORQ= +github.com/aerospike/aerospike-management-lib v1.3.1-0.20240404063536-2adfbedf9687 h1:d7oDvHmiKhq4rzcD/w3z9tP3wH0+iaDvxKDk3IYuqeU= +github.com/aerospike/aerospike-management-lib v1.3.1-0.20240404063536-2adfbedf9687/go.mod h1:E4dk798IikCp9a8fugpYoeQVIXuvdxogHvt6sKhaORQ= 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= diff --git a/test/cluster_test.go b/test/cluster_test.go index 2181b058a..cdb8efaa0 100644 --- a/test/cluster_test.go +++ b/test/cluster_test.go @@ -74,9 +74,68 @@ var _ = Describe( ScaleDownWithMigrateFillDelay(ctx) }, ) + Context( + "UpdateClusterPre600", func() { + UpdateClusterPre600(ctx) + }, + ) }, ) +func UpdateClusterPre600(ctx goctx.Context) { + Context( + "UpdateClusterPre600", func() { + clusterNamespacedName := getNamespacedName( + "deploy-cluster-pre6", namespace, + ) + + BeforeEach( + func() { + image := fmt.Sprintf( + "aerospike/aerospike-server-enterprise:%s", pre6Version, + ) + aeroCluster, err := getAeroClusterConfig( + clusterNamespacedName, image, + ) + Expect(err).ToNot(HaveOccurred()) + + 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( + "UpdateReplicationFactor: should fail for updating namespace replication-factor on server"+ + "before 6.0.0. Cannot be updated", func() { + aeroCluster, err := getCluster(k8sClient, ctx, clusterNamespacedName) + Expect(err).ToNot(HaveOccurred()) + + namespaceConfig := + aeroCluster.Spec.AerospikeConfig.Value["namespaces"].([]interface{})[0].(map[string]interface{}) + namespaceConfig["replication-factor"] = 5 + aeroCluster.Spec.AerospikeConfig.Value["namespaces"].([]interface{})[0] = namespaceConfig + + err = k8sClient.Update( + ctx, aeroCluster, + ) + Expect(err).Should(HaveOccurred()) + }, + ) + }, + ) +} + func ScaleDownWithMigrateFillDelay(ctx goctx.Context) { Context( "ScaleDownWithMigrateFillDelay", func() { @@ -920,6 +979,24 @@ 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 = k8sClient.Update( + ctx, aeroCluster, + ) + Expect(err).ToNot(HaveOccurred()) + By("Scaling up along with modifying Namespace storage Dynamically") err = scaleUpClusterTestWithNSDeviceHandling( @@ -1067,7 +1144,8 @@ func UpdateClusterTest(ctx goctx.Context) { Context( "Namespace", func() { It( - "UpdateReplicationFactor: should fail for updating namespace replication-factor. Cannot be updated", + "UpdateReplicationFactor: should fail for updating namespace"+ + "replication-factor on SC namespace. Cannot be updated", func() { aeroCluster, err := getCluster( k8sClient, ctx, diff --git a/test/services_test.go b/test/services_test.go index c28b0192c..8c80d1329 100644 --- a/test/services_test.go +++ b/test/services_test.go @@ -129,9 +129,7 @@ func createLoadBalancer() *asdbv1.LoadBalancerSpec { ), ) - result := lib.DeepCopy(&lb).(*asdbv1.LoadBalancerSpec) - - return result + return lib.DeepCopy(&lb).(*asdbv1.LoadBalancerSpec) } func loadBalancerName(aeroCluster *asdbv1.AerospikeCluster) types.NamespacedName { From 3ee87e1fae1ae4e3abd46beef71b13db3fa8915d Mon Sep 17 00:00:00 2001 From: Tanmay Jain Date: Wed, 10 Apr 2024 14:17:42 +0530 Subject: [PATCH 20/20] Updating init tag --- api/v1/utils.go | 4 ++-- test/cluster_test.go | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/api/v1/utils.go b/api/v1/utils.go index be7a731b3..f4062b48f 100644 --- a/api/v1/utils.go +++ b/api/v1/utils.go @@ -62,8 +62,8 @@ const ( AerospikeInitContainerName = "aerospike-init" AerospikeInitContainerRegistryEnvVar = "AEROSPIKE_KUBERNETES_INIT_REGISTRY" AerospikeInitContainerDefaultRegistry = "docker.io" - AerospikeInitContainerDefaultRegistryNamespace = "tanmayj10" - AerospikeInitContainerDefaultRepoAndTag = "aerospike-kubernetes-init:2.1.0-dev3" + AerospikeInitContainerDefaultRegistryNamespace = "aerospike" + AerospikeInitContainerDefaultRepoAndTag = "aerospike-kubernetes-init:2.2.0-dev2" AerospikeAppLabel = "app" AerospikeCustomResourceLabel = "aerospike.com/cr" AerospikeRackIDLabel = "aerospike.com/rack-id" diff --git a/test/cluster_test.go b/test/cluster_test.go index cdb8efaa0..28cd1ef25 100644 --- a/test/cluster_test.go +++ b/test/cluster_test.go @@ -992,9 +992,7 @@ func UpdateClusterTest(ctx goctx.Context) { namespaceConfig["replication-factor"] = 3 aeroCluster.Spec.AerospikeConfig.Value["namespaces"].([]interface{})[len(nsList)-1] = namespaceConfig - err = k8sClient.Update( - ctx, aeroCluster, - ) + err = updateCluster(k8sClient, ctx, aeroCluster) Expect(err).ToNot(HaveOccurred()) By("Scaling up along with modifying Namespace storage Dynamically")