예제 #1
0
func (task *provisionerTask) setErrorStatus(message string, machine *apiprovisioner.Machine, err error) error {
	logger.Errorf(message, machine, err)
	if err1 := machine.SetStatus(params.StatusError, err.Error(), nil); err1 != nil {
		// Something is wrong with this machine, better report it back.
		return errors.Annotatef(err1, "cannot set error status for machine %q", machine)
	}
	return nil
}
예제 #2
0
func (task *provisionerTask) startMachine(machine *apiprovisioner.Machine) error {
	provisioningInfo, err := task.provisioningInfo(machine)
	if err != nil {
		return err
	}
	possibleTools, err := task.possibleTools(provisioningInfo.Series, provisioningInfo.Constraints)
	if err != nil {
		return task.setErrorStatus("cannot find tools for machine %q: %v", machine, err)
	}
	inst, metadata, networkInfo, err := task.broker.StartInstance(environs.StartInstanceParams{
		Constraints:       provisioningInfo.Constraints,
		Tools:             possibleTools,
		MachineConfig:     provisioningInfo.MachineConfig,
		Placement:         provisioningInfo.Placement,
		DistributionGroup: machine.DistributionGroup,
	})
	if err != nil {
		// 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)
	}
	nonce := provisioningInfo.MachineConfig.MachineNonce
	networks, ifaces := task.prepareNetworkAndInterfaces(networkInfo)

	err = machine.SetInstanceInfo(inst.Id(), nonce, metadata, networks, ifaces)
	if err != nil && params.IsCodeNotImplemented(err) {
		return fmt.Errorf("cannot provision instance %v for machine %q with networks: not implemented", inst.Id(), machine)
	} else if err == nil {
		logger.Infof("started machine %s as instance %s with hardware %q, networks %v, interfaces %v", machine, inst.Id(), metadata, networks, ifaces)
		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.
		logger.Errorf("cannot stop instance %q for machine %v: %v", inst.Id(), machine, err)
		return err
	}
	return nil
}
예제 #3
0
func (task *provisionerTask) provisioningInfo(machine *apiprovisioner.Machine) (*provisioningInfo, error) {
	stateInfo, apiInfo, err := task.auth.SetupAuthentication(machine)
	if err != nil {
		logger.Errorf("failed to setup authentication: %v", err)
		return nil, err
	}
	// Generated a nonce for the new instance, with the format: "machine-#:UUID".
	// The first part is a badge, specifying the tag of the machine the provisioner
	// is running on, while the second part is a random UUID.
	uuid, err := utils.NewUUID()
	if err != nil {
		return nil, err
	}
	// ProvisioningInfo is new in 1.20; wait for the API server to be upgraded
	// so we don't spew errors on upgrade.
	var pInfo *params.ProvisioningInfo
	for {
		if pInfo, err = machine.ProvisioningInfo(); err == nil {
			break
		}
		if params.IsCodeNotImplemented(err) {
			logger.Infof("waiting for state server to be upgraded")
			select {
			case <-task.tomb.Dying():
				return nil, tomb.ErrDying
			case <-time.After(15 * time.Second):
				continue
			}
		}
		return nil, err
	}
	nonce := fmt.Sprintf("%s:%s", task.machineTag, uuid.String())
	machineConfig := environs.NewMachineConfig(machine.Id(), nonce, pInfo.Networks, stateInfo, apiInfo)
	return &provisioningInfo{
		Constraints:   pInfo.Constraints,
		Series:        pInfo.Series,
		Placement:     pInfo.Placement,
		MachineConfig: machineConfig,
	}, nil
}