~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/provider/maas/devices.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2016 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package maas
 
5
 
 
6
import (
 
7
        "encoding/json"
 
8
        "net/url"
 
9
        "path"
 
10
        "strconv"
 
11
 
 
12
        "github.com/juju/errors"
 
13
        "github.com/juju/gomaasapi"
 
14
 
 
15
        "github.com/juju/juju/instance"
 
16
        "github.com/juju/juju/network"
 
17
)
 
18
 
 
19
// TODO(dimitern): The types below should be part of gomaasapi.
 
20
// LKK Card: https://canonical.leankit.com/Boards/View/101652562/119310616
 
21
 
 
22
type maasZone struct {
 
23
        Name        string `json:"name"`
 
24
        Description string `json:"description"`
 
25
        ResourceURI string `json:"resource_uri"`
 
26
}
 
27
 
 
28
type maasMACAddress struct {
 
29
        MACAddress string `json:"mac_address"`
 
30
}
 
31
 
 
32
type maasDevice struct {
 
33
        SystemID      string           `json:"system_id"`
 
34
        Parent        string           `json:"parent"`
 
35
        Hostname      string           `json:"hostname"`
 
36
        IPAddresses   []string         `json:"ip_addresses"`
 
37
        Owner         string           `json:"owner"`
 
38
        Zone          maasZone         `json:"zone"`
 
39
        MACAddressSet []maasMACAddress `json:"macaddress_set"`
 
40
        TagNames      []string         `json:"tag_names"`
 
41
        ResourceURI   string           `json:"resource_uri"`
 
42
}
 
43
 
 
44
func parseDevice(jsonBytes []byte) (*maasDevice, error) {
 
45
        var device maasDevice
 
46
        if err := json.Unmarshal(jsonBytes, &device); err != nil {
 
47
                return nil, errors.Annotate(err, "parsing device")
 
48
        }
 
49
        return &device, nil
 
50
}
 
51
 
 
52
func getJSONBytes(object json.Marshaler) ([]byte, error) {
 
53
        rawBytes, err := object.MarshalJSON()
 
54
        if err != nil {
 
55
                return nil, errors.Annotate(err, "cannot get JSON bytes")
 
56
        }
 
57
        return rawBytes, nil
 
58
}
 
59
 
 
60
func (env *maasEnviron) createDevice(hostInstanceID instance.Id, hostname string, primaryMACAddress string) (*maasDevice, error) {
 
61
        devicesAPI := env.getMAASClient().GetSubObject("devices")
 
62
        params := make(url.Values)
 
63
        params.Add("hostname", hostname)
 
64
        params.Add("parent", extractSystemId(hostInstanceID))
 
65
        params.Add("mac_addresses", primaryMACAddress)
 
66
 
 
67
        result, err := devicesAPI.CallPost("new", params)
 
68
        if err != nil {
 
69
                return nil, errors.Trace(err)
 
70
        }
 
71
        deviceJSON, err := getJSONBytes(result)
 
72
        if err != nil {
 
73
                return nil, errors.Trace(err)
 
74
        }
 
75
        device, err := parseDevice(deviceJSON)
 
76
        if err != nil {
 
77
                return nil, errors.Trace(err)
 
78
        }
 
79
        logger.Debugf("created device: %+v", device)
 
80
        return device, nil
 
81
}
 
82
 
 
83
func parseInterface(jsonBytes []byte) (*maasInterface, error) {
 
84
        var iface maasInterface
 
85
        if err := json.Unmarshal(jsonBytes, &iface); err != nil {
 
86
                return nil, errors.Annotate(err, "parsing interface")
 
87
        }
 
88
        return &iface, nil
 
89
}
 
