// startBootstrapInstance starts the bootstrap instance for this environment. func (env *azureEnviron) startBootstrapInstance(cons constraints.Value) (instance.Instance, error) { // The bootstrap instance gets machine id "0". This is not related to // instance ids or anything in Azure. Juju assigns the machine ID. const machineID = "0" // Create an empty bootstrap state file so we can get its URL. // It will be updated with the instance id and hardware characteristics // after the bootstrap instance is started. stateFileURL, err := environs.CreateStateFile(env.Storage()) if err != nil { return nil, err } machineConfig := environs.NewBootstrapMachineConfig(machineID, stateFileURL) logger.Debugf("bootstrapping environment %q", env.Name()) possibleTools, err := environs.FindBootstrapTools(env, cons) if err != nil { return nil, err } inst, err := env.internalStartInstance(cons, possibleTools, machineConfig) if err != nil { return nil, fmt.Errorf("cannot start bootstrap instance: %v", err) } return inst, nil }
// TODO(bug 1199847): This work can be shared between providers. func (e *environ) Bootstrap(cons constraints.Value) error { // The bootstrap instance gets machine id "0". This is not related // to instance ids. Juju assigns the machine ID. const machineID = "0" log.Infof("environs/openstack: bootstrapping environment %q", e.name) if err := environs.VerifyBootstrapInit(e, shortAttempt); err != nil { return err } possibleTools, err := environs.FindBootstrapTools(e, cons) if err != nil { return err } err = environs.CheckToolsSeries(possibleTools, e.Config().DefaultSeries()) if err != nil { return err } // The client's authentication may have been reset by FindBootstrapTools() if the agent-version // attribute was updated so we need to re-authenticate. This will be a no-op if already authenticated. // An authenticated client is needed for the URL() call below. err = e.client.Authenticate() if err != nil { return err } stateFileURL, err := environs.CreateStateFile(e.Storage()) if err != nil { return err } machineConfig := environs.NewBootstrapMachineConfig(machineID, stateFileURL) // TODO(wallyworld) - save bootstrap machine metadata inst, characteristics, err := e.internalStartInstance(cons, possibleTools, machineConfig) if err != nil { return fmt.Errorf("cannot start bootstrap instance: %v", err) } err = environs.SaveState(e.Storage(), &environs.BootstrapState{ StateInstances: []instance.Id{inst.Id()}, Characteristics: []instance.HardwareCharacteristics{*characteristics}, }) if err != nil { // ignore error on StopInstance because the previous error is // more important. e.StopInstances([]instance.Instance{inst}) return fmt.Errorf("cannot save state: %v", err) } // TODO make safe in the case of racing Bootstraps // If two Bootstraps are called concurrently, there's // no way to use Swift to make sure that only one succeeds. // Perhaps consider using SimpleDB for state storage // which would enable that possibility. return nil }
// TODO(bug 1199847): Much of this work can be shared between providers. func (e *environ) Bootstrap(cons constraints.Value) error { // The bootstrap instance gets machine id "0". This is not related to // instance ids. Juju assigns the machine ID. const machineID = "0" log.Infof("environs/ec2: bootstrapping environment %q", e.name) // If the state file exists, it might actually have just been // removed by Destroy, and eventual consistency has not caught // up yet, so we retry to verify if that is happening. if err := environs.VerifyBootstrapInit(e, shortAttempt); err != nil { return err } possibleTools, err := environs.FindBootstrapTools(e, cons) if err != nil { return err } err = environs.CheckToolsSeries(possibleTools, e.Config().DefaultSeries()) if err != nil { return err } stateFileURL, err := environs.CreateStateFile(e.Storage()) if err != nil { return err } machineConfig := environs.NewBootstrapMachineConfig(machineID, stateFileURL) // TODO(wallyworld) - save bootstrap machine metadata inst, characteristics, err := e.internalStartInstance(cons, possibleTools, machineConfig) if err != nil { return fmt.Errorf("cannot start bootstrap instance: %v", err) } err = environs.SaveState(e.Storage(), &environs.BootstrapState{ StateInstances: []instance.Id{inst.Id()}, Characteristics: []instance.HardwareCharacteristics{*characteristics}, }) if err != nil { // ignore error on StopInstance because the previous error is // more important. e.StopInstances([]instance.Instance{inst}) return fmt.Errorf("cannot save state: %v", err) } // TODO make safe in the case of racing Bootstraps // If two Bootstraps are called concurrently, there's // no way to use S3 to make sure that only one succeeds. // Perhaps consider using SimpleDB for state storage // which would enable that possibility. return nil }
func (*StateSuite) TestCreateStateFileWritesEmptyStateFile(c *C) { storage, cleanup := makeDummyStorage(c) defer cleanup() url, err := environs.CreateStateFile(storage) c.Assert(err, IsNil) reader, err := storage.Get(environs.StateFile) c.Assert(err, IsNil) data, err := ioutil.ReadAll(reader) c.Assert(err, IsNil) c.Check(string(data), Equals, "") c.Assert(url, NotNil) expectedURL, err := storage.URL(environs.StateFile) c.Assert(err, IsNil) c.Check(url, Equals, expectedURL) }