1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package v1alpha1
17
18 import (
19 "fmt"
20 "reflect"
21 "strconv"
22 "time"
23
24 "k8s.io/apimachinery/pkg/api/meta"
25 "k8s.io/apimachinery/pkg/util/validation/field"
26
27 "github.com/chaos-mesh/chaos-mesh/api/genericwebhook"
28 )
29
30 const (
31
32 ValidateValueParseError = "parse value field error:%s"
33 )
34
35
36
37
38 type ContainsDuration interface {
39 GetDuration() (*time.Duration, error)
40 }
41
42 type Duration string
43
44 func (d *Duration) Validate(root interface{}, path *field.Path) field.ErrorList {
45 if d == nil {
46 return nil
47 }
48
49 if len(*d) == 0 {
50
51
52 return nil
53 }
54
55 _, err := time.ParseDuration(string(*d))
56 if err != nil {
57 return field.ErrorList{
58 field.Invalid(path, d, fmt.Sprintf("parse duration field error: %s", err.Error())),
59 }
60 }
61
62 return nil
63 }
64
65 func (d *Duration) Default(root interface{}, field *reflect.StructField) {
66 if d == nil {
67 return
68 }
69
70
71 if len(*d) == 0 && field != nil {
72 *d = Duration(field.Tag.Get("default"))
73 }
74 }
75
76 func (p *PodSelector) Validate(root interface{}, path *field.Path) field.ErrorList {
77 allErrs := field.ErrorList{}
78
79 if p == nil {
80 return nil
81 }
82
83 mode := p.Mode
84 value := p.Value
85 valueField := path.Child("value")
86
87 switch mode {
88 case FixedMode:
89 num, err := strconv.Atoi(value)
90 if err != nil {
91 allErrs = append(allErrs, field.Invalid(valueField, value,
92 fmt.Sprintf(ValidateValueParseError, err)))
93 break
94 }
95
96 if num <= 0 {
97 allErrs = append(allErrs, field.Invalid(valueField, value,
98 fmt.Sprintf("value must be greater than 0 with mode:%s", FixedMode)))
99 }
100
101 case RandomMaxPercentMode, FixedPercentMode:
102 percentage, err := strconv.Atoi(value)
103 if err != nil {
104 allErrs = append(allErrs, field.Invalid(valueField, value,
105 fmt.Sprintf(ValidateValueParseError, err)))
106 break
107 }
108
109 if percentage <= 0 || percentage > 100 {
110 allErrs = append(allErrs, field.Invalid(valueField, value,
111 fmt.Sprintf("value of %d is invalid, Must be (0,100] with mode:%s",
112 percentage, mode)))
113 }
114 }
115
116 return allErrs
117 }
118
119 func (p *PodSelector) Default(root interface{}, field *reflect.StructField) {
120 if p == nil {
121 return
122 }
123
124 metaData, err := meta.Accessor(root)
125 if err != nil {
126 return
127 }
128
129 if len(p.Selector.Namespaces) == 0 {
130 p.Selector.Namespaces = []string{metaData.GetNamespace()}
131 }
132 }
133
134 type Percent int
135
136 type FloatStr string
137
138 func (p *Percent) Validate(root interface{}, path *field.Path) field.ErrorList {
139 if p == nil {
140 return nil
141 }
142
143 allErrs := field.ErrorList{}
144
145 if *p > 100 || *p < 0 {
146 allErrs = append(allErrs, field.Invalid(path, p,
147 "percent field should be in 0-100"))
148 }
149
150 return allErrs
151 }
152
153 func (f *FloatStr) Validate(root interface{}, path *field.Path) field.ErrorList {
154 if f == nil {
155 return nil
156 }
157
158 _, err := strconv.ParseFloat(string(*f), 32)
159 if err != nil {
160 return field.ErrorList{
161 field.Invalid(path, f,
162 fmt.Sprintf("parse correlation field error:%s", err.Error())),
163 }
164 }
165
166 return nil
167 }
168
169 func (f *FloatStr) Default(root interface{}, field *reflect.StructField) {
170
171 if len(*f) == 0 && field != nil {
172 *f = FloatStr(field.Tag.Get("default"))
173 }
174 }
175
176 func init() {
177 genericwebhook.Register("Duration", reflect.PtrTo(reflect.TypeOf(Duration(""))))
178 genericwebhook.Register("Percent", reflect.PtrTo(reflect.TypeOf(Percent(0))))
179 genericwebhook.Register("FloatStr", reflect.PtrTo(reflect.TypeOf(FloatStr(""))))
180 }
181