90
 
 
91
func (env *maasEnviron) createDeviceInterface(deviceID instance.Id, name, macAddress, vlanID string) (*maasInterface, error) {
 
92
        deviceSystemID := extractSystemId(deviceID)
 
93
        uri := path.Join("nodes", deviceSystemID, "interfaces")
 
94
        interfacesAPI := env.getMAASClient().GetSubObject(uri)
 
95
 
 
96
        params := make(url.Values)
 
97
        params.Add("name", name)
 
98
        params.Add("mac_address", macAddress)
 
99
        params.Add("vlan", vlanID)
 
100
 
 
101
        result, err := interfacesAPI.CallPost("create_physical", params)
 
102
        if err != nil {
 
103
                return nil, errors.Trace(err)
 
104
        }
 
105
        interfaceJSON, err := getJSONBytes(result)
 
106
        if err != nil {
 
107
                return nil, errors.Trace(err)
 
108
        }
 
109
        iface, err := parseInterface(interfaceJSON)
 
110
        if err != nil {
 
111
                return nil, errors.Trace(err)
 
112
        }
 
113
        return iface, nil
 
114
}
 
115
 
 
116
func (env *maasEnviron) updateDeviceInterface(deviceID instance.Id, interfaceID, name, macAddress, vlanID string) (*maasInterface, error) {
 
117
        deviceSystemID := extractSystemId(deviceID)
 
118
        uri := path.Join("nodes", deviceSystemID, "interfaces", interfaceID)
 
119
        interfacesAPI := env.getMAASClient().GetSubObject(uri)
 
120
 
 
121
        params := make(url.Values)
 
122
        params.Add("name", name)
 
123
        params.Add("mac_address", macAddress)
 
124
        params.Add("vlan", vlanID)
 
125
 
 
126
        result, err := interfacesAPI.Update(params)
 
127
        if err != nil {
 
128
                return nil, errors.Trace(err)
 
129
        }
 
130
        interfaceJSON, err := getJSONBytes(result)
 
131
        if err != nil {
 
132
                return nil, errors.Trace(err)
 
133
        }
 
134
        iface, err := parseInterface(interfaceJSON)
 
135
        if err != nil {
 
136
                return nil, errors.Trace(err)
 
137
        }
 
138
        return iface, nil
 
139
}
 
140
 
 
141
func (env *maasEnviron) linkDeviceInterfaceToSubnet(deviceID instance.Id, interfaceID, subnetID string, mode maasLinkMode) (*maasInterface, error) {
 
142
        deviceSystemID := extractSystemId(deviceID)
 
143
        uri := path.Join("nodes", deviceSystemID, "interfaces", interfaceID)
 
144
        interfacesAPI := env.getMAASClient().GetSubObject(uri)
 
145
 
 
146
        params := make(url.Values)
 
147
        params.Add("mode", string(mode))
 
148
        params.Add("subnet", subnetID)
 
149
 
 
150
        result, err := interfacesAPI.CallPost("link_subnet", params)
 
151
        if err != nil {
 
152
                return nil, errors.Trace(err)
 
153
        }
 
154
        interfaceJSON, err := getJSONBytes(result)
 
155
        if err != nil {
 
156
                return nil, errors.Trace(err)
 
157
        }
 
158
        iface, err := parseInterface(interfaceJSON)
 
159
        if err != nil {
 
160
                return nil, errors.Trace(err)
 
161
        }
 
162
        return iface, nil
 
163
}
 
164
 
 
165
func (env *maasEnviron) deviceInterfaces(deviceID instance.Id) ([]maasInterface, error) {
 
166
        deviceSystemID := extractSystemId(deviceID)
 
167
        uri := path.Join("nodes", deviceSystemID, "interfaces")
 
168
        interfacesAPI := env.getMAASClient().GetSubObject(uri)
 
169
 
 
170
        result, err := interfacesAPI.CallGet("", nil)
 
171
        if err != nil {
 
172
                return nil, errors.Trace(err)
 
173
        }
 
174
        interfacesJSON, err := getJSONBytes(result)
 
175
        if err != nil {
 
176
                return nil, errors.Trace(err)
 
177
        }
 
178
        interfaces, err := parseInterfaces(interfacesJSON)
 
179
        if err != nil {
 
180
                return nil, errors.Trace(err)
 
181
        }
 
182
        logger.Debugf("device %q interfaces: %+v", deviceSystemID, interfaces)
 
183
        return interfaces, nil
 
184
 
 
185
}
 
