Beispiel #1
0
func (t *ToolsSuite) TestUnpackToolsContents(c *gc.C) {
	files := []*testing.TarFile{
		testing.NewTarFile("bar", 0755, "bar contents"),
		testing.NewTarFile("foo", 0755, "foo contents"),
	}
	testTools := &tools.Tools{
		URL:     "http://foo/bar",
		Version: version.MustParseBinary("1.2.3-foo-bar"),
	}

	err := tools.UnpackTools(t.dataDir, testTools, bytes.NewReader(testing.TarGz(files...)))
	c.Assert(err, gc.IsNil)
	assertDirNames(c, t.toolsDir(), []string{"1.2.3-foo-bar"})
	t.assertToolsContents(c, testTools, files)

	// Try to unpack the same version of tools again - it should succeed,
	// leaving the original version around.
	tools2 := &tools.Tools{
		URL:     "http://arble",
		Version: version.MustParseBinary("1.2.3-foo-bar"),
	}
	files2 := []*testing.TarFile{
		testing.NewTarFile("bar", 0755, "bar2 contents"),
		testing.NewTarFile("x", 0755, "x contents"),
	}
	err = tools.UnpackTools(t.dataDir, tools2, bytes.NewReader(testing.TarGz(files2...)))
	c.Assert(err, gc.IsNil)
	assertDirNames(c, t.toolsDir(), []string{"1.2.3-foo-bar"})
	t.assertToolsContents(c, testTools, files)
}
Beispiel #2
0
func (env *localEnviron) setupLocalMachineAgent(cons constraints.Value) error {
	dataDir := env.config.rootDir()
	toolList, err := environs.FindBootstrapTools(env, cons)
	if err != nil {
		return err
	}
	// ensure we have at least one valid tools
	if len(toolList) == 0 {
		return fmt.Errorf("No bootstrap tools found")
	}
	// unpack the first tools into the agent dir.
	agentTools := toolList[0]
	logger.Debugf("tools: %#v", agentTools)
	// brutally abuse our knowledge of storage to directly open the file
	toolsUrl, err := url.Parse(agentTools.URL)
	toolsLocation := filepath.Join(env.config.storageDir(), toolsUrl.Path)
	logger.Infof("tools location: %v", toolsLocation)
	toolsFile, err := os.Open(toolsLocation)
	defer toolsFile.Close()
	// Again, brutally abuse our knowledge here.

	// The tools that FindBootstrapTools has returned us are based on the
	// default series in the config.  However we are running potentially on a
	// different series.  When the machine agent is started, it will be
	// looking based on the current series, so we need to override the series
	// returned in the tools to be the current series.
	agentTools.Version.Series = version.CurrentSeries()
	err = tools.UnpackTools(dataDir, agentTools, toolsFile)

	machineId := "0" // Always machine 0
	tag := names.MachineTag(machineId)
	toolsDir := tools.SharedToolsDir(dataDir, agentTools.Version)
	logDir := env.config.logDir()
	logConfig := "--debug" // TODO(thumper): specify loggo config
	machineEnvironment := map[string]string{
		"USER":                      env.config.user,
		"HOME":                      os.Getenv("HOME"),
		osenv.JujuProviderType:      env.config.Type(),
		osenv.JujuStorageDir:        env.config.storageDir(),
		osenv.JujuStorageAddr:       env.config.storageAddr(),
		osenv.JujuSharedStorageDir:  env.config.sharedStorageDir(),
		osenv.JujuSharedStorageAddr: env.config.sharedStorageAddr(),
	}
	agent := upstart.MachineAgentUpstartService(
		env.machineAgentServiceName(),
		toolsDir, dataDir, logDir, tag, machineId, logConfig, machineEnvironment)

	agent.InitDir = upstartScriptLocation
	logger.Infof("installing service %s to %s", env.machineAgentServiceName(), agent.InitDir)
	if err := agent.Install(); err != nil {
		logger.Errorf("could not install machine agent service: %v", err)
		return err
	}
	return nil
}
Beispiel #3
0
// primeTools sets up the current version of the tools to vers and
// makes sure that they're available JujuConnSuite's DataDir.
func (s *agentSuite) primeTools(c *C, vers version.Binary) *tools.Tools {
	err := os.RemoveAll(filepath.Join(s.DataDir(), "tools"))
	c.Assert(err, IsNil)
	version.Current = vers
	agentTools := s.uploadTools(c, vers)
	resp, err := http.Get(agentTools.URL)
	c.Assert(err, IsNil)
	defer resp.Body.Close()
	err = tools.UnpackTools(s.DataDir(), agentTools, resp.Body)
	c.Assert(err, IsNil)
	return agentTools
}
Beispiel #4
0
func (t *ToolsSuite) TestUnpackToolsBadData(c *gc.C) {
	for i, test := range unpackToolsBadDataTests {
		c.Logf("test %d", i)
		testTools := &tools.Tools{
			URL:     "http://foo/bar",
			Version: version.MustParseBinary("1.2.3-foo-bar"),
		}
		err := tools.UnpackTools(t.dataDir, testTools, bytes.NewReader(test.data))
		c.Assert(err, gc.ErrorMatches, test.err)
		assertDirNames(c, t.toolsDir(), []string{})
	}
}
Beispiel #5
0
func (t *ToolsSuite) TestChangeAgentTools(c *gc.C) {
	files := []*testing.TarFile{
		testing.NewTarFile("jujuc", 0755, "juju executable"),
		testing.NewTarFile("jujud", 0755, "jujuc executable"),
	}
	testTools := &tools.Tools{
		URL:     "http://foo/bar1",
		Version: version.MustParseBinary("1.2.3-foo-bar"),
	}
	err := tools.UnpackTools(t.dataDir, testTools, bytes.NewReader(testing.TarGz(files...)))
	c.Assert(err, gc.IsNil)

	gotTools, err := tools.ChangeAgentTools(t.dataDir, "testagent", testTools.Version)
	c.Assert(err, gc.IsNil)
	c.Assert(*gotTools, gc.Equals, *testTools)

	assertDirNames(c, t.toolsDir(), []string{"1.2.3-foo-bar", "testagent"})
	assertDirNames(c, tools.ToolsDir(t.dataDir, "testagent"), []string{"jujuc", "jujud", urlFile})

	// Upgrade again to check that the link replacement logic works ok.
	files2 := []*testing.TarFile{
		testing.NewTarFile("foo", 0755, "foo content"),
		testing.NewTarFile("bar", 0755, "bar content"),
	}
	tools2 := &tools.Tools{
		URL:     "http://foo/bar2",
		Version: version.MustParseBinary("1.2.4-foo-bar"),
	}
	err = tools.UnpackTools(t.dataDir, tools2, bytes.NewReader(testing.TarGz(files2...)))
	c.Assert(err, gc.IsNil)

	gotTools, err = tools.ChangeAgentTools(t.dataDir, "testagent", tools2.Version)
	c.Assert(err, gc.IsNil)
	c.Assert(*gotTools, gc.Equals, *tools2)

	assertDirNames(c, t.toolsDir(), []string{"1.2.3-foo-bar", "1.2.4-foo-bar", "testagent"})
	assertDirNames(c, tools.ToolsDir(t.dataDir, "testagent"), []string{"foo", "bar", urlFile})
}
Beispiel #6
0
func (u *Upgrader) fetchTools(agentTools *tools.Tools) error {
	logger.Infof("fetching tools from %q", agentTools.URL)
	resp, err := http.Get(agentTools.URL)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("bad HTTP response: %v", resp.Status)
	}
	err = tools.UnpackTools(u.dataDir, agentTools, resp.Body)
	if err != nil {
		return fmt.Errorf("cannot unpack tools: %v", err)
	}
	return nil
}
Beispiel #7
0
func (u *Upgrader) run() error {
	// Let the state know the version that is currently running.
	currentTools, err := tools.ReadTools(u.dataDir, version.Current)
	if err != nil {
		// Don't abort everything because we can't find the tools directory.
		// The problem should sort itself out as we will immediately
		// download some more tools and upgrade.
		log.Warningf("upgrader cannot read current tools: %v", err)
		currentTools = &tools.Tools{
			Binary: version.Current,
		}
	}
	err = u.agentState.SetAgentTools(currentTools)
	if err != nil {
		return err
	}

	// TODO(fwereade): this whole package should be ignorant of environs,
	// so it shouldn't be watching environ config (and it shouldn't be
	// looking in storage): we should be able to find out what to download
	// from state, exactly as we do for charms.
	w := u.st.WatchEnvironConfig()
	defer watcher.Stop(w, &u.tomb)

	// Rather than using worker.WaitForEnviron, invalid environments are
	// managed explicitly so that all configuration changes are observed
	// by the loop below.
	var environ environs.Environ

	// TODO(rog) retry downloads when they fail.
	var (
		download      *downloader.Download
		downloadTools *tools.Tools
		downloadDone  <-chan downloader.Status
	)
	// If we're killed early on (probably as a result of some other
	// task dying) we allow ourselves some time to try to connect to
	// the state and download a new version. We return to normal
	// undelayed behaviour when:
	// 1) We find there's no upgrade to do.
	// 2) A download fails.
	tomb := delayedTomb(&u.tomb, upgraderKillDelay)
	noDelay := func() {
		if tomb != &u.tomb {
			tomb.Kill(nil)
			tomb = &u.tomb
		}
	}
	for {
		// We wait for the tools to change while we're downloading
		// so that if something goes wrong (for instance a bad URL
		// hangs up) another change to the proposed tools can
		// potentially fix things.
		select {
		case cfg, ok := <-w.Changes():
			if !ok {
				return watcher.MustErr(w)
			}
			var err error
			if environ == nil {
				environ, err = environs.New(cfg)
				if err != nil {
					log.Errorf("upgrader loaded invalid initial environment configuration: %v", err)
					break
				}
			} else {
				err = environ.SetConfig(cfg)
				if err != nil {
					log.Warningf("upgrader loaded invalid environment configuration: %v", err)
					// continue on, because the version number is still significant.
				}
			}
			proposed, ok := cfg.AgentVersion()
			if !ok {
				// This shouldn't be possible; but if it happens it's no reason
				// to kill this task. Just wait for the config to change again.
				continue
			}
			if download != nil {
				// There's a download in progress, stop it if we need to.
				if downloadTools.Number == proposed {
					// We are already downloading the requested tools.
					break
				}
				// Tools changed. We need to stop and restart.
				download.Stop()
				download, downloadTools, downloadDone = nil, nil, nil
			}
			// TODO: major version upgrades.
			if proposed.Major != version.Current.Major {
				log.Errorf("major version upgrades are not supported yet")
				noDelay()
				break
			}
			if proposed == version.Current.Number {
				noDelay()
				break
			}
			required := version.Binary{
				Number: proposed,
				Series: version.Current.Series,
				Arch:   version.Current.Arch,
			}
			if tools, err := tools.ReadTools(u.dataDir, required); err == nil {
				// The exact tools have already been downloaded, so use them.
				return u.upgradeReady(currentTools, tools)
			}
			tools, err := environs.FindExactTools(environ, required)
			if err != nil {
				log.Errorf("upgrader error finding tools for %v: %v", required, err)
				if !errors.IsNotFoundError(err) {
					return err
				}
				noDelay()
				// TODO(rog): poll until tools become available.
				break
			}
			log.Infof("upgrader downloading %q", tools.URL)
			download = downloader.New(tools.URL, "")
			downloadTools = tools
			downloadDone = download.Done()
		case status := <-downloadDone:
			newTools := downloadTools
			download, downloadTools, downloadDone = nil, nil, nil
			if status.Err != nil {
				log.Errorf("upgrader download of %v failed: %v", newTools.Binary, status.Err)
				noDelay()
				break
			}
			err := tools.UnpackTools(u.dataDir, newTools, status.File)
			status.File.Close()
			if err := os.Remove(status.File.Name()); err != nil {
				log.Warningf("upgrader cannot remove temporary download file: %v", err)
			}
			if err != nil {
				log.Errorf("upgrader cannot unpack %v tools: %v", newTools.Binary, err)
				noDelay()
				break
			}
			return u.upgradeReady(currentTools, newTools)
		case <-tomb.Dying():
			if download != nil {
				return fmt.Errorf("upgrader aborted download of %q", downloadTools.URL)
			}
			return nil
		}
	}
	panic("not reached")
}