func (s *BootstrapSuite) TestBootstrapJenvWarning(c *gc.C) { env, fake := makeEmptyFakeHome(c) defer fake.Restore() defaultSeriesVersion := version.Current defaultSeriesVersion.Series = config.PreferredSeries(env.Config()) // Force a dev version by having an odd minor version number. // This is because we have not uploaded any tools and auto // upload is only enabled for dev versions. defaultSeriesVersion.Minor = 11 s.PatchValue(&version.Current, defaultSeriesVersion) store, err := configstore.Default() c.Assert(err, gc.IsNil) ctx := coretesting.Context(c) environs.PrepareFromName("peckham", ctx, store) logger := "jenv.warning.test" testWriter := &loggo.TestWriter{} loggo.RegisterWriter(logger, testWriter, loggo.WARNING) defer loggo.RemoveWriter(logger) _, errc := runCommand(ctx, new(BootstrapCommand), "-e", "peckham") c.Assert(<-errc, gc.IsNil) c.Assert(testWriter.Log, jc.LogMatches, []string{"ignoring environments.yaml: using bootstrap config in .*"}) }
func (c *AddUserCommand) Run(ctx *cmd.Context) error { store, err := configstore.Default() if err != nil { return fmt.Errorf("cannot open environment info storage: %v", err) } storeInfo, err := store.ReadInfo(c.EnvName) if err != nil { return err } client, err := juju.NewUserManagerClient(c.EnvName) if err != nil { return err } defer client.Close() if c.GeneratePassword { c.Password, err = utils.RandomPassword() if err != nil { return fmt.Errorf("Failed to generate password: %v", err) } } outputInfo := configstore.EnvironInfoData{} outputInfo.User = c.User outputInfo.Password = c.Password outputInfo.StateServers = storeInfo.APIEndpoint().Addresses outputInfo.CACert = storeInfo.APIEndpoint().CACert err = c.out.Write(ctx, outputInfo) if err != nil { return err } return client.AddUser(c.User, c.Password) }
func (c *DestroyEnvironmentCommand) Run(ctx *cmd.Context) (result error) { store, err := configstore.Default() if err != nil { return fmt.Errorf("cannot open environment info storage: %v", err) } environ, err := environs.NewFromName(c.envName, store) if err != nil { if environs.IsEmptyConfig(err) { // Delete the .jenv file and call it done. ctx.Infof("removing empty environment file") return environs.DestroyInfo(c.envName, store) } return err } if !c.assumeYes { fmt.Fprintf(ctx.Stdout, destroyEnvMsg, environ.Name(), environ.Config().Type()) scanner := bufio.NewScanner(ctx.Stdin) scanner.Scan() err := scanner.Err() if err != nil && err != io.EOF { return fmt.Errorf("Environment destruction aborted: %s", err) } answer := strings.ToLower(scanner.Text()) if answer != "y" && answer != "yes" { return errors.New("environment destruction aborted") } } // If --force is supplied, then don't attempt to use the API. // This is necessary to destroy broken environments, where the // API server is inaccessible or faulty. if !c.force { defer func() { if result == nil { return } logger.Errorf(`failed to destroy environment %q If the environment is unusable, then you may run juju destroy-environment --force to forcefully destroy the environment. Upon doing so, review your environment provider console for any resources that need to be cleaned up. `, c.envName) }() apiclient, err := juju.NewAPIClientFromName(c.envName) if err != nil { return fmt.Errorf("cannot connect to API: %v", err) } defer apiclient.Close() err = apiclient.DestroyEnvironment() if err != nil && !params.IsCodeNotImplemented(err) { return fmt.Errorf("destroying environment: %v", err) } } return environs.Destroy(environ, store) }
// APIEndpointForEnv returns the endpoint information for a given environment // It tries to just return the information from the cached settings unless // there is nothing cached or refresh is True func APIEndpointForEnv(envName string, refresh bool) (configstore.APIEndpoint, error) { store, err := configstore.Default() if err != nil { return configstore.APIEndpoint{}, err } return apiEndpointInStore(envName, refresh, store, defaultAPIOpen) }
// makeEmptyFakeHome creates a faked home without envtools. func makeEmptyFakeHome(c *gc.C) (environs.Environ, *coretesting.FakeHome) { fake := coretesting.MakeFakeHome(c, envConfig) dummy.Reset() store, err := configstore.Default() c.Assert(err, gc.IsNil) env, err := environs.PrepareFromName("peckham", nullContext(c), store) c.Assert(err, gc.IsNil) envtesting.RemoveAllTools(c, env) return env, fake }
func newAPIClient(envName string) (*api.State, error) { store, err := configstore.Default() if err != nil { return nil, err } st, err := newAPIFromStore(envName, store, defaultAPIOpen) if err != nil { return nil, err } return st.(*api.State), nil }
// NewConnFromName returns a Conn pointing at the environName environment, or the // default environment if not specified. func NewConnFromName(environName string) (*Conn, error) { store, err := configstore.Default() if err != nil { return nil, err } environ, err := environs.NewFromName(environName, store) if err != nil { return nil, err } return NewConn(environ) }
func (s *syncToolsSuite) SetUpTest(c *gc.C) { s.LoggingSuite.SetUpTest(c) // Create a target environments.yaml and make sure its environment is empty. s.home = coretesting.MakeFakeHome(c, ` environments: test-target: type: dummy state-server: false authorized-keys: "not-really-one" `) var err error s.configStore, err = configstore.Default() c.Assert(err, gc.IsNil) s.origSyncTools = syncTools }
func (s *APIEndpointForEnvSuite) TestAPIEndpointNotCached(c *gc.C) { defer coretesting.MakeMultipleEnvHome(c).Restore() store, err := configstore.Default() c.Assert(err, gc.IsNil) ctx := coretesting.Context(c) env, err := environs.PrepareFromName("erewhemos", ctx, store) c.Assert(err, gc.IsNil) defer dummy.Reset() envtesting.UploadFakeTools(c, env.Storage()) err = bootstrap.Bootstrap(ctx, env, environs.BootstrapParams{}) c.Assert(err, gc.IsNil) // Note: if we get Bootstrap to start caching the API endpoint // immediately, we'll still want to have this test for compatibility. // We can just write blank info instead of reading and checking it is empty. savedInfo, err := store.ReadInfo("erewhemos") c.Assert(err, gc.IsNil) // Ensure that the data isn't cached c.Check(savedInfo.APIEndpoint().Addresses, gc.HasLen, 0) called := 0 expectState := &mockAPIState{ apiHostPorts: [][]instance.HostPort{ instance.AddressesWithPort([]instance.Address{instance.NewAddress("0.1.2.3", instance.NetworkUnknown)}, 1234), }, } apiOpen := func(apiInfo *api.Info, opts api.DialOpts) (juju.APIState, error) { c.Check(apiInfo.Tag, gc.Equals, "user-admin") c.Check(string(apiInfo.CACert), gc.Equals, coretesting.CACert) c.Check(apiInfo.Password, gc.Equals, coretesting.DefaultMongoPassword) c.Check(opts, gc.DeepEquals, api.DefaultDialOpts()) called++ return expectState, nil } endpoint, err := juju.APIEndpointInStore("erewhemos", false, store, apiOpen) c.Assert(err, gc.IsNil) c.Assert(called, gc.Equals, 1) c.Check(endpoint.Addresses, gc.DeepEquals, []string{"0.1.2.3:1234"}) }
// environFromName loads an existing environment or prepares a new one. func environFromName( ctx *cmd.Context, envName string, resultErr *error, action string) (environs.Environ, func(), error) { store, err := configstore.Default() if err != nil { return nil, nil, err } var existing bool if environInfo, err := store.ReadInfo(envName); !errors.IsNotFound(err) { existing = true logger.Warningf("ignoring environments.yaml: using bootstrap config in %s", environInfo.Location()) } environ, err := environs.PrepareFromName(envName, ctx, store) if err != nil { return nil, nil, err } cleanup := func() { if !existing { destroyPreparedEnviron(ctx, environ, store, resultErr, action) } } return environ, cleanup, nil }
func defaultConfigStore(c *gc.C) configstore.Storage { store, err := configstore.Default() c.Assert(err, gc.IsNil) return store }
func (s *JujuConnSuite) setUpConn(c *gc.C) { if s.RootDir != "" { panic("JujuConnSuite.setUpConn without teardown") } s.RootDir = c.MkDir() s.oldHome = osenv.Home() home := filepath.Join(s.RootDir, "/home/ubuntu") err := os.MkdirAll(home, 0777) c.Assert(err, gc.IsNil) osenv.SetHome(home) s.oldJujuHome = osenv.SetJujuHome(filepath.Join(home, ".juju")) err = os.Mkdir(osenv.JujuHome(), 0777) c.Assert(err, gc.IsNil) err = os.MkdirAll(s.DataDir(), 0777) c.Assert(err, gc.IsNil) s.PatchEnvironment(osenv.JujuEnvEnvKey, "") // TODO(rog) remove these files and add them only when // the tests specifically need them (in cmd/juju for example) s.writeSampleConfig(c, osenv.JujuHomePath("environments.yaml")) err = ioutil.WriteFile(osenv.JujuHomePath("dummyenv-cert.pem"), []byte(testing.CACert), 0666) c.Assert(err, gc.IsNil) err = ioutil.WriteFile(osenv.JujuHomePath("dummyenv-private-key.pem"), []byte(testing.CAKey), 0600) c.Assert(err, gc.IsNil) store, err := configstore.Default() c.Assert(err, gc.IsNil) s.ConfigStore = store ctx := testing.Context(c) environ, err := environs.PrepareFromName("dummyenv", ctx, s.ConfigStore) c.Assert(err, gc.IsNil) // sanity check we've got the correct environment. c.Assert(environ.Name(), gc.Equals, "dummyenv") s.PatchValue(&dummy.DataDir, s.DataDir()) s.LogDir = c.MkDir() s.PatchValue(&dummy.LogDir, s.LogDir) versions := PreferredDefaultVersions(environ.Config(), version.Binary{Number: version.Current.Number, Series: "precise", Arch: "amd64"}) versions = append(versions, version.Current) // Upload tools for both preferred and fake default series envtesting.MustUploadFakeToolsVersions(environ.Storage(), versions...) c.Assert(bootstrap.Bootstrap(ctx, environ, environs.BootstrapParams{}), gc.IsNil) s.BackingState = environ.(GetStater).GetStateInAPIServer() conn, err := juju.NewConn(environ) c.Assert(err, gc.IsNil) s.Conn = conn s.State = conn.State apiConn, err := juju.NewAPIConn(environ, api.DialOpts{}) c.Assert(err, gc.IsNil) s.APIConn = apiConn s.APIState = apiConn.State s.environ = environ }
func (c *ValidateToolsMetadataCommand) Run(context *cmd.Context) error { var params *simplestreams.MetadataLookupParams if c.providerType == "" { store, err := configstore.Default() if err != nil { return err } environ, err := environs.PrepareFromName(c.EnvName, context, store) if err == nil { mdLookup, ok := environ.(simplestreams.MetadataValidator) if !ok { return fmt.Errorf("%s provider does not support tools metadata validation", environ.Config().Type()) } params, err = mdLookup.MetadataLookupParams(c.region) if err != nil { return err } params.Sources, err = tools.GetMetadataSources(environ) if err != nil { return err } } else { if c.metadataDir == "" { return err } params = &simplestreams.MetadataLookupParams{ Architectures: arch.AllSupportedArches, } } } else { prov, err := environs.Provider(c.providerType) if err != nil { return err } mdLookup, ok := prov.(simplestreams.MetadataValidator) if !ok { return fmt.Errorf("%s provider does not support tools metadata validation", c.providerType) } params, err = mdLookup.MetadataLookupParams(c.region) if err != nil { return err } } if c.series != "" { params.Series = c.series } if c.region != "" { params.Region = c.region } if c.endpoint != "" { params.Endpoint = c.endpoint } if c.metadataDir != "" { if _, err := os.Stat(c.metadataDir); err != nil { return err } toolsURL, err := tools.ToolsURL(c.metadataDir) if err != nil { return err } params.Sources = []simplestreams.DataSource{simplestreams.NewURLDataSource( "local metadata directory", toolsURL, utils.VerifySSLHostnames), } } versions, resolveInfo, err := tools.ValidateToolsMetadata(&tools.ToolsMetadataLookupParams{ MetadataLookupParams: *params, Version: c.exactVersion, Major: c.major, Minor: c.minor, }) if err != nil { if resolveInfo != nil { metadata := map[string]interface{}{ "Resolve Metadata": *resolveInfo, } if metadataYaml, yamlErr := cmd.FormatYaml(metadata); yamlErr == nil { err = fmt.Errorf("%v\n%v", err, string(metadataYaml)) } } return err } if len(versions) > 0 { metadata := map[string]interface{}{ "Matching Tools Versions": versions, "Resolve Metadata": *resolveInfo, } c.out.Write(context, metadata) } else { var sources []string for _, s := range params.Sources { url, err := s.URL("") if err == nil { sources = append(sources, fmt.Sprintf("- %s (%s)", s.Description(), url)) } } return fmt.Errorf("no matching tools using sources:\n%s", strings.Join(sources, "\n")) } return nil }
func (c *restoreCommand) Run(ctx *cmd.Context) error { if c.showDescription { fmt.Fprintf(ctx.Stdout, "%s\n", c.Info().Purpose) return nil } if err := c.Log.Start(ctx); err != nil { return err } creds, err := extractCreds(c.backupFile) if err != nil { return fmt.Errorf("cannot extract credentials from backup file: %v", err) } progress("extracted credentials from backup file") store, err := configstore.Default() if err != nil { return err } cfg, _, err := environs.ConfigForName(c.EnvName, store) if err != nil { return err } env, err := rebootstrap(cfg, ctx, c.Constraints) if err != nil { return fmt.Errorf("cannot re-bootstrap environment: %v", err) } progress("connecting to newly bootstrapped instance") conn, err := juju.NewAPIConn(env, api.DefaultDialOpts()) if err != nil { return fmt.Errorf("cannot connect to bootstrap instance: %v", err) } progress("restoring bootstrap machine") newInstId, machine0Addr, err := restoreBootstrapMachine(conn, c.backupFile, creds) if err != nil { return fmt.Errorf("cannot restore bootstrap machine: %v", err) } progress("restored bootstrap machine") // Update the environ state to point to the new instance. if err := bootstrap.SaveState(env.Storage(), &bootstrap.BootstrapState{ StateInstances: []instance.Id{newInstId}, }); err != nil { return fmt.Errorf("cannot update environ bootstrap state storage: %v", err) } // Construct our own state info rather than using juju.NewConn so // that we can avoid storage eventual-consistency issues // (and it's faster too). caCert, ok := cfg.CACert() if !ok { return fmt.Errorf("configuration has no CA certificate") } progress("opening state") st, err := state.Open(&state.Info{ Addrs: []string{fmt.Sprintf("%s:%d", machine0Addr, cfg.StatePort())}, CACert: caCert, Tag: creds.Tag, Password: creds.Password, }, state.DefaultDialOpts(), environs.NewStatePolicy()) if err != nil { return fmt.Errorf("cannot open state: %v", err) } progress("updating all machines") if err := updateAllMachines(st, machine0Addr); err != nil { return fmt.Errorf("cannot update machines: %v", err) } return nil }
func (test bootstrapTest) run(c *gc.C) { // Create home with dummy provider and remove all // of its envtools. env, fake := makeEmptyFakeHome(c) defer fake.Restore() if test.version != "" { useVersion := strings.Replace(test.version, "%LTS%", config.LatestLtsSeries(), 1) origVersion := version.Current version.Current = version.MustParseBinary(useVersion) defer func() { version.Current = origVersion }() } if test.hostArch != "" { origVersion := arch.HostArch arch.HostArch = func() string { return test.hostArch } defer func() { arch.HostArch = origVersion }() } uploadCount := len(test.uploads) if uploadCount == 0 { usefulVersion := version.Current usefulVersion.Series = config.PreferredSeries(env.Config()) envtesting.AssertUploadFakeToolsVersions(c, env.Storage(), usefulVersion) } // Run command and check for uploads. opc, errc := runCommand(nullContext(c), new(BootstrapCommand), test.args...) // Check for remaining operations/errors. if test.err != "" { err := <-errc stripped := strings.Replace(err.Error(), "\n", "", -1) c.Check(stripped, gc.Matches, test.err) return } if !c.Check(<-errc, gc.IsNil) { return } if uploadCount > 0 { for i := 0; i < uploadCount; i++ { c.Check((<-opc).(dummy.OpPutFile).Env, gc.Equals, "peckham") } list, err := envtools.FindTools( env, version.Current.Major, version.Current.Minor, coretools.Filter{}, envtools.DoNotAllowRetry) c.Check(err, gc.IsNil) c.Logf("found: " + list.String()) urls := list.URLs() c.Check(urls, gc.HasLen, len(test.uploads)) for _, v := range test.uploads { v := strings.Replace(v, "%LTS%", config.LatestLtsSeries(), 1) c.Logf("seeking: " + v) vers := version.MustParseBinary(v) _, found := urls[vers] c.Check(found, gc.Equals, true) } } if len(test.uploads) > 0 { indexFile := (<-opc).(dummy.OpPutFile) c.Check(indexFile.FileName, gc.Equals, "tools/streams/v1/index.json") productFile := (<-opc).(dummy.OpPutFile) c.Check(productFile.FileName, gc.Equals, "tools/streams/v1/com.ubuntu.juju:released:tools.json") } opPutBootstrapVerifyFile := (<-opc).(dummy.OpPutFile) c.Check(opPutBootstrapVerifyFile.Env, gc.Equals, "peckham") c.Check(opPutBootstrapVerifyFile.FileName, gc.Equals, environs.VerificationFilename) opPutBootstrapInitFile := (<-opc).(dummy.OpPutFile) c.Check(opPutBootstrapInitFile.Env, gc.Equals, "peckham") c.Check(opPutBootstrapInitFile.FileName, gc.Equals, "provider-state") opBootstrap := (<-opc).(dummy.OpBootstrap) c.Check(opBootstrap.Env, gc.Equals, "peckham") c.Check(opBootstrap.Args.Constraints, gc.DeepEquals, test.constraints) c.Check(opBootstrap.Args.Placement, gc.Equals, test.placement) store, err := configstore.Default() c.Assert(err, gc.IsNil) // Check a CA cert/key was generated by reloading the environment. env, err = environs.NewFromName("peckham", store) c.Assert(err, gc.IsNil) _, hasCert := env.Config().CACert() c.Check(hasCert, gc.Equals, true) _, hasKey := env.Config().CAPrivateKey() c.Check(hasKey, gc.Equals, true) }
// setParams sets parameters based on the environment configuration // for those which have not been explicitly specified. func (c *ImageMetadataCommand) setParams(context *cmd.Context) error { c.privateStorage = "<private storage name>" var environ environs.Environ if store, err := configstore.Default(); err == nil { if environ, err = environs.PrepareFromName(c.EnvName, context, store); err == nil { logger.Infof("creating image metadata for environment %q", environ.Name()) // If the user has not specified region and endpoint, try and get it from the environment. if c.Region == "" || c.Endpoint == "" { var cloudSpec simplestreams.CloudSpec if inst, ok := environ.(simplestreams.HasRegion); ok { if cloudSpec, err = inst.Region(); err != nil { return err } } else { return fmt.Errorf("environment %q cannot provide region and endpoint", environ.Name()) } // If only one of region or endpoint is provided, that is a problem. if cloudSpec.Region != cloudSpec.Endpoint && (cloudSpec.Region == "" || cloudSpec.Endpoint == "") { return fmt.Errorf("cannot generate metadata without a complete cloud configuration") } if c.Region == "" { c.Region = cloudSpec.Region } if c.Endpoint == "" { c.Endpoint = cloudSpec.Endpoint } } cfg := environ.Config() if c.Series == "" { c.Series = config.PreferredSeries(cfg) } if v, ok := cfg.AllAttrs()["control-bucket"]; ok { c.privateStorage = v.(string) } } else { logger.Warningf("environment %q could not be opened: %v", c.EnvName, err) } } if environ == nil { logger.Infof("no environment found, creating image metadata using user supplied data") } if c.Series == "" { c.Series = config.LatestLtsSeries() } if c.ImageId == "" { return fmt.Errorf("image id must be specified") } if c.Region == "" { return fmt.Errorf("image region must be specified") } if c.Endpoint == "" { return fmt.Errorf("cloud endpoint URL must be specified") } if c.Dir == "" { logger.Infof("no destination directory specified, using current directory") var err error if c.Dir, err = os.Getwd(); err != nil { return err } } return nil }
func (c *ValidateImageMetadataCommand) Run(context *cmd.Context) error { var params *simplestreams.MetadataLookupParams if c.providerType == "" { store, err := configstore.Default() if err != nil { return err } environ, err := environs.PrepareFromName(c.EnvName, context, store) if err != nil { return err } mdLookup, ok := environ.(simplestreams.MetadataValidator) if !ok { return fmt.Errorf("%s provider does not support image metadata validation", environ.Config().Type()) } params, err = mdLookup.MetadataLookupParams(c.region) if err != nil { return err } oes := &overrideEnvStream{environ, c.stream} params.Sources, err = imagemetadata.GetMetadataSources(oes) if err != nil { return err } } else { prov, err := environs.Provider(c.providerType) if err != nil { return err } mdLookup, ok := prov.(simplestreams.MetadataValidator) if !ok { return fmt.Errorf("%s provider does not support image metadata validation", c.providerType) } params, err = mdLookup.MetadataLookupParams(c.region) if err != nil { return err } } if c.series != "" { params.Series = c.series } if c.region != "" { params.Region = c.region } if c.endpoint != "" { params.Endpoint = c.endpoint } if c.metadataDir != "" { dir := filepath.Join(c.metadataDir, "images") if _, err := os.Stat(dir); err != nil { return err } params.Sources = []simplestreams.DataSource{ simplestreams.NewURLDataSource( "local metadata directory", "file://"+dir, utils.VerifySSLHostnames), } } params.Stream = c.stream image_ids, resolveInfo, err := imagemetadata.ValidateImageMetadata(params) if err != nil { if resolveInfo != nil { metadata := map[string]interface{}{ "Resolve Metadata": *resolveInfo, } if metadataYaml, yamlErr := cmd.FormatYaml(metadata); yamlErr == nil { err = fmt.Errorf("%v\n%v", err, string(metadataYaml)) } } return err } if len(image_ids) > 0 { metadata := map[string]interface{}{ "ImageIds": image_ids, "Region": params.Region, "Resolve Metadata": *resolveInfo, } c.out.Write(context, metadata) } else { var sources []string for _, s := range params.Sources { url, err := s.URL("") if err == nil { sources = append(sources, fmt.Sprintf("- %s (%s)", s.Description(), url)) } } return fmt.Errorf( "no matching image ids for region %s using sources:\n%s", params.Region, strings.Join(sources, "\n")) } return nil }