186
 
 
187
func (env *maasEnviron) deviceInterfaceInfo(deviceID instance.Id, nameToParentName map[string]string) ([]network.InterfaceInfo, error) {
 
188
        interfaces, err := env.deviceInterfaces(deviceID)
 
189
        if err != nil {
 
190
                return nil, errors.Trace(err)
 
191
        }
 
192
 
 
193
        interfaceInfo := make([]network.InterfaceInfo, 0, len(interfaces))
 
194
        for _, nic := range interfaces {
 
195
                nicInfo := network.InterfaceInfo{
 
196
                        InterfaceName:       nic.Name,
 
197
                        InterfaceType:       network.EthernetInterface,
 
198
                        MACAddress:          nic.MACAddress,
 
199
                        MTU:                 nic.EffectveMTU,
 
200
                        VLANTag:             nic.VLAN.VID,
 
201
                        ProviderId:          network.Id(strconv.Itoa(nic.ID)),
 
202
                        ProviderVLANId:      network.Id(strconv.Itoa(nic.VLAN.ID)),
 
203
                        Disabled:            !nic.Enabled,
 
204
                        NoAutoStart:         !nic.Enabled,
 
205
                        ParentInterfaceName: nameToParentName[nic.Name],
 
206
                }
 
207
 
 
208
                if len(nic.Links) == 0 {
 
209
                        logger.Debugf("device %q interface %q has no links", deviceID, nic.Name)
 
210
                        interfaceInfo = append(interfaceInfo, nicInfo)
 
211
                        continue
 
212
                }
 
213
 
 
214
                for _, link := range nic.Links {
 
215
                        switch link.Mode {
 
216
                        case modeUnknown:
 
217
                                nicInfo.ConfigType = network.ConfigUnknown
 
218
                        case modeDHCP:
 
219
                                nicInfo.ConfigType = network.ConfigDHCP
 
220
                        case modeStatic, modeLinkUp:
 
221
                                nicInfo.ConfigType = network.ConfigStatic
 
222
                        default:
 
223
                                nicInfo.ConfigType = network.ConfigManual
 
224
                        }
 
225
 
 
226
                        if link.IPAddress == "" {
 
227
                                logger.Debugf("device %q interface %q has no address", deviceID, nic.Name)
 
228
                                continue
 
229
                        }
 
230
                        if link.Subnet == nil {
 
231
                                logger.Debugf("device %q interface %q link %d missing subnet", deviceID, nic.Name, link.ID)
 
232
                                continue
 
233
                        }
 
234
 
 
235
                        nicInfo.CIDR = link.Subnet.CIDR
 
236
                        nicInfo.Address = network.NewAddressOnSpace(link.Subnet.Space, link.IPAddress)
 
237
                        nicInfo.ProviderSubnetId = network.Id(strconv.Itoa(link.Subnet.ID))
 
238
                        nicInfo.ProviderAddressId = network.Id(strconv.Itoa(link.ID))
 
239
                        if link.Subnet.GatewayIP != "" {
 
240
                                nicInfo.GatewayAddress = network.NewAddressOnSpace(link.Subnet.Space, link.Subnet.GatewayIP)
 
241
                        }
 
242
                        if len(link.Subnet.DNSServers) > 0 {
 
243
                                nicInfo.DNSServers = network.NewAddressesOnSpace(link.Subnet.Space, link.Subnet.DNSServers...)
 
244
                        }
 
245
 
 
246
                        interfaceInfo = append(interfaceInfo, nicInfo)
 
247
                }
 
248
        }
 
249
        logger.Debugf("device %q has interface info: %+v", deviceID, interfaceInfo)
 
250
        return interfaceInfo, nil
 
251
}
 
