...

Source file src/github.com/chaos-mesh/chaos-mesh/tools/schedule-migration/main.go

Documentation: github.com/chaos-mesh/chaos-mesh/tools/schedule-migration

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