func (s *clientSuite) TestOpenUsesEnvironUUIDPaths(c *gc.C) { info := s.APIInfo(c) // Backwards compatibility, passing ModelTag = "" should just work info.ModelTag = names.NewModelTag("") apistate, err := api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) apistate.Close() // Passing in the correct model UUID should also work environ, err := s.State.Model() c.Assert(err, jc.ErrorIsNil) info.ModelTag = environ.ModelTag() apistate, err = api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) apistate.Close() // Passing in a bad model UUID should fail with a known error info.ModelTag = names.NewModelTag("dead-beef-123456") apistate, err = api.Open(info, api.DialOpts{}) c.Assert(errors.Cause(err), gc.DeepEquals, &rpc.RequestError{ Message: `unknown model: "dead-beef-123456"`, Code: "not found", }) c.Check(err, jc.Satisfies, params.IsCodeNotFound) c.Assert(apistate, gc.IsNil) }
func (s *apiclientSuite) TestOpenHonorsEnvironTag(c *gc.C) { info := s.APIInfo(c) // TODO(jam): 2014-06-05 http://pad.lv/1326802 // we want to test this eventually, but for now s.APIInfo uses // conn.StateInfo() which doesn't know about EnvironTag. // c.Check(info.EnvironTag, gc.Equals, env.Tag()) // c.Assert(info.EnvironTag, gc.Not(gc.Equals), "") // We start by ensuring we have an invalid tag, and Open should fail. info.EnvironTag = names.NewEnvironTag("bad-tag") _, err := api.Open(info, api.DialOpts{}) c.Check(err, gc.ErrorMatches, `unknown environment: "bad-tag"`) c.Check(params.ErrCode(err), gc.Equals, params.CodeNotFound) // Now set it to the right tag, and we should succeed. info.EnvironTag = s.State.EnvironTag() st, err := api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) st.Close() // Backwards compatibility, we should succeed if we do not set an // environ tag info.EnvironTag = names.NewEnvironTag("") st, err = api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) st.Close() }
func (s *serverSuite) TestAPIServerCanListenOnBothIPv4AndIPv6(c *gc.C) { err := s.State.SetAPIHostPorts(nil) c.Assert(err, jc.ErrorIsNil) // Start our own instance of the server listening on // both IPv4 and IPv6 localhost addresses and an ephemeral port. listener, err := net.Listen("tcp", ":0") c.Assert(err, jc.ErrorIsNil) srv, err := apiserver.NewServer(s.State, listener, apiserver.ServerConfig{ Cert: []byte(coretesting.ServerCert), Key: []byte(coretesting.ServerKey), Tag: names.NewMachineTag("0"), }) c.Assert(err, jc.ErrorIsNil) defer srv.Stop() port := srv.Addr().Port portString := fmt.Sprintf("%d", port) machine, password := s.Factory.MakeMachineReturningPassword( c, &factory.MachineParams{Nonce: "fake_nonce"}) // Now connect twice - using IPv4 and IPv6 endpoints. apiInfo := &api.Info{ Tag: machine.Tag(), Password: password, Nonce: "fake_nonce", Addrs: []string{net.JoinHostPort("127.0.0.1", portString)}, CACert: coretesting.CACert, EnvironTag: s.State.EnvironTag(), } ipv4State, err := api.Open(apiInfo, fastDialOpts) c.Assert(err, jc.ErrorIsNil) defer ipv4State.Close() c.Assert(ipv4State.Addr(), gc.Equals, net.JoinHostPort("127.0.0.1", portString)) c.Assert(ipv4State.APIHostPorts(), jc.DeepEquals, [][]network.HostPort{ network.NewHostPorts(port, "127.0.0.1"), }) _, err = ipv4State.Machiner().Machine(machine.MachineTag()) c.Assert(err, jc.ErrorIsNil) apiInfo.Addrs = []string{net.JoinHostPort("::1", portString)} ipv6State, err := api.Open(apiInfo, fastDialOpts) c.Assert(err, jc.ErrorIsNil) defer ipv6State.Close() c.Assert(ipv6State.Addr(), gc.Equals, net.JoinHostPort("::1", portString)) c.Assert(ipv6State.APIHostPorts(), jc.DeepEquals, [][]network.HostPort{ network.NewHostPorts(port, "::1"), }) _, err = ipv6State.Machiner().Machine(machine.MachineTag()) c.Assert(err, jc.ErrorIsNil) }
func (s *serverSuite) TestOpenAsMachineErrors(c *gc.C) { assertNotProvisioned := func(err error) { c.Assert(err, gc.NotNil) c.Assert(err, jc.Satisfies, params.IsCodeNotProvisioned) c.Assert(err, gc.ErrorMatches, `machine \d+ is not provisioned`) } stm, err := s.State.AddMachine("quantal", state.JobHostUnits) c.Assert(err, gc.IsNil) err = stm.SetProvisioned("foo", "fake_nonce", nil) c.Assert(err, gc.IsNil) password, err := utils.RandomPassword() c.Assert(err, gc.IsNil) err = stm.SetPassword(password) c.Assert(err, gc.IsNil) // This does almost exactly the same as OpenAPIAsMachine but checks // for failures instead. info := s.APIInfo(c) info.Tag = stm.Tag() info.Password = password info.Nonce = "invalid-nonce" st, err := api.Open(info, fastDialOpts) assertNotProvisioned(err) c.Assert(st, gc.IsNil) // Try with empty nonce as well. info.Nonce = "" st, err = api.Open(info, fastDialOpts) assertNotProvisioned(err) c.Assert(st, gc.IsNil) // Finally, with the correct one succeeds. info.Nonce = "fake_nonce" st, err = api.Open(info, fastDialOpts) c.Assert(err, gc.IsNil) c.Assert(st, gc.NotNil) st.Close() // Now add another machine, intentionally unprovisioned. stm1, err := s.State.AddMachine("quantal", state.JobHostUnits) c.Assert(err, gc.IsNil) err = stm1.SetPassword(password) c.Assert(err, gc.IsNil) // Try connecting, it will fail. info.Tag = stm1.Tag() info.Nonce = "" st, err = api.Open(info, fastDialOpts) assertNotProvisioned(err) c.Assert(st, gc.IsNil) }
func startNLogins(c *gc.C, n int, info *api.Info) (chan error, *sync.WaitGroup) { errResults := make(chan error, 100) var doneWG sync.WaitGroup var startedWG sync.WaitGroup c.Logf("starting %d concurrent logins to %v", n, info.Addrs) for i := 0; i < n; i++ { i := i c.Logf("starting login request %d", i) startedWG.Add(1) doneWG.Add(1) go func() { c.Logf("started login %d", i) startedWG.Done() st, err := api.Open(info, fastDialOpts) errResults <- err if err == nil { st.Close() } doneWG.Done() c.Logf("finished login %d: %v", i, err) }() } startedWG.Wait() return errResults, &doneWG }
func (s *loginSuite) TestMachineLoginOtherEnvironment(c *gc.C) { // User credentials are checked against a global user list. // Machine credentials are checked against environment specific // machines, so this makes sure that the credential checking is // using the correct state connection. info, cleanup := s.setupServerWithValidator(c, nil) defer cleanup() envOwner := s.Factory.MakeUser(c, nil) envState := s.Factory.MakeEnvironment(c, &factory.EnvParams{ Owner: envOwner.UserTag(), ConfigAttrs: map[string]interface{}{ "state-server": false, }, Prepare: true, }) defer envState.Close() f2 := factory.NewFactory(envState) machine, password := f2.MakeMachineReturningPassword(c, &factory.MachineParams{ Nonce: "nonce", }) info.EnvironTag = envState.EnvironTag() st, err := api.Open(info, fastDialOpts) c.Assert(err, jc.ErrorIsNil) defer st.Close() err = st.Login(machine.Tag(), password, "nonce") c.Assert(err, jc.ErrorIsNil) }
func (s *baseLoginSuite) openAPIWithoutLogin(c *gc.C, info *api.Info) api.Connection { info.Tag = nil info.Password = "" st, err := api.Open(info, fastDialOpts) c.Assert(err, jc.ErrorIsNil) return st }
func (s *apiclientSuite) TestOpenFailsIfUsernameAndUseMacaroon(c *gc.C) { info := s.APIInfo(c) info.Tag = names.NewUserTag("foobar") info.UseMacaroons = true _, err := api.Open(info, api.DialOpts{}) c.Assert(err, gc.ErrorMatches, "open should specifiy UseMacaroons or a username & password. Not both") }
func (s *apiEnvironmentSuite) TestUploadToolsOtherEnvironment(c *gc.C) { // setup other environment otherState := s.Factory.MakeModel(c, nil) defer otherState.Close() info := s.APIInfo(c) info.ModelTag = otherState.ModelTag() otherAPIState, err := api.Open(info, api.DefaultDialOpts()) c.Assert(err, jc.ErrorIsNil) defer otherAPIState.Close() otherClient := otherAPIState.Client() defer otherClient.ClientFacade.Close() newVersion := version.MustParseBinary("5.4.3-quantal-amd64") vers := newVersion.String() // build fake tools tgz, checksum := coretesting.TarGz( coretesting.NewTarFile(jujunames.Jujud, 0777, "jujud contents "+vers)) toolsList, err := otherClient.UploadTools(bytes.NewReader(tgz), newVersion) c.Assert(err, jc.ErrorIsNil) c.Assert(toolsList, gc.HasLen, 1) c.Assert(toolsList[0].SHA256, gc.Equals, checksum) toolStrg, err := otherState.ToolsStorage() defer toolStrg.Close() c.Assert(err, jc.ErrorIsNil) meta, closer, err := toolStrg.Open(vers) defer closer.Close() c.Assert(err, jc.ErrorIsNil) c.Assert(meta.SHA256, gc.Equals, checksum) c.Assert(meta.Version, gc.Equals, vers) }
func (s *loginSuite) TestLoginAsDeactivatedUser(c *gc.C) { info, cleanup := s.setupServerWithValidator(c, nil) defer cleanup() info.Tag = nil info.Password = "" st, err := api.Open(info, fastDialOpts) c.Assert(err, jc.ErrorIsNil) defer st.Close() password := "******" u := s.Factory.MakeUser(c, &factory.UserParams{Password: password, Disabled: true}) _, err = st.Client().Status([]string{}) c.Assert(errors.Cause(err), gc.DeepEquals, &rpc.RequestError{ Message: `unknown object type "Client"`, Code: "not implemented", }) // Since these are user login tests, the nonce is empty. err = st.Login(u.Tag(), password, "") c.Assert(errors.Cause(err), gc.DeepEquals, &rpc.RequestError{ Message: "invalid entity name or password", Code: "unauthorized access", }) _, err = st.Client().Status([]string{}) c.Assert(errors.Cause(err), gc.DeepEquals, &rpc.RequestError{ Message: `unknown object type "Client"`, Code: "not implemented", }) }
func (s *loginSuite) TestLoginUpdatesLastLoginAndConnection(c *gc.C) { _, cleanup := s.setupServerWithValidator(c, nil) defer cleanup() // Since the login and connection times truncate time to the second, // we need to make sure our start time is just before now. startTime := time.Now().Add(-time.Second) password := "******" user := s.Factory.MakeUser(c, &factory.UserParams{ Password: password, }) info := s.APIInfo(c) info.Tag = user.Tag() info.Password = password apiState, err := api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) defer apiState.Close() // The user now has last login updated. err = user.Refresh() c.Assert(err, jc.ErrorIsNil) c.Assert(user.LastLogin(), gc.NotNil) c.Assert(user.LastLogin().After(startTime), jc.IsTrue) // The env user is also updated. envUser, err := s.State.EnvironmentUser(user.UserTag()) c.Assert(err, jc.ErrorIsNil) c.Assert(envUser.LastConnection(), gc.NotNil) c.Assert(envUser.LastConnection().After(startTime), jc.IsTrue) }
func (s *upgradeSuite) attemptRestrictedAPIAsUser(c *gc.C, conf agent.Config) error { info, ok := conf.APIInfo() c.Assert(ok, jc.IsTrue) info.Tag = s.AdminUserTag(c) info.Password = "******" info.Nonce = "" apiState, err := api.Open(info, upgradeTestDialOpts) if err != nil { // If space discovery is in progress we'll get an error here // and need to retry. return err } defer apiState.Close() // This call should always work, but might fail if the apiserver // is restarting. If it fails just return the error so retries // can continue. err = apiState.APICall("Client", 1, "", "FullStatus", nil, new(params.FullStatus)) if err != nil { return errors.Annotate(err, "FullStatus call") } // this call should only work if API is not restricted err = apiState.APICall("Client", 1, "", "WatchAll", nil, nil) return errors.Annotate(err, "WatchAll call") }
func (s *apiclientSuite) TestOpenWithRedirect(c *gc.C) { redirectToHosts := []string{"0.1.2.3:1234", "0.1.2.4:1235"} redirectToCACert := "fake CA cert" srv := apiservertesting.NewAPIServer(func(modelUUID string) interface{} { return &redirectAPI{ modelUUID: modelUUID, redirectToHosts: redirectToHosts, redirectToCACert: redirectToCACert, } }) defer srv.Close() _, err := api.Open(&api.Info{ Addrs: srv.Addrs, CACert: jtesting.CACert, ModelTag: names.NewModelTag("beef1beef1-0000-0000-000011112222"), }, api.DialOpts{}) c.Assert(err, gc.ErrorMatches, `redirection to alternative server required`) hps, _ := network.ParseHostPorts(redirectToHosts...) c.Assert(errors.Cause(err), jc.DeepEquals, &api.RedirectError{ Servers: [][]network.HostPort{hps}, CACert: redirectToCACert, }) }
// testSNIHostName tests that when the API is dialed with the given info, // api.newWebsocketDialer is called with the expected information. func (s *apiclientSuite) testSNIHostName(c *gc.C, info *api.Info, expectDial apiDialInfo) { dialed := make(chan *websocket.Config) fakeDialer := func(cfg *websocket.Config) (*websocket.Conn, error) { dialed <- cfg return nil, errors.New("nope") } done := make(chan struct{}) go func() { defer close(done) conn, err := api.Open(info, api.DialOpts{ DialWebsocket: fakeDialer, }) c.Check(conn, gc.Equals, nil) c.Check(err, gc.ErrorMatches, `unable to connect to API: nope`) }() select { case cfg := <-dialed: c.Check(cfg.Location.String(), gc.Equals, expectDial.location) c.Assert(cfg.TlsConfig, gc.NotNil) c.Check(cfg.TlsConfig.RootCAs != nil, gc.Equals, expectDial.hasRootCAs) c.Check(cfg.TlsConfig.ServerName, gc.Equals, expectDial.serverName) case <-time.After(jtesting.LongWait): c.Fatalf("timed out waiting for dial") } select { case <-done: case <-time.After(jtesting.LongWait): c.Fatalf("timed out waiting for API open") } }
func (s *loginSuite) TestLoginUpdatesLastLoginAndConnection(c *gc.C) { // Since the login and connection times truncate time to the second, // we need to make sure our start time is just before now. startTime := time.Now().Add(-time.Second) password := "******" user := s.Factory.MakeUser(c, &factory.UserParams{ Password: password, }) info := s.APIInfo(c) info.Tag = user.Tag() info.Password = password apiState, err := api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) defer apiState.Close() // The user now has last login updated. err = user.Refresh() c.Assert(err, jc.ErrorIsNil) lastLogin, err := user.LastLogin() c.Assert(err, jc.ErrorIsNil) c.Assert(lastLogin, gc.NotNil) c.Assert(lastLogin.After(startTime), jc.IsTrue) // The env user is also updated. modelUser, err := s.State.UserAccess(user.UserTag(), s.State.ModelTag()) c.Assert(err, jc.ErrorIsNil) when, err := s.State.LastModelConnection(modelUser.UserTag) c.Assert(err, jc.ErrorIsNil) c.Assert(when, gc.NotNil) c.Assert(when.After(startTime), jc.IsTrue) }
func (s *undertakerSuite) hostedAPI(c *gc.C) (*undertaker.Client, *state.State) { otherState := s.Factory.MakeModel(c, &factory.ModelParams{Name: "hosted_env"}) password, err := utils.RandomPassword() c.Assert(err, jc.ErrorIsNil) machine := s.Factory.MakeMachine(c, &factory.MachineParams{ Jobs: []state.MachineJob{state.JobManageModel}, Password: password, Nonce: "fake_nonce", }) // Connect to hosted environ from controller. info := s.APIInfo(c) info.Tag = machine.Tag() info.Password = password info.Nonce = "fake_nonce" info.ModelTag = otherState.ModelTag() otherAPIState, err := api.Open(info, api.DefaultDialOpts()) c.Assert(err, jc.ErrorIsNil) undertakerClient := undertaker.NewClient(otherAPIState) c.Assert(undertakerClient, gc.NotNil) return undertakerClient, otherState }
func (s *migrationWatcherSuite) TestWatch(c *gc.C) { // Create a state server m, password := s.Factory.MakeMachineReturningPassword(c, &factory.MachineParams{ Jobs: []state.MachineJob{state.JobManageModel}, Nonce: "noncey", }) // Create a model to migrate. hostedState := s.Factory.MakeModel(c, nil) // Connect as a state server to the hosted environment. apiInfo := s.APIInfo(c) apiInfo.Tag = m.Tag() apiInfo.Password = password apiInfo.ModelTag = hostedState.ModelTag() apiInfo.Nonce = "noncey" apiConn, err := api.Open(apiInfo, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) defer apiConn.Close() // Start watching for a migration. client := migrationmaster.NewClient(apiConn) w, err := client.Watch() c.Assert(err, jc.ErrorIsNil) defer func() { c.Assert(worker.Stop(w), jc.ErrorIsNil) }() // Should be no initial events. select { case _, ok := <-w.Changes(): c.Fatalf("watcher sent unexpected change: (_, %v)", ok) case <-time.After(coretesting.ShortWait): } // Now create a migration. targetInfo := migration.TargetInfo{ ControllerTag: names.NewModelTag(utils.MustNewUUID().String()), Addrs: []string{"1.2.3.4:5"}, CACert: "trust me I'm an authority", AuthTag: names.NewUserTag("dog"), Password: "******", } _, err = hostedState.CreateModelMigration(state.ModelMigrationSpec{ InitiatedBy: names.NewUserTag("someone"), TargetInfo: targetInfo, }) c.Assert(err, jc.ErrorIsNil) // Event with correct target details should be emitted. select { case reportedTargetInfo, ok := <-w.Changes(): c.Assert(ok, jc.IsTrue) c.Assert(reportedTargetInfo, jc.DeepEquals, targetInfo) case <-time.After(coretesting.LongWait): c.Fatalf("watcher didn't emit an event") } }
func (s *macaroonLoginSuite) TestFailedToObtainDischargeLogin(c *gc.C) { s.DischargerLogin = func() string { return "" } client, err := api.Open(s.APIInfo(c), api.DialOpts{}) c.Assert(err, gc.ErrorMatches, `cannot get discharge from "https://.*": third party refused discharge: cannot discharge: login denied by discharger`) c.Assert(client, gc.Equals, nil) }
func (s *macaroonLoginSuite) TestUnknownUserLogin(c *gc.C) { s.DischargerLogin = func() string { return "testUnknown@somewhere" } client, err := api.Open(s.APIInfo(c), api.DialOpts{}) c.Assert(err, gc.ErrorMatches, "invalid entity name or password") c.Assert(client, gc.Equals, nil) }
func (s *macaroonLoginSuite) TestUnknownUserLogin(c *gc.C) { s.DischargerLogin = func() string { return "testUnknown@somewhere" } client, err := api.Open(s.APIInfo(c), api.DialOpts{}) assertInvalidEntityPassword(c, err) c.Assert(client, gc.Equals, nil) }
func (s *clientSuite) otherModel(c *gc.C) (*state.State, api.Connection) { otherSt := s.Factory.MakeModel(c, nil) info := s.APIInfo(c) info.ModelTag = otherSt.ModelTag() apiState, err := api.Open(info, api.DefaultDialOpts()) c.Assert(err, jc.ErrorIsNil) return otherSt, apiState }
func (s *clientSuite) otherEnviron(c *gc.C) (*state.State, *api.State) { otherSt := s.Factory.MakeEnvironment(c, nil) info := s.APIInfo(c) info.EnvironTag = otherSt.EnvironTag() apiState, err := api.Open(info, api.DefaultDialOpts()) c.Assert(err, jc.ErrorIsNil) return otherSt, apiState }
func (s *macaroonLoginSuite) TestLoginToEnvironmentSuccess(c *gc.C) { s.AddEnvUser(c, "test@somewhere") s.DischargerLogin = func() string { return "test@somewhere" } client, err := api.Open(s.APIInfo(c), api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) client.Close() }
func (s *pingerSuite) TestClientNoNeedToPing(c *gc.C) { s.PatchValue(apiserver.MaxClientPingInterval, time.Duration(0)) st, err := api.Open(s.APIInfo(c), api.DefaultDialOpts()) c.Assert(err, jc.ErrorIsNil) defer st.Close() time.Sleep(coretesting.ShortWait) err = st.Ping() c.Assert(err, jc.ErrorIsNil) }
func canLoginToAPIAsMachine(c *gc.C, fromConf, toConf agent.Config) bool { info := fromConf.APIInfo() info.Addrs = toConf.APIInfo().Addrs apiState, err := api.Open(info, upgradeTestDialOpts) if apiState != nil { apiState.Close() } return apiState != nil && err == nil }
func (s *loginSuite) TestNonEnvironUserLoginFails(c *gc.C) { info, cleanup := s.setupServer(c) defer cleanup() user := s.Factory.MakeUser(c, &factory.UserParams{Password: "******", NoEnvUser: true}) info.Password = "******" info.Tag = user.UserTag() _, err := api.Open(info, fastDialOpts) c.Assert(err, gc.ErrorMatches, "invalid entity name or password") }
func (s *baseLoginSuite) setupServerForEnvironment(c *gc.C, envTag names.EnvironTag) (api.Connection, func()) { info, cleanup := s.setupServerForEnvironmentWithValidator(c, envTag, nil) st, err := api.Open(info, fastDialOpts) c.Assert(err, jc.ErrorIsNil) return st, func() { st.Close() cleanup() } }
// OpenAPIWithoutLogin connects to the API and returns an api.State without // actually calling st.Login already. The returned strings are the "tag" and // "password" that we would have used to login. func (s *stateSuite) OpenAPIWithoutLogin(c *gc.C) (*api.State, string, string) { info := s.APIInfo(c) tag := info.Tag password := info.Password info.Tag = nil info.Password = "" apistate, err := api.Open(info, api.DialOpts{}) c.Assert(err, gc.IsNil) return apistate, tag.String(), password }
func (s *loginV3Suite) TestClientLoginToEnvironment(c *gc.C) { info := s.APIInfo(c) apiState, err := api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) defer apiState.Close() client := apiState.Client() _, err = client.GetModelConstraints() c.Assert(err, jc.ErrorIsNil) }
// OpenAPIWithoutLogin connects to the API and returns an api.State without // actually calling st.Login already. The returned strings are the "tag" and // "password" that we would have used to login. func (s *stateSuite) OpenAPIWithoutLogin(c *gc.C) (api.Connection, names.Tag, string) { info := s.APIInfo(c) tag := info.Tag password := info.Password info.Tag = nil info.Password = "" apistate, err := api.Open(info, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) return apistate, tag, password }