func newEnviron(cloud environs.CloudSpec, cfg *config.Config) (*environ, error) { ecfg, err := newValidConfig(cfg, configDefaults) if err != nil { return nil, errors.Annotate(err, "invalid config") } client, err := newClient(cloud) if err != nil { return nil, errors.Annotatef(err, "failed to create new client") } namespace, err := instance.NewNamespace(cfg.UUID()) if err != nil { return nil, errors.Trace(err) } env := &environ{ name: ecfg.Name(), cloud: cloud, ecfg: ecfg, client: client, namespace: namespace, } return env, nil }
func newEnviron(spec environs.CloudSpec, cfg *config.Config, newRawProvider newRawProviderFunc) (*environ, error) { ecfg, err := newValidConfig(cfg) if err != nil { return nil, errors.Annotate(err, "invalid config") } namespace, err := instance.NewNamespace(cfg.UUID()) if err != nil { return nil, errors.Trace(err) } raw, err := newRawProvider(spec) if err != nil { return nil, errors.Trace(err) } env := &environ{ name: ecfg.Name(), uuid: ecfg.UUID(), raw: raw, namespace: namespace, ecfg: ecfg, } env.base = common.DefaultProvider{Env: env} //TODO(wwitzel3) make sure we are also cleaning up profiles during destroy if err := env.initProfile(); err != nil { return nil, errors.Trace(err) } return env, nil }
// decorateAndWriteInfo decorates the info struct with information // from the given cfg, and the writes that out to the filesystem. func decorateAndWriteInfo(info configstore.EnvironInfo, cfg *config.Config) error { // Sanity check our config. var endpoint configstore.APIEndpoint if cert, ok := cfg.CACert(); !ok { return errors.Errorf("CACert is not set") } else if uuid, ok := cfg.UUID(); !ok { return errors.Errorf("UUID is not set") } else if adminSecret := cfg.AdminSecret(); adminSecret == "" { return errors.Errorf("admin-secret is not set") } else { endpoint = configstore.APIEndpoint{ CACert: cert, ModelUUID: uuid, } } creds := configstore.APICredentials{ User: configstore.DefaultAdminUsername, Password: cfg.AdminSecret(), } endpoint.ServerUUID = endpoint.ModelUUID info.SetAPICredentials(creds) info.SetAPIEndpoint(endpoint) info.SetBootstrapConfig(cfg.AllAttrs()) if err := info.Write(); err != nil { return errors.Annotatef(err, "cannot create model info %q", cfg.Name()) } return nil }
// decorateAndWriteInfo decorates the info struct with information // from the given cfg, and the writes that out to the filesystem. func decorateAndWriteInfo(info configstore.EnvironInfo, cfg *config.Config) error { // Sanity check our config. var endpoint configstore.APIEndpoint if cert, ok := cfg.CACert(); !ok { return errors.Errorf("CACert is not set") } else if uuid, ok := cfg.UUID(); !ok { return errors.Errorf("UUID is not set") } else if adminSecret := cfg.AdminSecret(); adminSecret == "" { return errors.Errorf("admin-secret is not set") } else { endpoint = configstore.APIEndpoint{ CACert: cert, EnvironUUID: uuid, } } creds := configstore.APICredentials{ User: "******", // TODO(waigani) admin@local once we have that set Password: cfg.AdminSecret(), } info.SetAPICredentials(creds) info.SetAPIEndpoint(endpoint) info.SetBootstrapConfig(cfg.AllAttrs()) if err := info.Write(); err != nil { return errors.Annotatef(err, "cannot create environment info %q", cfg.Name()) } return nil }
// InstanceTags returns the minimum set of tags that should be set on a // machine instance, if the provider supports them. func InstanceTags(cfg *config.Config, jobs []multiwatcher.MachineJob) map[string]string { instanceTags := tags.ResourceTags(names.NewModelTag(cfg.UUID()), cfg) if multiwatcher.AnyJobNeedsState(jobs...) { instanceTags[tags.JujuController] = "true" } return instanceTags }
// NewModel creates a new model with its own UUID and // prepares it for use. Model and State instances for the new // model are returned. // // The controller model's UUID is attached to the new // model's document. Having the server UUIDs stored with each // model document means that we have a way to represent external // models, perhaps for future use around cross model // relations. func (st *State) NewModel(cfg *config.Config, owner names.UserTag) (_ *Model, _ *State, err error) { if owner.IsLocal() { if _, err := st.User(owner); err != nil { return nil, nil, errors.Annotate(err, "cannot create model") } } ssEnv, err := st.ControllerModel() if err != nil { return nil, nil, errors.Annotate(err, "could not load controller model") } uuid := cfg.UUID() newState, err := st.ForModel(names.NewModelTag(uuid)) if err != nil { return nil, nil, errors.Annotate(err, "could not create state for new model") } defer func() { if err != nil { newState.Close() } }() ops, err := newState.envSetupOps(cfg, uuid, ssEnv.UUID(), owner) if err != nil { return nil, nil, errors.Annotate(err, "failed to create new model") } err = newState.runTransaction(ops) if err == txn.ErrAborted { // We have a unique key restriction on the "owner" and "name" fields, // which will cause the insert to fail if there is another record with // the same "owner" and "name" in the collection. If the txn is // aborted, check if it is due to the unique key restriction. models, closer := st.getCollection(modelsC) defer closer() envCount, countErr := models.Find(bson.D{ {"owner", owner.Canonical()}, {"name", cfg.Name()}}, ).Count() if countErr != nil { err = errors.Trace(countErr) } else if envCount > 0 { err = errors.AlreadyExistsf("model %q for %s", cfg.Name(), owner.Canonical()) } else { err = errors.New("model already exists") } } if err != nil { return nil, nil, errors.Trace(err) } newEnv, err := newState.Model() if err != nil { return nil, nil, errors.Trace(err) } return newEnv, newState, nil }
// InstanceTags returns the minimum set of tags that should be set on a // machine instance, if the provider supports them. func InstanceTags(cfg *config.Config, jobs []multiwatcher.MachineJob) map[string]string { uuid, _ := cfg.UUID() instanceTags := tags.ResourceTags(names.NewEnvironTag(uuid), cfg) if multiwatcher.AnyJobNeedsState(jobs...) { instanceTags[tags.JujuStateServer] = "true" } return instanceTags }
// 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 *mongo.MongoInfo, cfg *config.Config, opts mongo.DialOpts, policy Policy) (rst *State, err error) { st, err := open(info, opts, policy) 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.IsNotFound(err) { return nil, err } logger.Infof("initializing environment") if err := checkEnvironConfig(cfg); err != nil { return nil, err } uuid, ok := cfg.UUID() if !ok { return nil, errors.Errorf("environment uuid was not supplied") } st.environTag = names.NewEnvironTag(uuid) ops := []txn.Op{ createConstraintsOp(st, environGlobalKey, constraints.Value{}), createSettingsOp(st, environGlobalKey, cfg.AllAttrs()), createEnvironmentOp(st, cfg.Name(), uuid), { C: stateServersC, Id: environGlobalKey, Assert: txn.DocMissing, Insert: &stateServersDoc{ EnvUUID: uuid, }, }, { C: stateServersC, Id: apiHostPortsKey, Assert: txn.DocMissing, Insert: &apiHostPortsDoc{}, }, { C: stateServersC, Id: stateServingInfoKey, Assert: txn.DocMissing, Insert: ¶ms.StateServingInfo{}, }, } 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 }
// PrepareForCreateEnvironment is specified in the EnvironProvider interface. func (p maasEnvironProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) { attrs := cfg.UnknownAttrs() oldName, found := attrs["maas-agent-name"] if found && oldName != "" { return nil, errAgentNameAlreadySet } attrs["maas-agent-name"] = cfg.UUID() return cfg.Apply(attrs) }
func (s *BaseSuiteUnpatched) setConfig(c *gc.C, cfg *config.Config) { s.Config = cfg ecfg, err := newValidConfig(cfg, configDefaults) c.Assert(err, jc.ErrorIsNil) s.EnvConfig = ecfg uuid, _ := cfg.UUID() s.Env.uuid = uuid s.Env.ecfg = s.EnvConfig s.Prefix = "juju-" + uuid + "-" }
// resourceGroupName returns the name of the environment's resource group. func resourceGroupName(cfg *config.Config) string { uuid, _ := cfg.UUID() // UUID is always available for azure environments, since the (new) // provider was introduced after environment UUIDs. modelTag := names.NewModelTag(uuid) return fmt.Sprintf( "juju-%s-%s", cfg.Name(), resourceName(modelTag), ) }
// storageTags returns the tags that should be set on a volume or filesystem, // if the provider supports them. func storageTags( storageInstance state.StorageInstance, cfg *config.Config, ) (map[string]string, error) { storageTags := tags.ResourceTags(names.NewModelTag(cfg.UUID()), cfg) if storageInstance != nil { storageTags[tags.JujuStorageInstance] = storageInstance.Tag().Id() storageTags[tags.JujuStorageOwner] = storageInstance.Owner().Id() } return storageTags, nil }
// newEnviron creates a new azureEnviron. func newEnviron(provider *azureEnvironProvider, cfg *config.Config) (*azureEnviron, error) { env := azureEnviron{provider: provider} err := env.SetConfig(cfg) if err != nil { return nil, err } modelTag := names.NewModelTag(cfg.UUID()) env.resourceGroup = resourceGroupName(modelTag, cfg.Name()) env.envName = cfg.Name() return &env, nil }
// VolumeSource is defined on the Provider interface. func (e *ebsProvider) VolumeSource(environConfig *config.Config, cfg *storage.Config) (storage.VolumeSource, error) { ec2, _, _, err := awsClients(environConfig) if err != nil { return nil, errors.Annotate(err, "creating AWS clients") } source := &ebsVolumeSource{ ec2: ec2, envName: environConfig.Name(), modelUUID: environConfig.UUID(), } return source, nil }
// Prepare prepares a new environment based on the provided configuration. // If the environment is already prepared, it behaves like New. func Prepare(cfg *config.Config, ctx BootstrapContext, store configstore.Storage) (Environ, error) { p, err := Provider(cfg.Type()) if err != nil { return nil, err } info, err := store.ReadInfo(cfg.Name()) if errors.IsNotFound(errors.Cause(err)) { info = store.CreateInfo(cfg.Name()) env, err := prepare(ctx, cfg, info, p) if err != nil { if err := info.Destroy(); err != nil { logger.Warningf("cannot destroy newly created environment info: %v", err) } return nil, err } cfg = env.Config() creds := configstore.APICredentials{ User: "******", // TODO(waigani) admin@local once we have that set Password: cfg.AdminSecret(), } info.SetAPICredentials(creds) endpoint := configstore.APIEndpoint{} var ok bool endpoint.CACert, ok = cfg.CACert() if !ok { return nil, errors.Errorf("CACert is not set") } endpoint.EnvironUUID, ok = cfg.UUID() if !ok { return nil, errors.Errorf("CACert is not set") } info.SetAPIEndpoint(endpoint) info.SetBootstrapConfig(env.Config().AllAttrs()) if err := info.Write(); err != nil { return nil, errors.Annotatef(err, "cannot create environment info %q", env.Config().Name()) } return env, nil } if err != nil { return nil, errors.Annotatef(err, "error reading environment info %q", cfg.Name()) } if !info.Initialized() { return nil, errors.Errorf("found uninitialized environment info for %q; environment preparation probably in progress or interrupted", cfg.Name()) } if len(info.BootstrapConfig()) == 0 { return nil, errors.New("found environment info but no bootstrap config") } cfg, err = config.New(config.NoDefaults, info.BootstrapConfig()) if err != nil { return nil, errors.Annotate(err, "cannot parse bootstrap config") } return New(cfg) }
func (s *BaseSuiteUnpatched) setConfig(c *gc.C, cfg *config.Config) { s.Config = cfg ecfg, err := newConfig(cfg, nil) c.Assert(err, jc.ErrorIsNil) s.EnvConfig = ecfg uuid := cfg.UUID() s.Env.uuid = uuid s.Env.ecfg = s.EnvConfig namespace, err := instance.NewNamespace(uuid) c.Assert(err, jc.ErrorIsNil) s.Env.namespace = namespace }
// ensureUUID generates a new uuid and attaches it to // the given environment configuration, unless the // configuration already has one. func ensureUUID(cfg *config.Config) (*config.Config, error) { _, hasUUID := cfg.UUID() if hasUUID { return cfg, nil } uuid, err := utils.NewUUID() if err != nil { return nil, errors.Trace(err) } return cfg.Apply(map[string]interface{}{ "uuid": uuid.String(), }) }
func (g *storageProvider) VolumeSource(environConfig *config.Config, cfg *storage.Config) (storage.VolumeSource, error) { // Connect and authenticate. env, err := newEnviron(environConfig) if err != nil { return nil, errors.Annotate(err, "cannot create an environ with this config") } source := &volumeSource{ gce: env.gce, envName: environConfig.Name(), modelUUID: environConfig.UUID(), } return source, nil }
// VolumeSource implements storage.Provider. func (p *cinderProvider) VolumeSource(environConfig *config.Config, providerConfig *storage.Config) (storage.VolumeSource, error) { if err := p.ValidateConfig(providerConfig); err != nil { return nil, err } storageAdapter, err := p.newStorageAdapter(environConfig) if err != nil { return nil, err } source := &cinderVolumeSource{ storageAdapter: storageAdapter, envName: environConfig.Name(), modelUUID: environConfig.UUID(), } return source, nil }
// VolumeSource is defined on the Provider interface. func (e *ebsProvider) VolumeSource(environConfig *config.Config, cfg *storage.Config) (storage.VolumeSource, error) { ec2, _, _, err := awsClients(environConfig) if err != nil { return nil, errors.Annotate(err, "creating AWS clients") } uuid, ok := environConfig.UUID() if !ok { return nil, errors.NotFoundf("environment UUID") } source := &ebsVolumeSource{ ec2: ec2, envName: environConfig.Name(), envUUID: uuid, } return source, nil }
// VolumeSource is defined on the Provider interface. func (e *azureStorageProvider) VolumeSource(environConfig *config.Config, cfg *storage.Config) (storage.VolumeSource, error) { env, err := NewEnviron(environConfig) if err != nil { return nil, errors.Trace(err) } uuid, ok := environConfig.UUID() if !ok { return nil, errors.NotFoundf("environment UUID") } source := &azureVolumeSource{ env: env, envName: environConfig.Name(), envUUID: uuid, } return source, nil }
func newEnviron(cloud environs.CloudSpec, cfg *config.Config) (*environ, error) { ecfg, err := newConfig(cfg, nil) if err != nil { return nil, errors.Annotate(err, "invalid config") } credAttrs := cloud.Credential.Attributes() if cloud.Credential.AuthType() == jujucloud.JSONFileAuthType { contents := credAttrs[credAttrFile] credential, err := parseJSONAuthFile(strings.NewReader(contents)) if err != nil { return nil, errors.Trace(err) } credAttrs = credential.Attributes() } credential := &google.Credentials{ ClientID: credAttrs[credAttrClientID], ProjectID: credAttrs[credAttrProjectID], ClientEmail: credAttrs[credAttrClientEmail], PrivateKey: []byte(credAttrs[credAttrPrivateKey]), } connectionConfig := google.ConnectionConfig{ Region: cloud.Region, ProjectID: credential.ProjectID, } // Connect and authenticate. conn, err := newConnection(connectionConfig, credential) if err != nil { return nil, errors.Trace(err) } namespace, err := instance.NewNamespace(cfg.UUID()) if err != nil { return nil, errors.Trace(err) } return &environ{ name: ecfg.config.Name(), uuid: ecfg.config.UUID(), cloud: cloud, ecfg: ecfg, gce: conn, namespace: namespace, }, nil }
// newEnviron creates a new azureEnviron. func newEnviron( provider *azureEnvironProvider, cloud environs.CloudSpec, cfg *config.Config, ) (*azureEnviron, error) { // The Azure storage code wants the endpoint host only, not the URL. storageEndpointURL, err := url.Parse(cloud.StorageEndpoint) if err != nil { return nil, errors.Annotate(err, "parsing storage endpoint URL") } env := azureEnviron{ provider: provider, cloud: cloud, location: canonicalLocation(cloud.Region), storageEndpoint: storageEndpointURL.Host, } if err := env.initEnviron(); err != nil { return nil, errors.Trace(err) } if err := env.SetConfig(cfg); err != nil { return nil, errors.Trace(err) } modelTag := names.NewModelTag(cfg.UUID()) env.resourceGroup = resourceGroupName(modelTag, cfg.Name()) env.envName = cfg.Name() // We need a deterministic storage account name, so that we can // defer creation of the storage account to the VM deployment, // and retain the ability to create multiple deployments in // parallel. // // We use the last 20 non-hyphen hex characters of the model's // UUID as the storage account name, prefixed with "juju". The // probability of clashing with another storage account should // be negligible. uuidAlphaNumeric := strings.Replace(env.config.Config.UUID(), "-", "", -1) env.storageAccountName = "juju" + uuidAlphaNumeric[len(uuidAlphaNumeric)-20:] return &env, nil }
// VolumeSource implements storage.Provider. func (p *cinderProvider) VolumeSource(environConfig *config.Config, providerConfig *storage.Config) (storage.VolumeSource, error) { if err := p.ValidateConfig(providerConfig); err != nil { return nil, err } storageAdapter, err := p.newStorageAdapter(environConfig) if err != nil { return nil, err } uuid, ok := environConfig.UUID() if !ok { return nil, errors.NotFoundf("environment UUID") } source := &cinderVolumeSource{ storageAdapter: storageAdapter, envName: environConfig.Name(), envUUID: uuid, } return source, nil }
func (g *storageProvider) VolumeSource(environConfig *config.Config, cfg *storage.Config) (storage.VolumeSource, error) { uuid, ok := environConfig.UUID() if !ok { return nil, errors.NotFoundf("environment UUID") } // Connect and authenticate. env, err := newEnviron(environConfig) if err != nil { return nil, errors.Annotate(err, "cannot create an environ with this config") } source := &volumeSource{ gce: env.gce, envName: environConfig.Name(), envUUID: uuid, } return source, nil }
// ensureCertificate generates a new CA certificate and // attaches it to the given controller configuration, // unless the configuration already has one. func ensureCertificate(cfg *config.Config) (*config.Config, string, error) { caCert, hasCACert := cfg.CACert() _, hasCAKey := cfg.CAPrivateKey() if hasCACert && hasCAKey { return cfg, caCert, nil } if hasCACert && !hasCAKey { return nil, "", errors.Errorf("controller configuration with a certificate but no CA private key") } caCert, caKey, err := cert.NewCA(cfg.Name(), cfg.UUID(), time.Now().UTC().AddDate(10, 0, 0)) if err != nil { return nil, "", errors.Trace(err) } cfg, err = cfg.Apply(map[string]interface{}{ config.CACertKey: string(caCert), "ca-private-key": string(caKey), }) if err != nil { return nil, "", errors.Trace(err) } return cfg, string(caCert), nil }
// FinishInstanceConfig sets fields on a InstanceConfig that can be determined by // inspecting a plain config.Config and the machine constraints at the last // moment before bootstrapping. It assumes that the supplied Config comes from // an environment that has passed through all the validation checks in the // Bootstrap func, and that has set an agent-version (via finding the tools to, // use for bootstrap, or otherwise). // TODO(fwereade) This function is not meant to be "good" in any serious way: // it is better that this functionality be collected in one place here than // that it be spread out across 3 or 4 providers, but this is its only // redeeming feature. func FinishInstanceConfig(icfg *InstanceConfig, cfg *config.Config) (err error) { defer errors.DeferredAnnotatef(&err, "cannot complete machine configuration") if err := PopulateInstanceConfig( icfg, cfg.Type(), cfg.AuthorizedKeys(), cfg.SSLHostnameVerification(), cfg.ProxySettings(), cfg.AptProxySettings(), cfg.AptMirror(), cfg.PreferIPv6(), cfg.EnableOSRefreshUpdate(), cfg.EnableOSUpgrade(), ); err != nil { return errors.Trace(err) } if isStateInstanceConfig(icfg) { // Add NUMACTL preference. Needed to work for both bootstrap and high availability // Only makes sense for controller logger.Debugf("Setting numa ctl preference to %v", cfg.NumaCtlPreference()) // Unfortunately, AgentEnvironment can only take strings as values icfg.AgentEnvironment[agent.NumaCtlPreference] = fmt.Sprintf("%v", cfg.NumaCtlPreference()) } // The following settings are only appropriate at bootstrap time. At the // moment, the only controller is the bootstrap node, but this // will probably change. if !icfg.Bootstrap { return nil } if icfg.APIInfo != nil || icfg.MongoInfo != nil { return errors.New("machine configuration already has api/state info") } caCert, hasCACert := cfg.CACert() if !hasCACert { return errors.New("model configuration has no ca-cert") } password := cfg.AdminSecret() if password == "" { return errors.New("model configuration has no admin-secret") } icfg.APIInfo = &api.Info{ Password: password, CACert: caCert, ModelTag: names.NewModelTag(cfg.UUID()), } icfg.MongoInfo = &mongo.MongoInfo{Password: password, Info: mongo.Info{CACert: caCert}} // These really are directly relevant to running a controller. // Initially, generate a controller certificate with no host IP // addresses in the SAN field. Once the controller is up and the // NIC addresses become known, the certificate can be regenerated. cert, key, err := cfg.GenerateControllerCertAndKey(nil) if err != nil { return errors.Annotate(err, "cannot generate controller certificate") } caPrivateKey, hasCAPrivateKey := cfg.CAPrivateKey() if !hasCAPrivateKey { return errors.New("model configuration has no ca-private-key") } srvInfo := params.StateServingInfo{ StatePort: cfg.StatePort(), APIPort: cfg.APIPort(), Cert: string(cert), PrivateKey: string(key), CAPrivateKey: caPrivateKey, } icfg.StateServingInfo = &srvInfo if icfg.Config, err = bootstrapConfig(cfg); err != nil { return errors.Trace(err) } return nil }
// NewEnvironment creates a new environment with its own UUID and // prepares it for use. Environment and State instances for the new // environment are returned. // // The state server environment's UUID is attached to the new // environment's document. Having the server UUIDs stored with each // environment document means that we have a way to represent external // environments, perhaps for future use around cross environment // relations. func (st *State) NewEnvironment(cfg *config.Config, owner names.UserTag) (_ *Environment, _ *State, err error) { if owner.IsLocal() { if _, err := st.User(owner); err != nil { return nil, nil, errors.Annotate(err, "cannot create environment") } } ssEnv, err := st.StateServerEnvironment() if err != nil { return nil, nil, errors.Annotate(err, "could not load state server environment") } uuid, ok := cfg.UUID() if !ok { return nil, nil, errors.Errorf("environment uuid was not supplied") } newState, err := st.ForEnviron(names.NewEnvironTag(uuid)) if err != nil { return nil, nil, errors.Annotate(err, "could not create state for new environment") } defer func() { if err != nil { newState.Close() } }() ops, err := newState.envSetupOps(cfg, uuid, ssEnv.UUID(), owner) if err != nil { return nil, nil, errors.Annotate(err, "failed to create new environment") } err = newState.runTransactionNoEnvAliveAssert(ops) if err == txn.ErrAborted { // We have a unique key restriction on the "owner" and "name" fields, // which will cause the insert to fail if there is another record with // the same "owner" and "name" in the collection. If the txn is // aborted, check if it is due to the unique key restriction. environments, closer := st.getCollection(environmentsC) defer closer() envCount, countErr := environments.Find(bson.D{ {"owner", owner.Username()}, {"name", cfg.Name()}}, ).Count() if countErr != nil { err = errors.Trace(countErr) } else if envCount > 0 { err = errors.AlreadyExistsf("environment %q for %s", cfg.Name(), owner.Username()) } else { err = errors.New("environment already exists") } } if err != nil { return nil, nil, errors.Trace(err) } newEnv, err := newState.Environment() if err != nil { return nil, nil, errors.Trace(err) } return newEnv, newState, nil }
// Initialize sets up an initial empty state and returns it. // This needs to be performed only once for the initial state server environment. // It returns unauthorizedError if access is unauthorized. func Initialize(owner names.UserTag, info *mongo.MongoInfo, cfg *config.Config, opts mongo.DialOpts, policy Policy) (_ *State, err error) { uuid, ok := cfg.UUID() if !ok { return nil, errors.Errorf("environment uuid was not supplied") } envTag := names.NewEnvironTag(uuid) st, err := open(envTag, info, opts, policy) if err != nil { return nil, errors.Trace(err) } defer func() { if err != nil { if closeErr := st.Close(); closeErr != nil { logger.Errorf("error closing state while aborting Initialize: %v", closeErr) } } }() // 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 nil, errors.New("already initialized") } else if !errors.IsNotFound(err) { return nil, errors.Trace(err) } // When creating the state server environment, the new environment // UUID is also used as the state server UUID. logger.Infof("initializing state server environment %s", uuid) ops, err := st.envSetupOps(cfg, uuid, uuid, owner) if err != nil { return nil, errors.Trace(err) } ops = append(ops, createInitialUserOp(st, owner, info.Password), txn.Op{ C: stateServersC, Id: environGlobalKey, Assert: txn.DocMissing, Insert: &stateServersDoc{ EnvUUID: st.EnvironUUID(), }, }, txn.Op{ C: stateServersC, Id: apiHostPortsKey, Assert: txn.DocMissing, Insert: &apiHostPortsDoc{}, }, txn.Op{ C: stateServersC, Id: stateServingInfoKey, Assert: txn.DocMissing, Insert: &StateServingInfo{}, }, txn.Op{ C: stateServersC, Id: hostedEnvCountKey, Assert: txn.DocMissing, Insert: &hostedEnvCountDoc{}, }, ) if err := st.runTransaction(ops); err != nil { return nil, errors.Trace(err) } if err := st.start(envTag); err != nil { return nil, errors.Trace(err) } return st, nil }
// MigrationConfigUpdate implements MigrationConfigUpdater. func (*environ) MigrationConfigUpdate(controllerConfig *config.Config) map[string]interface{} { return map[string]interface{}{ "controller-uuid": controllerConfig.UUID(), } }