func (s *machineConfigSuite) TestMachineConfig(c *gc.C) { addrs := []instance.Address{instance.NewAddress("1.2.3.4", instance.NetworkUnknown)} hc := instance.MustParseHardware("mem=4G arch=amd64") apiParams := params.AddMachineParams{ Jobs: []params.MachineJob{params.JobHostUnits}, InstanceId: instance.Id("1234"), Nonce: "foo", HardwareCharacteristics: hc, Addrs: addrs, } machines, err := s.APIState.Client().AddMachines([]params.AddMachineParams{apiParams}) c.Assert(err, gc.IsNil) c.Assert(len(machines), gc.Equals, 1) machineId := machines[0].Machine machineConfig, err := client.MachineConfig(s.State, machineId, apiParams.Nonce, "") c.Assert(err, gc.IsNil) envConfig, err := s.State.EnvironConfig() c.Assert(err, gc.IsNil) env, err := environs.New(envConfig) c.Assert(err, gc.IsNil) stateInfo, apiInfo, err := env.StateInfo() c.Assert(err, gc.IsNil) c.Check(machineConfig.StateInfo.Addrs, gc.DeepEquals, stateInfo.Addrs) c.Check(machineConfig.APIInfo.Addrs, gc.DeepEquals, apiInfo.Addrs) c.Assert(machineConfig.Tools.URL, gc.Not(gc.Equals), "") }
// Tools finds the tools necessary for the given agents. func (t *ToolsGetter) Tools(args params.Entities) (params.ToolsResults, error) { result := params.ToolsResults{ Results: make([]params.ToolsResult, len(args.Entities)), } canRead, err := t.getCanRead() if err != nil { return result, err } agentVersion, cfg, err := t.getGlobalAgentVersion() if err != nil { return result, err } // SSLHostnameVerification defaults to true, so we need to // invert that, for backwards-compatibility (older versions // will have DisableSSLHostnameVerification: false by default). disableSSLHostnameVerification := !cfg.SSLHostnameVerification() env, err := environs.New(cfg) if err != nil { return result, err } for i, entity := range args.Entities { agentTools, err := t.oneAgentTools(canRead, entity.Tag, agentVersion, env) if err == nil { result.Results[i].Tools = agentTools result.Results[i].DisableSSLHostnameVerification = disableSSLHostnameVerification } result.Results[i].Error = ServerError(err) } return result, nil }
func (obs *EnvironObserver) loop() error { for { select { case <-obs.tomb.Dying(): return nil case _, ok := <-obs.environWatcher.Changes(): if !ok { return watcher.MustErr(obs.environWatcher) } } config, err := obs.st.EnvironConfig() if err != nil { logger.Warningf("error reading environment config: %v", err) continue } environ, err := environs.New(config) if err != nil { logger.Warningf("error creating Environ: %v", err) continue } obs.mu.Lock() obs.environ = environ obs.mu.Unlock() } }
func (s *localServerSuite) assertGetImageMetadataSources(c *gc.C, stream, officialSourcePath string) { // Create a config that matches s.TestConfig but with the specified stream. envAttrs := s.TestConfig if stream != "" { envAttrs = envAttrs.Merge(coretesting.Attrs{"image-stream": stream}) } cfg, err := config.New(config.NoDefaults, envAttrs) c.Assert(err, gc.IsNil) env, err := environs.New(cfg) c.Assert(err, gc.IsNil) sources, err := imagemetadata.GetMetadataSources(env) c.Assert(err, gc.IsNil) c.Assert(sources, gc.HasLen, 4) var urls = make([]string, len(sources)) for i, source := range sources { url, err := source.URL("") c.Assert(err, gc.IsNil) urls[i] = url } // The image-metadata-url ends with "/juju-dist-test/". c.Check(strings.HasSuffix(urls[0], "/juju-dist-test/"), jc.IsTrue) // The control bucket URL contains the bucket name. c.Check(strings.Contains(urls[1], openstack.ControlBucketName(env)+"/images"), jc.IsTrue) // The product-streams URL ends with "/imagemetadata". c.Check(strings.HasSuffix(urls[2], "/imagemetadata/"), jc.IsTrue) c.Assert(urls[3], gc.Equals, fmt.Sprintf("http://cloud-images.ubuntu.com/%s/", officialSourcePath)) }
func (s *LiveTests) assertStartInstanceDefaultSecurityGroup(c *gc.C, useDefault bool) { attrs := s.TestConfig.Merge(coretesting.Attrs{ "name": "sample-" + randomName(), "control-bucket": "juju-test-" + randomName(), "use-default-secgroup": useDefault, }) cfg, err := config.New(config.NoDefaults, attrs) c.Assert(err, gc.IsNil) // Set up a test environment. env, err := environs.New(cfg) c.Assert(err, gc.IsNil) c.Assert(env, gc.NotNil) defer env.Destroy() // Bootstrap and start an instance. err = bootstrap.Bootstrap(coretesting.Context(c), env, environs.BootstrapParams{}) c.Assert(err, gc.IsNil) inst, _ := jujutesting.AssertStartInstance(c, env, "100") // Check whether the instance has the default security group assigned. novaClient := openstack.GetNovaClient(env) groups, err := novaClient.GetServerSecurityGroups(string(inst.Id())) c.Assert(err, gc.IsNil) defaultGroupFound := false for _, group := range groups { if group.Name == "default" { defaultGroupFound = true break } } c.Assert(defaultGroupFound, gc.Equals, useDefault) }
// 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 secrets and API endpoints. auth, err := environs.NewEnvironAuthenticator(env) if err != nil { return nil, err } stateInfo, apiInfo, err := auth.SetupAuthentication(machine) if err != nil { return nil, err } // Find requested networks. includeNetworks, excludeNetworks, err := machine.RequestedNetworks() if err != nil { return nil, err } mcfg := environs.NewMachineConfig(machineId, nonce, includeNetworks, excludeNetworks, stateInfo, 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 }
// findTools1dot17 allows 1.17.x versions to be upgraded. func findTools1dot17(cfg *config.Config) (coretools.List, error) { logger.Warningf("running find tools in 1.17 compatibility mode") env, err := environs.New(cfg) if err != nil { return nil, err } clientVersion := version.Current.Number return envtools.FindTools(env, clientVersion.Major, -1, coretools.Filter{}, envtools.DoNotAllowRetry) }
// Open opens an instance of the testing environment. func (t *Tests) Open(c *gc.C) environs.Environ { info, err := t.ConfigStore.ReadInfo(t.TestConfig["name"].(string)) c.Assert(err, gc.IsNil) cfg, err := config.New(config.NoDefaults, info.BootstrapConfig()) c.Assert(err, gc.IsNil) e, err := environs.New(cfg) c.Assert(err, gc.IsNil, gc.Commentf("opening environ %#v", cfg.AllAttrs())) c.Assert(e, gc.NotNil) return e }
func (context *upgradeContext) uploadTools1dot17(builtTools *sync.BuiltTools, series ...string) (*coretools.Tools, error) { logger.Warningf("running upload tools in 1.17 compatibility mode") env, err := environs.New(context.config) if err != nil { return nil, err } return sync.SyncBuiltTools(env.Storage(), builtTools, series...) }
func (s *localServerSuite) TestStartInstanceNetworkUnknownLabel(c *gc.C) { cfg, err := config.New(config.NoDefaults, s.TestConfig.Merge(coretesting.Attrs{ // A label that has no related network in the nova test service "network": "no-network-with-this-label", })) c.Assert(err, gc.IsNil) env, err := environs.New(cfg) c.Assert(err, gc.IsNil) inst, _, _, err := testing.StartInstance(env, "100") c.Check(inst, gc.IsNil) c.Assert(err, gc.ErrorMatches, "No networks exist with label .*") }
func (*OpenSuite) TestNew(c *gc.C) { cfg, err := config.New(config.NoDefaults, dummy.SampleConfig().Merge( testing.Attrs{ "state-server": false, "name": "erewhemos", }, )) c.Assert(err, gc.IsNil) e, err := environs.New(cfg) c.Assert(err, gc.ErrorMatches, "environment is not prepared") c.Assert(e, gc.IsNil) }
func (s *localServerSuite) TestStartInstanceNetwork(c *gc.C) { cfg, err := config.New(config.NoDefaults, s.TestConfig.Merge(coretesting.Attrs{ // A label that corresponds to a nova test service network "network": "net", })) c.Assert(err, gc.IsNil) env, err := environs.New(cfg) c.Assert(err, gc.IsNil) inst, _ := testing.AssertStartInstance(c, env, "100") err = env.StopInstances([]instance.Instance{inst}) c.Assert(err, gc.IsNil) }
// destroyInstances directly destroys all non-manager, // non-manual machine instances. func destroyInstances(st *state.State, machines []*state.Machine) error { var ids []instance.Id for _, m := range machines { if m.IsManager() { continue } manual, err := m.IsManual() if manual { continue } else if err != nil { return err } id, err := m.InstanceId() if err != nil { continue } ids = append(ids, id) } if len(ids) == 0 { return nil } envcfg, err := st.EnvironConfig() if err != nil { return err } env, err := environs.New(envcfg) if err != nil { return err } // TODO(axw) 2013-12-12 #1260171 // Modify InstanceBroker.StopInstances to take // a slice of IDs rather than Instances. instances, err := env.Instances(ids) switch err { case nil: default: return err case environs.ErrNoInstances: return nil case environs.ErrPartialInstances: var nonNilInstances []instance.Instance for i, inst := range instances { if inst == nil { logger.Warningf("unknown instance ID: %v", ids[i]) continue } nonNilInstances = append(nonNilInstances, inst) } instances = nonNilInstances } return env.StopInstances(instances) }
// NewConnFromState returns a Conn that uses an Environ // made by reading the environment configuration. // The resulting Conn uses the given State - closing // it will close that State. func NewConnFromState(st *state.State) (*Conn, error) { cfg, err := st.EnvironConfig() if err != nil { return nil, err } environ, err := environs.New(cfg) if err != nil { return nil, err } return &Conn{ Environ: environ, State: st, }, nil }
// uploadToStorage uploads the tools from the specified directory to environment storage. func (h *toolsHandler) uploadToStorage(uploadedTools *tools.Tools, toolsDir, toolsFilename string, fakeSeries ...string) (*tools.Tools, bool, error) { // SyncTools requires simplestreams metadata to find the tools to upload. stor, err := filestorage.NewFileStorageWriter(toolsDir) if err != nil { return nil, false, fmt.Errorf("cannot create metadata storage: %v", err) } // Generate metadata for the fake series. The URL for each fake series // record points to the same tools tarball. allToolsMetadata := []*tools.Tools{uploadedTools} for _, series := range fakeSeries { vers := uploadedTools.Version vers.Series = series allToolsMetadata = append(allToolsMetadata, &tools.Tools{ Version: vers, URL: uploadedTools.URL, Size: uploadedTools.Size, SHA256: uploadedTools.SHA256, }) } err = envtools.MergeAndWriteMetadata(stor, allToolsMetadata, false) if err != nil { return nil, false, fmt.Errorf("cannot get environment config: %v", err) } // Create the environment so we can get the storage to which we upload the tools. envConfig, err := h.state.EnvironConfig() if err != nil { return nil, false, fmt.Errorf("cannot get environment config: %v", err) } env, err := environs.New(envConfig) if err != nil { return nil, false, fmt.Errorf("cannot access environment: %v", err) } // Now perform the upload. builtTools := &sync.BuiltTools{ Version: uploadedTools.Version, Dir: toolsDir, StorageName: toolsFilename, Size: uploadedTools.Size, Sha256Hash: uploadedTools.SHA256, } uploadedTools, err = sync.SyncBuiltTools(env.Storage(), builtTools, fakeSeries...) if err != nil { return nil, false, err } return uploadedTools, !envConfig.SSLHostnameVerification(), nil }
func (s *localServerSuite) TestDestroyEnvironmentDeletesSecurityGroupsFWModeGlobal(c *gc.C) { cfg, err := config.New(config.NoDefaults, s.TestConfig.Merge(coretesting.Attrs{ "firewall-mode": "global"})) c.Assert(err, gc.IsNil) env, err := environs.New(cfg) c.Assert(err, gc.IsNil) instanceName := "100" testing.AssertStartInstance(c, env, instanceName) allSecurityGroups := []string{"default", fmt.Sprintf("juju-%v", env.Name()), fmt.Sprintf("juju-%v-global", env.Name())} assertSecurityGroups(c, env, allSecurityGroups) err = env.Destroy() c.Check(err, gc.IsNil) assertSecurityGroups(c, env, []string{"default"}) }
func (s *localServerSuite) TestStartInstanceNetworkUnknownId(c *gc.C) { cfg, err := config.New(config.NoDefaults, s.TestConfig.Merge(coretesting.Attrs{ // A valid UUID but no related network in the nova test service "network": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6", })) c.Assert(err, gc.IsNil) env, err := environs.New(cfg) c.Assert(err, gc.IsNil) inst, _, _, err := testing.StartInstance(env, "100") c.Check(inst, gc.IsNil) c.Assert(err, gc.ErrorMatches, "cannot run instance: (\\n|.)*"+ "caused by: "+ "request \\(.*/servers\\) returned unexpected status: "+ "404; error info: .*itemNotFound.*") }
func rebootstrap(cfg *config.Config, ctx *cmd.Context, cons constraints.Value) (environs.Environ, error) { progress("re-bootstrapping environment") // Turn on safe mode so that the newly bootstrapped instance // will not destroy all the instances it does not know about. cfg, err := cfg.Apply(map[string]interface{}{ "provisioner-safe-mode": true, }) if err != nil { return nil, fmt.Errorf("cannot enable provisioner-safe-mode: %v", err) } env, err := environs.New(cfg) if err != nil { return nil, err } state, err := bootstrap.LoadState(env.Storage()) if err != nil { return nil, fmt.Errorf("cannot retrieve environment storage; perhaps the environment was not bootstrapped: %v", err) } if len(state.StateInstances) == 0 { return nil, fmt.Errorf("no instances found on bootstrap state; perhaps the environment was not bootstrapped") } if len(state.StateInstances) > 1 { return nil, fmt.Errorf("restore does not support HA juju configurations yet") } inst, err := env.Instances(state.StateInstances) if err == nil { return nil, fmt.Errorf("old bootstrap instance %q still seems to exist; will not replace", inst) } if err != environs.ErrNoInstances { return nil, fmt.Errorf("cannot detect whether old instance is still running: %v", err) } // Remove the storage so that we can bootstrap without the provider complaining. if err := env.Storage().Remove(bootstrap.StateFile); err != nil { return nil, fmt.Errorf("cannot remove %q from storage: %v", bootstrap.StateFile, err) } // TODO If we fail beyond here, then we won't have a state file and // we won't be able to re-run this script because it fails without it. // We could either try to recreate the file if we fail (which is itself // error-prone) or we could provide a --no-check flag to make // it go ahead anyway without the check. args := environs.BootstrapParams{Constraints: cons} if err := bootstrap.Bootstrap(ctx, env, args); err != nil { return nil, fmt.Errorf("cannot bootstrap new instance: %v", err) } return env, nil }
func (s *localServerSuite) TestStopInstance(c *gc.C) { cfg, err := config.New(config.NoDefaults, s.TestConfig.Merge(coretesting.Attrs{ "firewall-mode": "instance"})) c.Assert(err, gc.IsNil) env, err := environs.New(cfg) c.Assert(err, gc.IsNil) instanceName := "100" inst, _ := testing.AssertStartInstance(c, env, instanceName) // Openstack now has three security groups for the server, the default // group, one group for the entire environment, and another for the // new instance. assertSecurityGroups(c, env, []string{"default", fmt.Sprintf("juju-%v", env.Name()), fmt.Sprintf("juju-%v-%v", env.Name(), instanceName)}) err = env.StopInstances([]instance.Instance{inst}) c.Assert(err, gc.IsNil) // The security group for this instance is now removed. assertSecurityGroups(c, env, []string{"default", fmt.Sprintf("juju-%v", env.Name())}) }
// FindTools returns a List containing all tools matching the given parameters. func (c *Client) FindTools(args params.FindToolsParams) (params.FindToolsResults, error) { result := params.FindToolsResults{} // Get the existing environment config from the state. envConfig, err := c.api.state.EnvironConfig() if err != nil { return result, err } env, err := environs.New(envConfig) if err != nil { return result, err } filter := coretools.Filter{ Arch: args.Arch, Series: args.Series, } result.List, err = envtools.FindTools(env, args.MajorVersion, args.MinorVersion, filter, envtools.DoNotAllowRetry) result.Error = common.ServerError(err) return result, nil }
// If the bootstrap node is configured to require a public IP address, // bootstrapping fails if an address cannot be allocated. func (s *localServerSuite) TestBootstrapFailsWhenPublicIPError(c *gc.C) { cleanup := s.srv.Service.Nova.RegisterControlPoint( "addFloatingIP", func(sc hook.ServiceControl, args ...interface{}) error { return fmt.Errorf("failed on purpose") }, ) defer cleanup() // Create a config that matches s.TestConfig but with use-floating-ip set to true cfg, err := config.New(config.NoDefaults, s.TestConfig.Merge(coretesting.Attrs{ "use-floating-ip": true, })) c.Assert(err, gc.IsNil) env, err := environs.New(cfg) c.Assert(err, gc.IsNil) err = bootstrap.Bootstrap(coretesting.Context(c), env, environs.BootstrapParams{}) c.Assert(err, gc.ErrorMatches, "(.|\n)*cannot allocate a public IP as needed(.|\n)*") }
func (*ConfigSuite) TestNewEnvironConfig(c *gc.C) { for i, test := range newConfigTests { c.Logf("test %d: %s", i, test.info) for k, v := range test.envVars { os.Setenv(k, v) } attrs := validAttrs().Merge(test.insert).Delete(test.remove...) testConfig := newConfig(c, attrs) environ, err := environs.New(testConfig) if test.err == "" { c.Check(err, gc.IsNil) attrs := environ.Config().AllAttrs() for field, value := range test.expect { c.Check(attrs[field], gc.Equals, value) } } else { c.Check(environ, gc.IsNil) c.Check(err, gc.ErrorMatches, test.err) } } }
// 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, apiOpen apiOpenFunc, stop <-chan struct{}, delay time.Duration) (apiState, error) { select { case <-time.After(delay): case <-stop: return nil, errAborted } environ, err := environs.New(cfg) if err != nil { return nil, err } apiInfo, err := environAPIInfo(environ) if err != nil { return nil, err } st, err := apiOpen(apiInfo, api.DefaultDialOpts()) // TODO(rog): handle errUnauthorized when the API handles passwords. if err != nil { return nil, err } return apiStateCachedInfo{st, apiInfo}, nil }
func (u *UnitUpgraderAPI) getMachineTools(tag string) params.ToolsResult { var result params.ToolsResult machine, err := u.getAssignedMachine(tag) if err != nil { result.Error = common.ServerError(err) return result } machineTools, err := machine.AgentTools() if err != nil { result.Error = common.ServerError(err) return result } // For older 1.16 upgrader workers, we need to supply a tools URL since the worker will attempt to // download the tools even though they already have been fetched by the machine agent. Newer upgrader // workers do not have this problem. So to be compatible across all versions, we return the full // tools metadata. // TODO (wallyworld) - remove in 1.20, just return machineTools cfg, err := u.st.EnvironConfig() if err != nil { result.Error = common.ServerError(err) return result } // SSLHostnameVerification defaults to true, so we need to // invert that, for backwards-compatibility (older versions // will have DisableSSLHostnameVerification: false by default). result.DisableSSLHostnameVerification = !cfg.SSLHostnameVerification() env, err := environs.New(cfg) if err != nil { result.Error = common.ServerError(err) return result } agentTools, err := envtools.FindExactTools( env, machineTools.Version.Number, machineTools.Version.Series, machineTools.Version.Arch) if err != nil { result.Error = common.ServerError(err) return result } result.Tools = agentTools return result }
// AssertEnvironConfig provides a method to test the config from the // envWatcher. This allows other tests that embed this type to have // more than just the default test. func (s *EnvironWatcherTest) AssertEnvironConfig(c *gc.C, envWatcher EnvironmentWatcher, hasSecrets bool) { envConfig, err := s.st.EnvironConfig() c.Assert(err, gc.IsNil) result, err := envWatcher.EnvironConfig() c.Assert(err, gc.IsNil) configAttributes := envConfig.AllAttrs() // If the implementor doesn't provide secrets, we need to replace the config // values in our environment to compare against with the secrets replaced. if !hasSecrets { env, err := environs.New(envConfig) c.Assert(err, gc.IsNil) secretAttrs, err := env.Provider().SecretAttrs(envConfig) c.Assert(err, gc.IsNil) for key := range secretAttrs { configAttributes[key] = "not available" } } c.Assert(result.Config, jc.DeepEquals, params.EnvironConfig(configAttributes)) }
// NewEnvironObserver waits for the state to have a valid environment // configuration and returns a new environment observer. While waiting // for the first environment configuration, it will return with // tomb.ErrDying if it receives a value on dying. func NewEnvironObserver(st *state.State) (*EnvironObserver, error) { config, err := st.EnvironConfig() if err != nil { return nil, err } environ, err := environs.New(config) if err != nil { return nil, fmt.Errorf("cannot make Environ: %v", err) } environWatcher := st.WatchForEnvironConfigChanges() obs := &EnvironObserver{ st: st, environ: environ, environWatcher: environWatcher, } go func() { defer obs.tomb.Done() defer watcher.Stop(environWatcher, &obs.tomb) obs.tomb.Kill(obs.loop()) }() return obs, nil }
// WaitForEnviron waits for an valid environment to arrive from // the given watcher. It terminates with tomb.ErrDying if // it receives a value on dying. func WaitForEnviron(w apiwatcher.NotifyWatcher, st EnvironConfigGetter, dying <-chan struct{}) (environs.Environ, error) { for { select { case <-dying: return nil, tomb.ErrDying case _, ok := <-w.Changes(): if !ok { return nil, watcher.MustErr(w) } config, err := st.EnvironConfig() if err != nil { return nil, err } environ, err := environs.New(config) if err == nil { return environ, nil } logger.Errorf("loaded invalid environment configuration: %v", err) loadedInvalid() } } }
// Due to bug #1300755 it can happen that the security group intended for // an instance is also used as the common security group of another // environment. If this is the case, the attempt to delete the instance's // security group fails but StopInstance succeeds. func (s *localServerSuite) TestStopInstanceSecurityGroupNotDeleted(c *gc.C) { // Force an error when a security group is deleted. cleanup := s.srv.Service.Nova.RegisterControlPoint( "removeSecurityGroup", func(sc hook.ServiceControl, args ...interface{}) error { return fmt.Errorf("failed on purpose") }, ) defer cleanup() cfg, err := config.New(config.NoDefaults, s.TestConfig.Merge(coretesting.Attrs{ "firewall-mode": "instance"})) c.Assert(err, gc.IsNil) env, err := environs.New(cfg) c.Assert(err, gc.IsNil) instanceName := "100" inst, _ := testing.AssertStartInstance(c, env, instanceName) allSecurityGroups := []string{"default", fmt.Sprintf("juju-%v", env.Name()), fmt.Sprintf("juju-%v-%v", env.Name(), instanceName)} assertSecurityGroups(c, env, allSecurityGroups) err = env.StopInstances([]instance.Instance{inst}) c.Assert(err, gc.IsNil) assertSecurityGroups(c, env, allSecurityGroups) }
func (s *ConfigSuite) TestSetConfig(c *gc.C) { baseConfig := newConfig(c, validAttrs()) for i, test := range changeConfigTests { c.Logf("test %d: %s", i, test.info) environ, err := environs.New(baseConfig) c.Assert(err, gc.IsNil) attrs := validAttrs().Merge(test.insert).Delete(test.remove...) testConfig := newConfig(c, attrs) err = environ.SetConfig(testConfig) newAttrs := environ.Config().AllAttrs() if test.err == "" { c.Check(err, gc.IsNil) for field, value := range test.expect { c.Check(newAttrs[field], gc.Equals, value) } } else { c.Check(err, gc.ErrorMatches, test.err) for field, value := range baseConfig.UnknownAttrs() { c.Check(newAttrs[field], gc.Equals, value) } } } }
// EnvironConfig returns the current environment's configuration. func (e *EnvironWatcher) EnvironConfig() (params.EnvironConfigResult, error) { result := params.EnvironConfigResult{} canReadSecrets, err := e.getCanReadSecrets() if err != nil { return result, err } config, err := e.st.EnvironConfig() if err != nil { return result, err } allAttrs := config.AllAttrs() // TODO(dimitern) If we have multiple environments in state, use a // tag argument here and as a method argument. if !canReadSecrets("") { // Mask out any secrets in the environment configuration // with values of the same type, so it'll pass validation. // // TODO(dimitern) 201309-26 bug #1231384 // Delete the code below and mark the bug as fixed, // once it's live tested on MAAS and 1.16 compatibility // is dropped. env, err := environs.New(config) if err != nil { return result, err } secretAttrs, err := env.Provider().SecretAttrs(config) for k := range secretAttrs { allAttrs[k] = "not available" } } result.Config = allAttrs return result, nil }