func (p manualProvider) Prepare(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) { if _, ok := cfg.UnknownAttrs()["storage-auth-key"]; !ok { uuid, err := utils.NewUUID() if err != nil { return nil, err } cfg, err = cfg.Apply(map[string]interface{}{ "storage-auth-key": uuid.String(), }) if err != nil { return nil, err } } if use, ok := cfg.UnknownAttrs()["use-sshstorage"].(bool); ok && !use { return nil, fmt.Errorf("use-sshstorage must not be specified") } envConfig, err := p.validate(cfg, nil) if err != nil { return nil, err } if err := ensureBootstrapUbuntuUser(ctx, envConfig); err != nil { return nil, err } return p.open(envConfig) }
func prepareConfig(cfg *config.Config) (*config.Config, error) { // Turn an incomplete config into a valid one, if possible. attrs := cfg.UnknownAttrs() if _, ok := attrs["control-dir"]; !ok { uuid, err := utils.NewUUID() if err != nil { return nil, err } attrs["control-dir"] = fmt.Sprintf("%x", uuid.Raw()) } return cfg.Apply(attrs) }
func (p maasEnvironProvider) Prepare(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) { attrs := cfg.UnknownAttrs() oldName, found := attrs["maas-agent-name"] if found && oldName != "" { return nil, errAgentNameAlreadySet } uuid, err := utils.NewUUID() if err != nil { return nil, err } attrs["maas-agent-name"] = uuid.String() cfg, err = cfg.Apply(attrs) if err != nil { return nil, err } return p.Open(cfg) }
// Open implements environs.EnvironProvider.Open. func (environProvider) Open(cfg *config.Config) (environs.Environ, error) { logger.Infof("opening environment %q", cfg.Name()) if _, ok := cfg.AgentVersion(); !ok { newCfg, err := cfg.Apply(map[string]interface{}{ "agent-version": version.Current.Number.String(), }) if err != nil { return nil, err } cfg = newCfg } // Set the "namespace" attribute. We do this here, and not in Prepare, // for backwards compatibility: older versions did not store the namespace // in config. if namespace, _ := cfg.UnknownAttrs()["namespace"].(string); namespace == "" { username := os.Getenv("USER") if username == "" { u, err := userCurrent() if err != nil { return nil, fmt.Errorf("failed to determine username for namespace: %v", err) } username = u.Username } var err error namespace = fmt.Sprintf("%s-%s", username, cfg.Name()) cfg, err = cfg.Apply(map[string]interface{}{"namespace": namespace}) if err != nil { return nil, fmt.Errorf("failed to create namespace: %v", err) } } // Do the initial validation on the config. localConfig, err := providerInstance.newConfig(cfg) if err != nil { return nil, err } if err := VerifyPrerequisites(localConfig.container()); err != nil { return nil, fmt.Errorf("failed verification of local provider prerequisites: %v", err) } environ := &localEnviron{name: cfg.Name()} if err := environ.SetConfig(cfg); err != nil { return nil, fmt.Errorf("failure setting config: %v", err) } return environ, nil }
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 } if oldCfg != nil { oldAttrs := oldCfg.UnknownAttrs() validMaasAgentName := false if oldName, ok := oldAttrs["maas-agent-name"]; !ok || oldName == nil { // If maas-agent-name was nil (because the config was // generated pre-1.16.2 the only correct value for it is "" // See bug #1256179 validMaasAgentName = (validated["maas-agent-name"] == "") } else { validMaasAgentName = (validated["maas-agent-name"] == oldName) } if !validMaasAgentName { return nil, fmt.Errorf("cannot change maas-agent-name") } } 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) }
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 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) }
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} 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()) } } // 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. cfgAttrs := cfg.AllAttrs() if defaultImageId := cfgAttrs["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-metadata help' to see how suitable image"+ "metadata can be generated.", "default-image-id", defaultImageId) logger.Warningf(msg) } if defaultInstanceType := cfgAttrs["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) logger.Warningf(msg) } // Construct a new config with the deprecated attributes removed. for _, attr := range []string{"default-image-id", "default-instance-type"} { delete(cfgAttrs, attr) delete(ecfg.attrs, attr) } for k, v := range ecfg.attrs { cfgAttrs[k] = v } return config.New(config.NoDefaults, cfgAttrs) }
// Prepare implements environs.EnvironProvider.Prepare. func (p environProvider) Prepare(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) { // The user must not set bootstrap-ip; this is determined by the provider, // and its presence used to determine whether the environment has yet been // bootstrapped. if _, ok := cfg.UnknownAttrs()["bootstrap-ip"]; ok { return nil, fmt.Errorf("bootstrap-ip must not be specified") } err := checkLocalPort(cfg.StatePort(), "state port") if err != nil { return nil, err } err = checkLocalPort(cfg.APIPort(), "API port") if err != nil { return nil, err } // If the user has specified no values for any of the three normal // proxies, then look in the environment and set them. attrs := map[string]interface{}{ // We must not proxy SSH through the API server in a // local provider environment. Besides not being useful, // it may not work; there is no requirement for sshd to // be available on machine-0. "proxy-ssh": false, } setIfNotBlank := func(key, value string) { if value != "" { attrs[key] = value } } logger.Tracef("Look for proxies?") if cfg.HttpProxy() == "" && cfg.HttpsProxy() == "" && cfg.FtpProxy() == "" && cfg.NoProxy() == "" { proxy := osenv.DetectProxies() logger.Tracef("Proxies detected %#v", proxy) setIfNotBlank("http-proxy", proxy.Http) setIfNotBlank("https-proxy", proxy.Https) setIfNotBlank("ftp-proxy", proxy.Ftp) setIfNotBlank("no-proxy", proxy.NoProxy) } if cfg.AptHttpProxy() == "" && cfg.AptHttpsProxy() == "" && cfg.AptFtpProxy() == "" { proxy, err := detectAptProxies() if err != nil { return nil, err } setIfNotBlank("apt-http-proxy", proxy.Http) setIfNotBlank("apt-https-proxy", proxy.Https) setIfNotBlank("apt-ftp-proxy", proxy.Ftp) } if len(attrs) > 0 { cfg, err = cfg.Apply(attrs) if err != nil { return nil, err } } return p.Open(cfg) }