...

Source file src/github.com/chaos-mesh/chaos-mesh/api/genericwebhook/defaulter.go

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

     1  // Copyright 2021 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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package genericwebhook
    17  
    18  import (
    19  	"reflect"
    20  	"strings"
    21  
    22  	"k8s.io/apimachinery/pkg/util/validation/field"
    23  )
    24  
    25  type Defaulter interface {
    26  	Default(root interface{}, field *reflect.StructField)
    27  }
    28  
    29  // Default would walk through all the fields of target struct recursively, and set the default value which declared with struct tag "default".
    30  //
    31  // Parameter obj should be a pointer to a data struct.
    32  //
    33  // Default should return an empty field.ErrorList.
    34  func Default(obj interface{}) field.ErrorList {
    35  	// TODO: how to resolve invalid input, for example: obj is a pointer to pointer
    36  	errorList := field.ErrorList{}
    37  
    38  	root := obj
    39  	walker := NewFieldWalker(obj, func(path *field.Path, obj interface{}, field *reflect.StructField) bool {
    40  		webhookAttr := ""
    41  		if field != nil {
    42  			webhookAttr = field.Tag.Get("webhook")
    43  		}
    44  		attributes := strings.Split(webhookAttr, ",")
    45  
    46  		webhook := ""
    47  		nilable := false
    48  		if len(attributes) > 0 {
    49  			webhook = attributes[0]
    50  		}
    51  		if len(attributes) > 1 {
    52  			nilable = attributes[1] == "nilable"
    53  		}
    54  
    55  		defaulter := getDefaulter(obj, webhook, nilable)
    56  		if defaulter != nil {
    57  			defaulter.Default(root, field)
    58  		}
    59  
    60  		return true
    61  	})
    62  	walker.Walk()
    63  
    64  	return errorList
    65  }
    66  
    67  func getDefaulter(obj interface{}, webhook string, nilable bool) Defaulter {
    68  	// There are two possible situations:
    69  	// 1. The field is a value (int, string, normal struct, etc), and the obj is the reference of it.
    70  	// 2. The field is a pointer to a value or a slice, then the obj is itself.
    71  
    72  	val := reflect.ValueOf(obj)
    73  
    74  	if defaulter, ok := obj.(Defaulter); ok {
    75  		if nilable || !val.IsZero() {
    76  			return defaulter
    77  		}
    78  	}
    79  
    80  	if webhook != "" {
    81  		webhookImpl := webhooks[webhook]
    82  
    83  		v := val.Convert(webhookImpl).Interface()
    84  		if defaulter, ok := v.(Defaulter); ok {
    85  			if nilable || !val.IsZero() {
    86  				return defaulter
    87  			}
    88  		}
    89  	}
    90  
    91  	return nil
    92  }
    93