...

Source file src/github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder/annotations.go

Documentation: github.com/chaos-mesh/chaos-mesh/controllers/utils/recorder

     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 recorder
    17  
    18  import (
    19  	"encoding"
    20  	"encoding/json"
    21  	"errors"
    22  	"reflect"
    23  	"strconv"
    24  
    25  	"github.com/iancoleman/strcase"
    26  )
    27  
    28  var ErrInvalidType = errors.New("invalid type of fields")
    29  var ErrUknownType = errors.New("uknown type of fields")
    30  
    31  var annotationPrefix = "chaos-mesh.org/"
    32  
    33  func generateAnnotations(e ChaosEvent) (map[string]string, error) {
    34  	annotations := make(map[string]string)
    35  
    36  	if e == nil {
    37  		return annotations, nil
    38  	}
    39  
    40  	val := reflect.ValueOf(e)
    41  	val = reflect.Indirect(val)
    42  	for index := 0; index < val.NumField(); index++ {
    43  		fieldName := val.Type().Field(index).Name
    44  		key := annotationPrefix + strcase.ToKebab(fieldName)
    45  		field := val.Field(index)
    46  		switch field.Kind() {
    47  		case reflect.Invalid:
    48  			return nil, ErrInvalidType
    49  		case reflect.String:
    50  			annotations[key] = field.String()
    51  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    52  			annotations[key] = strconv.Itoa(int(field.Int()))
    53  		default:
    54  			if marshaler, ok := field.Interface().(encoding.TextMarshaler); ok {
    55  				text, err := marshaler.MarshalText()
    56  				if err != nil {
    57  					return nil, err
    58  				}
    59  
    60  				annotations[key] = string(text)
    61  			} else {
    62  				text, err := json.Marshal(field.Interface())
    63  				if err != nil {
    64  					return nil, err
    65  				}
    66  				annotations[key] = string(text)
    67  			}
    68  		}
    69  	}
    70  	annotations[annotationPrefix+"type"] = strcase.ToKebab(val.Type().Name())
    71  
    72  	return annotations, nil
    73  }
    74  
    75  // FromAnnotations will iterate over all the registered event,
    76  // return `nil` if there is no suitable event.
    77  func FromAnnotations(annotations map[string]string) (ChaosEvent, error) {
    78  	typeName := annotations[annotationPrefix+"type"]
    79  	ev := allEvents[typeName]
    80  
    81  	if ev == nil {
    82  		return nil, ErrUknownType
    83  	}
    84  
    85  	val := reflect.ValueOf(ev)
    86  	val = reflect.Indirect(val)
    87  	newEmptyValue := reflect.Indirect(reflect.New(val.Type()))
    88  
    89  	for index := 0; index < newEmptyValue.NumField(); index++ {
    90  		fieldName := newEmptyValue.Type().Field(index).Name
    91  		key := annotationPrefix + strcase.ToKebab(fieldName)
    92  		field := newEmptyValue.Field(index)
    93  		switch field.Kind() {
    94  		case reflect.Invalid:
    95  			return nil, ErrInvalidType
    96  		case reflect.String:
    97  			field.SetString(annotations[key])
    98  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    99  			num, err := strconv.Atoi(annotations[key])
   100  			if err != nil {
   101  				return nil, err
   102  			}
   103  			field.SetInt(int64(num))
   104  		default:
   105  			if unmarshaler, ok := field.Interface().(encoding.TextUnmarshaler); ok {
   106  				err := unmarshaler.UnmarshalText([]byte(annotations[key]))
   107  				if err != nil {
   108  					return nil, err
   109  				}
   110  			} else if unmarshaler, ok := field.Addr().Interface().(encoding.TextUnmarshaler); ok {
   111  				err := unmarshaler.UnmarshalText([]byte(annotations[key]))
   112  				if err != nil {
   113  					return nil, err
   114  				}
   115  			} else {
   116  				err := json.Unmarshal([]byte(annotations[key]), field.Addr().Interface())
   117  				if err != nil {
   118  					return nil, err
   119  				}
   120  			}
   121  		}
   122  	}
   123  	return newEmptyValue.Interface().(ChaosEvent), nil
   124  }
   125