Exemple #1
0
func (api *MachinerAPI) getOneMachineProviderNetworkConfig(m *state.Machine) ([]params.NetworkConfig, error) {
	instId, err := m.InstanceId()
	if err != nil {
		return nil, errors.Trace(err)
	}

	netEnviron, err := networkingcommon.NetworkingEnvironFromModelConfig(
		stateenvirons.EnvironConfigGetter{api.st},
	)
	if errors.IsNotSupported(err) {
		logger.Infof("not updating provider network config: %v", err)
		return nil, nil
	} else if err != nil {
		return nil, errors.Annotate(err, "cannot get provider network config")
	}

	interfaceInfos, err := netEnviron.NetworkInterfaces(instId)
	if err != nil {
		return nil, errors.Annotatef(err, "cannot get network interfaces of %q", instId)
	}
	if len(interfaceInfos) == 0 {
		logger.Infof("not updating provider network config: no interfaces returned")
		return nil, nil
	}

	providerConfig := networkingcommon.NetworkConfigFromInterfaceInfo(interfaceInfos)
	logger.Tracef("provider network config instance %q: %+v", instId, providerConfig)

	return providerConfig, nil
}
Exemple #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
}
Exemple #3
0
func (task *provisionerTask) startMachine(
	machine *apiprovisioner.Machine,
	provisioningInfo *params.ProvisioningInfo,
	startInstanceParams environs.StartInstanceParams,
) error {
	var result *environs.StartInstanceResult
	for attemptsLeft := task.retryStartInstanceStrategy.retryCount; attemptsLeft >= 0; attemptsLeft-- {
		attemptResult, err := task.broker.StartInstance(startInstanceParams)
		if err == nil {
			result = attemptResult
			break
		} else if attemptsLeft <= 0 {
			// Set the state to error, so the machine will be skipped
			// next time until the error is resolved, but don't return
			// an error; just keep going with the other machines.
			return task.setErrorStatus("cannot start instance for machine %q: %v", machine, err)
		}

		logger.Warningf("%v", errors.Annotate(err, "starting instance"))
		retryMsg := fmt.Sprintf("will retry to start instance in %v", task.retryStartInstanceStrategy.retryDelay)
		if err2 := machine.SetStatus(status.Pending, retryMsg, nil); err2 != nil {
			logger.Errorf("%v", err2)
		}
		logger.Infof(retryMsg)

		select {
		case <-task.catacomb.Dying():
			return task.catacomb.ErrDying()
		case <-time.After(task.retryStartInstanceStrategy.retryDelay):
		}
	}

	networkConfig := networkingcommon.NetworkConfigFromInterfaceInfo(result.NetworkInfo)
	volumes := volumesToAPIserver(result.Volumes)
	volumeNameToAttachmentInfo := volumeAttachmentsToAPIserver(result.VolumeAttachments)

	if err := machine.SetInstanceInfo(
		result.Instance.Id(),
		startInstanceParams.InstanceConfig.MachineNonce,
		result.Hardware,
		networkConfig,
		volumes,
		volumeNameToAttachmentInfo,
	); err != nil {
		// We need to stop the instance right away here, set error status and go on.
		if err2 := task.setErrorStatus("cannot register instance for machine %v: %v", machine, err); err2 != nil {
			logger.Errorf("%v", errors.Annotate(err2, "cannot set machine's status"))
		}
		if err2 := task.broker.StopInstances(result.Instance.Id()); err2 != nil {
			logger.Errorf("%v", errors.Annotate(err2, "after failing to set instance info"))
		}
		return errors.Annotate(err, "cannot set instance info")
	}

	logger.Infof(
		"started machine %s as instance %s with hardware %q, network config %+v, volumes %v, volume attachments %v, subnets to zones %v",
		machine,
		result.Instance.Id(),
		result.Hardware,
		networkConfig,
		volumes,
		volumeNameToAttachmentInfo,
		startInstanceParams.SubnetsToZones,
	)
	return nil
}
Exemple #4
0
func (task *provisionerTask) startMachine(
	machine *apiprovisioner.Machine,
	provisioningInfo *params.ProvisioningInfo,
	startInstanceParams environs.StartInstanceParams,
) error {

	result, err := task.broker.StartInstance(startInstanceParams)
	if err != nil {
		if !instance.IsRetryableCreationError(errors.Cause(err)) {
			// Set the state to error, so the machine will be skipped next
			// time until the error is resolved, but don't return an
			// error; just keep going with the other machines.
			return task.setErrorStatus("cannot start instance for machine %q: %v", machine, err)
		}
		logger.Infof("retryable error received on start instance: %v", err)
		for count := task.retryStartInstanceStrategy.retryCount; count > 0; count-- {
			if task.retryStartInstanceStrategy.retryDelay > 0 {
				select {
				case <-task.catacomb.Dying():
					return task.catacomb.ErrDying()
				case <-time.After(task.retryStartInstanceStrategy.retryDelay):
				}

			}
			result, err = task.broker.StartInstance(startInstanceParams)
			if err == nil {
				break
			}
			// If this was the last attempt and an error was received, set the error
			// status on the machine.
			if count == 1 {
				return task.setErrorStatus("cannot start instance for machine %q: %v", machine, err)
			}
		}
	}

	inst := result.Instance
	hardware := result.Hardware
	nonce := startInstanceParams.InstanceConfig.MachineNonce
	networkConfig := networkingcommon.NetworkConfigFromInterfaceInfo(result.NetworkInfo)
	volumes := volumesToApiserver(result.Volumes)
	volumeAttachments := volumeAttachmentsToApiserver(result.VolumeAttachments)

	err = machine.SetInstanceInfo(inst.Id(), nonce, hardware, networkConfig, volumes, volumeAttachments)
	if err == nil {
		logger.Infof(
			"started machine %s as instance %s with hardware %q, network config %+v, volumes %v, volume attachments %v, subnets to zones %v",
			machine, inst.Id(), hardware,
			networkConfig,
			volumes, volumeAttachments,
			startInstanceParams.SubnetsToZones,
		)
		return nil
	}
	// We need to stop the instance right away here, set error status and go on.
	task.setErrorStatus("cannot register instance for machine %v: %v", machine, err)
	if err := task.broker.StopInstances(inst.Id()); err != nil {
		// We cannot even stop the instance, log the error and quit.
		return errors.Annotatef(err, "cannot stop instance %q for machine %v", inst.Id(), machine)
	}
	return nil
}