github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/jobspec/parse_multiregion.go (about) 1 package jobspec 2 3 import ( 4 "fmt" 5 6 multierror "github.com/hashicorp/go-multierror" 7 "github.com/hashicorp/hcl" 8 "github.com/hashicorp/hcl/hcl/ast" 9 "github.com/hashicorp/nomad/api" 10 "github.com/mitchellh/mapstructure" 11 ) 12 13 func parseMultiregion(result *api.Multiregion, list *ast.ObjectList) error { 14 15 list = list.Elem() 16 if len(list.Items) > 1 { 17 return fmt.Errorf("only one 'multiregion' block allowed") 18 } 19 if len(list.Items) == 0 { 20 return nil 21 } 22 23 // Get our multiregion object and decode it 24 obj := list.Items[0] 25 var m map[string]interface{} 26 if err := hcl.DecodeObject(&m, obj.Val); err != nil { 27 return err 28 } 29 30 // Value should be an object 31 var listVal *ast.ObjectList 32 if ot, ok := obj.Val.(*ast.ObjectType); ok { 33 listVal = ot.List 34 } else { 35 return fmt.Errorf("multiregion should be an object") 36 } 37 38 // Check for invalid keys 39 valid := []string{ 40 "strategy", 41 "region", 42 } 43 if err := checkHCLKeys(obj.Val, valid); err != nil { 44 return err 45 } 46 47 // If we have a strategy, then parse that 48 if o := listVal.Filter("strategy"); len(o.Items) > 0 { 49 if err := parseMultiregionStrategy(&result.Strategy, o); err != nil { 50 return multierror.Prefix(err, "strategy ->") 51 } 52 } 53 // If we have regions, then parse those 54 if o := listVal.Filter("region"); len(o.Items) > 0 { 55 if err := parseMultiregionRegions(result, o); err != nil { 56 return multierror.Prefix(err, "regions ->") 57 } 58 } else { 59 return fmt.Errorf("'multiregion' requires one or more 'region' blocks") 60 } 61 return nil 62 } 63 64 func parseMultiregionStrategy(final **api.MultiregionStrategy, list *ast.ObjectList) error { 65 list = list.Elem() 66 if len(list.Items) > 1 { 67 return fmt.Errorf("only one 'strategy' block allowed") 68 } 69 70 // Get our job object 71 obj := list.Items[0] 72 73 // Check for invalid keys 74 valid := []string{ 75 "max_parallel", 76 "on_failure", 77 } 78 if err := checkHCLKeys(obj.Val, valid); err != nil { 79 return err 80 } 81 82 var m map[string]interface{} 83 if err := hcl.DecodeObject(&m, obj.Val); err != nil { 84 return err 85 } 86 87 var result api.MultiregionStrategy 88 dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ 89 WeaklyTypedInput: true, 90 Result: &result, 91 }) 92 93 if err != nil { 94 return err 95 } 96 if err := dec.Decode(m); err != nil { 97 return err 98 } 99 *final = &result 100 return nil 101 } 102 103 func parseMultiregionRegions(result *api.Multiregion, list *ast.ObjectList) error { 104 list = list.Children() 105 if len(list.Items) == 0 { 106 return nil 107 } 108 109 // Go through each object and turn it into an actual result. 110 collection := make([]*api.MultiregionRegion, 0, len(list.Items)) 111 seen := make(map[string]struct{}) 112 for _, item := range list.Items { 113 n := item.Keys[0].Token.Value().(string) 114 115 // Make sure we haven't already found this 116 if _, ok := seen[n]; ok { 117 return fmt.Errorf("region '%s' defined more than once", n) 118 } 119 seen[n] = struct{}{} 120 121 // We need this later 122 var listVal *ast.ObjectList 123 if ot, ok := item.Val.(*ast.ObjectType); ok { 124 listVal = ot.List 125 } else { 126 return fmt.Errorf("region '%s': should be an object", n) 127 } 128 129 // Check for invalid keys 130 valid := []string{ 131 "count", 132 "datacenters", 133 "meta", 134 } 135 if err := checkHCLKeys(listVal, valid); err != nil { 136 return multierror.Prefix(err, fmt.Sprintf("'%s' ->", n)) 137 } 138 139 var m map[string]interface{} 140 if err := hcl.DecodeObject(&m, item.Val); err != nil { 141 return err 142 } 143 144 // Build the region with the basic decode 145 var r api.MultiregionRegion 146 r.Name = n 147 dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ 148 WeaklyTypedInput: true, 149 Result: &r, 150 }) 151 if err != nil { 152 return err 153 } 154 if err := dec.Decode(m); err != nil { 155 return err 156 } 157 collection = append(collection, &r) 158 } 159 160 result.Regions = append(result.Regions, collection...) 161 return nil 162 }