github.com/Ilhicas/nomad@v1.0.4-0.20210304152020-e86851182bc3/jobspec/parse_network.go (about) 1 package jobspec 2 3 import ( 4 "fmt" 5 "strings" 6 7 multierror "github.com/hashicorp/go-multierror" 8 "github.com/hashicorp/hcl" 9 "github.com/hashicorp/hcl/hcl/ast" 10 "github.com/hashicorp/nomad/api" 11 "github.com/mitchellh/mapstructure" 12 ) 13 14 // ParseNetwork parses a collection containing exactly one NetworkResource 15 func ParseNetwork(o *ast.ObjectList) (*api.NetworkResource, error) { 16 if len(o.Items) > 1 { 17 return nil, fmt.Errorf("only one 'network' resource allowed") 18 } 19 20 // Check for invalid keys 21 valid := []string{ 22 "mode", 23 "mbits", 24 "dns", 25 "port", 26 } 27 if err := checkHCLKeys(o.Items[0].Val, valid); err != nil { 28 return nil, multierror.Prefix(err, "network ->") 29 } 30 31 var r api.NetworkResource 32 var m map[string]interface{} 33 if err := hcl.DecodeObject(&m, o.Items[0].Val); err != nil { 34 return nil, err 35 } 36 37 delete(m, "dns") 38 if err := mapstructure.WeakDecode(m, &r); err != nil { 39 return nil, err 40 } 41 42 var networkObj *ast.ObjectList 43 if ot, ok := o.Items[0].Val.(*ast.ObjectType); ok { 44 networkObj = ot.List 45 } else { 46 return nil, fmt.Errorf("should be an object") 47 } 48 if err := parsePorts(networkObj, &r); err != nil { 49 return nil, multierror.Prefix(err, "network, ports ->") 50 } 51 52 // Filter dns 53 if dns := networkObj.Filter("dns"); len(dns.Items) > 0 { 54 if len(dns.Items) > 1 { 55 return nil, multierror.Prefix(fmt.Errorf("cannot have more than 1 dns stanza"), "network ->") 56 } 57 58 d, err := parseDNS(dns.Items[0]) 59 if err != nil { 60 return nil, multierror.Prefix(err, "network ->") 61 } 62 63 r.DNS = d 64 } 65 66 return &r, nil 67 } 68 69 func parsePorts(networkObj *ast.ObjectList, nw *api.NetworkResource) error { 70 portsObjList := networkObj.Filter("port") 71 knownPortLabels := make(map[string]bool) 72 for _, port := range portsObjList.Items { 73 if len(port.Keys) == 0 { 74 return fmt.Errorf("ports must be named") 75 } 76 77 // check for invalid keys 78 valid := []string{ 79 "static", 80 "to", 81 "host_network", 82 } 83 if err := checkHCLKeys(port.Val, valid); err != nil { 84 return err 85 } 86 87 label := port.Keys[0].Token.Value().(string) 88 if !reDynamicPorts.MatchString(label) { 89 return errPortLabel 90 } 91 l := strings.ToLower(label) 92 if knownPortLabels[l] { 93 return fmt.Errorf("found a port label collision: %s", label) 94 } 95 var p map[string]interface{} 96 var res api.Port 97 if err := hcl.DecodeObject(&p, port.Val); err != nil { 98 return err 99 } 100 if err := mapstructure.WeakDecode(p, &res); err != nil { 101 return err 102 } 103 res.Label = label 104 if res.Value > 0 { 105 nw.ReservedPorts = append(nw.ReservedPorts, res) 106 } else { 107 nw.DynamicPorts = append(nw.DynamicPorts, res) 108 } 109 knownPortLabels[l] = true 110 } 111 return nil 112 } 113 114 func parseDNS(dns *ast.ObjectItem) (*api.DNSConfig, error) { 115 valid := []string{ 116 "servers", 117 "searches", 118 "options", 119 } 120 121 if err := checkHCLKeys(dns.Val, valid); err != nil { 122 return nil, multierror.Prefix(err, "dns ->") 123 } 124 125 var dnsCfg api.DNSConfig 126 var m map[string]interface{} 127 if err := hcl.DecodeObject(&m, dns.Val); err != nil { 128 return nil, err 129 } 130 131 if err := mapstructure.WeakDecode(m, &dnsCfg); err != nil { 132 return nil, err 133 } 134 135 return &dnsCfg, nil 136 }