// Bootstrap is specified in the Environ interface. // TODO(bug 1199847): This work can be shared between providers. func (env *maasEnviron) Bootstrap(cons constraints.Value) error { if err := environs.VerifyBootstrapInit(env, shortAttempt); err != nil { return err } inst, err := env.startBootstrapNode(cons) if err != nil { return err } // TODO(wallyworld) add hardware characteristics to BootstrapState err = environs.SaveState( env.Storage(), &environs.BootstrapState{StateInstances: []instance.Id{inst.Id()}}) if err != nil { err2 := env.releaseInstance(inst) if err2 != nil { // Failure upon failure. Log it, but return the // original error. logger.Errorf("cannot release failed bootstrap instance: %v", err2) } 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 make sure that only one succeeds. return 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 }
// Bootstrap is specified in the Environ interface. func (env *localEnviron) Bootstrap(cons constraints.Value) error { logger.Infof("bootstrapping environment %q", env.name) if !env.config.runningAsRoot { return fmt.Errorf("bootstrapping a local environment must be done as root") } if err := env.config.createDirs(); err != nil { logger.Errorf("failed to create necessary directories: %v", err) return err } if err := env.ensureCertOwner(); err != nil { logger.Errorf("failed to reassign ownership of the certs to the user: %v", err) return err } // TODO(thumper): check that the constraints don't include "container=lxc" for now. var noRetry = utils.AttemptStrategy{} if err := environs.VerifyBootstrapInit(env, noRetry); err != nil { return err } cert, key, err := env.setupLocalMongoService() if err != nil { return err } // Before we write the agent config file, we need to make sure the // instance is saved in the StateInfo. bootstrapId := instance.Id(boostrapInstanceId) if err := environs.SaveState(env.Storage(), &environs.BootstrapState{StateInstances: []instance.Id{bootstrapId}}); err != nil { logger.Errorf("failed to save state instances: %v", err) return err } // Need to write out the agent file for machine-0 before initializing // state, as as part of that process, it will reset the password in the // agent file. if err := env.writeBootstrapAgentConfFile(cert, key); err != nil { return err } // Have to initialize the state configuration with localhost so we get // "special" permissions. stateConnection, err := env.initialStateConfiguration(boostrapInstanceId, cons) if err != nil { return err } defer stateConnection.Close() return env.setupLocalMachineAgent(cons) }
// Bootstrap is specified in the Environ interface. // TODO(bug 1199847): This work can be shared between providers. func (env *azureEnviron) Bootstrap(cons constraints.Value) (err error) { if err := environs.VerifyBootstrapInit(env, shortAttempt); err != nil { return err } // TODO(bug 1199847). The creation of the affinity group and the // virtual network is specific to the Azure provider. err = env.createAffinityGroup() if err != nil { return err } // If we fail after this point, clean up the affinity group. defer func() { if err != nil { env.deleteAffinityGroup() } }() err = env.createVirtualNetwork() if err != nil { return err } // If we fail after this point, clean up the virtual network. defer func() { if err != nil { env.deleteVirtualNetwork() } }() inst, err := env.startBootstrapInstance(cons) if err != nil { return err } // TODO(wallyworld) - save hardware characteristics err = environs.SaveState( env.Storage(), &environs.BootstrapState{StateInstances: []instance.Id{inst.Id()}}) if err != nil { err2 := env.StopInstances([]instance.Instance{inst}) if err2 != nil { // Failure upon failure. Log it, but return the // original error. logger.Errorf("cannot release failed bootstrap instance: %v", err2) } 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 make sure that only one succeeds. return nil }
func (suite *StateSuite) TestLoadStateIntegratesWithSaveState(c *C) { storage, cleanup := makeDummyStorage(c) defer cleanup() arch := "amd64" state := environs.BootstrapState{ StateInstances: []instance.Id{instance.Id("an-instance-id")}, Characteristics: []instance.HardwareCharacteristics{{Arch: &arch}}} err := environs.SaveState(storage, &state) c.Assert(err, IsNil) storedState, err := environs.LoadState(storage) c.Assert(err, IsNil) c.Check(*storedState, DeepEquals, state) }
// 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 := e.Storage().URL(environs.StateFile) if err != nil { return fmt.Errorf("cannot create bootstrap state file: %v", 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 (suite *StateSuite) TestSaveStateWritesStateFile(c *C) { storage, cleanup := makeDummyStorage(c) defer cleanup() arch := "amd64" state := environs.BootstrapState{ StateInstances: []instance.Id{instance.Id("an-instance-id")}, Characteristics: []instance.HardwareCharacteristics{{Arch: &arch}}} marshaledState, err := goyaml.Marshal(state) c.Assert(err, IsNil) err = environs.SaveState(storage, &state) c.Assert(err, IsNil) loadedState, err := storage.Get(environs.StateFile) c.Assert(err, IsNil) content, err := ioutil.ReadAll(loadedState) c.Assert(err, IsNil) c.Check(content, DeepEquals, marshaledState) }
func (suite *EnvironSuite) TestStateInfo(c *C) { env := suite.makeEnviron() hostname := "test" input := `{"system_id": "system_id", "hostname": "` + hostname + `"}` node := suite.testMAASObject.TestServer.NewNode(input) testInstance := &maasInstance{&node, suite.environ} err := environs.SaveState( env.Storage(), &environs.BootstrapState{StateInstances: []instance.Id{testInstance.Id()}}) c.Assert(err, IsNil) stateInfo, apiInfo, err := env.StateInfo() c.Assert(err, IsNil) config := env.Config() statePortSuffix := fmt.Sprintf(":%d", config.StatePort()) apiPortSuffix := fmt.Sprintf(":%d", config.APIPort()) c.Assert(stateInfo.Addrs, DeepEquals, []string{hostname + statePortSuffix}) c.Assert(apiInfo.Addrs, DeepEquals, []string{hostname + apiPortSuffix}) }
func (*EnvironSuite) TestStateInfo(c *C) { instanceID := "my-instance" patchWithServiceListResponse(c, []gwacl.HostedServiceDescriptor{{ ServiceName: instanceID, }}) env := makeEnviron(c) cleanup := setDummyStorage(c, env) defer cleanup() err := environs.SaveState( env.Storage(), &environs.BootstrapState{StateInstances: []instance.Id{instance.Id(instanceID)}}) c.Assert(err, IsNil) stateInfo, apiInfo, err := env.StateInfo() c.Assert(err, IsNil) config := env.Config() dnsName := "my-instance." + AZURE_DOMAIN_NAME stateServerAddr := fmt.Sprintf("%s:%d", dnsName, config.StatePort()) apiServerAddr := fmt.Sprintf("%s:%d", dnsName, config.APIPort()) c.Check(stateInfo.Addrs, DeepEquals, []string{stateServerAddr}) c.Check(apiInfo.Addrs, DeepEquals, []string{apiServerAddr}) }