Beispiel #1
0
// prepareOrGetContainerInterfaceInfo returns the necessary information to
// configure network interfaces of a container with allocated static
// IP addresses.
//
// TODO(dimitern): Before we start using this, we need to rename both
// the method and the network.InterfaceInfo type to be called
// InterfaceConfig.
func (st *State) prepareOrGetContainerInterfaceInfo(
	containerTag names.MachineTag, allocateNewAddress bool) (
	[]network.InterfaceInfo, error) {
	var result params.MachineNetworkConfigResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: containerTag.String()}},
	}
	facadeName := ""
	if allocateNewAddress {
		facadeName = "PrepareContainerInterfaceInfo"
	} else {
		facadeName = "GetContainerInterfaceInfo"
	}
	if err := st.facade.FacadeCall(facadeName, args, &result); err != nil {
		return nil, err
	}
	if len(result.Results) != 1 {
		return nil, errors.Errorf("expected 1 result, got %d", len(result.Results))
	}
	if err := result.Results[0].Error; err != nil {
		return nil, err
	}
	ifaceInfo := make([]network.InterfaceInfo, len(result.Results[0].Config))
	for i, cfg := range result.Results[0].Config {
		ifaceInfo[i] = network.InterfaceInfo{
			DeviceIndex:         cfg.DeviceIndex,
			MACAddress:          cfg.MACAddress,
			CIDR:                cfg.CIDR,
			MTU:                 cfg.MTU,
			ProviderId:          network.Id(cfg.ProviderId),
			ProviderSubnetId:    network.Id(cfg.ProviderSubnetId),
			ProviderSpaceId:     network.Id(cfg.ProviderSpaceId),
			ProviderVLANId:      network.Id(cfg.ProviderVLANId),
			ProviderAddressId:   network.Id(cfg.ProviderAddressId),
			VLANTag:             cfg.VLANTag,
			InterfaceName:       cfg.InterfaceName,
			ParentInterfaceName: cfg.ParentInterfaceName,
			InterfaceType:       network.InterfaceType(cfg.InterfaceType),
			Disabled:            cfg.Disabled,
			NoAutoStart:         cfg.NoAutoStart,
			ConfigType:          network.InterfaceConfigType(cfg.ConfigType),
			Address:             network.NewAddress(cfg.Address),
			DNSServers:          network.NewAddresses(cfg.DNSServers...),
			DNSSearchDomains:    cfg.DNSSearchDomains,
			GatewayAddress:      network.NewAddress(cfg.GatewayAddress),
		}
	}
	return ifaceInfo, nil
}
Beispiel #2
0
func (p *ProvisionerAPI) prepareOrGetContainerInterfaceInfo(args params.Entities, maintain bool) (params.MachineNetworkConfigResults, error) {
	result := params.MachineNetworkConfigResults{
		Results: make([]params.MachineNetworkConfigResult, len(args.Entities)),
	}

	netEnviron, hostMachine, canAccess, err := p.prepareContainerAccessEnvironment()
	if err != nil {
		return result, errors.Trace(err)
	}
	instId, err := hostMachine.InstanceId()
	if errors.IsNotProvisioned(err) {
		err = errors.NotProvisionedf("cannot prepare container network config: host machine %q", hostMachine)
		return result, err
	} else if err != nil {
		return result, errors.Trace(err)
	}

	for i, entity := range args.Entities {
		machineTag, err := names.ParseMachineTag(entity.Tag)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		// The auth function (canAccess) checks that the machine is a
		// top level machine (we filter those out next) or that the
		// machine has the host as a parent.
		container, err := p.getMachine(canAccess, machineTag)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		} else if !container.IsContainer() {
			err = errors.Errorf("cannot prepare network config for %q: not a container", machineTag)
			result.Results[i].Error = common.ServerError(err)
			continue
		} else if ciid, cerr := container.InstanceId(); maintain == true && cerr == nil {
			// Since we want to configure and create NICs on the
			// container before it starts, it must also be not
			// provisioned yet.
			err = errors.Errorf("container %q already provisioned as %q", container, ciid)
			result.Results[i].Error = common.ServerError(err)
			continue
		} else if cerr != nil && !errors.IsNotProvisioned(cerr) {
			// Any other error needs to be reported.
			result.Results[i].Error = common.ServerError(cerr)
			continue
		}

		if err := hostMachine.SetContainerLinkLayerDevices(container); err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}

		containerDevices, err := container.AllLinkLayerDevices()
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}

		preparedInfo := make([]network.InterfaceInfo, len(containerDevices))
		preparedOK := true
		for j, device := range containerDevices {
			parentDevice, err := device.ParentDevice()
			if err != nil || parentDevice == nil {
				err = errors.Errorf(
					"cannot get parent %q of container device %q: %v",
					device.ParentName(), device.Name(), err,
				)
				result.Results[i].Error = common.ServerError(err)
				preparedOK = false
				break
			}
			parentAddrs, err := parentDevice.Addresses()
			if err != nil {
				result.Results[i].Error = common.ServerError(err)
				preparedOK = false
				break
			}

			info := network.InterfaceInfo{
				InterfaceName:       device.Name(),
				MACAddress:          device.MACAddress(),
				ConfigType:          network.ConfigManual,
				InterfaceType:       network.InterfaceType(device.Type()),
				NoAutoStart:         !device.IsAutoStart(),
				Disabled:            !device.IsUp(),
				MTU:                 int(device.MTU()),
				ParentInterfaceName: parentDevice.Name(),
			}

			if len(parentAddrs) > 0 {
				logger.Infof("host machine device %q has addresses %v", parentDevice.Name(), parentAddrs)

				firstAddress := parentAddrs[0]
				parentDeviceSubnet, err := firstAddress.Subnet()
				if err != nil {
					err = errors.Annotatef(err,
						"cannot get subnet %q used by address %q of host machine device %q",
						firstAddress.SubnetCIDR(), firstAddress.Value(), parentDevice.Name(),
					)
					result.Results[i].Error = common.ServerError(err)
					preparedOK = false
					break
				}
				info.ConfigType = network.ConfigStatic
				info.CIDR = parentDeviceSubnet.CIDR()
				info.ProviderSubnetId = parentDeviceSubnet.ProviderId()
				info.VLANTag = parentDeviceSubnet.VLANTag()
			} else {
				logger.Infof("host machine device %q has no addresses %v", parentDevice.Name(), parentAddrs)
			}

			logger.Tracef("prepared info for container interface %q: %+v", info.InterfaceName, info)
			preparedOK = true
			preparedInfo[j] = info
		}

		if !preparedOK {
			// Error result is already set.
			continue
		}

		allocatedInfo, err := netEnviron.AllocateContainerAddresses(instId, machineTag, preparedInfo)
		if err != nil {
			result.Results[i].Error = common.ServerError(err)
			continue
		}
		logger.Debugf("got allocated info from provider: %+v", allocatedInfo)

		allocatedConfig := networkingcommon.NetworkConfigFromInterfaceInfo(allocatedInfo)
		logger.Tracef("allocated network config: %+v", allocatedConfig)
		result.Results[i].Config = allocatedConfig
	}
	return result, nil
}