// JujuConnSuite very helpfully uploads some default // tools to the environment's storage. We don't want // 'em there; but we do want a consistent default-series // in the environment state. func (s *UpgradeJujuSuite) Reset(c *gc.C) { s.JujuConnSuite.Reset(c) envtesting.RemoveTools(c, s.Conn.Environ.Storage()) updateAttrs := map[string]interface{}{ "default-series": "raring", "agent-version": "1.2.3", } err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil) c.Assert(err, gc.IsNil) s.PatchValue(&sync.BuildToolsTarball, toolstesting.GetMockBuildTools(c)) }
func (s *toolsSuite) TestDownloadFetchesAndVerifiesSize(c *gc.C) { // Upload fake tools, then upload over the top so the SHA256 hash does not match. stor := s.Environ.Storage() envtesting.RemoveTools(c, stor) tools := envtesting.AssertUploadFakeToolsVersions(c, stor, version.Current)[0] err := stor.Put(envtools.StorageName(tools.Version), strings.NewReader("!"), 1) resp, err := s.downloadRequest(c, tools.Version, "") c.Assert(err, gc.IsNil) s.assertErrorResponse(c, resp, http.StatusBadRequest, "error fetching tools: size mismatch for .*") s.assertToolsNotStored(c, tools.Version) }
func (s *toolsSuite) TestDownloadFetchesAndVerifiesSize(c *gc.C) { // Upload fake tools, then upload over the top so the SHA256 hash does not match. s.PatchValue(&version.Current.Number, testing.FakeVersionNumber) stor := s.DefaultToolsStorage envtesting.RemoveTools(c, stor, "released") tools := envtesting.AssertUploadFakeToolsVersions(c, stor, "released", "released", version.Current)[0] err := stor.Put(envtools.StorageName(tools.Version, "released"), strings.NewReader("!"), 1) c.Assert(err, jc.ErrorIsNil) resp, err := s.downloadRequest(c, tools.Version, "") c.Assert(err, jc.ErrorIsNil) s.assertErrorResponse(c, resp, http.StatusBadRequest, "error fetching tools: size mismatch for .*") s.assertToolsNotStored(c, tools.Version) }
func (s *toolsSuite) TestDownloadFetchesAndCaches(c *gc.C) { // The tools are not in binarystorage, so the download request causes // the API server to search for the tools in simplestreams, fetch // them, and then cache them in binarystorage. vers := version.MustParseBinary("1.23.0-trusty-amd64") stor := s.DefaultToolsStorage envtesting.RemoveTools(c, stor, "released") tools := envtesting.AssertUploadFakeToolsVersions(c, stor, "released", "released", vers)[0] data := s.testDownload(c, tools, "") metadata, cachedData := s.getToolsFromStorage(c, s.State, tools.Version.String()) c.Assert(metadata.Size, gc.Equals, tools.Size) c.Assert(metadata.SHA256, gc.Equals, tools.SHA256) c.Assert(string(cachedData), gc.Equals, string(data)) }
func (suite *environSuite) TestBootstrapFailsIfNoTools(c *gc.C) { suite.setupFakeTools(c) env := suite.makeEnviron() // Can't RemoveAllTools, no public storage. envtesting.RemoveTools(c, env.Storage()) // Disable auto-uploading by setting the agent version. cfg, err := env.Config().Apply(map[string]interface{}{ "agent-version": version.Current.Number.String(), }) c.Assert(err, gc.IsNil) err = env.SetConfig(cfg) c.Assert(err, gc.IsNil) err = bootstrap.Bootstrap(coretesting.Context(c), env, bootstrap.BootstrapParams{}) c.Check(err, gc.ErrorMatches, "Juju cannot bootstrap because no tools are available for your environment(.|\n)*") }
func (s *toolsSuite) testDownload(c *gc.C, uuid string) { stor := s.Environ.Storage() envtesting.RemoveTools(c, stor) tools := envtesting.AssertUploadFakeToolsVersions(c, stor, version.Current)[0] resp, err := s.downloadRequest(c, tools.Version, uuid) c.Assert(err, gc.IsNil) defer resp.Body.Close() data, err := ioutil.ReadAll(resp.Body) c.Assert(err, gc.IsNil) c.Assert(data, gc.HasLen, int(tools.Size)) hash := sha256.New() hash.Write(data) c.Assert(fmt.Sprintf("%x", hash.Sum(nil)), gc.Equals, tools.SHA256) }
func (s *toolsSuite) TestDownloadFetchesAndVerifiesHash(c *gc.C) { // Upload fake tools, then upload over the top so the SHA256 hash does not match. s.PatchValue(&jujuversion.Current, testing.FakeVersionNumber) stor := s.DefaultToolsStorage envtesting.RemoveTools(c, stor, "released") current := version.Binary{ Number: jujuversion.Current, Arch: arch.HostArch(), Series: series.HostSeries(), } tools := envtesting.AssertUploadFakeToolsVersions(c, stor, "released", "released", current)[0] sameSize := strings.Repeat("!", int(tools.Size)) err := stor.Put(envtools.StorageName(tools.Version, "released"), strings.NewReader(sameSize), tools.Size) c.Assert(err, jc.ErrorIsNil) resp := s.downloadRequest(c, tools.Version, "") s.assertErrorResponse(c, resp, http.StatusBadRequest, "error fetching tools: hash mismatch for .*") s.assertToolsNotStored(c, tools.Version.String()) }
// JujuConnSuite very helpfully uploads some default // tools to the environment's storage. We don't want // 'em there; but we do want a consistent default-series // in the environment state. func (s *UpgradeJujuSuite) Reset(c *gc.C) { s.JujuConnSuite.Reset(c) envtesting.RemoveTools(c, s.Environ.Storage()) updateAttrs := map[string]interface{}{ "default-series": "raring", "agent-version": "1.2.3", } err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil) c.Assert(err, gc.IsNil) s.PatchValue(&sync.BuildToolsTarball, toolstesting.GetMockBuildTools(c)) // Set API host ports so FindTools works. hostPorts := [][]network.HostPort{{{ Address: network.NewAddress("0.1.2.3", network.ScopeUnknown), Port: 1234, }}} err = s.State.SetAPIHostPorts(hostPorts) c.Assert(err, gc.IsNil) }
// JujuConnSuite very helpfully uploads some default // tools to the environment's storage. We don't want // 'em there; but we do want a consistent default-series // in the environment state. func (s *UpgradeJujuSuite) Reset(c *gc.C) { s.JujuConnSuite.Reset(c) envtesting.RemoveTools(c, s.DefaultToolsStorage, s.Environ.Config().AgentStream()) updateAttrs := map[string]interface{}{ "default-series": "raring", "agent-version": "1.2.3", } err := s.State.UpdateModelConfig(updateAttrs, nil, nil) c.Assert(err, jc.ErrorIsNil) s.PatchValue(&sync.BuildAgentTarball, toolstesting.GetMockBuildTools(c)) // Set API host ports so FindTools works. hostPorts := [][]network.HostPort{ network.NewHostPorts(1234, "0.1.2.3"), } err = s.State.SetAPIHostPorts(hostPorts) c.Assert(err, jc.ErrorIsNil) s.CmdBlockHelper = coretesting.NewCmdBlockHelper(s.APIState) c.Assert(s.CmdBlockHelper, gc.NotNil) s.AddCleanup(func(*gc.C) { s.CmdBlockHelper.Close() }) }
func (s *provisionerSuite) TestProvisionMachine(c *gc.C) { const series = "precise" const arch = "amd64" const operatingSystem = version.Ubuntu args := s.getArgs(c) hostname := args.Host args.Host = "ubuntu@" + args.Host envtesting.RemoveTools(c, s.Environ.Storage()) defer fakeSSH{ Series: series, Arch: arch, InitUbuntuUser: true, SkipProvisionAgent: true, }.install(c).Restore() // Attempt to provision a machine with no tools available, expect it to fail. machineId, err := manual.ProvisionMachine(args) c.Assert(err, jc.Satisfies, params.IsCodeNotFound) c.Assert(machineId, gc.Equals, "") cfg := s.Environ.Config() number, ok := cfg.AgentVersion() c.Assert(ok, jc.IsTrue) binVersion := version.Binary{number, series, arch, operatingSystem} envtesting.AssertUploadFakeToolsVersions(c, s.Environ.Storage(), binVersion) for i, errorCode := range []int{255, 0} { c.Logf("test %d: code %d", i, errorCode) defer fakeSSH{ Series: series, Arch: arch, InitUbuntuUser: true, ProvisionAgentExitCode: errorCode, }.install(c).Restore() machineId, err = manual.ProvisionMachine(args) if errorCode != 0 { c.Assert(err, gc.ErrorMatches, fmt.Sprintf("subprocess encountered error code %d", errorCode)) c.Assert(machineId, gc.Equals, "") } else { c.Assert(err, gc.IsNil) c.Assert(machineId, gc.Not(gc.Equals), "") // machine ID will be incremented. Even though we failed and the // machine is removed, the ID is not reused. c.Assert(machineId, gc.Equals, fmt.Sprint(i+1)) m, err := s.State.Machine(machineId) c.Assert(err, gc.IsNil) instanceId, err := m.InstanceId() c.Assert(err, gc.IsNil) c.Assert(instanceId, gc.Equals, instance.Id("manual:"+hostname)) } } // Attempting to provision a machine twice should fail. We effect // this by checking for existing juju upstart configurations. defer fakeSSH{ Provisioned: true, InitUbuntuUser: true, SkipDetection: true, SkipProvisionAgent: true, }.install(c).Restore() _, err = manual.ProvisionMachine(args) c.Assert(err, gc.Equals, manual.ErrProvisioned) defer fakeSSH{ Provisioned: true, CheckProvisionedExitCode: 255, InitUbuntuUser: true, SkipDetection: true, SkipProvisionAgent: true, }.install(c).Restore() _, err = manual.ProvisionMachine(args) c.Assert(err, gc.ErrorMatches, "error checking if provisioned: subprocess encountered error code 255") }
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 *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(fmt.Sprintf( `{"system_id": "node0", "hostname": "host0", "architecture": "%s/generic", "memory": 1024, "cpu_count": 1}`, version.Current.Arch), ) 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, bootstrap.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 StateServerInstances returns the id of the bootstrap machine. instanceIds, err := env.StateServerInstances() c.Assert(err, gc.IsNil) c.Assert(instanceIds, 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, instanceIds[0]) // Create node 1: it will be used as instance number 1. suite.testMAASObject.TestServer.NewNode(fmt.Sprintf( `{"system_id": "node1", "hostname": "host1", "architecture": "%s/generic", "memory": 1024, "cpu_count": 1}`, version.Current.Arch), ) 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) instance, hc := testing.AssertStartInstance(c, env, "1") c.Assert(err, gc.IsNil) c.Check(instance, gc.NotNil) c.Assert(hc, gc.NotNil) c.Check(hc.String(), gc.Equals, fmt.Sprintf("arch=%s cpu-cores=1 mem=1024M", version.Current.Arch)) // 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("precise") c.Assert(err, gc.IsNil) data, err := goyaml.Marshal(cloudinitRunCmd) c.Assert(err, gc.IsNil) c.Check(string(decodedUserData), jc.Contains, string(data)) // 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) }