// MachineConfig returns information from the environment config that is // needed for machine cloud-init (for non-state servers only). // It is exposed for testing purposes. // TODO(rog) fix environs/manual tests so they do not need to // call this, or move this elsewhere. func MachineConfig(st *state.State, machineId, nonce, dataDir string) (*cloudinit.MachineConfig, error) { environConfig, err := st.EnvironConfig() if err != nil { return nil, err } // Get the machine so we can get its series and arch. // If the Arch is not set in hardware-characteristics, // an error is returned. machine, err := st.Machine(machineId) if err != nil { return nil, err } hc, err := machine.HardwareCharacteristics() if err != nil { return nil, err } if hc.Arch == nil { return nil, fmt.Errorf("arch is not set for %q", machine.Tag()) } // Find the appropriate tools information. env, err := environs.New(environConfig) if err != nil { return nil, err } tools, err := findInstanceTools(env, machine.Series(), *hc.Arch) if err != nil { return nil, err } // Find the API endpoints. apiInfo, err := environs.APIInfo(env) if err != nil { return nil, err } auth := authentication.NewAuthenticator(st.MongoConnectionInfo(), apiInfo) mongoInfo, apiInfo, err := auth.SetupAuthentication(machine) if err != nil { return nil, err } // Find requested networks. networks, err := machine.RequestedNetworks() if err != nil { return nil, err } mcfg := environs.NewMachineConfig(machineId, nonce, networks, mongoInfo, apiInfo) if dataDir != "" { mcfg.DataDir = dataDir } mcfg.Tools = tools err = environs.FinishMachineConfig(mcfg, environConfig, constraints.Value{}) if err != nil { return nil, err } return mcfg, nil }
// apiConfigConnect looks for configuration info on the given environment, // and tries to use an Environ constructed from that to connect to // its endpoint. It only starts the attempt after the given delay, // to allow the faster apiInfoConnect to hopefully succeed first. // It returns nil if there was no configuration information found. func apiConfigConnect( cfg *config.Config, accountDetails *jujuclient.AccountDetails, modelUUID string, apiOpen api.OpenFunc, stop <-chan struct{}, delay time.Duration, dialOpts api.DialOpts, ) (api.Connection, error) { select { case <-time.After(delay): // TODO(fwereade): 2016-03-17 lp:1558657 case <-stop: return nil, errAborted } environ, err := environs.New(cfg) if err != nil { return nil, errors.Annotate(err, "constructing environ") } apiInfo, err := environs.APIInfo(environ) if err != nil { return nil, errors.Annotate(err, "getting API info") } st, err := commonConnect(apiOpen, apiInfo, accountDetails, modelUUID, dialOpts) if err != nil { return nil, errors.Annotate(err, "connecting with bootstrap config") } return apiStateCachedInfo{st, apiInfo}, nil }
func (s *JujuConnSuite) APIInfo(c *gc.C) *api.Info { apiInfo, err := environs.APIInfo(s.Environ) c.Assert(err, gc.IsNil) apiInfo.Tag = names.NewUserTag("admin") apiInfo.Password = "******" return apiInfo }
func (s *JujuConnSuite) APIInfo(c *gc.C) *api.Info { apiInfo, err := environs.APIInfo(s.Environ) c.Assert(err, jc.ErrorIsNil) apiInfo.Tag = s.AdminUserTag(c) apiInfo.Password = "******" apiInfo.EnvironTag = s.State.EnvironTag() return apiInfo }
func (s *JujuConnSuite) APIInfo(c *gc.C) *api.Info { apiInfo, err := environs.APIInfo(s.ControllerConfig.ControllerUUID(), testing.ModelTag.Id(), testing.CACert, s.ControllerConfig.APIPort(), s.Environ) c.Assert(err, jc.ErrorIsNil) apiInfo.Tag = s.AdminUserTag(c) apiInfo.Password = "******" apiInfo.ModelTag = s.State.ModelTag() return apiInfo }
func environAPIInfo(environ environs.Environ, user names.UserTag) (*api.Info, error) { config := environ.Config() password := config.AdminSecret() if password == "" { return nil, fmt.Errorf("cannot connect to API servers without admin-secret") } info, err := environs.APIInfo(environ) if err != nil { return nil, err } info.Tag = user info.Password = password return info, nil }
func environAPIInfo(environ environs.Environ, user names.Tag) (*api.Info, error) { config := environ.Config() password := config.AdminSecret() info, err := environs.APIInfo(environ) if err != nil { return nil, err } info.Tag = user info.Password = password if info.Tag == nil { info.UseMacaroons = true } return info, nil }
// InstanceConfig returns information from the environment config that // is needed for machine cloud-init (for non-controllers only). It // is exposed for testing purposes. // TODO(rog) fix environs/manual tests so they do not need to call this, or move this elsewhere. func InstanceConfig(st *state.State, machineId, nonce, dataDir string) (*instancecfg.InstanceConfig, error) { environConfig, err := st.ModelConfig() if err != nil { return nil, err } // Get the machine so we can get its series and arch. // If the Arch is not set in hardware-characteristics, // an error is returned. machine, err := st.Machine(machineId) if err != nil { return nil, err } hc, err := machine.HardwareCharacteristics() if err != nil { return nil, err } if hc.Arch == nil { return nil, fmt.Errorf("arch is not set for %q", machine.Tag()) } // Find the appropriate tools information. agentVersion, ok := environConfig.AgentVersion() if !ok { return nil, errors.New("no agent version set in model configuration") } environment, err := st.Model() if err != nil { return nil, err } urlGetter := common.NewToolsURLGetter(environment.UUID(), st) toolsFinder := common.NewToolsFinder(st, st, urlGetter) findToolsResult, err := toolsFinder.FindTools(params.FindToolsParams{ Number: agentVersion, MajorVersion: -1, MinorVersion: -1, Series: machine.Series(), Arch: *hc.Arch, }) if err != nil { return nil, err } if findToolsResult.Error != nil { return nil, findToolsResult.Error } tools := findToolsResult.List[0] // Find the API endpoints. env, err := environs.New(environConfig) if err != nil { return nil, err } apiInfo, err := environs.APIInfo(env) if err != nil { return nil, err } auth := authentication.NewAuthenticator(st.MongoConnectionInfo(), apiInfo) mongoInfo, apiInfo, err := auth.SetupAuthentication(machine) if err != nil { return nil, err } // Find requested networks. networks, err := machine.RequestedNetworks() if err != nil { return nil, err } // Figure out if secure connections are supported. info, err := st.StateServingInfo() if err != nil { return nil, err } secureServerConnection := info.CAPrivateKey != "" icfg, err := instancecfg.NewInstanceConfig(machineId, nonce, env.Config().ImageStream(), machine.Series(), "", secureServerConnection, networks, mongoInfo, apiInfo, ) if err != nil { return nil, err } if dataDir != "" { icfg.DataDir = dataDir } icfg.Tools = tools err = instancecfg.FinishInstanceConfig(icfg, environConfig) if err != nil { return nil, err } return icfg, nil }
func (t *LiveTests) TestBootstrapAndDeploy(c *gc.C) { if !t.CanOpenState || !t.HasProvisioner { c.Skip(fmt.Sprintf("skipping provisioner test, CanOpenState: %v, HasProvisioner: %v", t.CanOpenState, t.HasProvisioner)) } t.BootstrapOnce(c) // TODO(niemeyer): Stop growing this kitchen sink test and split it into proper parts. c.Logf("opening state") st := t.Env.(jujutesting.GetStater).GetStateInAPIServer() env, err := st.Model() c.Assert(err, jc.ErrorIsNil) owner := env.Owner() c.Logf("opening API connection") apiInfo, err := environs.APIInfo(t.Env) c.Assert(err, jc.ErrorIsNil) apiInfo.Tag = owner apiInfo.Password = t.Env.Config().AdminSecret() apiState, err := api.Open(apiInfo, api.DefaultDialOpts()) c.Assert(err, jc.ErrorIsNil) defer apiState.Close() // Check that the agent version has made it through the // bootstrap process (it's optional in the config.Config) cfg, err := st.ModelConfig() c.Assert(err, jc.ErrorIsNil) agentVersion, ok := cfg.AgentVersion() c.Check(ok, jc.IsTrue) c.Check(agentVersion, gc.Equals, jujuversion.Current) // Check that the constraints have been set in the environment. cons, err := st.ModelConstraints() c.Assert(err, jc.ErrorIsNil) c.Assert(cons.String(), gc.Equals, "mem=2048M") // Wait for machine agent to come up on the bootstrap // machine and find the deployed series from that. m0, err := st.Machine("0") c.Assert(err, jc.ErrorIsNil) instId0, err := m0.InstanceId() c.Assert(err, jc.ErrorIsNil) // Check that the API connection is working. status, err := apiState.Client().Status(nil) c.Assert(err, jc.ErrorIsNil) c.Assert(status.Machines["0"].InstanceId, gc.Equals, string(instId0)) mw0 := newMachineToolWaiter(m0) defer mw0.Stop() // If the series has not been specified, we expect the most recent Ubuntu LTS release to be used. expectedVersion := version.Binary{ Number: jujuversion.Current, Arch: arch.HostArch(), Series: config.LatestLtsSeries(), } mtools0 := waitAgentTools(c, mw0, expectedVersion) // Create a new service and deploy a unit of it. c.Logf("deploying service") repoDir := c.MkDir() url := testcharms.Repo.ClonedURL(repoDir, mtools0.Version.Series, "dummy") sch, err := jujutesting.PutCharm(st, url, &charmrepo.LocalRepository{Path: repoDir}, false) c.Assert(err, jc.ErrorIsNil) svc, err := st.AddService(state.AddServiceArgs{Name: "dummy", Owner: owner.String(), Charm: sch}) c.Assert(err, jc.ErrorIsNil) units, err := juju.AddUnits(st, svc, 1, nil) c.Assert(err, jc.ErrorIsNil) unit := units[0] // Wait for the unit's machine and associated agent to come up // and announce itself. mid1, err := unit.AssignedMachineId() c.Assert(err, jc.ErrorIsNil) m1, err := st.Machine(mid1) c.Assert(err, jc.ErrorIsNil) mw1 := newMachineToolWaiter(m1) defer mw1.Stop() waitAgentTools(c, mw1, mtools0.Version) err = m1.Refresh() c.Assert(err, jc.ErrorIsNil) instId1, err := m1.InstanceId() c.Assert(err, jc.ErrorIsNil) uw := newUnitToolWaiter(unit) defer uw.Stop() utools := waitAgentTools(c, uw, expectedVersion) // Check that we can upgrade the environment. newVersion := utools.Version newVersion.Patch++ t.checkUpgrade(c, st, newVersion, mw0, mw1, uw) // BUG(niemeyer): Logic below is very much wrong. Must be: // // 1. EnsureDying on the unit and EnsureDying on the machine // 2. Unit dies by itself // 3. Machine removes dead unit // 4. Machine dies by itself // 5. Provisioner removes dead machine // // Now remove the unit and its assigned machine and // check that the PA removes it. c.Logf("removing unit") err = unit.Destroy() c.Assert(err, jc.ErrorIsNil) // Wait until unit is dead uwatch := unit.Watch() defer uwatch.Stop() for unit.Life() != state.Dead { c.Logf("waiting for unit change") <-uwatch.Changes() err := unit.Refresh() c.Logf("refreshed; err %v", err) if errors.IsNotFound(err) { c.Logf("unit has been removed") break } c.Assert(err, jc.ErrorIsNil) } for { c.Logf("destroying machine") err := m1.Destroy() if err == nil { break } c.Assert(err, gc.FitsTypeOf, &state.HasAssignedUnitsError{}) time.Sleep(5 * time.Second) err = m1.Refresh() if errors.IsNotFound(err) { break } c.Assert(err, jc.ErrorIsNil) } c.Logf("waiting for instance to be removed") t.assertStopInstance(c, t.Env, instId1) }
func (s *JujuConnSuite) setUpConn(c *gc.C) { if s.RootDir != "" { c.Fatal("JujuConnSuite.setUpConn without teardown") } s.RootDir = c.MkDir() s.oldHome = utils.Home() home := filepath.Join(s.RootDir, "/home/ubuntu") err := os.MkdirAll(home, 0777) c.Assert(err, jc.ErrorIsNil) utils.SetHome(home) err = os.MkdirAll(filepath.Join(home, ".local", "share"), 0777) c.Assert(err, jc.ErrorIsNil) s.oldJujuXDGDataHome = osenv.SetJujuXDGDataHome(filepath.Join(home, ".local", "share", "juju")) err = os.MkdirAll(osenv.JujuXDGDataHome(), 0777) c.Assert(err, jc.ErrorIsNil) err = os.MkdirAll(s.DataDir(), 0777) c.Assert(err, jc.ErrorIsNil) s.PatchEnvironment(osenv.JujuModelEnvKey, "admin") cfg, err := config.New(config.UseDefaults, (map[string]interface{})(s.sampleConfig())) c.Assert(err, jc.ErrorIsNil) s.ControllerStore = jujuclient.NewFileClientStore() ctx := testing.Context(c) environ, err := environs.Prepare( modelcmd.BootstrapContext(ctx), s.ControllerStore, environs.PrepareParams{ BaseConfig: cfg.AllAttrs(), Credential: cloud.NewEmptyCredential(), ControllerName: ControllerName, CloudName: "dummy", }, ) c.Assert(err, jc.ErrorIsNil) // sanity check we've got the correct environment. c.Assert(environ.Config().Name(), gc.Equals, "admin") s.PatchValue(&dummy.DataDir, s.DataDir()) s.LogDir = c.MkDir() s.PatchValue(&dummy.LogDir, s.LogDir) versions := PreferredDefaultVersions(environ.Config(), version.Binary{ Number: jujuversion.Current, Arch: "amd64", Series: "precise", }) current := version.Binary{ Number: jujuversion.Current, Arch: arch.HostArch(), Series: series.HostSeries(), } versions = append(versions, current) // Upload tools for both preferred and fake default series s.DefaultToolsStorageDir = c.MkDir() s.PatchValue(&tools.DefaultBaseURL, s.DefaultToolsStorageDir) stor, err := filestorage.NewFileStorageWriter(s.DefaultToolsStorageDir) c.Assert(err, jc.ErrorIsNil) // Upload tools to both release and devel streams since config will dictate that we // end up looking in both places. envtesting.AssertUploadFakeToolsVersions(c, stor, "released", "released", versions...) envtesting.AssertUploadFakeToolsVersions(c, stor, "devel", "devel", versions...) s.DefaultToolsStorage = stor s.PatchValue(&juju.JujuPublicKey, sstesting.SignedMetadataPublicKey) err = bootstrap.Bootstrap(modelcmd.BootstrapContext(ctx), environ, bootstrap.BootstrapParams{}) c.Assert(err, jc.ErrorIsNil) s.BackingState = environ.(GetStater).GetStateInAPIServer() s.State, err = newState(environ, s.BackingState.MongoConnectionInfo()) c.Assert(err, jc.ErrorIsNil) apiInfo, err := environs.APIInfo(environ) c.Assert(err, jc.ErrorIsNil) apiInfo.Tag = s.AdminUserTag(c) apiInfo.Password = environ.Config().AdminSecret() s.APIState, err = api.Open(apiInfo, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) err = s.State.SetAPIHostPorts(s.APIState.APIHostPorts()) c.Assert(err, jc.ErrorIsNil) // Make sure the controller store has the controller api endpoint address set controller, err := s.ControllerStore.ControllerByName(ControllerName) c.Assert(err, jc.ErrorIsNil) controller.APIEndpoints = []string{s.APIState.APIHostPorts()[0][0].String()} err = s.ControllerStore.UpdateController(ControllerName, *controller) c.Assert(err, jc.ErrorIsNil) err = modelcmd.WriteCurrentController(ControllerName) c.Assert(err, jc.ErrorIsNil) s.Environ = environ // Insert expected values... servingInfo := state.StateServingInfo{ PrivateKey: testing.ServerKey, Cert: testing.ServerCert, CAPrivateKey: testing.CAKey, SharedSecret: "really, really secret", APIPort: 4321, StatePort: 1234, } s.State.SetStateServingInfo(servingInfo) }
func (s *JujuConnSuite) setUpConn(c *gc.C) { if s.RootDir != "" { c.Fatal("JujuConnSuite.setUpConn without teardown") } s.RootDir = c.MkDir() s.oldHome = utils.Home() userHomeParams := UserHomeParams{ Username: "******", ModelEnvKey: "controller", SetOldHome: true, } s.CreateUserHome(c, &userHomeParams) cfg, err := config.New(config.UseDefaults, (map[string]interface{})(s.sampleConfig())) c.Assert(err, jc.ErrorIsNil) ctx := testing.Context(c) s.ControllerConfig = testing.FakeControllerConfig() for key, value := range s.ControllerConfigAttrs { s.ControllerConfig[key] = value } cloudSpec := dummy.SampleCloudSpec() environ, err := bootstrap.Prepare( modelcmd.BootstrapContext(ctx), s.ControllerStore, bootstrap.PrepareParams{ ControllerConfig: s.ControllerConfig, ModelConfig: cfg.AllAttrs(), Cloud: cloudSpec, ControllerName: ControllerName, AdminSecret: AdminSecret, }, ) c.Assert(err, jc.ErrorIsNil) // sanity check we've got the correct environment. c.Assert(environ.Config().Name(), gc.Equals, "controller") s.PatchValue(&dummy.DataDir, s.DataDir()) s.LogDir = c.MkDir() s.PatchValue(&dummy.LogDir, s.LogDir) versions := DefaultVersions(environ.Config()) // Upload tools for both preferred and fake default series s.DefaultToolsStorageDir = c.MkDir() s.PatchValue(&tools.DefaultBaseURL, s.DefaultToolsStorageDir) stor, err := filestorage.NewFileStorageWriter(s.DefaultToolsStorageDir) c.Assert(err, jc.ErrorIsNil) // Upload tools to both release and devel streams since config will dictate that we // end up looking in both places. envtesting.AssertUploadFakeToolsVersions(c, stor, "released", "released", versions...) envtesting.AssertUploadFakeToolsVersions(c, stor, "devel", "devel", versions...) s.DefaultToolsStorage = stor s.PatchValue(&keys.JujuPublicKey, sstesting.SignedMetadataPublicKey) // Dummy provider uses a random port, which is added to cfg used to create environment. apiPort := dummy.APIPort(environ.Provider()) s.ControllerConfig["api-port"] = apiPort err = bootstrap.Bootstrap(modelcmd.BootstrapContext(ctx), environ, bootstrap.BootstrapParams{ ControllerConfig: s.ControllerConfig, CloudName: cloudSpec.Name, CloudRegion: "dummy-region", Cloud: cloud.Cloud{ Type: cloudSpec.Type, AuthTypes: []cloud.AuthType{cloud.EmptyAuthType, cloud.UserPassAuthType}, Endpoint: cloudSpec.Endpoint, IdentityEndpoint: cloudSpec.IdentityEndpoint, StorageEndpoint: cloudSpec.StorageEndpoint, Regions: []cloud.Region{ { Name: "dummy-region", Endpoint: "dummy-endpoint", IdentityEndpoint: "dummy-identity-endpoint", StorageEndpoint: "dummy-storage-endpoint", }, }, }, CloudCredential: cloudSpec.Credential, CloudCredentialName: "cred", AdminSecret: AdminSecret, CAPrivateKey: testing.CAKey, }) c.Assert(err, jc.ErrorIsNil) getStater := environ.(GetStater) s.BackingState = getStater.GetStateInAPIServer() s.BackingStatePool = getStater.GetStatePoolInAPIServer() s.State, err = newState(s.ControllerConfig.ControllerUUID(), environ, s.BackingState.MongoConnectionInfo()) c.Assert(err, jc.ErrorIsNil) apiInfo, err := environs.APIInfo(s.ControllerConfig.ControllerUUID(), testing.ModelTag.Id(), testing.CACert, s.ControllerConfig.APIPort(), environ) c.Assert(err, jc.ErrorIsNil) apiInfo.Tag = s.AdminUserTag(c) apiInfo.Password = AdminSecret s.APIState, err = api.Open(apiInfo, api.DialOpts{}) c.Assert(err, jc.ErrorIsNil) err = s.State.SetAPIHostPorts(s.APIState.APIHostPorts()) c.Assert(err, jc.ErrorIsNil) // Make sure the controller store has the controller api endpoint address set controller, err := s.ControllerStore.ControllerByName(ControllerName) c.Assert(err, jc.ErrorIsNil) controller.APIEndpoints = []string{s.APIState.APIHostPorts()[0][0].String()} err = s.ControllerStore.UpdateController(ControllerName, *controller) c.Assert(err, jc.ErrorIsNil) err = s.ControllerStore.SetCurrentController(ControllerName) c.Assert(err, jc.ErrorIsNil) s.Environ = environ // Insert expected values... servingInfo := state.StateServingInfo{ PrivateKey: testing.ServerKey, Cert: testing.ServerCert, CAPrivateKey: testing.CAKey, SharedSecret: "really, really secret", APIPort: s.ControllerConfig.APIPort(), StatePort: s.ControllerConfig.StatePort(), } s.State.SetStateServingInfo(servingInfo) }