github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 14 "github.com/juju/juju/instance" 15 "github.com/juju/juju/network" 16 ) 17 18 // TODO(dimitern): The types below should be part of gomaasapi. 19 // LKK Card: https://canonical.leankit.com/Boards/View/101652562/119310616 20 21 type maasZone struct { 22 Name string `json:"name"` 23 Description string `json:"description"` 24 ResourceURI string `json:"resource_uri"` 25 } 26 27 type maasMACAddress struct { 28 MACAddress string `json:"mac_address"` 29 } 30 31 type maasDevice struct { 32 SystemID string `json:"system_id"` 33 Parent string `json:"parent"` 34 Hostname string `json:"hostname"` 35 IPAddresses []string `json:"ip_addresses"` 36 Owner string `json:"owner"` 37 Zone maasZone `json:"zone"` 38 MACAddressSet []maasMACAddress `json:"macaddress_set"` 39 TagNames []string `json:"tag_names"` 40 ResourceURI string `json:"resource_uri"` 41 } 42 43 func parseDevice(jsonBytes []byte) (*maasDevice, error) { 44 var device maasDevice 45 if err := json.Unmarshal(jsonBytes, &device); err != nil { 46 return nil, errors.Annotate(err, "parsing device") 47 } 48 return &device, nil 49 } 50 51 func getJSONBytes(object json.Marshaler) ([]byte, error) { 52 rawBytes, err := object.MarshalJSON() 53 if err != nil { 54 return nil, errors.Annotate(err, "cannot get JSON bytes") 55 } 56 return rawBytes, nil 57 } 58 59 func (env *maasEnviron) createDevice(hostInstanceID instance.Id, primaryMACAddress string) (*maasDevice, error) { 60 devicesAPI := env.getMAASClient().GetSubObject("devices") 61 params := make(url.Values) 62 params.Add("parent", extractSystemId(hostInstanceID)) 63 params.Add("mac_addresses", primaryMACAddress) 64 65 result, err := devicesAPI.CallPost("new", params) 66 if err != nil { 67 return nil, errors.Trace(err) 68 } 69 deviceJSON, err := getJSONBytes(result) 70 if err != nil { 71 return nil, errors.Trace(err) 72 } 73 device, err := parseDevice(deviceJSON) 74 if err != nil { 75 return nil, errors.Trace(err) 76 } 77 logger.Debugf("created device: %+v", device) 78 return device, nil 79 } 80 81 func parseInterface(jsonBytes []byte) (*maasInterface, error) { 82 var iface maasInterface 83 if err := json.Unmarshal(jsonBytes, &iface); err != nil { 84 return nil, errors.Annotate(err, "parsing interface") 85 } 86 return &iface, nil 87 } 88 89 func (env *maasEnviron) createDeviceInterface(deviceID instance.Id, name, macAddress, vlanID string) (*maasInterface, error) { 90 deviceSystemID := extractSystemId(deviceID) 91 uri := path.Join("nodes", deviceSystemID, "interfaces") 92 interfacesAPI := env.getMAASClient().GetSubObject(uri) 93 94 params := make(url.Values) 95 params.Add("name", name) 96 params.Add("mac_address", macAddress) 97 params.Add("vlan", vlanID) 98 99 result, err := interfacesAPI.CallPost("create_physical", params) 100 if err != nil { 101 return nil, errors.Trace(err) 102 } 103 interfaceJSON, err := getJSONBytes(result) 104 if err != nil { 105 return nil, errors.Trace(err) 106 } 107 iface, err := parseInterface(interfaceJSON) 108 if err != nil { 109 return nil, errors.Trace(err) 110 } 111 return iface, nil 112 } 113 114 func (env *maasEnviron) updateDeviceInterface(deviceID instance.Id, interfaceID, name, macAddress, vlanID string) (*maasInterface, error) { 115 deviceSystemID := extractSystemId(deviceID) 116 uri := path.Join("nodes", deviceSystemID, "interfaces", interfaceID) 117 interfacesAPI := env.getMAASClient().GetSubObject(uri) 118 119 params := make(url.Values) 120 params.Add("name", name) 121 params.Add("mac_address", macAddress) 122 params.Add("vlan", vlanID) 123 124 result, err := interfacesAPI.Update(params) 125 if err != nil { 126 return nil, errors.Trace(err) 127 } 128 interfaceJSON, err := getJSONBytes(result) 129 if err != nil { 130 return nil, errors.Trace(err) 131 } 132 iface, err := parseInterface(interfaceJSON) 133 if err != nil { 134 return nil, errors.Trace(err) 135 } 136 return iface, nil 137 } 138 139 func (env *maasEnviron) linkDeviceInterfaceToSubnet(deviceID instance.Id, interfaceID, subnetID string, mode maasLinkMode) (*maasInterface, error) { 140 deviceSystemID := extractSystemId(deviceID) 141 uri := path.Join("nodes", deviceSystemID, "interfaces", interfaceID) 142 interfacesAPI := env.getMAASClient().GetSubObject(uri) 143 144 params := make(url.Values) 145 params.Add("mode", string(mode)) 146 params.Add("subnet", subnetID) 147 148 result, err := interfacesAPI.CallPost("link_subnet", params) 149 if err != nil { 150 return nil, errors.Trace(err) 151 } 152 interfaceJSON, err := getJSONBytes(result) 153 if err != nil { 154 return nil, errors.Trace(err) 155 } 156 iface, err := parseInterface(interfaceJSON) 157 if err != nil { 158 return nil, errors.Trace(err) 159 } 160 return iface, nil 161 } 162 163 func (env *maasEnviron) deviceInterfaces(deviceID instance.Id) ([]maasInterface, error) { 164 deviceSystemID := extractSystemId(deviceID) 165 uri := path.Join("nodes", deviceSystemID, "interfaces") 166 interfacesAPI := env.getMAASClient().GetSubObject(uri) 167 168 result, err := interfacesAPI.CallGet("", nil) 169 if err != nil { 170 return nil, errors.Trace(err) 171 } 172 interfacesJSON, err := getJSONBytes(result) 173 if err != nil { 174 return nil, errors.Trace(err) 175 } 176 interfaces, err := parseInterfaces(interfacesJSON) 177 if err != nil { 178 return nil, errors.Trace(err) 179 } 180 logger.Debugf("device %q interfaces: %+v", deviceSystemID, interfaces) 181 return interfaces, nil 182 183 } 184 185 func (env *maasEnviron) deviceInterfaceInfo(deviceID instance.Id, nameToParentName map[string]string) ([]network.InterfaceInfo, error) { 186 interfaces, err := env.deviceInterfaces(deviceID) 187 if err != nil { 188 return nil, errors.Trace(err) 189 } 190 191 interfaceInfo := make([]network.InterfaceInfo, 0, len(interfaces)) 192 for _, nic := range interfaces { 193 nicInfo := network.InterfaceInfo{ 194 InterfaceName: nic.Name, 195 InterfaceType: network.EthernetInterface, 196 MACAddress: nic.MACAddress, 197 MTU: nic.EffectveMTU, 198 VLANTag: nic.VLAN.VID, 199 ProviderId: network.Id(strconv.Itoa(nic.ID)), 200 ProviderVLANId: network.Id(strconv.Itoa(nic.VLAN.ID)), 201 Disabled: !nic.Enabled, 202 NoAutoStart: !nic.Enabled, 203 ParentInterfaceName: nameToParentName[nic.Name], 204 } 205 206 if len(nic.Links) == 0 { 207 logger.Debugf("device %q interface %q has no links", deviceID, nic.Name) 208 interfaceInfo = append(interfaceInfo, nicInfo) 209 continue 210 } 211 212 for _, link := range nic.Links { 213 switch link.Mode { 214 case modeUnknown: 215 nicInfo.ConfigType = network.ConfigUnknown 216 case modeDHCP: 217 nicInfo.ConfigType = network.ConfigDHCP 218 case modeStatic, modeLinkUp: 219 nicInfo.ConfigType = network.ConfigStatic 220 default: 221 nicInfo.ConfigType = network.ConfigManual 222 } 223 224 if link.IPAddress == "" { 225 logger.Debugf("device %q interface %q has no address", deviceID, nic.Name) 226 continue 227 } 228 if link.Subnet == nil { 229 logger.Debugf("device %q interface %q link %d missing subnet", deviceID, nic.Name, link.ID) 230 continue 231 } 232 233 nicInfo.CIDR = link.Subnet.CIDR 234 nicInfo.Address = network.NewAddressOnSpace(link.Subnet.Space, link.IPAddress) 235 nicInfo.ProviderSubnetId = network.Id(strconv.Itoa(link.Subnet.ID)) 236 nicInfo.ProviderAddressId = network.Id(strconv.Itoa(link.ID)) 237 if link.Subnet.GatewayIP != "" { 238 nicInfo.GatewayAddress = network.NewAddressOnSpace(link.Subnet.Space, link.Subnet.GatewayIP) 239 } 240 if len(link.Subnet.DNSServers) > 0 { 241 nicInfo.DNSServers = network.NewAddressesOnSpace(link.Subnet.Space, link.Subnet.DNSServers...) 242 } 243 244 interfaceInfo = append(interfaceInfo, nicInfo) 245 } 246 } 247 logger.Debugf("device %q has interface info: %+v", deviceID, interfaceInfo) 248 return interfaceInfo, nil 249 }