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  }