// Run initializes state for an environment. func (c *BootstrapCommand) Run(_ *cmd.Context) error { if err := c.Conf.read("bootstrap"); err != nil { return err } cfg, err := config.New(c.EnvConfig) if err != nil { return err } // There is no entity that's created at init time. c.Conf.StateInfo.Tag = "" st, err := state.Initialize(c.Conf.StateInfo, cfg, state.DefaultDialOpts()) if err != nil { return err } defer st.Close() if err := environs.BootstrapUsers(st, cfg, c.Conf.OldPassword); err != nil { return err } // TODO(fwereade): we need to be able to customize machine jobs, // not just hardcode these values; in particular, JobHostUnits // on a machine, like this one, that is running JobManageEnviron // (not to mention the actual state server itself...) will allow // a malicious or compromised unit to trivially access to the // user's environment credentials. However, given that this point // is currently moot (see Upgrader in this package), the pseudo- // local provider mode (in which everything is deployed with // `--to 0`) offers enough value to enough people that // JobHostUnits is currently always enabled. This will one day // have to change, but it's strictly less important than fixing // Upgrader, and it's a capability we'll always want to have // available for the aforementioned use case. jobs := []state.MachineJob{ state.JobManageEnviron, state.JobManageState, state.JobHostUnits, } data, err := ioutil.ReadFile(providerStateURLFile) if err != nil { return fmt.Errorf("cannot read provider-state-url file: %v", err) } stateInfoURL := strings.Split(string(data), "\n")[0] bsState, err := environs.LoadStateFromURL(stateInfoURL) if err != nil { return fmt.Errorf("cannot load state from URL %q (read from %q): %v", stateInfoURL, providerStateURLFile, err) } instId := bsState.StateInstances[0] var characteristics instance.HardwareCharacteristics if len(bsState.Characteristics) > 0 { characteristics = bsState.Characteristics[0] } return environs.ConfigureBootstrapMachine(st, c.Constraints, c.Conf.DataDir, jobs, instance.Id(instId), characteristics) }
func (env *localEnviron) initialStateConfiguration(addr string, cons constraints.Value) (*state.State, error) { // We don't check the existance of the CACert here as if it wasn't set, we // wouldn't get this far. cfg := env.config.Config caCert, _ := cfg.CACert() addr = fmt.Sprintf("%s:%d", addr, cfg.StatePort()) info := &state.Info{ Addrs: []string{addr}, CACert: caCert, } timeout := state.DialOpts{60 * time.Second} bootstrap, err := environs.BootstrapConfig(cfg) if err != nil { return nil, err } st, err := state.Initialize(info, bootstrap, timeout) if err != nil { logger.Errorf("failed to initialize state: %v", err) return nil, err } logger.Debugf("state initialized") passwordHash := utils.PasswordHash(cfg.AdminSecret()) if err := environs.BootstrapUsers(st, cfg, passwordHash); err != nil { st.Close() return nil, err } jobs := []state.MachineJob{state.JobManageEnviron, state.JobManageState} if err := environs.ConfigureBootstrapMachine( st, cons, env.config.rootDir(), jobs, instance.Id(boostrapInstanceId), instance.HardwareCharacteristics{}); err != nil { st.Close() return nil, err } // Return an open state reference. return st, nil }