// prepare is the internal version of Prepare - it prepares the // environment but does not open it. func (p *environProvider) prepare(cfg *config.Config) (*config.Config, error) { ecfg, err := p.newConfig(cfg) if err != nil { return nil, err } p.mu.Lock() defer p.mu.Unlock() name := cfg.Name() if ecfg.stateId() != noStateId { return cfg, nil } // The environment has not been prepared, // so create it and set its state identifier accordingly. if ecfg.stateServer() && len(p.state) != 0 { for _, old := range p.state { panic(fmt.Errorf("cannot share a state between two dummy environs; old %q; new %q", old.name, name)) } } state := newState(name, p.ops, p.statePolicy) p.maxStateId++ state.id = p.maxStateId p.state[state.id] = state // Add the state id to the configuration we use to // in the returned environment. return cfg.Apply(map[string]interface{}{ "state-id": fmt.Sprint(state.id), }) }
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 }
// 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 }
// 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, 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, 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()), { C: st.stateServers.Name, Id: environGlobalKey, Insert: &stateServersDoc{}, }, { C: st.stateServers.Name, Id: apiHostPortsKey, Insert: &apiHostPortsDoc{}, }, } 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 }
// newEnviron create a new Joyent environ instance from config. func newEnviron(cfg *config.Config) (*joyentEnviron, error) { env := new(joyentEnviron) if err := env.SetConfig(cfg); err != nil { return nil, err } env.name = cfg.Name() var err error env.storage, err = newStorage(env.ecfg, "") if err != nil { return nil, err } env.compute, err = newCompute(env.ecfg) if err != nil { return nil, err } return env, nil }
// ensureCertificate generates a new CA certificate and // attaches it to the given environment configuration, // unless the configuration already has one. func ensureCertificate(cfg *config.Config) (*config.Config, error) { _, hasCACert := cfg.CACert() _, hasCAKey := cfg.CAPrivateKey() if hasCACert && hasCAKey { return cfg, nil } if hasCACert && !hasCAKey { return nil, fmt.Errorf("environment configuration with a certificate but no CA private key") } caCert, caKey, err := cert.NewCA(cfg.Name(), time.Now().UTC().AddDate(10, 0, 0)) if err != nil { return nil, err } return cfg.Apply(map[string]interface{}{ "ca-cert": string(caCert), "ca-private-key": string(caKey), }) }
// 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.CreateInfo(cfg.Name()) if err == configstore.ErrEnvironInfoAlreadyExists { logger.Infof("environment info already exists; using New not Prepare") info, err := store.ReadInfo(cfg.Name()) if err != nil { return nil, fmt.Errorf("error reading environment info %q: %v", cfg.Name(), err) } if !info.Initialized() { return nil, fmt.Errorf("found uninitialized environment info for %q; environment preparation probably in progress or interrupted", cfg.Name()) } if len(info.BootstrapConfig()) == 0 { return nil, fmt.Errorf("found environment info but no bootstrap config") } cfg, err = config.New(config.NoDefaults, info.BootstrapConfig()) if err != nil { return nil, fmt.Errorf("cannot parse bootstrap config: %v", err) } return New(cfg) } if err != nil { return nil, fmt.Errorf("cannot create new info for environment %q: %v", cfg.Name(), err) } 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 } info.SetBootstrapConfig(env.Config().AllAttrs()) if err := info.Write(); err != nil { return nil, fmt.Errorf("cannot create environment info %q: %v", env.Config().Name(), err) } return env, nil }
// 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 }
// 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, fmt.Errorf("failed to validate unknown attrs: %v", err) } localConfig := newEnvironConfig(cfg, validated) // Before potentially creating directories, make sure that the // root directory has not changed. containerType := localConfig.container() 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 containerType != oldLocalConfig.container() { return nil, fmt.Errorf("cannot change container from %q to %q", oldLocalConfig.container(), containerType) } if localConfig.rootDir() != oldLocalConfig.rootDir() { return nil, fmt.Errorf("cannot change root-dir from %q to %q", oldLocalConfig.rootDir(), localConfig.rootDir()) } if localConfig.networkBridge() != oldLocalConfig.networkBridge() { return nil, fmt.Errorf("cannot change network-bridge 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()) } } // Currently only supported containers are "lxc" and "kvm". if containerType != instance.LXC && containerType != instance.KVM { return nil, fmt.Errorf("unsupported container type: %q", containerType) } dir, err := utils.NormalizePath(localConfig.rootDir()) if err != nil { return nil, err } if dir == "." { dir = osenv.JujuHomePath(cfg.Name()) } // Always assign the normalized path. localConfig.attrs["root-dir"] = dir if containerType != instance.KVM { fastOptionAvailable := useFastLXC(containerType) if _, found := localConfig.attrs["lxc-clone"]; !found { localConfig.attrs["lxc-clone"] = fastOptionAvailable } } // Apply the coerced unknown values back into the config. return cfg.Apply(localConfig.attrs) }