1
2
3
4
5
6
7
8
9
10
11
12
13
14 package main
15
16 import (
17 "bytes"
18 "fmt"
19 "strings"
20 "text/template"
21
22 "github.com/iancoleman/strcase"
23 )
24
25
26 type workflowCodeGenerator struct {
27
28 chaosTypes []string
29 }
30
31 func newWorkflowCodeGenerator(types []string) *workflowCodeGenerator {
32 return &workflowCodeGenerator{chaosTypes: types}
33 }
34
35 func (it *workflowCodeGenerator) AppendTypes(typeName string) {
36 it.chaosTypes = append(it.chaosTypes, typeName)
37 }
38
39 func (it *workflowCodeGenerator) Render() string {
40
41 workflowTemplateTypesEntries := ""
42 for _, item := range it.chaosTypes {
43 workflowTemplateTypesEntries += generateTemplateTypes(item)
44 }
45
46 embedChaosEntries := ""
47 for _, item := range it.chaosTypes {
48 embedChaosEntries += generateEmbedChaos(item)
49 }
50
51 spawnObjectMethod := ""
52 for _, item := range it.chaosTypes {
53 spawnObjectMethod += generateSpawnObjectMethodItem(item)
54 }
55 spawnListMethod := ""
56 for _, item := range it.chaosTypes {
57 spawnListMethod += generateSpawnListMethodItem(item)
58 }
59 allChaosTemplateTypeEntries := ""
60 for _, item := range it.chaosTypes {
61 allChaosTemplateTypeEntries += fmt.Sprintf(` Type%s,
62 `, item)
63 }
64
65 genericChaosListImplementations := ""
66 for _, item := range it.chaosTypes {
67 genericChaosListImplementations += generateGenericChaosList(item)
68 }
69
70 imports := `import (
71 "fmt"
72 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
73 "k8s.io/apimachinery/pkg/runtime"
74 )
75 `
76
77 workflowTemplateTypesCodes := fmt.Sprintf(`%s
78
79 %s
80
81 const (
82 %s
83 )
84
85 var allChaosTemplateType = []TemplateType{
86 TypeSchedule,
87 %s
88 }
89
90 type EmbedChaos struct {
91 %s
92 }
93
94 func (it *EmbedChaos) SpawnNewObject(templateType TemplateType) (runtime.Object, metav1.Object, error) {
95
96 switch templateType {
97 %s
98 default:
99 return nil, nil, fmt.Errorf("unsupported template type %%s", templateType)
100 }
101
102 return nil, &metav1.ObjectMeta{}, nil
103 }
104
105 func (it *EmbedChaos) SpawnNewList(templateType TemplateType) (GenericChaosList, error) {
106
107 switch templateType {
108 %s
109 default:
110 return nil, fmt.Errorf("unsupported template type %%s", templateType)
111 }
112
113 return nil, nil
114 }
115
116 %s
117 `,
118 boilerplate,
119 imports,
120 workflowTemplateTypesEntries,
121 allChaosTemplateTypeEntries,
122 embedChaosEntries,
123 spawnObjectMethod,
124 spawnListMethod,
125 genericChaosListImplementations,
126 )
127
128 return workflowTemplateTypesCodes
129 }
130
131 const workflowTemplateTypeEntryTemplate = ` Type{{.Type}} TemplateType = "{{.Type}}"
132 `
133
134 func generateTemplateTypes(typeName string) string {
135 tmpl, err := template.New("workflowTemplates").Parse(workflowTemplateTypeEntryTemplate)
136 if err != nil {
137 log.Error(err, "fail to build template")
138 return ""
139 }
140
141 buf := new(bytes.Buffer)
142 err = tmpl.Execute(buf, &metadata{
143 Type: typeName,
144 })
145 if err != nil {
146 log.Error(err, "fail to execute template")
147 return ""
148 }
149
150 return buf.String()
151 }
152
153 const embedChaosEntryTemplate = ` // +optional
154 {{.Type}} *{{.Type}}Spec ` + "`" + `json:"{{.JsonField}},omitempty"` + "`" + `
155 `
156
157 func generateEmbedChaos(typeName string) string {
158 value := struct {
159 Type string
160 JsonField string
161 }{
162 Type: typeName,
163 JsonField: lowercaseCamelCase(typeName),
164 }
165 tmpl, err := template.New("workflowTemplates").Parse(embedChaosEntryTemplate)
166 if err != nil {
167 log.Error(err, "fail to build template")
168 return ""
169 }
170
171 buf := new(bytes.Buffer)
172 err = tmpl.Execute(buf, &value)
173 if err != nil {
174 log.Error(err, "fail to execute template")
175 return ""
176 }
177
178 return buf.String()
179 }
180
181 func lowercaseCamelCase(str string) string {
182
183
184 if strings.Contains(str, "Chaos") {
185 position := strings.Index(str, "Chaos")
186 return strings.ToLower(str[:position]) + str[position:]
187 }
188 return strcase.ToLowerCamel(str)
189 }
190
191 const spawnObjectEntryTemplate = ` case Type{{.Type}}:
192 result := {{.Type}}{}
193 result.Spec = *it.{{.Type}}
194 return &result, result.GetObjectMeta(), nil
195 `
196
197 func generateSpawnObjectMethodItem(typeName string) string {
198 tmpl, err := template.New("spawnObjectEntry").Parse(spawnObjectEntryTemplate)
199 if err != nil {
200 log.Error(err, "fail to build template")
201 return ""
202 }
203
204 buf := new(bytes.Buffer)
205 err = tmpl.Execute(buf, &metadata{
206 Type: typeName,
207 })
208 if err != nil {
209 log.Error(err, "fail to execute template")
210 return ""
211 }
212
213 return buf.String()
214 }
215
216 const spawnListEntryTemplate = ` case Type{{.Type}}:
217 result := {{.Type}}List{}
218 return &result, nil
219 `
220
221 func generateSpawnListMethodItem(typeName string) string {
222 tmpl, err := template.New("fillingMethod").Parse(spawnListEntryTemplate)
223 if err != nil {
224 log.Error(err, "fail to build template")
225 return ""
226 }
227
228 buf := new(bytes.Buffer)
229 err = tmpl.Execute(buf, &metadata{
230 Type: typeName,
231 })
232 if err != nil {
233 log.Error(err, "fail to execute template")
234 return ""
235 }
236
237 return buf.String()
238 }
239
240 const genericChaosList = `func (in *{{.Type}}List) GetItems() []GenericChaos {
241 var result []GenericChaos
242 for _, item := range in.Items {
243 item := item
244 result = append(result, &item)
245 }
246 return result
247 }
248 `
249
250 func generateGenericChaosList(typeName string) string {
251 tmpl, err := template.New("genericChaosList").Parse(genericChaosList)
252 if err != nil {
253 log.Error(err, "fail to build template")
254 return ""
255 }
256
257 buf := new(bytes.Buffer)
258 err = tmpl.Execute(buf, &metadata{
259 Type: typeName,
260 })
261 if err != nil {
262 log.Error(err, "fail to execute template")
263 return ""
264 }
265
266 return buf.String()
267 }
268