...

Source file src/github.com/chaos-mesh/chaos-mesh/api/v1alpha1/common_validation.go

Documentation: github.com/chaos-mesh/chaos-mesh/api/v1alpha1

     1  // Copyright 2020 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package v1alpha1
    15  
    16  import (
    17  	"fmt"
    18  	"strconv"
    19  	"time"
    20  
    21  	cronv3 "github.com/robfig/cron/v3"
    22  
    23  	"k8s.io/apimachinery/pkg/util/validation/field"
    24  )
    25  
    26  const (
    27  	// ValidateSchedulerError defines the error message for ValidateScheduler
    28  	ValidateSchedulerError = "schedule and duration should be omitted or defined at the same time"
    29  
    30  	// ValidatePodchaosSchedulerError defines the error message for ValidateScheduler of Podchaos
    31  	ValidatePodchaosSchedulerError = "schedule should be omitted"
    32  
    33  	// ValidateValueParseError defines the error message for value parse error
    34  	ValidateValueParseError = "parse value field error:%s"
    35  )
    36  
    37  // ValidateScheduler validates the InnerSchedulerObject
    38  func ValidateScheduler(schedulerObject InnerSchedulerObject, spec *field.Path) field.ErrorList {
    39  
    40  	allErrs := field.ErrorList{}
    41  
    42  	schedulerField := spec.Child("scheduler")
    43  	durationField := spec.Child("duration")
    44  	duration, err := schedulerObject.GetDuration()
    45  	if err != nil {
    46  		allErrs = append(allErrs, field.Invalid(durationField, nil,
    47  			fmt.Sprintf("parse duration field error:%s", err)))
    48  	}
    49  
    50  	scheduler := schedulerObject.GetScheduler()
    51  
    52  	if duration != nil && scheduler != nil {
    53  		errs := validateSchedulerParams(duration, durationField, scheduler, schedulerField)
    54  		if len(errs) != 0 {
    55  			allErrs = append(allErrs, errs...)
    56  		}
    57  	} else if (duration == nil && scheduler != nil) || (duration != nil && scheduler == nil) {
    58  		allErrs = append(allErrs, field.Invalid(schedulerField, scheduler, ValidateSchedulerError))
    59  	}
    60  	return allErrs
    61  }
    62  
    63  func validateSchedulerParams(duration *time.Duration, durationField *field.Path, spec *SchedulerSpec, schedulerField *field.Path) field.ErrorList {
    64  	allErrs := field.ErrorList{}
    65  	if duration != nil && spec != nil {
    66  		cronField := schedulerField.Child("cron")
    67  		_, err := ParseCron(spec.Cron, cronField)
    68  		if len(err) != 0 {
    69  			allErrs = append(allErrs, err...)
    70  		}
    71  	}
    72  	return allErrs
    73  }
    74  
    75  // ParseCron returns a new crontab schedule representing the given standardSpec (https://en.wikipedia.org/wiki/Cron)
    76  func ParseCron(standardSpec string, cronField *field.Path) (cronv3.Schedule, field.ErrorList) {
    77  	allErrs := field.ErrorList{}
    78  	scheduler, err := cronv3.ParseStandard(standardSpec)
    79  	if err != nil {
    80  		allErrs = append(allErrs, field.Invalid(cronField, standardSpec,
    81  			fmt.Sprintf("parse cron field error:%s", err)))
    82  	}
    83  	return scheduler, allErrs
    84  }
    85  
    86  // ValidatePodMode validates the value with podmode
    87  func ValidatePodMode(value string, mode PodMode, valueField *field.Path) field.ErrorList {
    88  	allErrs := field.ErrorList{}
    89  
    90  	switch mode {
    91  	case FixedPodMode:
    92  		num, err := strconv.Atoi(value)
    93  		if err != nil {
    94  			allErrs = append(allErrs, field.Invalid(valueField, value,
    95  				fmt.Sprintf(ValidateValueParseError, err)))
    96  			break
    97  		}
    98  
    99  		if num <= 0 {
   100  			allErrs = append(allErrs, field.Invalid(valueField, value,
   101  				fmt.Sprintf("value must be greater than 0 with mode:%s", FixedPodMode)))
   102  		}
   103  
   104  	case RandomMaxPercentPodMode, FixedPercentPodMode:
   105  		percentage, err := strconv.Atoi(value)
   106  		if err != nil {
   107  			allErrs = append(allErrs, field.Invalid(valueField, value,
   108  				fmt.Sprintf(ValidateValueParseError, err)))
   109  			break
   110  		}
   111  
   112  		if percentage <= 0 || percentage > 100 {
   113  			allErrs = append(allErrs, field.Invalid(valueField, value,
   114  				fmt.Sprintf("value of %d is invalid, Must be (0,100] with mode:%s",
   115  					percentage, mode)))
   116  		}
   117  	}
   118  
   119  	return allErrs
   120  }
   121