func (s *destroyEnvSuite) TestDestroyEnvironmentCommandConfirmation(c *gc.C) { var stdin, stdout bytes.Buffer ctx, err := cmd.DefaultContext() c.Assert(err, gc.IsNil) ctx.Stdout = &stdout ctx.Stdin = &stdin // Prepare the environment so we can destroy it. env, err := environs.PrepareFromName("dummyenv", nullContext(c), s.ConfigStore) c.Assert(err, gc.IsNil) assertEnvironNotDestroyed(c, env, s.ConfigStore) // Ensure confirmation is requested if "-y" is not specified. stdin.WriteString("n") opc, errc := runCommand(ctx, new(DestroyEnvironmentCommand), "dummyenv") c.Check(<-errc, gc.ErrorMatches, "environment destruction aborted") c.Check(<-opc, gc.IsNil) c.Check(stdout.String(), gc.Matches, "WARNING!.*dummyenv.*\\(type: dummy\\)(.|\n)*") assertEnvironNotDestroyed(c, env, s.ConfigStore) // EOF on stdin: equivalent to answering no. stdin.Reset() stdout.Reset() opc, errc = runCommand(ctx, new(DestroyEnvironmentCommand), "dummyenv") c.Check(<-opc, gc.IsNil) c.Check(<-errc, gc.ErrorMatches, "environment destruction aborted") assertEnvironNotDestroyed(c, env, s.ConfigStore) // "--yes" passed: no confirmation request. stdin.Reset() stdout.Reset() opc, errc = runCommand(ctx, new(DestroyEnvironmentCommand), "dummyenv", "--yes") c.Check(<-errc, gc.IsNil) c.Check((<-opc).(dummy.OpDestroy).Env, gc.Equals, "dummyenv") c.Check(stdout.String(), gc.Equals, "") assertEnvironDestroyed(c, env, s.ConfigStore) // Any of casing of "y" and "yes" will confirm. for _, answer := range []string{"y", "Y", "yes", "YES"} { // Prepare the environment so we can destroy it. s.Reset(c) env, err := environs.PrepareFromName("dummyenv", nullContext(c), s.ConfigStore) c.Assert(err, gc.IsNil) stdin.Reset() stdout.Reset() stdin.WriteString(answer) opc, errc = runCommand(ctx, new(DestroyEnvironmentCommand), "dummyenv") c.Check(<-errc, gc.IsNil) c.Check((<-opc).(dummy.OpDestroy).Env, gc.Equals, "dummyenv") c.Check(stdout.String(), gc.Matches, "WARNING!.*dummyenv.*\\(type: dummy\\)(.|\n)*") assertEnvironDestroyed(c, env, s.ConfigStore) } }
func (s *destroyEnvSuite) TestDestroyEnvironmentCommandBroken(c *gc.C) { oldinfo, err := s.ConfigStore.ReadInfo("dummyenv") c.Assert(err, gc.IsNil) bootstrapConfig := oldinfo.BootstrapConfig() apiEndpoint := oldinfo.APIEndpoint() apiCredentials := oldinfo.APICredentials() err = oldinfo.Destroy() c.Assert(err, gc.IsNil) newinfo, err := s.ConfigStore.CreateInfo("dummyenv") c.Assert(err, gc.IsNil) bootstrapConfig["broken"] = "Destroy" newinfo.SetBootstrapConfig(bootstrapConfig) newinfo.SetAPIEndpoint(apiEndpoint) newinfo.SetAPICredentials(apiCredentials) err = newinfo.Write() c.Assert(err, gc.IsNil) // Prepare the environment so we can destroy it. _, err = environs.PrepareFromName("dummyenv", nullContext(c), s.ConfigStore) c.Assert(err, gc.IsNil) // destroy with broken environment opc, errc := runCommand(nullContext(c), new(DestroyEnvironmentCommand), "dummyenv", "--yes") op, ok := (<-opc).(dummy.OpDestroy) c.Assert(ok, jc.IsTrue) c.Assert(op.Error, gc.ErrorMatches, "dummy.Destroy is broken") c.Check(<-errc, gc.Equals, op.Error) c.Check(<-opc, gc.IsNil) }
func (s *destroyEnvSuite) TestDestroyEnvironmentCommandEFlag(c *gc.C) { // Prepare the environment so we can destroy it. _, err := environs.PrepareFromName("dummyenv", nullContext(c), s.ConfigStore) c.Assert(err, gc.IsNil) // check that either environment or the flag is mandatory opc, errc := runCommand(nullContext(c), new(DestroyEnvironmentCommand)) c.Check(<-errc, gc.Equals, NoEnvironmentError) // We don't allow them to supply both entries at the same time opc, errc = runCommand(nullContext(c), new(DestroyEnvironmentCommand), "-e", "dummyenv", "dummyenv", "--yes") c.Check(<-errc, gc.Equals, DoubleEnvironmentError) // We treat --environment the same way opc, errc = runCommand(nullContext(c), new(DestroyEnvironmentCommand), "--environment", "dummyenv", "dummyenv", "--yes") c.Check(<-errc, gc.Equals, DoubleEnvironmentError) // destroy using the -e flag opc, errc = runCommand(nullContext(c), new(DestroyEnvironmentCommand), "-e", "dummyenv", "--yes") c.Check(<-errc, gc.IsNil) c.Check((<-opc).(dummy.OpDestroy).Env, gc.Equals, "dummyenv") // Verify that the environment information has been removed. _, err = s.ConfigStore.ReadInfo("dummyenv") c.Assert(err, jc.Satisfies, errors.IsNotFound) }
func (s *syncToolsSuite) TestSyncToolsCommand(c *gc.C) { for i, test := range syncToolsCommandTests { c.Logf("test %d: %s", i, test.description) targetEnv, err := environs.PrepareFromName("test-target", nullContext(c), s.configStore) c.Assert(err, gc.IsNil) called := false syncTools = func(sctx *sync.SyncContext) error { c.Assert(sctx.AllVersions, gc.Equals, test.sctx.AllVersions) c.Assert(sctx.MajorVersion, gc.Equals, test.sctx.MajorVersion) c.Assert(sctx.MinorVersion, gc.Equals, test.sctx.MinorVersion) c.Assert(sctx.DryRun, gc.Equals, test.sctx.DryRun) c.Assert(sctx.Dev, gc.Equals, test.sctx.Dev) c.Assert(sctx.Public, gc.Equals, test.sctx.Public) c.Assert(sctx.Source, gc.Equals, test.sctx.Source) c.Assert(dummy.IsSameStorage(sctx.Target, targetEnv.Storage()), jc.IsTrue) called = true return nil } ctx, err := runSyncToolsCommand(c, test.args...) c.Assert(err, gc.IsNil) c.Assert(ctx, gc.NotNil) c.Assert(called, jc.IsTrue) s.Reset(c) } }
func (s *verifyStorageSuite) TestVerifyStorageFails(c *gc.C) { ctx := testing.Context(c) environ, err := environs.PrepareFromName("test", ctx, configstore.NewMem()) c.Assert(err, gc.IsNil) stor := environ.Storage() someError := errors.Unauthorizedf("you shall not pass") dummy.Poison(stor, environs.VerificationFilename, someError) err = environs.VerifyStorage(stor) c.Assert(err, gc.Equals, environs.VerifyStorageError) }
// resetJujuHome restores an new, clean Juju home environment without tools. func resetJujuHome(c *gc.C) environs.Environ { jenvDir := coretesting.HomePath(".juju", "environments") err := os.RemoveAll(jenvDir) c.Assert(err, gc.IsNil) coretesting.WriteEnvironments(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 }
func (s *verifyStorageSuite) TestVerifyStorage(c *gc.C) { ctx := testing.Context(c) environ, err := environs.PrepareFromName("test", ctx, configstore.NewMem()) c.Assert(err, gc.IsNil) stor := environ.Storage() err = environs.VerifyStorage(stor) c.Assert(err, gc.IsNil) reader, err := storage.Get(stor, environs.VerificationFilename) c.Assert(err, gc.IsNil) defer reader.Close() contents, err := ioutil.ReadAll(reader) c.Assert(err, gc.IsNil) c.Check(string(contents), gc.Equals, "juju-core storage writing verified: ok\n") }
func (s *destroyEnvSuite) TestDestroyEnvironmentCommand(c *gc.C) { // Prepare the environment so we can destroy it. _, err := environs.PrepareFromName("dummyenv", nullContext(c), s.ConfigStore) c.Assert(err, gc.IsNil) // check environment is mandatory opc, errc := runCommand(nullContext(c), new(DestroyEnvironmentCommand)) c.Check(<-errc, gc.Equals, NoEnvironmentError) // normal destroy opc, errc = runCommand(nullContext(c), new(DestroyEnvironmentCommand), "dummyenv", "--yes") c.Check(<-errc, gc.IsNil) c.Check((<-opc).(dummy.OpDestroy).Env, gc.Equals, "dummyenv") // Verify that the environment information has been removed. _, err = s.ConfigStore.ReadInfo("dummyenv") c.Assert(err, jc.Satisfies, errors.IsNotFound) }
func (s *APIEndpointForEnvSuite) TestAPIEndpointNotCached(c *gc.C) { coretesting.WriteEnvironments(c, coretesting.MultipleEnvConfig) 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"}) }
func (s *BootstrapSuite) TestBootstrapJenvWarning(c *gc.C) { env := resetJujuHome(c) 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, envcmd.Wrap(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 *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 }
// 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 }