func (t *LiveTests) TestBootstrapWithDefaultSeries(c *C) { if !t.HasProvisioner { c.Skip("HasProvisioner is false; cannot test deployment") } current := version.Current other := current other.Series = "precise" if current == other { other.Series = "quantal" } cfg := t.Env.Config() cfg, err := cfg.Apply(map[string]interface{}{"default-series": other.Series}) c.Assert(err, IsNil) env, err := environs.New(cfg) c.Assert(err, IsNil) dummyenv, err := environs.NewFromAttrs(map[string]interface{}{ "type": "dummy", "name": "dummy storage", "secret": "pizza", "state-server": false, }) c.Assert(err, IsNil) defer dummyenv.Destroy(nil) currentPath := environs.ToolsStoragePath(current) otherPath := environs.ToolsStoragePath(other) envStorage := env.Storage() dummyStorage := dummyenv.Storage() defer envStorage.Remove(otherPath) _, err = environs.PutTools(dummyStorage, ¤t.Number) c.Assert(err, IsNil) // This will only work while cross-compiling across releases is safe, // which depends on external elements. Tends to be safe for the last // few releases, but we may have to refactor some day. err = storageCopy(dummyStorage, currentPath, envStorage, otherPath) c.Assert(err, IsNil) err = environs.Bootstrap(env, false, panicWrite) c.Assert(err, IsNil) defer env.Destroy(nil) conn, err := juju.NewConn(env) c.Assert(err, IsNil) defer conn.Close() // Wait for machine agent to come up on the bootstrap // machine and ensure it deployed the proper series. m0, err := conn.State.Machine("0") c.Assert(err, IsNil) mw0 := newMachineToolWaiter(m0) defer mw0.Stop() waitAgentTools(c, mw0, other) }
func (t *ToolsSuite) TestPutGetTools(c *C) { tools, err := environs.PutTools(t.env.Storage(), nil) c.Assert(err, IsNil) c.Assert(tools.Binary, Equals, version.Current) c.Assert(tools.URL, Not(Equals), "") for i, get := range []func(dataDir string, t *state.Tools) error{ getTools, getToolsWithTar, } { c.Logf("test %d", i) // Unarchive the tool executables into a temp directory. dataDir := c.MkDir() err = get(dataDir, tools) c.Assert(err, IsNil) dir := environs.ToolsDir(dataDir, version.Current) // Verify that each tool executes and produces some // characteristic output. for i, test := range commandTests { c.Logf("command test %d", i) out, err := exec.Command(filepath.Join(dir, test.cmd[0]), test.cmd[1:]...).CombinedOutput() if err != nil { c.Assert(err, FitsTypeOf, (*exec.ExitError)(nil)) } c.Check(string(out), Matches, test.output) } data, err := ioutil.ReadFile(filepath.Join(dir, urlFile)) c.Assert(err, IsNil) c.Assert(string(data), Equals, tools.URL) } }
func (t *ToolsSuite) TestPutToolsAndForceVersion(c *C) { // This test actually tests three things: // the writing of the FORCE-VERSION file; // the reading of the FORCE-VERSION file by the version package; // and the reading of the version from jujud. vers := version.Current vers.Patch++ tools, err := environs.PutTools(t.env.Storage(), &vers.Number) c.Assert(err, IsNil) c.Assert(tools.Binary, Equals, vers) }
func (e *environ) Bootstrap(uploadTools bool, cert, key []byte) error { defer delay() if err := e.checkBroken("Bootstrap"); err != nil { return err } password := e.Config().AdminSecret() if password == "" { return fmt.Errorf("admin-secret is required for bootstrap") } if _, ok := e.Config().CACert(); !ok { return fmt.Errorf("no CA certificate in environment configuration") } var tools *state.Tools var err error if uploadTools { tools, err = environs.PutTools(e.Storage(), nil) if err != nil { return err } } else { flags := environs.HighestVersion | environs.CompatVersion tools, err = environs.FindTools(e, version.Current, flags) if err != nil { return err } } e.state.mu.Lock() defer e.state.mu.Unlock() e.state.ops <- OpBootstrap{Env: e.state.name} if e.state.bootstrapped { return fmt.Errorf("environment is already bootstrapped") } if e.ecfg().stateServer() { info := stateInfo() cfg, err := environs.BootstrapConfig(&providerInstance, e.ecfg().Config, tools) if err != nil { return fmt.Errorf("cannot make bootstrap config: %v", err) } st, err := state.Initialize(info, cfg) if err != nil { panic(err) } if err := st.SetAdminMongoPassword(trivial.PasswordHash(password)); err != nil { return err } if err := st.Close(); err != nil { panic(err) } } e.state.bootstrapped = true return nil }
// checkUpgrade sets the environment agent version and checks that // all the provided watchers upgrade to the requested version. func (t *LiveTests) checkUpgrade(c *C, conn *juju.Conn, newVersion version.Binary, waiters ...*toolsWaiter) { c.Logf("putting testing version of juju tools") upgradeTools, err := environs.PutTools(t.Env.Storage(), &newVersion.Number) c.Assert(err, IsNil) // Check that the put version really is the version we expect. c.Assert(upgradeTools.Binary, Equals, newVersion) err = setAgentVersion(conn.State, newVersion.Number) c.Assert(err, IsNil) for i, w := range waiters { c.Logf("waiting for upgrade of %d: %v", i, w.tooler.String()) waitAgentTools(c, w, newVersion) c.Logf("upgrade %d successful", i) } }
// Test that the upload procedure fails correctly // when the build process fails (because of a bad Go source // file in this case). func (t *ToolsSuite) TestUploadBadBuild(c *C) { gopath := c.MkDir() join := append([]string{gopath, "src"}, strings.Split("launchpad.net/juju-core/cmd/broken", "/")...) pkgdir := filepath.Join(join...) err := os.MkdirAll(pkgdir, 0777) c.Assert(err, IsNil) err = ioutil.WriteFile(filepath.Join(pkgdir, "broken.go"), []byte("nope"), 0666) c.Assert(err, IsNil) defer os.Setenv("GOPATH", os.Getenv("GOPATH")) os.Setenv("GOPATH", gopath) tools, err := environs.PutTools(t.env.Storage(), nil) c.Assert(tools, IsNil) c.Assert(err, ErrorMatches, `build command "go" failed: exit status 1; can't load package:(.|\n)*`) }
func (e *environ) Bootstrap(uploadTools bool, cert, key []byte) error { password := e.Config().AdminSecret() if password == "" { return fmt.Errorf("admin-secret is required for bootstrap") } log.Printf("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. var err error for a := shortAttempt.Start(); a.Next(); { _, err = e.loadState() if err != nil { break } } if err == nil { return fmt.Errorf("environment is already bootstrapped") } if _, notFound := err.(*environs.NotFoundError); !notFound { return fmt.Errorf("cannot query old bootstrap state: %v", err) } var tools *state.Tools if uploadTools { tools, err = environs.PutTools(e.Storage(), nil) if err != nil { return fmt.Errorf("cannot upload tools: %v", err) } } else { flags := environs.HighestVersion | environs.CompatVersion v := version.Current v.Series = e.Config().DefaultSeries() tools, err = environs.FindTools(e, v, flags) if err != nil { return fmt.Errorf("cannot find tools: %v", err) } } config, err := environs.BootstrapConfig(providerInstance, e.Config(), tools) if err != nil { return fmt.Errorf("unable to determine inital configuration: %v", err) } caCert, hasCert := e.Config().CACert() if !hasCert { return fmt.Errorf("no CA certificate in environment configuration") } info := &state.Info{ Password: trivial.PasswordHash(password), CACert: caCert, } inst, err := e.startInstance(&startInstanceParams{ machineId: "0", info: info, tools: tools, stateServer: true, config: config, stateServerCert: cert, stateServerKey: key, }) if err != nil { return fmt.Errorf("cannot start bootstrap instance: %v", err) } err = e.saveState(&bootstrapState{ StateInstances: []state.InstanceId{inst.Id()}, }) if err != nil { // ignore error on StopInstance because the previous error is // more important. e.StopInstances([]environs.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 }