// pendingOrDead looks up machines with ids and returns those that do not // have an instance id assigned yet, and also those that are dead. func (task *provisionerTask) pendingOrDead(ids []string) (pending, dead []*apiprovisioner.Machine, err error) { for _, id := range ids { machine, found := task.machines[id] if !found { logger.Infof("machine %q not found", id) continue } switch machine.Life() { case params.Dying: if _, err := machine.InstanceId(); err == nil { continue } else if !params.IsCodeNotProvisioned(err) { logger.Errorf("failed to load machine %q instance id: %v", machine, err) return nil, nil, err } logger.Infof("killing dying, unprovisioned machine %q", machine) if err := machine.EnsureDead(); err != nil { logger.Errorf("failed to ensure machine dead %q: %v", machine, err) return nil, nil, err } fallthrough case params.Dead: dead = append(dead, machine) continue } if instId, err := machine.InstanceId(); err != nil { if !params.IsCodeNotProvisioned(err) { logger.Errorf("failed to load machine %q instance id: %v", machine, err) continue } status, _, err := machine.Status() if err != nil { logger.Infof("cannot get machine %q status: %v", machine, err) continue } if status == params.StatusPending { pending = append(pending, machine) logger.Infof("found machine %q pending provisioning", machine) continue } } else { logger.Infof("machine %v already started as instance %q", machine, instId) } } logger.Tracef("pending machines: %v", pending) logger.Tracef("dead machines: %v", dead) return }
// findUnknownInstances finds instances which are not associated with a machine. func (task *provisionerTask) findUnknownInstances(stopping []instance.Instance) ([]instance.Instance, error) { // Make a copy of the instances we know about. instances := make(map[instance.Id]instance.Instance) for k, v := range task.instances { instances[k] = v } for _, m := range task.machines { instId, err := m.InstanceId() switch { case err == nil: delete(instances, instId) case params.IsCodeNotProvisioned(err): case params.IsCodeNotFoundOrCodeUnauthorized(err): default: return nil, err } } // Now remove all those instances that we are stopping already as we // know about those and don't want to include them in the unknown list. for _, inst := range stopping { delete(instances, inst.Id()) } var unknown []instance.Instance for _, inst := range instances { unknown = append(unknown, inst) } return unknown, nil }
// openAPIState opens the API using the given information, and // returns the opened state and the api entity with // the given tag. The given changeConfig function is // called if the password changes to set the password. func openAPIState( agentConfig agent.Config, a Agent, ) (_ *api.State, _ *apiagent.Entity, err error) { // We let the API dial fail immediately because the // runner's loop outside the caller of openAPIState will // keep on retrying. If we block for ages here, // then the worker that's calling this cannot // be interrupted. info := agentConfig.APIInfo() st, err := apiOpen(info, api.DialOpts{}) usedOldPassword := false if params.IsCodeUnauthorized(err) { // We've perhaps used the wrong password, so // try again with the fallback password. info := *info info.Password = agentConfig.OldPassword() usedOldPassword = true st, err = apiOpen(&info, api.DialOpts{}) } if err != nil { if params.IsCodeNotProvisioned(err) { return nil, nil, worker.ErrTerminateAgent } if params.IsCodeUnauthorized(err) { return nil, nil, worker.ErrTerminateAgent } return nil, nil, err } defer func() { if err != nil { st.Close() } }() entity, err := st.Agent().Entity(a.Tag()) if err == nil && entity.Life() == params.Dead { return nil, nil, worker.ErrTerminateAgent } if err != nil { if params.IsCodeUnauthorized(err) { return nil, nil, worker.ErrTerminateAgent } return nil, nil, err } if usedOldPassword { // We succeeded in connecting with the fallback // password, so we need to create a new password // for the future. newPassword, err := utils.RandomPassword() if err != nil { return nil, nil, err } // Change the configuration *before* setting the entity // password, so that we avoid the possibility that // we might successfully change the entity's // password but fail to write the configuration, // thus locking us out completely. if err := a.ChangeConfig(func(c agent.ConfigSetter) { c.SetPassword(newPassword) c.SetOldPassword(info.Password) }); err != nil { return nil, nil, err } if err := entity.SetPassword(newPassword); err != nil { return nil, nil, err } } return st, entity, nil }