// 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)
}
Exemple #2
0
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
}