...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package main
17
18 import (
19 "bytes"
20 "text/template"
21 )
22
23 const implImport = `
24 import (
25 "encoding/json"
26 "reflect"
27 "time"
28 "fmt"
29
30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 "sigs.k8s.io/controller-runtime/pkg/webhook"
32 logf "sigs.k8s.io/controller-runtime/pkg/log"
33 "k8s.io/apimachinery/pkg/runtime"
34
35 gw "github.com/chaos-mesh/chaos-mesh/api/v1alpha1/genericwebhook"
36 )
37
38 // updating spec of a chaos will have no effect, we'd better reject it
39 var ErrCanNotUpdateChaos = fmt.Errorf("Cannot update chaos spec")
40 `
41
42 const implTemplate = `
43 const Kind{{.Type}} = "{{.Type}}"
44 {{if .IsExperiment}}
45 // IsDeleted returns whether this resource has been deleted
46 func (in *{{.Type}}) IsDeleted() bool {
47 return !in.DeletionTimestamp.IsZero()
48 }
49
50 // IsPaused returns whether this resource has been paused
51 func (in *{{.Type}}) IsPaused() bool {
52 if in.Annotations == nil || in.Annotations[PauseAnnotationKey] != "true" {
53 return false
54 }
55 return true
56 }
57
58 // GetObjectMeta would return the ObjectMeta for chaos
59 func (in *{{.Type}}) GetObjectMeta() *metav1.ObjectMeta {
60 return &in.ObjectMeta
61 }
62
63 // GetDuration would return the duration for chaos
64 func (in *{{.Type}}Spec) GetDuration() (*time.Duration, error) {
65 if in.Duration == nil {
66 return nil, nil
67 }
68 duration, err := time.ParseDuration(string(*in.Duration))
69 if err != nil {
70 return nil, err
71 }
72 return &duration, nil
73 }
74
75 // GetStatus returns the status
76 func (in *{{.Type}}) GetStatus() *ChaosStatus {
77 return &in.Status.ChaosStatus
78 }
79
80 // GetSpecAndMetaString returns a string including the meta and spec field of this chaos object.
81 func (in *{{.Type}}) GetSpecAndMetaString() (string, error) {
82 spec, err := json.Marshal(in.Spec)
83 if err != nil {
84 return "", err
85 }
86
87 meta := in.ObjectMeta.DeepCopy()
88 meta.SetResourceVersion("")
89 meta.SetGeneration(0)
90
91 return string(spec) + meta.String(), nil
92 }
93
94 // +kubebuilder:object:root=true
95
96 // {{.Type}}List contains a list of {{.Type}}
97 type {{.Type}}List struct {
98 metav1.TypeMeta ` + "`" + `json:",inline"` + "`" + `
99 metav1.ListMeta ` + "`" + `json:"metadata,omitempty"` + "`" + `
100 Items []{{.Type}} ` + "`" + `json:"items"` + "`" + `
101 }
102
103 func (in *{{.Type}}List) DeepCopyList() GenericChaosList {
104 return in.DeepCopy()
105 }
106
107 // ListChaos returns a list of chaos
108 func (in *{{.Type}}List) ListChaos() []GenericChaos {
109 var result []GenericChaos
110 for _, item := range in.Items {
111 item := item
112 result = append(result, &item)
113 }
114 return result
115 }
116
117 func (in *{{.Type}}) DurationExceeded(now time.Time) (bool, time.Duration, error) {
118 duration, err := in.Spec.GetDuration()
119 if err != nil {
120 return false, 0, err
121 }
122
123 if duration != nil {
124 stopTime := in.GetCreationTimestamp().Add(*duration)
125 if stopTime.Before(now) {
126 return true, 0, nil
127 }
128
129 return false, stopTime.Sub(now), nil
130 }
131
132 return false, 0, nil
133 }
134
135 func (in *{{.Type}}) IsOneShot() bool {
136 {{- if .OneShotExp}}
137 if {{.OneShotExp}} {
138 return true
139 }
140
141 return false
142 {{- else}}
143 return false
144 {{- end}}
145 }
146 {{end}}
147 var {{.Type}}WebhookLog = logf.Log.WithName("{{.Type}}-resource")
148
149 func (in *{{.Type}}) ValidateCreate() error {
150 {{.Type}}WebhookLog.Info("validate create", "name", in.Name)
151 return in.Validate()
152 }
153
154 // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
155 func (in *{{.Type}}) ValidateUpdate(old runtime.Object) error {
156 {{.Type}}WebhookLog.Info("validate update", "name", in.Name)
157 {{- if not .EnableUpdate}}
158 if !reflect.DeepEqual(in.Spec, old.(*{{.Type}}).Spec) {
159 return ErrCanNotUpdateChaos
160 }
161 {{- end}}
162 return in.Validate()
163 }
164
165 // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
166 func (in *{{.Type}}) ValidateDelete() error {
167 {{.Type}}WebhookLog.Info("validate delete", "name", in.Name)
168
169 // Nothing to do?
170 return nil
171 }
172
173 var _ webhook.Validator = &{{.Type}}{}
174
175 func (in *{{.Type}}) Validate() error {
176 errs := gw.Validate(in)
177 return gw.Aggregate(errs)
178 }
179
180 var _ webhook.Defaulter = &{{.Type}}{}
181
182 func (in *{{.Type}}) Default() {
183 gw.Default(in)
184 }
185 `
186
187 func generateImpl(name string, oneShotExp string, isExperiment, enableUpdate bool) string {
188 tmpl, err := template.New("impl").Parse(implTemplate)
189 if err != nil {
190 log.Error(err, "fail to build template")
191 return ""
192 }
193
194 buf := new(bytes.Buffer)
195 err = tmpl.Execute(buf, &metadata{
196 Type: name,
197 OneShotExp: oneShotExp,
198 IsExperiment: isExperiment,
199 EnableUpdate: enableUpdate,
200 })
201 if err != nil {
202 log.Error(err, "fail to execute template")
203 return ""
204 }
205
206 return buf.String()
207 }
208