func (prov maasEnvironProvider) Validate(cfg, oldCfg *config.Config) (*config.Config, error) { // Validate base configuration change before validating MAAS specifics. err := config.Validate(cfg, oldCfg) if err != nil { return nil, err } validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults) if err != nil { return nil, err } envCfg := new(maasEnvironConfig) envCfg.Config = cfg envCfg.attrs = validated server := envCfg.MAASServer() serverURL, err := url.Parse(server) if err != nil || serverURL.Scheme == "" || serverURL.Host == "" { return nil, fmt.Errorf("malformed maas-server URL '%v': %s", server, err) } oauth := envCfg.MAASOAuth() if strings.Count(oauth, ":") != 2 { return nil, errMalformedMaasOAuth } return cfg.Apply(envCfg.attrs) }
// Validate ensures that config is a valid configuration for this // provider like specified in the EnvironProvider interface. func (prov azureEnvironProvider) Validate(cfg, oldCfg *config.Config) (*config.Config, error) { // Validate base configuration change before validating Azure specifics. err := config.Validate(cfg, oldCfg) if err != nil { return nil, err } validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults) if err != nil { return nil, err } envCfg := new(azureEnvironConfig) envCfg.Config = cfg envCfg.attrs = validated cert := envCfg.managementCertificate() if cert == "" { certPath := envCfg.attrs["management-certificate-path"].(string) pemData, err := ioutil.ReadFile(certPath) if err != nil { return nil, fmt.Errorf("invalid management-certificate-path: %s", err) } envCfg.attrs["management-certificate"] = string(pemData) } delete(envCfg.attrs, "management-certificate-path") if envCfg.location() == "" { return nil, fmt.Errorf("environment has no location; you need to set one. E.g. 'West US'") } if (envCfg.publicStorageAccountName() == "") != (envCfg.publicStorageContainerName() == "") { return nil, fmt.Errorf("public-storage-account-name and public-storage-container-name must be specified both or none of them") } return cfg.Apply(envCfg.attrs) }
// bootstrapAddressAndStorage finishes up the setup of the environment in // situations where there is no machine agent running yet. func (env *localEnviron) bootstrapAddressAndStorage(cfg *config.Config) error { // If we get to here, it is because we haven't yet bootstrapped an // environment, and saved the config in it, or we are running a command // from the command line, so it is ok to work on the assumption that we // have direct access to the directories. if err := env.config.createDirs(); err != nil { return err } bridgeAddress, err := env.findBridgeAddress() if err != nil { return err } logger.Debugf("found %q as address for %q", bridgeAddress, lxcBridgeName) cfg, err = cfg.Apply(map[string]interface{}{ "bootstrap-ip": bridgeAddress, }) if err != nil { logger.Errorf("failed to apply new addresses to config: %v", err) return err } config, err := provider.newConfig(cfg) if err != nil { logger.Errorf("failed to create new environ config: %v", err) return err } env.config = config return env.setupLocalStorage() }
func (p *environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { // Check for valid changes for the base config values. if err := config.Validate(cfg, old); err != nil { return nil, err } validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults) if err != nil { return nil, err } // Apply the coerced unknown values back into the config. return cfg.Apply(validated) }
func (p *environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { v, err := checker.Coerce(cfg.UnknownAttrs(), nil) if err != nil { return nil, err } attrs := v.(map[string]interface{}) switch cfg.FirewallMode() { case config.FwDefault: attrs["firewall-mode"] = config.FwInstance case config.FwInstance, config.FwGlobal: default: return nil, fmt.Errorf("unsupported firewall mode: %q", cfg.FirewallMode()) } return cfg.Apply(attrs) }
func (p environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { v, err := configChecker.Coerce(cfg.UnknownAttrs(), nil) if err != nil { return nil, err } ecfg := &environConfig{cfg, v.(map[string]interface{})} if ecfg.accessKey() == "" || ecfg.secretKey() == "" { auth, err := aws.EnvAuth() if err != nil || ecfg.accessKey() != "" || ecfg.secretKey() != "" { return nil, fmt.Errorf("environment has no access-key or secret-key") } ecfg.attrs["access-key"] = auth.AccessKey ecfg.attrs["secret-key"] = auth.SecretKey } if _, ok := aws.Regions[ecfg.region()]; !ok { return nil, fmt.Errorf("invalid region name %q", ecfg.region()) } if _, ok := aws.Regions[ecfg.publicBucketRegion()]; !ok { return nil, fmt.Errorf("invalid public-bucket-region name %q", ecfg.publicBucketRegion()) } if old != nil { attrs := old.UnknownAttrs() if region, _ := attrs["region"].(string); ecfg.region() != region { return nil, fmt.Errorf("cannot change region from %q to %q", region, ecfg.region()) } if bucket, _ := attrs["control-bucket"].(string); ecfg.controlBucket() != bucket { return nil, fmt.Errorf("cannot change control-bucket from %q to %q", bucket, ecfg.controlBucket()) } } switch cfg.FirewallMode() { case config.FwDefault: ecfg.attrs["firewall-mode"] = config.FwInstance case config.FwInstance, config.FwGlobal: default: return nil, fmt.Errorf("unsupported firewall mode: %q", cfg.FirewallMode()) } // ssl-hostname-verification cannot be disabled if !ecfg.SSLHostnameVerification() { return nil, fmt.Errorf("disabling ssh-hostname-verification is not supported") } return cfg.Apply(ecfg.attrs) }
// Open implements environs.EnvironProvider.Open. func (environProvider) Open(cfg *config.Config) (env environs.Environ, err error) { logger.Infof("opening environment %q", cfg.Name()) if _, ok := cfg.AgentVersion(); !ok { cfg, err = cfg.Apply(map[string]interface{}{ "agent-version": version.CurrentNumber().String(), }) if err != nil { return nil, err } } environ := &localEnviron{name: cfg.Name()} err = environ.SetConfig(cfg) if err != nil { logger.Errorf("failure setting config: %v", err) return nil, err } return environ, nil }
func (p environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { // Check for valid changes for the base config values. if err := config.Validate(cfg, old); err != nil { return nil, err } validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults) if err != nil { return nil, err } ecfg := &environConfig{cfg, validated} if ecfg.accessKey() == "" || ecfg.secretKey() == "" { auth, err := aws.EnvAuth() if err != nil || ecfg.accessKey() != "" || ecfg.secretKey() != "" { return nil, fmt.Errorf("environment has no access-key or secret-key") } ecfg.attrs["access-key"] = auth.AccessKey ecfg.attrs["secret-key"] = auth.SecretKey } if _, ok := aws.Regions[ecfg.region()]; !ok { return nil, fmt.Errorf("invalid region name %q", ecfg.region()) } if _, ok := aws.Regions[ecfg.publicBucketRegion()]; !ok { return nil, fmt.Errorf("invalid public-bucket-region name %q", ecfg.publicBucketRegion()) } if old != nil { attrs := old.UnknownAttrs() if region, _ := attrs["region"].(string); ecfg.region() != region { return nil, fmt.Errorf("cannot change region from %q to %q", region, ecfg.region()) } if bucket, _ := attrs["control-bucket"].(string); ecfg.controlBucket() != bucket { return nil, fmt.Errorf("cannot change control-bucket from %q to %q", bucket, ecfg.controlBucket()) } } // ssl-hostname-verification cannot be disabled if !ecfg.SSLHostnameVerification() { return nil, fmt.Errorf("disabling ssh-hostname-verification is not supported") } // Apply the coerced unknown values back into the config. return cfg.Apply(ecfg.attrs) }
// Validate implements environs.EnvironProvider.Validate. func (provider environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { // Check for valid changes for the base config values. if err := config.Validate(cfg, old); err != nil { return nil, err } validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults) if err != nil { return nil, err } localConfig := newEnvironConfig(cfg, validated) // Before potentially creating directories, make sure that the // root directory has not changed. if old != nil { oldLocalConfig, err := provider.newConfig(old) if err != nil { return nil, fmt.Errorf("old config is not a valid local config: %v", old) } if localConfig.rootDir() != oldLocalConfig.rootDir() { return nil, fmt.Errorf("cannot change root-dir from %q to %q", oldLocalConfig.rootDir(), localConfig.rootDir()) } if localConfig.storagePort() != oldLocalConfig.storagePort() { return nil, fmt.Errorf("cannot change storage-port from %v to %v", oldLocalConfig.storagePort(), localConfig.storagePort()) } if localConfig.sharedStoragePort() != oldLocalConfig.sharedStoragePort() { return nil, fmt.Errorf("cannot change shared-storage-port from %v to %v", oldLocalConfig.sharedStoragePort(), localConfig.sharedStoragePort()) } } dir := utils.NormalizePath(localConfig.rootDir()) if dir == "." { dir = config.JujuHomePath(cfg.Name()) localConfig.attrs["root-dir"] = dir } // Apply the coerced unknown values back into the config. return cfg.Apply(localConfig.attrs) }
// Validate ensures that config is a valid configuration for this // provider like specified in the EnvironProvider interface. func (prov azureEnvironProvider) Validate(cfg, oldCfg *config.Config) (*config.Config, error) { // Validate base configuration change before validating Azure specifics. err := config.Validate(cfg, oldCfg) if err != nil { return nil, err } validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults) if err != nil { return nil, err } envCfg := new(azureEnvironConfig) envCfg.Config = cfg envCfg.attrs = validated cert := envCfg.ManagementCertificate() if cert == "" { certPath := envCfg.attrs["management-certificate-path"].(string) pemData, err := ioutil.ReadFile(certPath) if err != nil { return nil, fmt.Errorf("invalid management-certificate-path: %s", err) } envCfg.attrs["management-certificate"] = string(pemData) } delete(envCfg.attrs, "management-certificate-path") if envCfg.StorageContainerName() == "" { return nil, fmt.Errorf("environment has no storage-container-name; auto-creation of storage containers is not yet supported") } if (envCfg.PublicStorageAccountName() == "") != (envCfg.PublicStorageContainerName() == "") { return nil, fmt.Errorf("public-storage-account-name and public-storage-container-name must be specified both or none of them") } if oldCfg != nil { attrs := oldCfg.UnknownAttrs() if storageContainerName, _ := attrs["storage-container-name"].(string); envCfg.StorageContainerName() != storageContainerName { return nil, fmt.Errorf("cannot change storage-container-name from %q to %q", storageContainerName, envCfg.StorageContainerName()) } } return cfg.Apply(envCfg.attrs) }
func (p environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { v, err := configChecker.Coerce(cfg.UnknownAttrs(), nil) if err != nil { return nil, err } ecfg := &environConfig{cfg, v.(map[string]interface{})} authMethod := ecfg.authMethod() switch AuthMethod(authMethod) { case AuthLegacy: case AuthUserPass: default: return nil, fmt.Errorf("invalid authorization method: %q", authMethod) } if ecfg.authURL() != "" { parts, err := url.Parse(ecfg.authURL()) if err != nil || parts.Host == "" || parts.Scheme == "" { return nil, fmt.Errorf("invalid auth-url value %q", ecfg.authURL()) } } cred := identity.CredentialsFromEnv() format := "required environment variable not set for credentials attribute: %s" if ecfg.username() == "" { if cred.User == "" { return nil, fmt.Errorf(format, "User") } ecfg.attrs["username"] = cred.User } if ecfg.password() == "" { if cred.Secrets == "" { return nil, fmt.Errorf(format, "Secrets") } ecfg.attrs["password"] = cred.Secrets } if ecfg.authURL() == "" { if cred.URL == "" { return nil, fmt.Errorf(format, "URL") } ecfg.attrs["auth-url"] = cred.URL } if ecfg.tenantName() == "" { if cred.TenantName == "" { return nil, fmt.Errorf(format, "TenantName") } ecfg.attrs["tenant-name"] = cred.TenantName } if ecfg.region() == "" { if cred.Region == "" { return nil, fmt.Errorf(format, "Region") } ecfg.attrs["region"] = cred.Region } if old != nil { attrs := old.UnknownAttrs() if region, _ := attrs["region"].(string); ecfg.region() != region { return nil, fmt.Errorf("cannot change region from %q to %q", region, ecfg.region()) } if controlBucket, _ := attrs["control-bucket"].(string); ecfg.controlBucket() != controlBucket { return nil, fmt.Errorf("cannot change control-bucket from %q to %q", controlBucket, ecfg.controlBucket()) } } switch cfg.FirewallMode() { case config.FwDefault: ecfg.attrs["firewall-mode"] = config.FwInstance case config.FwInstance, config.FwGlobal: default: return nil, fmt.Errorf("unsupported firewall mode: %q", cfg.FirewallMode()) } return cfg.Apply(ecfg.attrs) }
func (t configTest) check(c *C) { envs := attrs{ "environments": attrs{ "testenv": attrs{ "type": "ec2", "ca-cert": testing.CACert, "ca-private-key": testing.CAKey, }, }, } testenv := envs["environments"].(attrs)["testenv"].(attrs) for k, v := range t.config { testenv[k] = v } if _, ok := testenv["control-bucket"]; !ok { testenv["control-bucket"] = "x" } data, err := goyaml.Marshal(envs) c.Assert(err, IsNil) es, err := environs.ReadEnvironsBytes(data) c.Check(err, IsNil) e, err := es.Open("testenv") if t.change != nil { c.Assert(err, IsNil) // Testing a change in configuration. var old, changed, valid *config.Config ec2env := e.(*environ) old = ec2env.ecfg().Config changed, err = old.Apply(t.change) c.Assert(err, IsNil) // Keep err for validation below. valid, err = providerInstance.Validate(changed, old) if err == nil { err = ec2env.SetConfig(valid) } } if t.err != "" { c.Check(err, ErrorMatches, t.err) return } c.Assert(err, IsNil) ecfg := e.(*environ).ecfg() c.Assert(ecfg.Name(), Equals, "testenv") c.Assert(ecfg.controlBucket(), Equals, "x") if t.region != "" { c.Assert(ecfg.region(), Equals, t.region) } if t.pbucket != "" { c.Assert(ecfg.publicBucket(), Equals, t.pbucket) } if t.accessKey != "" { c.Assert(ecfg.accessKey(), Equals, t.accessKey) c.Assert(ecfg.secretKey(), Equals, t.secretKey) expected := map[string]interface{}{ "access-key": t.accessKey, "secret-key": t.secretKey, } c.Assert(err, IsNil) actual, err := e.Provider().SecretAttrs(ecfg.Config) c.Assert(err, IsNil) c.Assert(expected, DeepEquals, actual) } else { c.Assert(ecfg.accessKey(), DeepEquals, testAuth.AccessKey) c.Assert(ecfg.secretKey(), DeepEquals, testAuth.SecretKey) } if t.firewallMode != "" { c.Assert(ecfg.FirewallMode(), Equals, t.firewallMode) } // check storage buckets are configured correctly env := e.(*environ) c.Assert(env.Storage().(*storage).bucket.Region.Name, Equals, ecfg.region()) c.Assert(env.PublicStorage().(*storage).bucket.Region.Name, Equals, ecfg.publicBucketRegion()) }
func (t configTest) check(c *gc.C) { envs := attrs{ "environments": attrs{ "testenv": attrs{ "type": "openstack", "authorized-keys": "fakekey", }, }, } testenv := envs["environments"].(attrs)["testenv"].(attrs) for k, v := range t.config { testenv[k] = v } if _, ok := testenv["control-bucket"]; !ok { testenv["control-bucket"] = "x" } data, err := goyaml.Marshal(envs) c.Assert(err, gc.IsNil) es, err := environs.ReadEnvironsBytes(data) c.Check(err, gc.IsNil) // Set environment variables if any. savedVars := make(map[string]string) if t.envVars != nil { for k, v := range t.envVars { savedVars[k] = os.Getenv(k) os.Setenv(k, v) } } defer restoreEnvVars(savedVars) e, err := es.Open("testenv") if t.change != nil { c.Assert(err, gc.IsNil) // Testing a change in configuration. var old, changed, valid *config.Config osenv := e.(*environ) old = osenv.ecfg().Config changed, err = old.Apply(t.change) c.Assert(err, gc.IsNil) // Keep err for validation below. valid, err = providerInstance.Validate(changed, old) if err == nil { err = osenv.SetConfig(valid) } } if t.err != "" { c.Check(err, gc.ErrorMatches, t.err) return } c.Assert(err, gc.IsNil) ecfg := e.(*environ).ecfg() c.Assert(ecfg.Name(), gc.Equals, "testenv") c.Assert(ecfg.controlBucket(), gc.Equals, "x") if t.region != "" { c.Assert(ecfg.region(), gc.Equals, t.region) } if t.authMode != "" { c.Assert(ecfg.authMode(), gc.Equals, t.authMode) } if t.accessKey != "" { c.Assert(ecfg.accessKey(), gc.Equals, t.accessKey) } if t.secretKey != "" { c.Assert(ecfg.secretKey(), gc.Equals, t.secretKey) } if t.username != "" { c.Assert(ecfg.username(), gc.Equals, t.username) c.Assert(ecfg.password(), gc.Equals, t.password) c.Assert(ecfg.tenantName(), gc.Equals, t.tenantName) c.Assert(ecfg.authURL(), gc.Equals, t.authURL) expected := map[string]interface{}{ "username": t.username, "password": t.password, "tenant-name": t.tenantName, } c.Assert(err, gc.IsNil) actual, err := e.Provider().SecretAttrs(ecfg.Config) c.Assert(err, gc.IsNil) c.Assert(expected, gc.DeepEquals, actual) } if t.pbucketURL != "" { c.Assert(ecfg.publicBucketURL(), gc.Equals, t.pbucketURL) c.Assert(ecfg.publicBucket(), gc.Equals, t.publicBucket) } if t.firewallMode != "" { c.Assert(ecfg.FirewallMode(), gc.Equals, t.firewallMode) } c.Assert(ecfg.useFloatingIP(), gc.Equals, t.useFloatingIP) for name, expect := range t.expect { actual, found := ecfg.UnknownAttrs()[name] c.Check(found, gc.Equals, true) c.Check(actual, gc.Equals, expect) } }
func (p environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { // Check for valid changes for the base config values. if err := config.Validate(cfg, old); err != nil { return nil, err } // Check for deprecated fields and log a warning. We also print to stderr to ensure the user sees the message // even if they are not running with --debug. if defaultImageId := cfg.AllAttrs()["default-image-id"]; defaultImageId != nil && defaultImageId.(string) != "" { msg := fmt.Sprintf( "config attribute %q (%v) is deprecated and ignored, use simplestreams metadata instead", "default-image-id", defaultImageId) log.Warningf(msg) } if defaultInstanceType := cfg.AllAttrs()["default-instance-type"]; defaultInstanceType != nil && defaultInstanceType.(string) != "" { msg := fmt.Sprintf( "config attribute %q (%v) is deprecated and ignored", "default-instance-type", defaultInstanceType) log.Warningf(msg) } validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults) if err != nil { return nil, err } ecfg := &environConfig{cfg, validated} authMode := AuthMode(ecfg.authMode()) switch authMode { case AuthKeyPair: case AuthLegacy: case AuthUserPass: default: return nil, fmt.Errorf("invalid authorization mode: %q", authMode) } if ecfg.authURL() != "" { parts, err := url.Parse(ecfg.authURL()) if err != nil || parts.Host == "" || parts.Scheme == "" { return nil, fmt.Errorf("invalid auth-url value %q", ecfg.authURL()) } } cred := identity.CredentialsFromEnv() format := "required environment variable not set for credentials attribute: %s" if authMode == AuthUserPass || authMode == AuthLegacy { if ecfg.username() == "" { if cred.User == "" { return nil, fmt.Errorf(format, "User") } ecfg.attrs["username"] = cred.User } if ecfg.password() == "" { if cred.Secrets == "" { return nil, fmt.Errorf(format, "Secrets") } ecfg.attrs["password"] = cred.Secrets } } else if authMode == AuthKeyPair { if ecfg.accessKey() == "" { if cred.User == "" { return nil, fmt.Errorf(format, "User") } ecfg.attrs["access-key"] = cred.User } if ecfg.secretKey() == "" { if cred.Secrets == "" { return nil, fmt.Errorf(format, "Secrets") } ecfg.attrs["secret-key"] = cred.Secrets } } if ecfg.authURL() == "" { if cred.URL == "" { return nil, fmt.Errorf(format, "URL") } ecfg.attrs["auth-url"] = cred.URL } if ecfg.tenantName() == "" { if cred.TenantName == "" { return nil, fmt.Errorf(format, "TenantName") } ecfg.attrs["tenant-name"] = cred.TenantName } if ecfg.region() == "" { if cred.Region == "" { return nil, fmt.Errorf(format, "Region") } ecfg.attrs["region"] = cred.Region } if old != nil { attrs := old.UnknownAttrs() if region, _ := attrs["region"].(string); ecfg.region() != region { return nil, fmt.Errorf("cannot change region from %q to %q", region, ecfg.region()) } if controlBucket, _ := attrs["control-bucket"].(string); ecfg.controlBucket() != controlBucket { return nil, fmt.Errorf("cannot change control-bucket from %q to %q", controlBucket, ecfg.controlBucket()) } } // Apply the coerced unknown values back into the config. return cfg.Apply(ecfg.attrs) }
func (t configTest) check(c *C) { envs := attrs{ "environments": attrs{ "testenv": attrs{ "type": "openstack", }, }, } testenv := envs["environments"].(attrs)["testenv"].(attrs) for k, v := range t.config { testenv[k] = v } if _, ok := testenv["control-bucket"]; !ok { testenv["control-bucket"] = "x" } data, err := goyaml.Marshal(envs) c.Assert(err, IsNil) es, err := environs.ReadEnvironsBytes(data) c.Check(err, IsNil) e, err := es.Open("testenv") if t.change != nil { c.Assert(err, IsNil) // Testing a change in configuration. var old, changed, valid *config.Config osenv := e.(*environ) old = osenv.ecfg().Config changed, err = old.Apply(t.change) c.Assert(err, IsNil) // Keep err for validation below. valid, err = providerInstance.Validate(changed, old) if err == nil { err = osenv.SetConfig(valid) } } if t.err != "" { c.Check(err, ErrorMatches, t.err) return } c.Assert(err, IsNil) ecfg := e.(*environ).ecfg() c.Assert(ecfg.Name(), Equals, "testenv") c.Assert(ecfg.controlBucket(), Equals, "x") if t.region != "" { c.Assert(ecfg.region(), Equals, t.region) } if t.username != "" { c.Assert(ecfg.username(), Equals, t.username) c.Assert(ecfg.password(), Equals, t.password) c.Assert(ecfg.tenantName(), Equals, t.tenantName) c.Assert(ecfg.authURL(), Equals, t.authURL) expected := map[string]interface{}{ "username": t.username, "password": t.password, "tenant-name": t.tenantName, } c.Assert(err, IsNil) actual, err := e.Provider().SecretAttrs(ecfg.Config) c.Assert(err, IsNil) c.Assert(expected, DeepEquals, actual) } if t.pbucketURL != "" { c.Assert(ecfg.publicBucketURL(), Equals, t.pbucketURL) c.Assert(ecfg.publicBucket(), Equals, t.publicBucket) } if t.firewallMode != "" { c.Assert(ecfg.FirewallMode(), Equals, t.firewallMode) } }
func (p environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { // Check for valid changes for the base config values. if err := config.Validate(cfg, old); err != nil { return nil, err } // Check for deprecated fields and log a warning. We also print to stderr to ensure the user sees the message // even if they are not running with --debug. if defaultImageId := cfg.AllAttrs()["default-image-id"]; defaultImageId != nil && defaultImageId.(string) != "" { msg := fmt.Sprintf( "Config attribute %q (%v) is deprecated and ignored.\n"+ "Your cloud provider should have set up image metadata to provide the correct image id\n"+ "for your chosen series and archietcure. If this is a private Openstack deployment without\n"+ "existing image metadata, please run 'juju help image-metadata' to see how suitable image"+ "metadata can be generated.", "default-image-id", defaultImageId) log.Warningf(msg) } if defaultInstanceType := cfg.AllAttrs()["default-instance-type"]; defaultInstanceType != nil && defaultInstanceType.(string) != "" { msg := fmt.Sprintf( "Config attribute %q (%v) is deprecated and ignored.\n"+ "The correct instance flavor is determined using constraints, globally specified\n"+ "when an environment is bootstrapped, or individually when a charm is deployed.\n"+ "See 'juju help bootstrap' or 'juju help deploy'.", "default-instance-type", defaultInstanceType) log.Warningf(msg) } validated, err := cfg.ValidateUnknownAttrs(configFields, configDefaults) if err != nil { return nil, err } ecfg := &environConfig{cfg, validated} authMode := AuthMode(ecfg.authMode()) switch authMode { case AuthKeyPair: case AuthLegacy: case AuthUserPass: default: return nil, fmt.Errorf("invalid authorization mode: %q", authMode) } if ecfg.authURL() != "" { parts, err := url.Parse(ecfg.authURL()) if err != nil || parts.Host == "" || parts.Scheme == "" { return nil, fmt.Errorf("invalid auth-url value %q", ecfg.authURL()) } } cred := identity.CredentialsFromEnv() format := "required environment variable not set for credentials attribute: %s" if authMode == AuthUserPass || authMode == AuthLegacy { if ecfg.username() == "" { if cred.User == "" { return nil, fmt.Errorf(format, "User") } ecfg.attrs["username"] = cred.User } if ecfg.password() == "" { if cred.Secrets == "" { return nil, fmt.Errorf(format, "Secrets") } ecfg.attrs["password"] = cred.Secrets } } else if authMode == AuthKeyPair { if ecfg.accessKey() == "" { if cred.User == "" { return nil, fmt.Errorf(format, "User") } ecfg.attrs["access-key"] = cred.User } if ecfg.secretKey() == "" { if cred.Secrets == "" { return nil, fmt.Errorf(format, "Secrets") } ecfg.attrs["secret-key"] = cred.Secrets } } if ecfg.authURL() == "" { if cred.URL == "" { return nil, fmt.Errorf(format, "URL") } ecfg.attrs["auth-url"] = cred.URL } if ecfg.tenantName() == "" { if cred.TenantName == "" { return nil, fmt.Errorf(format, "TenantName") } ecfg.attrs["tenant-name"] = cred.TenantName } if ecfg.region() == "" { if cred.Region == "" { return nil, fmt.Errorf(format, "Region") } ecfg.attrs["region"] = cred.Region } if old != nil { attrs := old.UnknownAttrs() if region, _ := attrs["region"].(string); ecfg.region() != region { return nil, fmt.Errorf("cannot change region from %q to %q", region, ecfg.region()) } if controlBucket, _ := attrs["control-bucket"].(string); ecfg.controlBucket() != controlBucket { return nil, fmt.Errorf("cannot change control-bucket from %q to %q", controlBucket, ecfg.controlBucket()) } } // Apply the coerced unknown values back into the config. return cfg.Apply(ecfg.attrs) }