// BootstrapConfig returns a copy of the supplied configuration with // secret attributes removed. If the resulting config is not suitable // for bootstrapping an environment, an error is returned. func BootstrapConfig(cfg *config.Config) (*config.Config, error) { p, err := Provider(cfg.Type()) if err != nil { return nil, err } secrets, err := p.SecretAttrs(cfg) if err != nil { return nil, err } m := cfg.AllAttrs() for k := range secrets { delete(m, k) } // We never want to push admin-secret or the root CA private key to the cloud. delete(m, "admin-secret") m["ca-private-key"] = "" if cfg, err = config.New(m); err != nil { return nil, err } if _, ok := cfg.AgentVersion(); !ok { return nil, fmt.Errorf("environment configuration has no agent-version") } return cfg, nil }
func base64yaml(m *config.Config) string { data, err := goyaml.Marshal(m.AllAttrs()) if err != nil { // can't happen, these values have been validated a number of times panic(err) } return base64.StdEncoding.EncodeToString(data) }
// SetEnvironConfig replaces the current configuration of the // environment with the provided configuration. func (st *State) SetEnvironConfig(cfg *config.Config) error { if err := checkEnvironConfig(cfg); err != nil { return err } // TODO(niemeyer): This isn't entirely right as the change is done as a // delta that the user didn't ask for. Instead, take a (old, new) config // pair, and apply *known* delta. settings, err := readSettings(st, environGlobalKey) if err != nil { return err } settings.Update(cfg.AllAttrs()) _, err = settings.Write() return err }
// BootstrapConfig returns an environment configuration suitable for // priming the juju state using the given provider, configuration and // tools. // // The returned configuration contains no secret attributes. func BootstrapConfig(p EnvironProvider, cfg *config.Config, tools *state.Tools) (*config.Config, error) { secrets, err := p.SecretAttrs(cfg) if err != nil { return nil, err } m := cfg.AllAttrs() for k, _ := range secrets { delete(m, k) } // We never want to push admin-secret or the root CA private key to the cloud. delete(m, "admin-secret") m["ca-private-key"] = "" m["agent-version"] = tools.Number.String() return config.New(m) }
// SetEnvironConfig replaces the current configuration of the // environment with the provided configuration. func (st *State) SetEnvironConfig(cfg *config.Config) error { if cfg.AdminSecret() != "" { return fmt.Errorf("admin-secret should never be written to the state") } // TODO(niemeyer): This isn't entirely right as the change is done as a // delta that the user didn't ask for. Instead, take a (old, new) config // pair, and apply *known* delta. settings, err := readSettings(st, "e") if err != nil { return err } settings.Update(cfg.AllAttrs()) _, err = settings.Write() return err }
// check that any --env-config $base64 is valid and matches t.cfg.Config func checkEnvConfig(c *C, cfg *config.Config, x map[interface{}]interface{}, scripts []string) { re := regexp.MustCompile(`--env-config '([\w,=]+)'`) found := false for _, s := range scripts { m := re.FindStringSubmatch(s) if m == nil { continue } found = true buf, err := base64.StdEncoding.DecodeString(m[1]) c.Assert(err, IsNil) var actual map[string]interface{} err = goyaml.Unmarshal(buf, &actual) c.Assert(err, IsNil) c.Assert(cfg.AllAttrs(), DeepEquals, actual) } c.Assert(found, Equals, true) }
// Initialize sets up an initial empty state and returns it. // This needs to be performed only once for a given environment. // It returns unauthorizedError if access is unauthorized. func Initialize(info *Info, cfg *config.Config, opts DialOpts) (rst *State, err error) { st, err := Open(info, opts) if err != nil { return nil, err } defer func() { if err != nil { st.Close() } }() // A valid environment is used as a signal that the // state has already been initalized. If this is the case // do nothing. if _, err := st.Environment(); err == nil { return st, nil } else if !errors.IsNotFoundError(err) { return nil, err } log.Infof("state: initializing environment") if err := checkEnvironConfig(cfg); err != nil { return nil, err } uuid, err := utils.NewUUID() if err != nil { return nil, fmt.Errorf("environment UUID cannot be created: %v", err) } ops := []txn.Op{ createConstraintsOp(st, environGlobalKey, constraints.Value{}), createSettingsOp(st, environGlobalKey, cfg.AllAttrs()), createEnvironmentOp(st, cfg.Name(), uuid.String()), } if err := st.runTransaction(ops); err == txn.ErrAborted { // The config was created in the meantime. return st, nil } else if err != nil { return nil, err } return st, 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 } // 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 (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) }