func opClientResolved(c *gc.C, st *api.State, _ *state.State) (func(), error) { err := st.Client().Resolved("wordpress/1", false) // There are several scenarios in which this test is called, one is // that the user is not authorized. In that case we want to exit now, // letting the error percolate out so the caller knows that the // permission error was correctly generated. if err != nil && params.IsCodeUnauthorized(err) { return func() {}, err } // Otherwise, the user was authorized, but we expect an error anyway // because the unit is not in an error state when we tried to resolve // the error. Therefore, since it is complaining it means that the // call to Resolved worked, so we're happy. c.Assert(err, gc.NotNil) c.Assert(err.Error(), gc.Equals, `unit "wordpress/1" is not in an error state`) return func() {}, 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, resultErr 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 resultErr != 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 }