Skip to content

Commit

Permalink
Merge branch 'master' into KO-360
Browse files Browse the repository at this point in the history
  • Loading branch information
abhishekdwivedi3060 committed Jan 21, 2025
2 parents b07a5f2 + 6915cb1 commit a5c6126
Show file tree
Hide file tree
Showing 40 changed files with 1,339 additions and 775 deletions.
38 changes: 26 additions & 12 deletions api/v1/aerospikecluster_mutating_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,14 @@ func (c *AerospikeCluster) Default(operation v1.Operation) admission.Response {
c.Spec,
)

if err := c.setDefaults(asLog); err != nil {
var (
warn admission.Warnings
err error
)

if warn, err = c.setDefaults(asLog); err != nil {
asLog.Error(err, "Mutate AerospikeCluster create failed")
return webhook.Denied(err.Error())
return webhook.Denied(err.Error()).WithWarnings(warn...)
}

asLog.Info("Setting defaults for aerospikeCluster completed")
Expand All @@ -67,12 +72,19 @@ func (c *AerospikeCluster) Default(operation v1.Operation) admission.Response {
return webhook.Patched(
"Patched aerospike spec with defaults",
patches...,
)
).WithWarnings(warn...)
}

func (c *AerospikeCluster) setDefaults(asLog logr.Logger) error {
// Set maxUnavailable default to 1
if !GetBool(c.Spec.DisablePDB) && c.Spec.MaxUnavailable == nil {
func (c *AerospikeCluster) setDefaults(asLog logr.Logger) (admission.Warnings, error) {
var warn admission.Warnings
// If PDB is disabled, set maxUnavailable to nil
if GetBool(c.Spec.DisablePDB) {
c.Spec.MaxUnavailable = nil

warn = append(warn, fmt.Sprintf("Spec field 'spec.maxUnavailable' will be omitted from Custom Resource (CR) "+
"because 'spec.disablePDB' is true."))
} else if c.Spec.MaxUnavailable == nil {
// Set default maxUnavailable if not set
maxUnavailable := intstr.FromInt32(1)
c.Spec.MaxUnavailable = &maxUnavailable
}
Expand All @@ -87,26 +99,28 @@ func (c *AerospikeCluster) setDefaults(asLog logr.Logger) error {
// Need to set before setting defaults in aerospikeConfig.
// aerospikeConfig.namespace checks for racks
if err := c.setDefaultRackConf(asLog); err != nil {
return err
return warn, err
}

if c.Spec.AerospikeConfig == nil {
return fmt.Errorf("spec.aerospikeConfig cannot be nil")
return warn, fmt.Errorf("spec.aerospikeConfig cannot be nil")
}

// Set common aerospikeConfig defaults
// Update configMap
if err := c.setDefaultAerospikeConfigs(asLog, *c.Spec.AerospikeConfig, nil); err != nil {
return err
return warn, err
}

// Update racks configuration using global values where required.
if err := c.updateRacks(asLog); err != nil {
return err
return warn, err
}

// Set defaults for pod spec
c.Spec.PodSpec.SetDefaults()
if err := c.Spec.PodSpec.SetDefaults(); err != nil {
return warn, err
}

// Validation policy
if c.Spec.ValidationPolicy == nil {
Expand All @@ -133,7 +147,7 @@ func (c *AerospikeCluster) setDefaults(asLog logr.Logger) error {
c.Labels[AerospikeAPIVersionLabel] = AerospikeAPIVersion
}

return nil
return warn, nil
}

// SetDefaults applies defaults to the pod spec.
Expand Down
16 changes: 9 additions & 7 deletions api/v1/aerospikecluster_validating_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -2298,17 +2298,19 @@ func validateIntOrStringField(value *intstr.IntOrString, fieldPath string) error
}

func (c *AerospikeCluster) validateMaxUnavailable() error {
// safe check for corner cases when mutation webhook somehow didn't work
if !GetBool(c.Spec.DisablePDB) && c.Spec.MaxUnavailable == nil {
return fmt.Errorf("maxUnavailable cannot be nil if PDB is not disabled. Mutation webhook didn't work")
}

if GetBool(c.Spec.DisablePDB) {
// safe checks for corner cases when mutation webhook somehow didn't work
if !GetBool(c.Spec.DisablePDB) {
// Ensure maxUnavailable is set when PDB is enabled
if c.Spec.MaxUnavailable == nil {
return fmt.Errorf("maxUnavailable cannot be nil if PDB is not disabled. Mutation webhook might not have worked")
}
} else {
// Ensure maxUnavailable is unset when PDB is disabled
if c.Spec.MaxUnavailable != nil {
return fmt.Errorf("maxUnavailable must be nil if PDB is disabled")
}

// PDB is disabled, so no need to validate further
// PDB is disabled, no further validation required
return nil
}

Expand Down
3 changes: 1 addition & 2 deletions api/v1/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import (
"regexp"
"strings"

"k8s.io/apimachinery/pkg/util/sets"

v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/utils/ptr"

internalerrors "github.com/aerospike/aerospike-kubernetes-operator/errors"
Expand Down
127 changes: 51 additions & 76 deletions api/v1beta1/aerospikebackup_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,20 @@ limitations under the License.
package v1beta1

import (
"context"
"fmt"
"reflect"
"strings"

"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
utilRuntime "k8s.io/apimachinery/pkg/util/runtime"
clientGoScheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
"sigs.k8s.io/yaml"

"github.com/aerospike/aerospike-backup-service/pkg/model"
asdbv1 "github.com/aerospike/aerospike-kubernetes-operator/api/v1"
"github.com/aerospike/aerospike-kubernetes-operator/internal/controller/common"
"github.com/aerospike/aerospike-backup-service/v3/pkg/dto"
"github.com/aerospike/aerospike-backup-service/v3/pkg/validation"
)

func (r *AerospikeBackup) SetupWebhookWithManager(mgr ctrl.Manager) error {
Expand Down Expand Up @@ -65,12 +60,12 @@ func (r *AerospikeBackup) ValidateCreate() (admission.Warnings, error) {

abLog.Info("Validate create")

if len(r.Spec.OnDemandBackups) != 0 {
return nil, fmt.Errorf("onDemand backups config cannot be specified while creating backup")
if err := r.validate(); err != nil {
return nil, err
}

if err := r.validateBackupConfig(); err != nil {
return nil, err
if len(r.Spec.OnDemandBackups) != 0 {
return nil, fmt.Errorf("onDemand backups config cannot be specified while creating backup")
}

return nil, nil
Expand All @@ -88,7 +83,7 @@ func (r *AerospikeBackup) ValidateUpdate(old runtime.Object) (admission.Warnings
return nil, fmt.Errorf("backup service cannot be updated")
}

if err := r.validateBackupConfig(); err != nil {
if err := r.validate(); err != nil {
return nil, err
}

Expand All @@ -103,6 +98,22 @@ func (r *AerospikeBackup) ValidateUpdate(old runtime.Object) (admission.Warnings
return nil, nil
}

func (r *AerospikeBackup) validate() error {
k8sClient, gErr := getK8sClient()
if gErr != nil {
return gErr
}

if err := ValidateBackupSvcSupportedVersion(k8sClient,
r.Spec.BackupService.Name,
r.Spec.BackupService.Namespace,
); err != nil {
return err
}

return r.validateBackupConfig(k8sClient)
}

// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
func (r *AerospikeBackup) ValidateDelete() (admission.Warnings, error) {
abLog := logf.Log.WithName(namespacedName(r))
Expand All @@ -113,45 +124,32 @@ func (r *AerospikeBackup) ValidateDelete() (admission.Warnings, error) {
return nil, nil
}

func (r *AerospikeBackup) validateBackupConfig() error {
func (r *AerospikeBackup) validateBackupConfig(k8sClient client.Client) error {
backupConfig := make(map[string]interface{})

if err := yaml.Unmarshal(r.Spec.Config.Raw, &backupConfig); err != nil {
return err
}

if _, ok := backupConfig[common.ServiceKey]; ok {
if _, ok := backupConfig[ServiceKey]; ok {
return fmt.Errorf("service field cannot be specified in backup config")
}

if _, ok := backupConfig[common.BackupPoliciesKey]; ok {
if _, ok := backupConfig[BackupPoliciesKey]; ok {
return fmt.Errorf("backup-policies field cannot be specified in backup config")
}

if _, ok := backupConfig[common.StorageKey]; ok {
if _, ok := backupConfig[StorageKey]; ok {
return fmt.Errorf("storage field cannot be specified in backup config")
}

if _, ok := backupConfig[common.SecretAgentsKey]; ok {
if _, ok := backupConfig[SecretAgentsKey]; ok {
return fmt.Errorf("secret-agent field cannot be specified in backup config")
}

var backupSvc AerospikeBackupService

cl, gErr := getK8sClient()
if gErr != nil {
return gErr
}

if err := cl.Get(context.TODO(),
types.NamespacedName{Name: r.Spec.BackupService.Name, Namespace: r.Spec.BackupService.Namespace},
&backupSvc); err != nil {
return err
}

var backupSvcConfig model.Config

if err := yaml.UnmarshalStrict(backupSvc.Spec.Config.Raw, &backupSvcConfig); err != nil {
backupSvcConfig, err := getBackupServiceFullConfig(k8sClient, r.Spec.BackupService.Name,
r.Spec.BackupService.Namespace)
if err != nil {
return err
}

Expand All @@ -165,7 +163,7 @@ func (r *AerospikeBackup) validateBackupConfig() error {
return err
}

err = updateValidateBackupSvcConfig(aeroClusters, backupRoutines, &backupSvcConfig)
err = updateValidateBackupSvcConfig(aeroClusters, backupRoutines, backupSvcConfig)
if err != nil {
return err
}
Expand All @@ -181,32 +179,13 @@ func (r *AerospikeBackup) validateBackupConfig() error {
return nil
}

func getK8sClient() (client.Client, error) {
restConfig := ctrl.GetConfigOrDie()

scheme := runtime.NewScheme()

utilRuntime.Must(asdbv1.AddToScheme(scheme))
utilRuntime.Must(clientGoScheme.AddToScheme(scheme))
utilRuntime.Must(AddToScheme(scheme))

cl, err := client.New(restConfig, client.Options{
Scheme: scheme,
})
if err != nil {
return nil, err
}

return cl, nil
}

func (r *AerospikeBackup) getValidatedAerospikeClusters(backupConfig map[string]interface{},
) (map[string]*model.AerospikeCluster, error) {
if _, ok := backupConfig[common.AerospikeClusterKey]; !ok {
) (map[string]*dto.AerospikeCluster, error) {
if _, ok := backupConfig[AerospikeClusterKey]; !ok {
return nil, fmt.Errorf("aerospike-cluster field is required field in backup config")
}

cluster, ok := backupConfig[common.AerospikeClusterKey].(map[string]interface{})
cluster, ok := backupConfig[AerospikeClusterKey].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("aerospike-cluster field is not in the right format")
}
Expand All @@ -216,7 +195,7 @@ func (r *AerospikeBackup) getValidatedAerospikeClusters(backupConfig map[string]
return nil, cErr
}

aeroClusters := make(map[string]*model.AerospikeCluster)
aeroClusters := make(map[string]*dto.AerospikeCluster)

if err := yaml.UnmarshalStrict(clusterBytes, &aeroClusters); err != nil {
return nil, err
Expand Down Expand Up @@ -272,8 +251,8 @@ func (r *AerospikeBackup) validateAerospikeClusterUpdate(oldObj *AerospikeBackup
return err
}

oldCluster := oldObjConfig[common.AerospikeClusterKey].(map[string]interface{})
newCluster := currentConfig[common.AerospikeClusterKey].(map[string]interface{})
oldCluster := oldObjConfig[AerospikeClusterKey].(map[string]interface{})
newCluster := currentConfig[AerospikeClusterKey].(map[string]interface{})

for clusterName := range newCluster {
if _, ok := oldCluster[clusterName]; !ok {
Expand All @@ -286,13 +265,13 @@ func (r *AerospikeBackup) validateAerospikeClusterUpdate(oldObj *AerospikeBackup

func (r *AerospikeBackup) getValidatedBackupRoutines(
backupConfig map[string]interface{},
aeroClusters map[string]*model.AerospikeCluster,
) (map[string]*model.BackupRoutine, error) {
if _, ok := backupConfig[common.BackupRoutinesKey]; !ok {
aeroClusters map[string]*dto.AerospikeCluster,
) (map[string]*dto.BackupRoutine, error) {
if _, ok := backupConfig[BackupRoutinesKey]; !ok {
return nil, fmt.Errorf("backup-routines field is required in backup config")
}

routines, ok := backupConfig[common.BackupRoutinesKey].(map[string]interface{})
routines, ok := backupConfig[BackupRoutinesKey].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("backup-routines field is not in the right format")
}
Expand All @@ -302,7 +281,7 @@ func (r *AerospikeBackup) getValidatedBackupRoutines(
return nil, rErr
}

backupRoutines := make(map[string]*model.BackupRoutine)
backupRoutines := make(map[string]*dto.BackupRoutine)

if err := yaml.UnmarshalStrict(routineBytes, &backupRoutines); err != nil {
return nil, err
Expand All @@ -329,40 +308,36 @@ func (r *AerospikeBackup) getValidatedBackupRoutines(
}

func updateValidateBackupSvcConfig(
clusters map[string]*model.AerospikeCluster,
routines map[string]*model.BackupRoutine,
backupSvcConfig *model.Config,
clusters map[string]*dto.AerospikeCluster,
routines map[string]*dto.BackupRoutine,
backupSvcConfig *dto.Config,
) error {
if len(backupSvcConfig.AerospikeClusters) == 0 {
backupSvcConfig.AerospikeClusters = make(map[string]*model.AerospikeCluster)
backupSvcConfig.AerospikeClusters = make(map[string]*dto.AerospikeCluster)
}

for name, cluster := range clusters {
backupSvcConfig.AerospikeClusters[name] = cluster
}

if len(backupSvcConfig.BackupRoutines) == 0 {
backupSvcConfig.BackupRoutines = make(map[string]*model.BackupRoutine)
backupSvcConfig.BackupRoutines = make(map[string]*dto.BackupRoutine)
}

for name, routine := range routines {
backupSvcConfig.BackupRoutines[name] = routine
}

// Add empty placeholders for missing backupSvcConfig sections. This is required for validation to work.
if backupSvcConfig.ServiceConfig == nil {
backupSvcConfig.ServiceConfig = &model.BackupServiceConfig{}
}

if backupSvcConfig.ServiceConfig.HTTPServer == nil {
backupSvcConfig.ServiceConfig.HTTPServer = &model.HTTPServerConfig{}
backupSvcConfig.ServiceConfig.HTTPServer = &dto.HTTPServerConfig{}
}

if backupSvcConfig.ServiceConfig.Logger == nil {
backupSvcConfig.ServiceConfig.Logger = &model.LoggerConfig{}
backupSvcConfig.ServiceConfig.Logger = &dto.LoggerConfig{}
}

return backupSvcConfig.Validate()
return validation.ValidateConfiguration(backupSvcConfig)
}

func (r *AerospikeBackup) NamePrefix() string {
Expand Down
Loading

0 comments on commit a5c6126

Please sign in to comment.