func (env *maasEnviron) deviceInterfaceInfo(deviceID instance.Id, nameToParentName map[string]string) ([]network.InterfaceInfo, error) { interfaces, err := env.deviceInterfaces(deviceID) if err != nil { return nil, errors.Trace(err) } interfaceInfo := make([]network.InterfaceInfo, 0, len(interfaces)) for _, nic := range interfaces { nicInfo := network.InterfaceInfo{ InterfaceName: nic.Name, InterfaceType: network.EthernetInterface, MACAddress: nic.MACAddress, MTU: nic.EffectveMTU, VLANTag: nic.VLAN.VID, ProviderId: network.Id(strconv.Itoa(nic.ID)), ProviderVLANId: network.Id(strconv.Itoa(nic.VLAN.ID)), Disabled: !nic.Enabled, NoAutoStart: !nic.Enabled, ParentInterfaceName: nameToParentName[nic.Name], } if len(nic.Links) == 0 { logger.Debugf("device %q interface %q has no links", deviceID, nic.Name) interfaceInfo = append(interfaceInfo, nicInfo) continue } for _, link := range nic.Links { nicInfo.ConfigType = maasLinkToInterfaceConfigType(string(link.Mode)) if link.IPAddress == "" { logger.Debugf("device %q interface %q has no address", deviceID, nic.Name) interfaceInfo = append(interfaceInfo, nicInfo) continue } if link.Subnet == nil { logger.Debugf("device %q interface %q link %d missing subnet", deviceID, nic.Name, link.ID) interfaceInfo = append(interfaceInfo, nicInfo) continue } nicInfo.CIDR = link.Subnet.CIDR nicInfo.Address = network.NewAddressOnSpace(link.Subnet.Space, link.IPAddress) nicInfo.ProviderSubnetId = network.Id(strconv.Itoa(link.Subnet.ID)) nicInfo.ProviderAddressId = network.Id(strconv.Itoa(link.ID)) if link.Subnet.GatewayIP != "" { nicInfo.GatewayAddress = network.NewAddressOnSpace(link.Subnet.Space, link.Subnet.GatewayIP) } if len(link.Subnet.DNSServers) > 0 { nicInfo.DNSServers = network.NewAddressesOnSpace(link.Subnet.Space, link.Subnet.DNSServers...) } interfaceInfo = append(interfaceInfo, nicInfo) } } logger.Debugf("device %q has interface info: %+v", deviceID, interfaceInfo) return interfaceInfo, nil }
// maasObjectNetworkInterfaces implements environs.NetworkInterfaces() using the // new (1.9+) MAAS API, parsing the node details JSON embedded into the given // maasObject to extract all the relevant InterfaceInfo fields. It returns an // error satisfying errors.IsNotSupported() if it cannot find the required // "interface_set" node details field. func maasObjectNetworkInterfaces(maasObject *gomaasapi.MAASObject, subnetsMap map[string]network.Id) ([]network.InterfaceInfo, error) { interfaceSet, ok := maasObject.GetMap()["interface_set"] if !ok || interfaceSet.IsNil() { // This means we're using an older MAAS API. return nil, errors.NotSupportedf("interface_set") } // TODO(dimitern): Change gomaasapi JSONObject to give access to the raw // JSON bytes directly, rather than having to do call MarshalJSON just so // the result can be unmarshaled from it. // // LKK Card: https://canonical.leankit.com/Boards/View/101652562/119311323 rawBytes, err := interfaceSet.MarshalJSON() if err != nil { return nil, errors.Annotate(err, "cannot get interface_set JSON bytes") } interfaces, err := parseInterfaces(rawBytes) if err != nil { return nil, errors.Trace(err) } infos := make([]network.InterfaceInfo, 0, len(interfaces)) for i, iface := range interfaces { // The below works for all types except bonds and their members. parentName := strings.Join(iface.Parents, "") var nicType network.InterfaceType switch iface.Type { case typePhysical: nicType = network.EthernetInterface children := strings.Join(iface.Children, "") if parentName == "" && len(iface.Children) == 1 && strings.HasPrefix(children, "bond") { // FIXME: Verify the bond exists, regardless of its name. // This is a bond member, set the parent correctly (from // Juju's perspective) - to the bond itself. parentName = children } case typeBond: parentName = "" nicType = network.BondInterface case typeVLAN: nicType = network.VLAN_8021QInterface } nicInfo := network.InterfaceInfo{ DeviceIndex: i, MACAddress: iface.MACAddress, ProviderId: network.Id(fmt.Sprintf("%v", iface.ID)), VLANTag: iface.VLAN.VID, InterfaceName: iface.Name, InterfaceType: nicType, ParentInterfaceName: parentName, Disabled: !iface.Enabled, NoAutoStart: !iface.Enabled, } for _, link := range iface.Links { switch link.Mode { case modeUnknown: nicInfo.ConfigType = network.ConfigUnknown case modeDHCP: nicInfo.ConfigType = network.ConfigDHCP case modeStatic, modeLinkUp: nicInfo.ConfigType = network.ConfigStatic default: nicInfo.ConfigType = network.ConfigManual } if link.IPAddress == "" { logger.Debugf("interface %q has no address", iface.Name) } else { // We set it here initially without a space, just so we don't // lose it when we have no linked subnet below. nicInfo.Address = network.NewAddress(link.IPAddress) nicInfo.ProviderAddressId = network.Id(fmt.Sprintf("%v", link.ID)) } if link.Subnet == nil { logger.Debugf("interface %q link %d missing subnet", iface.Name, link.ID) infos = append(infos, nicInfo) continue } sub := link.Subnet nicInfo.CIDR = sub.CIDR nicInfo.ProviderSubnetId = network.Id(fmt.Sprintf("%v", sub.ID)) nicInfo.ProviderVLANId = network.Id(fmt.Sprintf("%v", sub.VLAN.ID)) // Now we know the subnet and space, we can update the address to // store the space with it. nicInfo.Address = network.NewAddressOnSpace(sub.Space, link.IPAddress) spaceId, ok := subnetsMap[string(sub.CIDR)] if !ok { // The space we found is not recognised, no // provider id available. logger.Warningf("interface %q link %d has unrecognised space %q", iface.Name, link.ID, sub.Space) } else { nicInfo.Address.SpaceProviderId = spaceId nicInfo.ProviderSpaceId = spaceId } gwAddr := network.NewAddressOnSpace(sub.Space, sub.GatewayIP) nicInfo.DNSServers = network.NewAddressesOnSpace(sub.Space, sub.DNSServers...) if ok { gwAddr.SpaceProviderId = spaceId for i := range nicInfo.DNSServers { nicInfo.DNSServers[i].SpaceProviderId = spaceId } } nicInfo.GatewayAddress = gwAddr nicInfo.MTU = sub.VLAN.MTU // Each link we represent as a separate InterfaceInfo, but with the // same name and device index, just different addres, subnet, etc. infos = append(infos, nicInfo) } } return infos, nil }
func maas2NetworkInterfaces(instance *maas2Instance, subnetsMap map[string]network.Id) ([]network.InterfaceInfo, error) { interfaces := instance.machine.InterfaceSet() infos := make([]network.InterfaceInfo, 0, len(interfaces)) for i, iface := range interfaces { // The below works for all types except bonds and their members. parentName := strings.Join(iface.Parents(), "") var nicType network.InterfaceType switch maasInterfaceType(iface.Type()) { case typePhysical: nicType = network.EthernetInterface children := strings.Join(iface.Children(), "") if parentName == "" && len(iface.Children()) == 1 && strings.HasPrefix(children, "bond") { // FIXME: Verify the bond exists, regardless of its name. // This is a bond member, set the parent correctly (from // Juju's perspective) - to the bond itself. parentName = children } case typeBond: parentName = "" nicType = network.BondInterface case typeVLAN: nicType = network.VLAN_8021QInterface } vlanTag := 0 if iface.VLAN() != nil { vlanTag = iface.VLAN().VID() } nicInfo := network.InterfaceInfo{ DeviceIndex: i, MACAddress: iface.MACAddress(), ProviderId: network.Id(fmt.Sprintf("%v", iface.ID())), VLANTag: vlanTag, InterfaceName: iface.Name(), InterfaceType: nicType, ParentInterfaceName: parentName, Disabled: !iface.Enabled(), NoAutoStart: !iface.Enabled(), } for _, link := range iface.Links() { switch maasLinkMode(link.Mode()) { case modeUnknown: nicInfo.ConfigType = network.ConfigUnknown case modeDHCP: nicInfo.ConfigType = network.ConfigDHCP case modeStatic, modeLinkUp: nicInfo.ConfigType = network.ConfigStatic default: nicInfo.ConfigType = network.ConfigManual } if link.IPAddress() == "" { logger.Debugf("interface %q has no address", iface.Name()) } else { // We set it here initially without a space, just so we don't // lose it when we have no linked subnet below. nicInfo.Address = network.NewAddress(link.IPAddress()) nicInfo.ProviderAddressId = network.Id(fmt.Sprintf("%v", link.ID())) } if link.Subnet() == nil { logger.Debugf("interface %q link %d missing subnet", iface.Name(), link.ID()) infos = append(infos, nicInfo) continue } sub := link.Subnet() nicInfo.CIDR = sub.CIDR() nicInfo.ProviderSubnetId = network.Id(fmt.Sprintf("%v", sub.ID())) nicInfo.ProviderVLANId = network.Id(fmt.Sprintf("%v", sub.VLAN().ID())) // Now we know the subnet and space, we can update the address to // store the space with it. nicInfo.Address = network.NewAddressOnSpace(sub.Space(), link.IPAddress()) spaceId, ok := subnetsMap[string(sub.CIDR())] if !ok { // The space we found is not recognised, no // provider id available. logger.Warningf("interface %q link %d has unrecognised space %q", iface.Name(), link.ID(), sub.Space()) } else { nicInfo.Address.SpaceProviderId = spaceId nicInfo.ProviderSpaceId = spaceId } gwAddr := network.NewAddressOnSpace(sub.Space(), sub.Gateway()) nicInfo.DNSServers = network.NewAddressesOnSpace(sub.Space(), sub.DNSServers()...) if ok { gwAddr.SpaceProviderId = spaceId for i := range nicInfo.DNSServers { nicInfo.DNSServers[i].SpaceProviderId = spaceId } } nicInfo.GatewayAddress = gwAddr nicInfo.MTU = sub.VLAN().MTU() // Each link we represent as a separate InterfaceInfo, but with the // same name and device index, just different addres, subnet, etc. infos = append(infos, nicInfo) } } return infos, nil }
func (env *maasEnviron) deviceInterfaceInfo2(deviceID string, nameToParentName map[string]string) ([]network.InterfaceInfo, error) { args := gomaasapi.DevicesArgs{SystemIDs: []string{deviceID}} devices, err := env.maasController.Devices(args) if err != nil { return nil, errors.Trace(err) } if len(devices) != 1 { return nil, errors.Errorf("unexpected response requesting device %v: %v", deviceID, devices) } interfaces := devices[0].InterfaceSet() interfaceInfo := make([]network.InterfaceInfo, 0, len(interfaces)) for _, nic := range interfaces { vlanId := 0 vlanVid := 0 vlan := nic.VLAN() if vlan != nil { vlanId = vlan.ID() vlanVid = vlan.VID() } nicInfo := network.InterfaceInfo{ InterfaceName: nic.Name(), InterfaceType: network.EthernetInterface, MACAddress: nic.MACAddress(), MTU: nic.EffectiveMTU(), VLANTag: vlanVid, ProviderId: network.Id(strconv.Itoa(nic.ID())), ProviderVLANId: network.Id(strconv.Itoa(vlanId)), Disabled: !nic.Enabled(), NoAutoStart: !nic.Enabled(), ParentInterfaceName: nameToParentName[nic.Name()], } if len(nic.Links()) == 0 { logger.Debugf("device %q interface %q has no links", deviceID, nic.Name()) interfaceInfo = append(interfaceInfo, nicInfo) continue } for _, link := range nic.Links() { nicInfo.ConfigType = maasLinkToInterfaceConfigType(link.Mode()) subnet := link.Subnet() if link.IPAddress() == "" || subnet == nil { logger.Debugf("device %q interface %q has no address", deviceID, nic.Name()) interfaceInfo = append(interfaceInfo, nicInfo) continue } nicInfo.CIDR = subnet.CIDR() nicInfo.Address = network.NewAddressOnSpace(subnet.Space(), link.IPAddress()) nicInfo.ProviderSubnetId = network.Id(strconv.Itoa(subnet.ID())) nicInfo.ProviderAddressId = network.Id(strconv.Itoa(link.ID())) if subnet.Gateway() != "" { nicInfo.GatewayAddress = network.NewAddressOnSpace(subnet.Space(), subnet.Gateway()) } if len(subnet.DNSServers()) > 0 { nicInfo.DNSServers = network.NewAddressesOnSpace(subnet.Space(), subnet.DNSServers()...) } interfaceInfo = append(interfaceInfo, nicInfo) } } logger.Debugf("device %q has interface info: %+v", deviceID, interfaceInfo) return interfaceInfo, nil }
// legacyNetworkInterfaces implements Environ.NetworkInterfaces() on MAAS 1.8 and earlier. func (environ *maasEnviron) legacyNetworkInterfaces(instId instance.Id) ([]network.InterfaceInfo, error) { instances, err := environ.acquiredInstances([]instance.Id{instId}) if err != nil { return nil, errors.Annotatef(err, "could not find instance %q", instId) } if len(instances) == 0 { return nil, errors.NotFoundf("instance %q", instId) } inst := instances[0] interfaces, err := environ.getInstanceNetworkInterfaces(inst) if err != nil { return nil, errors.Annotatef(err, "failed to get instance %q network interfaces", instId) } networks, err := environ.getInstanceNetworks(inst) if err != nil { return nil, errors.Annotatef(err, "failed to get instance %q subnets", instId) } macToNetworksMap := make(map[string][]networkDetails) for _, network := range networks { macs, err := environ.listConnectedMacs(network) if err != nil { return nil, errors.Trace(err) } for _, mac := range macs { if networks, found := macToNetworksMap[mac]; found { macToNetworksMap[mac] = append(networks, network) } else { macToNetworksMap[mac] = append([]networkDetails(nil), network) } } } result := []network.InterfaceInfo{} for serial, iface := range interfaces { deviceIndex := iface.DeviceIndex interfaceName := iface.InterfaceName disabled := iface.Disabled ifaceInfo := network.InterfaceInfo{ DeviceIndex: deviceIndex, InterfaceName: interfaceName, Disabled: disabled, NoAutoStart: disabled, MACAddress: serial, ConfigType: network.ConfigDHCP, } allDetails, ok := macToNetworksMap[serial] if !ok { logger.Debugf("no subnet information for MAC address %q, instance %q", serial, instId) continue } for _, details := range allDetails { ifaceInfo.VLANTag = details.VLANTag ifaceInfo.ProviderSubnetId = network.Id(details.Name) mask := net.IPMask(net.ParseIP(details.Mask)) cidr := net.IPNet{ IP: net.ParseIP(details.IP), Mask: mask, } ifaceInfo.CIDR = cidr.String() ifaceInfo.Address = network.NewAddress(cidr.IP.String()) if details.DefaultGateway != "" { ifaceInfo.GatewayAddress = network.NewAddress(details.DefaultGateway) } result = append(result, ifaceInfo) } } return result, nil }
// maasObjectNetworkInterfaces implements environs.NetworkInterfaces() using the // new (1.9+) MAAS API, parsing the node details JSON embedded into the given // maasObject to extract all the relevant InterfaceInfo fields. It returns an // error satisfying errors.IsNotSupported() if it cannot find the required // "interface_set" node details field. func maasObjectNetworkInterfaces(maasObject *gomaasapi.MAASObject) ([]network.InterfaceInfo, error) { interfaceSet, ok := maasObject.GetMap()["interface_set"] if !ok || interfaceSet.IsNil() { // This means we're using an older MAAS API. return nil, errors.NotSupportedf("interface_set") } // TODO(dimitern): Change gomaasapi JSONObject to give access to the raw // JSON bytes directly, rather than having to do call MarshalJSON just so // the result can be unmarshaled from it. // // LKK Card: https://canonical.leankit.com/Boards/View/101652562/119311323 rawBytes, err := interfaceSet.MarshalJSON() if err != nil { return nil, errors.Annotate(err, "cannot get interface_set JSON bytes") } interfaces, err := parseInterfaces(rawBytes) if err != nil { return nil, errors.Trace(err) } infos := make([]network.InterfaceInfo, 0, len(interfaces)) for i, iface := range interfaces { nicInfo := network.InterfaceInfo{ DeviceIndex: i, MACAddress: iface.MACAddress, ProviderId: network.Id(fmt.Sprintf("%v", iface.ID)), VLANTag: iface.VLAN.VID, InterfaceName: iface.Name, Disabled: !iface.Enabled, NoAutoStart: !iface.Enabled, // This is not needed anymore, but the provisioner still validates it's set. NetworkName: network.DefaultPrivate, } for _, link := range iface.Links { switch link.Mode { case modeUnknown: nicInfo.ConfigType = network.ConfigUnknown case modeDHCP: nicInfo.ConfigType = network.ConfigDHCP case modeStatic, modeLinkUp: nicInfo.ConfigType = network.ConfigStatic default: nicInfo.ConfigType = network.ConfigManual } if link.IPAddress == "" { logger.Warningf("interface %q has no address", iface.Name) } else { // We set it here initially without a space, just so we don't // lose it when we have no linked subnet below. nicInfo.Address = network.NewAddress(link.IPAddress) } if link.Subnet == nil { logger.Warningf("interface %q link %d missing subnet", iface.Name, link.ID) infos = append(infos, nicInfo) continue } sub := link.Subnet nicInfo.CIDR = sub.CIDR nicInfo.ProviderSubnetId = network.Id(fmt.Sprintf("%v", sub.ID)) // Now we know the subnet and space, we can update the address to // store the space with it. nicInfo.Address = network.NewAddressOnSpace(sub.Space, link.IPAddress) gwAddr := network.NewAddressOnSpace(sub.Space, sub.GatewayIP) nicInfo.GatewayAddress = gwAddr nicInfo.DNSServers = network.NewAddressesOnSpace(sub.Space, sub.DNSServers...) nicInfo.MTU = sub.VLAN.MTU // Each link we represent as a separate InterfaceInfo, but with the // same name and device index, just different addres, subnet, etc. infos = append(infos, nicInfo) } } return infos, nil }