blob: f509ccda3062038c9afd12fe3c88919f7f8172c0 [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001// Copyright 2016 Canonical Ltd.
2// Licensed under the LGPLv3, see LICENCE file for details.
3
4package gomaasapi
5
6import (
7 "github.com/juju/errors"
8 "github.com/juju/schema"
9 "github.com/juju/version"
10)
11
12type subnet struct {
13 // Add the controller in when we need to do things with the subnet.
14 // controller Controller
15
16 resourceURI string
17
18 id int
19 name string
20 space string
21 vlan *vlan
22
23 gateway string
24 cidr string
25
26 dnsServers []string
27}
28
29// ID implements Subnet.
30func (s *subnet) ID() int {
31 return s.id
32}
33
34// Name implements Subnet.
35func (s *subnet) Name() string {
36 return s.name
37}
38
39// Space implements Subnet.
40func (s *subnet) Space() string {
41 return s.space
42}
43
44// VLAN implements Subnet.
45func (s *subnet) VLAN() VLAN {
46 if s.vlan == nil {
47 return nil
48 }
49 return s.vlan
50}
51
52// Gateway implements Subnet.
53func (s *subnet) Gateway() string {
54 return s.gateway
55}
56
57// CIDR implements Subnet.
58func (s *subnet) CIDR() string {
59 return s.cidr
60}
61
62// DNSServers implements Subnet.
63func (s *subnet) DNSServers() []string {
64 return s.dnsServers
65}
66
67func readSubnets(controllerVersion version.Number, source interface{}) ([]*subnet, error) {
68 checker := schema.List(schema.StringMap(schema.Any()))
69 coerced, err := checker.Coerce(source, nil)
70 if err != nil {
71 return nil, errors.Annotatef(err, "subnet base schema check failed")
72 }
73 valid := coerced.([]interface{})
74
75 var deserialisationVersion version.Number
76 for v := range subnetDeserializationFuncs {
77 if v.Compare(deserialisationVersion) > 0 && v.Compare(controllerVersion) <= 0 {
78 deserialisationVersion = v
79 }
80 }
81 if deserialisationVersion == version.Zero {
82 return nil, errors.Errorf("no subnet read func for version %s", controllerVersion)
83 }
84 readFunc := subnetDeserializationFuncs[deserialisationVersion]
85 return readSubnetList(valid, readFunc)
86}
87
88// readSubnetList expects the values of the sourceList to be string maps.
89func readSubnetList(sourceList []interface{}, readFunc subnetDeserializationFunc) ([]*subnet, error) {
90 result := make([]*subnet, 0, len(sourceList))
91 for i, value := range sourceList {
92 source, ok := value.(map[string]interface{})
93 if !ok {
94 return nil, errors.Errorf("unexpected value for subnet %d, %T", i, value)
95 }
96 subnet, err := readFunc(source)
97 if err != nil {
98 return nil, errors.Annotatef(err, "subnet %d", i)
99 }
100 result = append(result, subnet)
101 }
102 return result, nil
103}
104
105type subnetDeserializationFunc func(map[string]interface{}) (*subnet, error)
106
107var subnetDeserializationFuncs = map[version.Number]subnetDeserializationFunc{
108 twoDotOh: subnet_2_0,
109}
110
111func subnet_2_0(source map[string]interface{}) (*subnet, error) {
112 fields := schema.Fields{
113 "resource_uri": schema.String(),
114 "id": schema.ForceInt(),
115 "name": schema.String(),
116 "space": schema.String(),
117 "gateway_ip": schema.OneOf(schema.Nil(""), schema.String()),
118 "cidr": schema.String(),
119 "vlan": schema.StringMap(schema.Any()),
120 "dns_servers": schema.OneOf(schema.Nil(""), schema.List(schema.String())),
121 }
122 checker := schema.FieldMap(fields, nil) // no defaults
123 coerced, err := checker.Coerce(source, nil)
124 if err != nil {
125 return nil, errors.Annotatef(err, "subnet 2.0 schema check failed")
126 }
127 valid := coerced.(map[string]interface{})
128 // From here we know that the map returned from the schema coercion
129 // contains fields of the right type.
130
131 vlan, err := vlan_2_0(valid["vlan"].(map[string]interface{}))
132 if err != nil {
133 return nil, errors.Trace(err)
134 }
135
136 // Since the gateway_ip is optional, we use the two part cast assignment. If
137 // the cast fails, then we get the default value we care about, which is the
138 // empty string.
139 gateway, _ := valid["gateway_ip"].(string)
140
141 result := &subnet{
142 resourceURI: valid["resource_uri"].(string),
143 id: valid["id"].(int),
144 name: valid["name"].(string),
145 space: valid["space"].(string),
146 vlan: vlan,
147 gateway: gateway,
148 cidr: valid["cidr"].(string),
149 dnsServers: convertToStringSlice(valid["dns_servers"]),
150 }
151 return result, nil
152}