// 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 }
// FinishMachineConfig sets fields on a MachineConfig 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 FindBootstrapTools, // 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 FinishMachineConfig(mcfg *cloudinit.MachineConfig, cfg *config.Config, cons constraints.Value) (err error) { defer utils.ErrorContextf(&err, "cannot complete machine configuration") // Everything needs the environment's authorized keys. authKeys := cfg.AuthorizedKeys() if authKeys == "" { return fmt.Errorf("environment configuration has no authorized-keys") } mcfg.AuthorizedKeys = authKeys if mcfg.MachineEnvironment == nil { mcfg.MachineEnvironment = make(map[string]string) } mcfg.MachineEnvironment[osenv.JujuProviderType] = cfg.Type() if !mcfg.StateServer { return nil } // These settings are only appropriate at bootstrap time. At the // moment, the only state server is the bootstrap node, but this // will probably change. if mcfg.APIInfo != nil || mcfg.StateInfo != nil { return fmt.Errorf("machine configuration already has api/state info") } caCert, hasCACert := cfg.CACert() if !hasCACert { return fmt.Errorf("environment configuration has no ca-cert") } password := cfg.AdminSecret() if password == "" { return fmt.Errorf("environment configuration has no admin-secret") } passwordHash := utils.PasswordHash(password) mcfg.APIInfo = &api.Info{Password: passwordHash, CACert: caCert} mcfg.StateInfo = &state.Info{Password: passwordHash, CACert: caCert} mcfg.StatePort = cfg.StatePort() mcfg.APIPort = cfg.APIPort() mcfg.Constraints = cons if mcfg.Config, err = BootstrapConfig(cfg); err != nil { return err } // These really are directly relevant to running a state server. cert, key, err := cfg.GenerateStateServerCertAndKey() if err != nil { return fmt.Errorf("cannot generate state server certificate: %v", err) } mcfg.StateServerCert = cert mcfg.StateServerKey = key return nil }
// 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) }