1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
12
"github.com/juju/errors"
13
"github.com/juju/gomaasapi"
15
"github.com/juju/juju/instance"
16
"github.com/juju/juju/network"
19
// TODO(dimitern): The types below should be part of gomaasapi.
20
// LKK Card: https://canonical.leankit.com/Boards/View/101652562/119310616
22
type maasZone struct {
23
Name string `json:"name"`
24
Description string `json:"description"`
25
ResourceURI string `json:"resource_uri"`
28
type maasMACAddress struct {
29
MACAddress string `json:"mac_address"`
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"`
44
func parseDevice(jsonBytes []byte) (*maasDevice, error) {
46
if err := json.Unmarshal(jsonBytes, &device); err != nil {
47
return nil, errors.Annotate(err, "parsing device")
52
func getJSONBytes(object json.Marshaler) ([]byte, error) {
53
rawBytes, err := object.MarshalJSON()
55
return nil, errors.Annotate(err, "cannot get JSON bytes")
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)
67
result, err := devicesAPI.CallPost("new", params)
69
return nil, errors.Trace(err)
71
deviceJSON, err := getJSONBytes(result)
73
return nil, errors.Trace(err)
75
device, err := parseDevice(deviceJSON)
77
return nil, errors.Trace(err)
79
logger.Debugf("created device: %+v", device)
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")
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)
96
params := make(url.Values)
97
params.Add("name", name)
98
params.Add("mac_address", macAddress)
99
params.Add("vlan", vlanID)
101
result, err := interfacesAPI.CallPost("create_physical", params)
103
return nil, errors.Trace(err)
105
interfaceJSON, err := getJSONBytes(result)
107
return nil, errors.Trace(err)
109
iface, err := parseInterface(interfaceJSON)
111
return nil, errors.Trace(err)
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)
121
params := make(url.Values)
122
params.Add("name", name)
123
params.Add("mac_address", macAddress)
124
params.Add("vlan", vlanID)
126
result, err := interfacesAPI.Update(params)
128
return nil, errors.Trace(err)
130
interfaceJSON, err := getJSONBytes(result)
132
return nil, errors.Trace(err)
134
iface, err := parseInterface(interfaceJSON)
136
return nil, errors.Trace(err)
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)
146
params := make(url.Values)
147
params.Add("mode", string(mode))
148
params.Add("subnet", subnetID)
150
result, err := interfacesAPI.CallPost("link_subnet", params)
152
return nil, errors.Trace(err)
154
interfaceJSON, err := getJSONBytes(result)
156
return nil, errors.Trace(err)
158
iface, err := parseInterface(interfaceJSON)
160
return nil, errors.Trace(err)
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)
170
result, err := interfacesAPI.CallGet("", nil)
172
return nil, errors.Trace(err)
174
interfacesJSON, err := getJSONBytes(result)
176
return nil, errors.Trace(err)
178
interfaces, err := parseInterfaces(interfacesJSON)
180
return nil, errors.Trace(err)
182
logger.Debugf("device %q interfaces: %+v", deviceSystemID, interfaces)
183
return interfaces, nil
187
func (env *maasEnviron) deviceInterfaceInfo(deviceID instance.Id, nameToParentName map[string]string) ([]network.InterfaceInfo, error) {
188
interfaces, err := env.deviceInterfaces(deviceID)
190
return nil, errors.Trace(err)
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],
208
if len(nic.Links) == 0 {
209
logger.Debugf("device %q interface %q has no links", deviceID, nic.Name)
210
interfaceInfo = append(interfaceInfo, nicInfo)
214
for _, link := range nic.Links {
217
nicInfo.ConfigType = network.ConfigUnknown
219
nicInfo.ConfigType = network.ConfigDHCP
220
case modeStatic, modeLinkUp:
221
nicInfo.ConfigType = network.ConfigStatic
223
nicInfo.ConfigType = network.ConfigManual
226
if link.IPAddress == "" {
227
logger.Debugf("device %q interface %q has no address", deviceID, nic.Name)
230
if link.Subnet == nil {
231
logger.Debugf("device %q interface %q link %d missing subnet", deviceID, nic.Name, link.ID)
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)
242
if len(link.Subnet.DNSServers) > 0 {
243
nicInfo.DNSServers = network.NewAddressesOnSpace(link.Subnet.Space, link.Subnet.DNSServers...)
246
interfaceInfo = append(interfaceInfo, nicInfo)
249
logger.Debugf("device %q has interface info: %+v", deviceID, interfaceInfo)
250
return interfaceInfo, nil
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)
257
return nil, errors.Trace(err)
259
if len(devices) != 1 {
260
return nil, errors.Errorf("unexpected response requesting device %v: %v", deviceID, devices)
262
interfaces := devices[0].InterfaceSet()
264
interfaceInfo := make([]network.InterfaceInfo, 0, len(interfaces))
265
for _, nic := range interfaces {
273
nicInfo := network.InterfaceInfo{
274
InterfaceName: nic.Name(),
275
InterfaceType: network.EthernetInterface,
276
MACAddress: nic.MACAddress(),
277
MTU: nic.EffectiveMTU(),
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()],
286
if len(nic.Links()) == 0 {
287
logger.Debugf("device %q interface %q has no links", deviceID, nic.Name())
288
interfaceInfo = append(interfaceInfo, nicInfo)
292
for _, link := range nic.Links() {
293
mode := maasLinkMode(link.Mode())
296
nicInfo.ConfigType = network.ConfigUnknown
298
nicInfo.ConfigType = network.ConfigDHCP
299
case modeStatic, modeLinkUp:
300
nicInfo.ConfigType = network.ConfigStatic
302
nicInfo.ConfigType = network.ConfigManual
305
subnet := link.Subnet()
306
if link.IPAddress() == "" || subnet == nil {
307
logger.Debugf("device %q interface %q has no address", deviceID, nic.Name())
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())
318
if len(subnet.DNSServers()) > 0 {
319
nicInfo.DNSServers = network.NewAddressesOnSpace(subnet.Space(), subnet.DNSServers()...)
322
interfaceInfo = append(interfaceInfo, nicInfo)
325
logger.Debugf("device %q has interface info: %+v", deviceID, interfaceInfo)
326
return interfaceInfo, nil