func (p *environProvider) Open(cfg *config.Config) (environs.Environ, error) { p.mu.Lock() defer p.mu.Unlock() name := cfg.Name() ecfg, err := p.newConfig(cfg) if err != nil { return nil, err } state := p.state[name] if state == nil { if ecfg.stateServer() && len(p.state) != 0 { var old string for oldName := range p.state { old = oldName break } panic(fmt.Errorf("cannot share a state between two dummy environs; old %q; new %q", old, name)) } state = newState(name, p.ops, ecfg.FirewallMode()) p.state[name] = state } env := &environ{ state: state, ecfgUnlocked: ecfg, } if err := env.checkBroken("Open"); err != nil { return nil, err } return env, nil }
// 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() }
// 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) }
// initVersions collects state relevant to an upgrade decision. The returned // agent and client versions, and the list of currently available tools, will // always be accurate; the chosen version, and the flag indicating development // mode, may remain blank until uploadTools or validate is called. func (c *UpgradeJujuCommand) initVersions(cfg *config.Config, env environs.Environ) (*upgradeVersions, error) { agent, ok := cfg.AgentVersion() if !ok { // Can't happen. In theory. return nil, fmt.Errorf("incomplete environment configuration") } if c.Version == agent { return nil, errUpToDate } client := version.Current.Number available, err := environs.FindAvailableTools(env, client.Major) if err != nil { if !errors.IsNotFoundError(err) { return nil, err } if !c.UploadTools { if c.Version == version.Zero { return nil, errUpToDate } return nil, err } } dev := c.Development || cfg.Development() || agent.IsDev() || client.IsDev() return &upgradeVersions{ dev: dev, agent: agent, client: client, chosen: c.Version, tools: available, }, 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 } 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 (maasEnvironProvider) Open(cfg *config.Config) (environs.Environ, error) { logger.Debugf("opening environment %q.", cfg.Name()) env, err := NewEnviron(cfg) if err != nil { return nil, err } return env, 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) }
// checkEnvironConfig returns an error if the config is definitely invalid. func checkEnvironConfig(cfg *config.Config) error { if cfg.AdminSecret() != "" { return fmt.Errorf("admin-secret should never be written to the state") } if _, ok := cfg.AgentVersion(); !ok { return fmt.Errorf("agent-version must always be set in state") } return nil }
// getUploadSeries returns the supplied series with duplicates removed if // non-empty; otherwise it returns a default list of series we should // probably upload, based on cfg. func getUploadSeries(cfg *config.Config, series []string) []string { unique := set.NewStrings(series...) if unique.IsEmpty() { unique.Add(version.Current.Series) unique.Add(config.DefaultSeries) unique.Add(cfg.DefaultSeries()) } return unique.Values() }
func (p environProvider) Open(cfg *config.Config) (environs.Environ, error) { log.Printf("environs/openstack: opening environment %q", cfg.Name()) e := new(environ) err := e.SetConfig(cfg) if err != nil { return nil, err } return e, nil }
func NewEnviron(cfg *config.Config) (*maasEnviron, error) { env := new(maasEnviron) err := env.SetConfig(cfg) if err != nil { return nil, err } env.name = cfg.Name() env.storageUnlocked = NewStorage(env) return env, nil }
func (p environProvider) Open(cfg *config.Config) (environs.Environ, error) { log.Infof("environs/ec2: opening environment %q", cfg.Name()) e := new(environ) err := e.SetConfig(cfg) if err != nil { return nil, err } e.name = cfg.Name() return e, nil }
// Open is specified in the EnvironProvider interface. func (prov azureEnvironProvider) Open(cfg *config.Config) (environs.Environ, error) { logger.Debugf("opening environment %q.", cfg.Name()) // We can't return NewEnviron(cfg) directly here because otherwise, // when err is not nil, we end up with a non-nil returned environ and // this breaks the loop in cmd/jujud/upgrade.go:run() (see // http://golang.org/doc/faq#nil_error for the gory details). environ, err := NewEnviron(cfg) if err != nil { 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 } // Apply the coerced unknown values back into the config. return cfg.Apply(validated) }
// composeStateInfo puts together the state.Info and api.Info for the given // config, with the given state-server host names. // The given config absolutely must have a CACert. func getStateInfo(config *config.Config, hostnames []string) (*state.Info, *api.Info) { cert, hasCert := config.CACert() if !hasCert { panic(errors.New("getStateInfo: config has no CACert")) } return &state.Info{ Addrs: composeAddresses(hostnames, config.StatePort()), CACert: cert, }, &api.Info{ Addrs: composeAddresses(hostnames, config.APIPort()), CACert: cert, } }
// 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 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 }
// 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 }
// New returns a new environment based on the provided configuration. func New(config *config.Config) (Environ, error) { p, err := Provider(config.Type()) if err != nil { return nil, err } return p.Open(config) }
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) }
// 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) }
// 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 }
// 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) { 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) }
// NewEnviron creates a new azureEnviron. func NewEnviron(cfg *config.Config) (*azureEnviron, error) { env := azureEnviron{name: cfg.Name()} err := env.SetConfig(cfg) if err != nil { return nil, err } // Set up storage. env.storage = &azureStorage{ storageContext: &environStorageContext{environ: &env}, } // Set up public storage. publicContext := publicEnvironStorageContext{environ: &env} if publicContext.getContainer() == "" { // No public storage configured. Use EmptyStorage. env.publicStorage = environs.EmptyStorage } else { // Set up real public storage. env.publicStorage = &azureStorage{storageContext: &publicContext} } return &env, nil }
// 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) }