252
 
 
253
func (env *maasEnviron) deviceInterfaceInfo2(deviceID string, nameToParentName map[string]string) ([]network.InterfaceInfo, error) {
 
254
        args := gomaasapi.DevicesArgs{SystemIDs: []string{deviceID}}
 
255
        devices, err := env.maasController.Devices(args)
 
256
        if err != nil {
 
257
                return nil, errors.Trace(err)
 
258
        }
 
259
        if len(devices) != 1 {
 
260
                return nil, errors.Errorf("unexpected response requesting device %v: %v", deviceID, devices)
 
261
        }
 
262
        interfaces := devices[0].InterfaceSet()
 
263
 
 
264
        interfaceInfo := make([]network.InterfaceInfo, 0, len(interfaces))
 
265
        for _, nic := range interfaces {
 
266
                vlanId := 0
 
267
                vlanVid := 0
 
268
                vlan := nic.VLAN()
 
269
                if vlan != nil {
 
270
                        vlanId = vlan.ID()
 
271
                        vlanVid = vlan.VID()
 
272
                }
 
273
                nicInfo := network.InterfaceInfo{
 
274
                        InterfaceName:       nic.Name(),
 
275
                        InterfaceType:       network.EthernetInterface,
 
276
                        MACAddress:          nic.MACAddress(),
 
277
                        MTU:                 nic.EffectiveMTU(),
 
278
                        VLANTag:             vlanVid,
 
279
                        ProviderId:          network.Id(strconv.Itoa(nic.ID())),
 
280
                        ProviderVLANId:      network.Id(strconv.Itoa(vlanId)),
 
281
                        Disabled:            !nic.Enabled(),
 
282
                        NoAutoStart:         !nic.Enabled(),
 
283
                        ParentInterfaceName: nameToParentName[nic.Name()],
 
284
                }
 
285
 
 
286
                if len(nic.Links()) == 0 {
 
287
                        logger.Debugf("device %q interface %q has no links", deviceID, nic.Name())
 
288
                        interfaceInfo = append(interfaceInfo, nicInfo)
 
289
                        continue
 
290
                }
 
291
 
 
292
                for _, link := range nic.Links() {
 
293
                        mode := maasLinkMode(link.Mode())
 
294
                        switch mode {
 
295
                        case modeUnknown:
 
296
                                nicInfo.ConfigType = network.ConfigUnknown
 
297
                        case modeDHCP:
 
298
                                nicInfo.ConfigType = network.ConfigDHCP
 
299
                        case modeStatic, modeLinkUp:
 
300
                                nicInfo.ConfigType = network.ConfigStatic
 
301
                        default:
 
302
                                nicInfo.ConfigType = network.ConfigManual
 
303
                        }
 
304
 
 
305
                        subnet := link.Subnet()
 
306
                        if link.IPAddress() == "" || subnet == nil {
 
307
                                logger.Debugf("device %q interface %q has no address", deviceID, nic.Name())
 
308
                                continue
 
309
                        }
 
310
 
 
311
                        nicInfo.CIDR = subnet.CIDR()
 
312
                        nicInfo.Address = network.NewAddressOnSpace(subnet.Space(), link.IPAddress())
 
313
                        nicInfo.ProviderSubnetId = network.Id(strconv.Itoa(subnet.ID()))
 
314
                        nicInfo.ProviderAddressId = network.Id(strconv.Itoa(link.ID()))
 
315
                        if subnet.Gateway() != "" {
 
316
                                nicInfo.GatewayAddress = network.NewAddressOnSpace(subnet.Space(), subnet.Gateway())
 
317
                        }
 
318
                        if len(subnet.DNSServers()) > 0 {
 
319
                                nicInfo.DNSServers = network.NewAddressesOnSpace(subnet.Space(), subnet.DNSServers()...)
 
320
                        }
 
321
 
 
322
                        interfaceInfo = append(interfaceInfo, nicInfo)
 
323
                }
 
324
        }
 
325
        logger.Debugf("device %q has interface info: %+v", deviceID, interfaceInfo)
 
326
        return interfaceInfo, nil
 
327
}