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. logger.Errorf("cannot set error status for machine %q: %v", machine, err1) return err1 } return nil }
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 } includeNetworks := pInfo.IncludeNetworks excludeNetworks := pInfo.ExcludeNetworks nonce := fmt.Sprintf("%s:%s", task.machineTag, uuid.String()) machineConfig := environs.NewMachineConfig(machine.Id(), nonce, includeNetworks, excludeNetworks, stateInfo, apiInfo) return &provisioningInfo{ Constraints: pInfo.Constraints, Series: pInfo.Series, Placement: pInfo.Placement, MachineConfig: machineConfig, }, nil }
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([]instance.Instance{inst}); 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 }