github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/maas/devices.go (about) 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 nicInfo.ConfigType = maasLinkToInterfaceConfigType(string(link.Mode)) 216 217 if link.IPAddress == "" { 218 logger.Debugf("device %q interface %q has no address", deviceID, nic.Name) 219 interfaceInfo = append(interfaceInfo, nicInfo) 220 continue 221 } 222 223 if link.Subnet == nil { 224 logger.Debugf("device %q interface %q link %d missing subnet", deviceID, nic.Name, link.ID) 225 interfaceInfo = append(interfaceInfo, nicInfo) 226 continue 227 } 228 229 nicInfo.CIDR = link.Subnet.CIDR 230 nicInfo.Address = network.NewAddressOnSpace(link.Subnet.Space, link.IPAddress) 231 nicInfo.ProviderSubnetId = network.Id(strconv.Itoa(link.Subnet.ID)) 232 nicInfo.ProviderAddressId = network.Id(strconv.Itoa(link.ID)) 233 if link.Subnet.GatewayIP != "" { 234 nicInfo.GatewayAddress = network.NewAddressOnSpace(link.Subnet.Space, link.Subnet.GatewayIP) 235 } 236 if len(link.Subnet.DNSServers) > 0 { 237 nicInfo.DNSServers = network.NewAddressesOnSpace(link.Subnet.Space, link.Subnet.DNSServers...) 238 } 239 240 interfaceInfo = append(interfaceInfo, nicInfo) 241 } 242 } 243 logger.Debugf("device %q has interface info: %+v", deviceID, interfaceInfo) 244 return interfaceInfo, nil 245 } 246 247 func (env *maasEnviron) deviceInterfaceInfo2(deviceID string, nameToParentName map[string]string) ([]network.InterfaceInfo, error) { 248 args := gomaasapi.DevicesArgs{SystemIDs: []string{deviceID}} 249 devices, err := env.maasController.Devices(args) 250 if err != nil { 251 return nil, errors.Trace(err) 252 } 253 if len(devices) != 1 { 254 return nil, errors.Errorf("unexpected response requesting device %v: %v", deviceID, devices) 255 } 256 interfaces := devices[0].InterfaceSet() 257 258 interfaceInfo := make([]network.InterfaceInfo, 0, len(interfaces)) 259 for _, nic := range interfaces { 260 vlanId := 0 261 vlanVid := 0 262 vlan := nic.VLAN() 263 if vlan != nil { 264 vlanId = vlan.ID() 265 vlanVid = vlan.VID() 266 } 267 nicInfo := network.InterfaceInfo{ 268 InterfaceName: nic.Name(), 269 InterfaceType: network.EthernetInterface, 270 MACAddress: nic.MACAddress(), 271 MTU: nic.EffectiveMTU(), 272 VLANTag: vlanVid, 273 ProviderId: network.Id(strconv.Itoa(nic.ID())), 274 ProviderVLANId: network.Id(strconv.Itoa(vlanId)), 275 Disabled: !nic.Enabled(), 276 NoAutoStart: !nic.Enabled(), 277 ParentInterfaceName: nameToParentName[nic.Name()], 278 } 279 280 if len(nic.Links()) == 0 { 281 logger.Debugf("device %q interface %q has no links", deviceID, nic.Name()) 282 interfaceInfo = append(interfaceInfo, nicInfo) 283 continue 284 } 285 286 for _, link := range nic.Links() { 287 nicInfo.ConfigType = maasLinkToInterfaceConfigType(link.Mode()) 288 289 subnet := link.Subnet() 290 if link.IPAddress() == "" || subnet == nil { 291 logger.Debugf("device %q interface %q has no address", deviceID, nic.Name()) 292 interfaceInfo = append(interfaceInfo, nicInfo) 293 continue 294 } 295 296 nicInfo.CIDR = subnet.CIDR() 297 nicInfo.Address = network.NewAddressOnSpace(subnet.Space(), link.IPAddress()) 298 nicInfo.ProviderSubnetId = network.Id(strconv.Itoa(subnet.ID())) 299 nicInfo.ProviderAddressId = network.Id(strconv.Itoa(link.ID())) 300 if subnet.Gateway() != "" { 301 nicInfo.GatewayAddress = network.NewAddressOnSpace(subnet.Space(), subnet.Gateway()) 302 } 303 if len(subnet.DNSServers()) > 0 { 304 nicInfo.DNSServers = network.NewAddressesOnSpace(subnet.Space(), subnet.DNSServers()...) 305 } 306 307 interfaceInfo = append(interfaceInfo, nicInfo) 308 } 309 } 310 logger.Debugf("device %q has interface info: %+v", deviceID, interfaceInfo) 311 return interfaceInfo, nil 312 }