...
1
2
3
4
5
6
7
8
9
10
11
12
13
14 package main
15
16 import (
17 "fmt"
18 "io/ioutil"
19 "os"
20 "strings"
21
22 "gopkg.in/yaml.v2"
23 )
24
25 type Item struct {
26 ApiVersion string `yaml:"apiVersion"`
27 Kind string `yaml:"kind"`
28 Metadata yaml.MapSlice `yaml:"metadata"`
29 Spec yaml.MapSlice `yaml:"spec"`
30 }
31
32 func main() {
33 if len(os.Args) != 3 {
34 fmt.Println("migrator <old-yaml> <new-yaml>")
35 os.Exit(1)
36 }
37 data, err := ioutil.ReadFile(os.Args[1])
38 if err != nil {
39 fmt.Println(err)
40 os.Exit(1)
41 }
42 var (
43 old Item
44 new Item
45 )
46 err = yaml.Unmarshal(data, &old)
47 if err != nil {
48 fmt.Println(err)
49 os.Exit(1)
50 }
51 {
52 var (
53 schedule yaml.MapSlice
54 findSchedule bool
55 )
56
57 if isIncompatibleChaos(old) {
58 fmt.Printf("the define of %s is changed in v2.0, please modify it according to the document, refer to https://chaos-mesh.org/docs/\n", old.Kind)
59 os.Exit(1)
60 }
61
62 for _, item := range old.Spec {
63 if item.Key == "scheduler" {
64 schedule = item.Value.(yaml.MapSlice)
65 findSchedule = true
66 }
67 }
68
69 if findSchedule {
70 new = toScheduleObject(old, schedule)
71 } else {
72 new = old
73 new.Spec = transformChaosSpec(old)
74 }
75 }
76 data, err = yaml.Marshal(new)
77 if err != nil {
78 fmt.Println(err)
79 os.Exit(1)
80 }
81 err = ioutil.WriteFile(os.Args[2], data, 0644)
82 if err != nil {
83 fmt.Println(err)
84 os.Exit(1)
85 }
86 }
87
88 func getKeyName(name string) string {
89 s := strings.ToLower(name)
90 return strings.ReplaceAll(s, "chaos", "Chaos")
91 }
92
93 func toNewKind(kind string) string {
94 if kind == "IoChaos" {
95 return "IOChaos"
96 }
97 return kind
98 }
99
100 func toScheduleObject(old Item, schedule yaml.MapSlice) Item {
101 var new Item
102 var cron string
103 for _, item := range schedule {
104 if item.Key == "cron" {
105 cron = item.Value.(string)
106 }
107 }
108 new.ApiVersion = old.ApiVersion
109 new.Metadata = old.Metadata
110 new.Kind = "Schedule"
111 new.Spec = append(new.Spec, yaml.MapItem{Key: "schedule", Value: cron})
112 new.Spec = append(new.Spec, yaml.MapItem{Key: "type", Value: toNewKind(old.Kind)})
113 new.Spec = append(new.Spec, yaml.MapItem{Key: "historyLimit", Value: 5})
114 new.Spec = append(new.Spec, yaml.MapItem{Key: "concurrencyPolicy", Value: "Forbid"})
115
116 newSpec := transformChaosSpec(old)
117 new.Spec = append(new.Spec, yaml.MapItem{Key: getKeyName(old.Kind), Value: newSpec})
118 return new
119 }
120
121 func transformChaosSpec(item Item) yaml.MapSlice {
122 var (
123 newSpec yaml.MapSlice
124 containerNames []string
125 )
126 for _, kv := range item.Spec {
127 if kv.Key == "scheduler" {
128 continue
129 }
130
131 if kv.Key == "containerName" {
132 containerNames = append(containerNames, kv.Value.(string))
133 continue
134 }
135
136 if item.Kind == "DNSChaos" {
137
138
139
140 if kv.Key == "scope" && kv.Value == "all" {
141 patterns := []string{"*"}
142 kv = yaml.MapItem{Key: "patterns", Value: patterns}
143 }
144 }
145
146 newSpec = append(newSpec, kv)
147 }
148
149 if len(containerNames) != 0 {
150 newSpec = append(newSpec, yaml.MapItem{Key: "containerNames", Value: containerNames})
151 }
152
153 return newSpec
154 }
155
156 func isIncompatibleChaos(item Item) bool {
157 incompatible := false
158 switch item.Kind {
159 case "DNSChaos":
160 for _, kv := range item.Spec {
161
162
163
164 if kv.Key == "scope" && kv.Value != "all" {
165 incompatible = true
166 }
167 }
168 default:
169 }
170
171 return incompatible
172 }
173