// TODO (wallyworld) - this test was copied from the ec2 provider. // It should be moved to environs.jujutests.Tests. func (s *localServerSuite) TestBootstrapInstanceUserDataAndState(c *gc.C) { env := s.Prepare(c) err := bootstrap.Bootstrap(coretesting.Context(c), env, environs.BootstrapParams{}) c.Assert(err, gc.IsNil) // check that the state holds the id of the bootstrap machine. stateData, err := bootstrap.LoadState(env.Storage()) c.Assert(err, gc.IsNil) c.Assert(stateData.StateInstances, gc.HasLen, 1) insts, err := env.AllInstances() c.Assert(err, gc.IsNil) c.Assert(insts, gc.HasLen, 1) c.Check(insts[0].Id(), gc.Equals, stateData.StateInstances[0]) addresses, err := insts[0].Addresses() c.Assert(err, gc.IsNil) c.Assert(addresses, gc.Not(gc.HasLen), 0) // TODO(wallyworld) - 2013-03-01 bug=1137005 // The nova test double needs to be updated to support retrieving instance userData. // Until then, we can't check the cloud init script was generated correctly. // When we can, we should also check cloudinit for a non-manager node (as in the // ec2 tests). }
func (suite *StateSuite) TestLoadStateReadsStateFile(c *gc.C) { storage, dataDir := suite.newStorageWithDataDir(c) state := suite.setUpSavedState(c, dataDir) storedState, err := bootstrap.LoadState(storage) c.Assert(err, gc.IsNil) c.Check(*storedState, gc.DeepEquals, state) }
func (s *bootstrapSuite) TestBootstrap(c *gc.C) { args := s.getArgs(c) args.Host = "ubuntu@" + args.Host defer fakeSSH{SkipDetection: true}.install(c).Restore() err := manual.Bootstrap(args) c.Assert(err, gc.IsNil) bootstrapState, err := bootstrap.LoadState(s.env.Storage()) c.Assert(err, gc.IsNil) c.Assert( bootstrapState.StateInstances, gc.DeepEquals, []instance.Id{manual.BootstrapInstanceId}, ) // Do it all again; this should work, despite the fact that // there's a bootstrap state file. Existence for that is // checked in general bootstrap code (environs/bootstrap). defer fakeSSH{SkipDetection: true}.install(c).Restore() err = manual.Bootstrap(args) c.Assert(err, gc.IsNil) // We *do* check that the machine has no juju* upstart jobs, though. defer fakeSSH{ Provisioned: true, SkipDetection: true, SkipProvisionAgent: true, }.install(c).Restore() err = manual.Bootstrap(args) c.Assert(err, gc.Equals, manual.ErrProvisioned) }
// StateInfo is a reusable implementation of Environ.StateInfo, available to // providers that also use the other functionality from this file. func StateInfo(env environs.Environ) (*state.Info, *api.Info, error) { st, err := bootstrap.LoadState(env.Storage()) if err != nil { return nil, nil, err } config := env.Config() if _, hasCert := config.CACert(); !hasCert { return nil, nil, fmt.Errorf("no CA certificate in environment configuration") } // Wait for the addresses of at least one of the instances to become available. logger.Debugf("waiting for addresses of state server instances %v", st.StateInstances) var addresses []string for a := LongAttempt.Start(); len(addresses) == 0 && a.Next(); { insts, err := env.Instances(st.StateInstances) if err != nil && err != environs.ErrPartialInstances { logger.Debugf("error getting state instances: %v", err.Error()) return nil, nil, err } addresses = getAddresses(insts) } if len(addresses) == 0 { return nil, nil, fmt.Errorf("timed out waiting for addresses from %v", st.StateInstances) } stateInfo, apiInfo := getStateInfo(config, addresses) return stateInfo, apiInfo, nil }
// ProviderStateInstances extracts the instance IDs from provider-state. func ProviderStateInstances(env environs.Environ, stor storage.StorageReader) ([]instance.Id, error) { st, err := bootstrap.LoadState(stor) if err != nil { return nil, err } return st.StateInstances, nil }
func (s *bootstrapSuite) TestBootstrapScriptFailure(c *gc.C) { args := s.getArgs(c) args.Host = "ubuntu@" + args.Host defer fakeSSH{SkipDetection: true, ProvisionAgentExitCode: 1}.install(c).Restore() err := manual.Bootstrap(args) c.Assert(err, gc.NotNil) // Since the script failed, the state file should have been // removed from storage. _, err = bootstrap.LoadState(s.env.Storage()) c.Check(err, gc.Equals, environs.ErrNotBootstrapped) }
func (suite *StateSuite) TestLoadStateIntegratesWithSaveState(c *gc.C) { storage := suite.newStorage(c) state := bootstrap.BootstrapState{ StateInstances: []instance.Id{instance.Id("an-instance-id")}, } err := bootstrap.SaveState(storage, &state) c.Assert(err, gc.IsNil) storedState, err := bootstrap.LoadState(storage) c.Assert(err, gc.IsNil) c.Check(*storedState, gc.DeepEquals, state) }
func rebootstrap(cfg *config.Config, ctx *cmd.Context, cons constraints.Value) (environs.Environ, error) { progress("re-bootstrapping environment") // Turn on safe mode so that the newly bootstrapped instance // will not destroy all the instances it does not know about. cfg, err := cfg.Apply(map[string]interface{}{ "provisioner-safe-mode": true, }) if err != nil { return nil, fmt.Errorf("cannot enable provisioner-safe-mode: %v", err) } env, err := environs.New(cfg) if err != nil { return nil, err } st, err := bootstrap.LoadState(env.Storage()) if err != nil { return nil, fmt.Errorf("cannot retrieve environment storage; perhaps the environment was not bootstrapped: %v", err) } if len(st.StateInstances) == 0 { return nil, fmt.Errorf("no instances found on bootstrap state; perhaps the environment was not bootstrapped") } if len(st.StateInstances) > 1 { return nil, fmt.Errorf("restore does not support HA juju configurations yet") } inst, err := env.Instances(st.StateInstances) if err == nil { return nil, fmt.Errorf("old bootstrap instance %q still seems to exist; will not replace", inst) } if err != environs.ErrNoInstances { return nil, fmt.Errorf("cannot detect whether old instance is still running: %v", err) } // Remove the storage so that we can bootstrap without the provider complaining. if err := env.Storage().Remove(bootstrap.StateFile); err != nil { return nil, fmt.Errorf("cannot remove %q from storage: %v", bootstrap.StateFile, err) } // TODO If we fail beyond here, then we won't have a state file and // we won't be able to re-run this script because it fails without it. // We could either try to recreate the file if we fail (which is itself // error-prone) or we could provide a --no-check flag to make // it go ahead anyway without the check. args := environs.BootstrapParams{Constraints: cons} if err := bootstrap.Bootstrap(ctx, env, args); err != nil { return nil, fmt.Errorf("cannot bootstrap new instance: %v", err) } return env, nil }
// It should be moved to environs.jujutests.Tests. func (s *localServerSuite) TestBootstrapInstanceUserDataAndState(c *gc.C) { env := s.Prepare(c) s.Tests.UploadFakeTools(c, env.Storage()) err := bootstrap.Bootstrap(bootstrapContext(c), env, environs.BootstrapParams{}) c.Assert(err, gc.IsNil) // check that the state holds the id of the bootstrap machine. stateData, err := bootstrap.LoadState(env.Storage()) c.Assert(err, gc.IsNil) c.Assert(stateData.StateInstances, gc.HasLen, 1) insts, err := env.AllInstances() c.Assert(err, gc.IsNil) c.Assert(insts, gc.HasLen, 1) c.Check(stateData.StateInstances[0], gc.Equals, insts[0].Id()) addresses, err := insts[0].Addresses() c.Assert(err, gc.IsNil) c.Assert(addresses, gc.HasLen, 2) }
func (suite *environSuite) TestStartInstanceStartsInstance(c *gc.C) { suite.setupFakeTools(c) env := suite.makeEnviron() // Create node 0: it will be used as the bootstrap node. suite.testMAASObject.TestServer.NewNode(`{"system_id": "node0", "hostname": "host0"}`) lshwXML, err := suite.generateHWTemplate(map[string]string{"aa:bb:cc:dd:ee:f0": "eth0"}) c.Assert(err, gc.IsNil) suite.testMAASObject.TestServer.AddNodeDetails("node0", lshwXML) err = bootstrap.Bootstrap(coretesting.Context(c), env, environs.BootstrapParams{}) c.Assert(err, gc.IsNil) // The bootstrap node has been acquired and started. operations := suite.testMAASObject.TestServer.NodeOperations() actions, found := operations["node0"] c.Check(found, gc.Equals, true) c.Check(actions, gc.DeepEquals, []string{"acquire", "start"}) // Test the instance id is correctly recorded for the bootstrap node. // Check that the state holds the id of the bootstrap machine. stateData, err := bootstrap.LoadState(env.Storage()) c.Assert(err, gc.IsNil) c.Assert(stateData.StateInstances, gc.HasLen, 1) insts, err := env.AllInstances() c.Assert(err, gc.IsNil) c.Assert(insts, gc.HasLen, 1) c.Check(insts[0].Id(), gc.Equals, stateData.StateInstances[0]) // Create node 1: it will be used as instance number 1. suite.testMAASObject.TestServer.NewNode(`{"system_id": "node1", "hostname": "host1"}`) lshwXML, err = suite.generateHWTemplate(map[string]string{"aa:bb:cc:dd:ee:f1": "eth0"}) c.Assert(err, gc.IsNil) suite.testMAASObject.TestServer.AddNodeDetails("node1", lshwXML) // TODO(wallyworld) - test instance metadata instance, _ := testing.AssertStartInstance(c, env, "1") c.Assert(err, gc.IsNil) c.Check(instance, gc.NotNil) // The instance number 1 has been acquired and started. actions, found = operations["node1"] c.Assert(found, gc.Equals, true) c.Check(actions, gc.DeepEquals, []string{"acquire", "start"}) // The value of the "user data" parameter used when starting the node // contains the run cmd used to write the machine information onto // the node's filesystem. requestValues := suite.testMAASObject.TestServer.NodeOperationRequestValues() nodeRequestValues, found := requestValues["node1"] c.Assert(found, gc.Equals, true) c.Assert(len(nodeRequestValues), gc.Equals, 2) userData := nodeRequestValues[1].Get("user_data") decodedUserData, err := decodeUserData(userData) c.Assert(err, gc.IsNil) info := machineInfo{"host1"} cloudinitRunCmd, err := info.cloudinitRunCmd() c.Assert(err, gc.IsNil) data, err := goyaml.Marshal(cloudinitRunCmd) c.Assert(err, gc.IsNil) c.Check(string(decodedUserData), gc.Matches, "(.|\n)*"+string(data)+"(\n|.)*") // Trash the tools and try to start another instance. envtesting.RemoveTools(c, env.Storage()) instance, _, _, err = testing.StartInstance(env, "2") c.Check(instance, gc.IsNil) c.Check(err, jc.Satisfies, errors.IsNotFound) }
func (suite *StateSuite) TestLoadStateMissingFile(c *gc.C) { stor := suite.newStorage(c) _, err := bootstrap.LoadState(stor) c.Check(err, gc.Equals, environs.ErrNotBootstrapped) }
func (t *localServerSuite) TestBootstrapInstanceUserDataAndState(c *gc.C) { env := t.Prepare(c) envtesting.UploadFakeTools(c, env.Storage()) err := bootstrap.Bootstrap(coretesting.Context(c), env, environs.BootstrapParams{}) c.Assert(err, gc.IsNil) // check that the state holds the id of the bootstrap machine. bootstrapState, err := bootstrap.LoadState(env.Storage()) c.Assert(err, gc.IsNil) c.Assert(bootstrapState.StateInstances, gc.HasLen, 1) insts, err := env.AllInstances() c.Assert(err, gc.IsNil) c.Assert(insts, gc.HasLen, 1) c.Check(insts[0].Id(), gc.Equals, bootstrapState.StateInstances[0]) // check that the user data is configured to start zookeeper // and the machine and provisioning agents. // check that the user data is configured to only configure // authorized SSH keys and set the log output; everything // else happens after the machine is brought up. inst := t.srv.ec2srv.Instance(string(insts[0].Id())) c.Assert(inst, gc.NotNil) addresses, err := insts[0].Addresses() c.Assert(err, gc.IsNil) c.Assert(addresses, gc.Not(gc.HasLen), 0) userData, err := utils.Gunzip(inst.UserData) c.Assert(err, gc.IsNil) c.Logf("first instance: UserData: %q", userData) var userDataMap map[interface{}]interface{} err = goyaml.Unmarshal(userData, &userDataMap) c.Assert(err, gc.IsNil) c.Assert(userDataMap, jc.DeepEquals, map[interface{}]interface{}{ "output": map[interface{}]interface{}{ "all": "| tee -a /var/log/cloud-init-output.log", }, "ssh_authorized_keys": splitAuthKeys(env.Config().AuthorizedKeys()), "runcmd": []interface{}{ "set -xe", "install -D -m 644 /dev/null '/var/lib/juju/nonce.txt'", "printf '%s\\n' 'user-admin:bootstrap' > '/var/lib/juju/nonce.txt'", }, }) // check that a new instance will be started with a machine agent inst1, hc := testing.AssertStartInstance(c, env, "1") c.Check(*hc.Arch, gc.Equals, "amd64") c.Check(*hc.Mem, gc.Equals, uint64(1740)) c.Check(*hc.CpuCores, gc.Equals, uint64(1)) c.Assert(*hc.CpuPower, gc.Equals, uint64(100)) inst = t.srv.ec2srv.Instance(string(inst1.Id())) c.Assert(inst, gc.NotNil) userData, err = utils.Gunzip(inst.UserData) c.Assert(err, gc.IsNil) c.Logf("second instance: UserData: %q", userData) userDataMap = nil err = goyaml.Unmarshal(userData, &userDataMap) c.Assert(err, gc.IsNil) CheckPackage(c, userDataMap, "git", true) CheckPackage(c, userDataMap, "mongodb-server", false) CheckScripts(c, userDataMap, "jujud bootstrap-state", false) CheckScripts(c, userDataMap, "/var/lib/juju/agents/machine-1/agent.conf", true) // TODO check for provisioning agent err = env.Destroy() c.Assert(err, gc.IsNil) _, err = bootstrap.LoadState(env.Storage()) c.Assert(err, gc.NotNil) }