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