func (s *UpgraderSuite) TestUpgraderUpgradesImmediately(c *gc.C) { stor := s.DefaultToolsStorage oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) s.PatchValue(&version.Current, oldTools.Version) newTools := envtesting.AssertUploadFakeToolsVersions( c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.5-precise-amd64"))[0] err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) c.Assert(err, jc.ErrorIsNil) // Make the download take a while so that we verify that // the download happens before the upgrader checks if // it's been stopped. dummy.SetStorageDelay(coretesting.ShortWait) u := s.makeUpgrader(c) err = u.Stop() s.expectUpgradeChannelNotClosed(c) envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ AgentName: s.machine.Tag().String(), OldTools: oldTools.Version, NewTools: newTools.Version, DataDir: s.DataDir(), }) foundTools, err := agenttools.ReadTools(s.DataDir(), newTools.Version) c.Assert(err, jc.ErrorIsNil) newTools.URL = fmt.Sprintf("https://%s/environment/%s/tools/5.4.5-precise-amd64", s.APIState.Addr(), coretesting.EnvironmentTag.Id()) envtesting.CheckTools(c, foundTools, newTools) }
func (s *UpgraderSuite) TestUpgraderAllowsDowngradeToOrigVersionIfUpgradeInProgress(c *gc.C) { // note: otherwise illegal version jump downgradeVersion := version.MustParseBinary("5.3.0-precise-amd64") s.confVersion = downgradeVersion.Number s.upgradeRunning = true stor := s.DefaultToolsStorage origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) s.PatchValue(&version.Current, origTools.Version) downgradeTools := envtesting.AssertUploadFakeToolsVersions( c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), downgradeVersion)[0] err := statetesting.SetAgentVersion(s.State, downgradeVersion.Number) c.Assert(err, jc.ErrorIsNil) dummy.SetStorageDelay(coretesting.ShortWait) u := s.makeUpgrader(c) err = u.Stop() s.expectUpgradeChannelNotClosed(c) envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ AgentName: s.machine.Tag().String(), OldTools: origTools.Version, NewTools: downgradeVersion, DataDir: s.DataDir(), }) foundTools, err := agenttools.ReadTools(s.DataDir(), downgradeTools.Version) c.Assert(err, jc.ErrorIsNil) downgradeTools.URL = fmt.Sprintf("https://%s/environment/%s/tools/5.3.0-precise-amd64", s.APIState.Addr(), coretesting.EnvironmentTag.Id()) envtesting.CheckTools(c, foundTools, downgradeTools) }
func (s *UpgraderSuite) TestUpgraderUpgradesImmediately(c *gc.C) { stor := s.Environ.Storage() oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), version.MustParseBinary("5.4.3-precise-amd64")) s.PatchValue(&version.Current, oldTools.Version) newTools := envtesting.AssertUploadFakeToolsVersions( c, stor, version.MustParseBinary("5.4.5-precise-amd64"))[0] err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) c.Assert(err, gc.IsNil) // Make the download take a while so that we verify that // the download happens before the upgrader checks if // it's been stopped. dummy.SetStorageDelay(coretesting.ShortWait) u := s.makeUpgrader() err = u.Stop() envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ AgentName: s.machine.Tag().String(), OldTools: oldTools.Version, NewTools: newTools.Version, DataDir: s.DataDir(), }) foundTools, err := agenttools.ReadTools(s.DataDir(), newTools.Version) c.Assert(err, gc.IsNil) envtesting.CheckTools(c, foundTools, newTools) }
// populateTools stores uploaded tools in provider storage // and updates the tools metadata. func (c *BootstrapCommand) populateTools(st *state.State, env environs.Environ) error { agentConfig := c.CurrentConfig() dataDir := agentConfig.DataDir() current := version.Binary{ Number: jujuversion.Current, Arch: arch.HostArch(), Series: series.HostSeries(), } tools, err := agenttools.ReadTools(dataDir, current) if err != nil { return errors.Trace(err) } data, err := ioutil.ReadFile(filepath.Join( agenttools.SharedToolsDir(dataDir, current), "tools.tar.gz", )) if err != nil { return errors.Trace(err) } toolstorage, err := st.ToolsStorage() if err != nil { return errors.Trace(err) } defer toolstorage.Close() var toolsVersions []version.Binary if strings.HasPrefix(tools.URL, "file://") { // Tools were uploaded: clone for each series of the same OS. os, err := series.GetOSFromSeries(tools.Version.Series) if err != nil { return errors.Trace(err) } osSeries := series.OSSupportedSeries(os) for _, series := range osSeries { toolsVersion := tools.Version toolsVersion.Series = series toolsVersions = append(toolsVersions, toolsVersion) } } else { // Tools were downloaded from an external source: don't clone. toolsVersions = []version.Binary{tools.Version} } for _, toolsVersion := range toolsVersions { metadata := binarystorage.Metadata{ Version: toolsVersion.String(), Size: tools.Size, SHA256: tools.SHA256, } logger.Debugf("Adding tools: %v", toolsVersion) if err := toolstorage.Add(bytes.NewReader(data), metadata); err != nil { return errors.Trace(err) } } return nil }
func (t *ToolsSuite) TestReadToolsErrors(c *gc.C) { vers := version.MustParseBinary("1.2.3-precise-amd64") testTools, err := agenttools.ReadTools(t.dataDir, vers) c.Assert(testTools, gc.IsNil) c.Assert(err, gc.ErrorMatches, "cannot read tools metadata in tools directory: .*") dir := agenttools.SharedToolsDir(t.dataDir, vers) err = os.MkdirAll(dir, agenttools.DirPerm) c.Assert(err, jc.ErrorIsNil) err = ioutil.WriteFile(filepath.Join(dir, agenttools.ToolsFile), []byte(" \t\n"), 0644) c.Assert(err, jc.ErrorIsNil) testTools, err = agenttools.ReadTools(t.dataDir, vers) c.Assert(testTools, gc.IsNil) c.Assert(err, gc.ErrorMatches, "invalid tools metadata in tools directory .*") }
// populateTools stores uploaded tools in provider storage // and updates the tools metadata. // // TODO(axw) store tools in gridfs, catalogue in state. func (c *BootstrapCommand) populateTools(env environs.Environ) error { agentConfig := c.CurrentConfig() dataDir := agentConfig.DataDir() tools, err := agenttools.ReadTools(dataDir, version.Current) if err != nil { return err } if !strings.HasPrefix(tools.URL, "file://") { // Nothing to do since the tools were not uploaded. return nil } // This is a hack: providers using localstorage (local, manual) // can't use storage during bootstrap as the localstorage worker // isn't running. Use filestorage instead. var stor storage.Storage storageDir := agentConfig.Value(agent.StorageDir) if storageDir != "" { stor, err = filestorage.NewFileStorageWriter(storageDir) if err != nil { return err } } else { stor = env.Storage() } // Create a temporary directory to contain source and cloned tools. tempDir, err := ioutil.TempDir("", "juju-sync-tools") if err != nil { return err } defer os.RemoveAll(tempDir) destTools := filepath.Join(tempDir, filepath.FromSlash(envtools.StorageName(tools.Version))) if err := os.MkdirAll(filepath.Dir(destTools), 0700); err != nil { return err } srcTools := filepath.Join( agenttools.SharedToolsDir(dataDir, version.Current), "tools.tar.gz", ) if err := utils.CopyFile(destTools, srcTools); err != nil { return err } // Until we catalogue tools in state, we clone the tools // for each of the supported series of the same OS. otherSeries := version.OSSupportedSeries(version.Current.OS) _, err = sync.SyncBuiltTools(stor, &sync.BuiltTools{ Version: tools.Version, Dir: tempDir, StorageName: envtools.StorageName(tools.Version), Sha256Hash: tools.SHA256, Size: tools.Size, }, otherSeries...) return err }
// assertToolsContents asserts that the directory for the tools // has the given contents. func (t *ToolsSuite) assertToolsContents(c *gc.C, testTools *coretest.Tools, files []*testing.TarFile) { var wantNames []string for _, f := range files { wantNames = append(wantNames, f.Header.Name) } wantNames = append(wantNames, agenttools.ToolsFile) dir := agenttools.SharedToolsDir(t.dataDir, testTools.Version) assertDirNames(c, dir, wantNames) expectedURLFileContents, err := json.Marshal(testTools) c.Assert(err, jc.ErrorIsNil) assertFileContents(c, dir, agenttools.ToolsFile, string(expectedURLFileContents), 0200) for _, f := range files { assertFileContents(c, dir, f.Header.Name, f.Contents, 0400) } gotTools, err := agenttools.ReadTools(t.dataDir, testTools.Version) c.Assert(err, jc.ErrorIsNil) c.Assert(*gotTools, gc.Equals, *testTools) }
func (s *UpgraderSuite) TestUpgraderRefusesToDowngradeMinorVersions(c *gc.C) { stor := s.Environ.Storage() origTools := envtesting.PrimeTools(c, stor, s.DataDir(), version.MustParseBinary("5.4.3-precise-amd64")) s.PatchValue(&version.Current, origTools.Version) downgradeTools := envtesting.AssertUploadFakeToolsVersions( c, stor, version.MustParseBinary("5.3.3-precise-amd64"))[0] err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number) c.Assert(err, gc.IsNil) u := s.makeUpgrader() err = u.Stop() // If the upgrade would have triggered, we would have gotten an // UpgradeReadyError, since it was skipped, we get no error c.Check(err, gc.IsNil) _, err = agenttools.ReadTools(s.DataDir(), downgradeTools.Version) // TODO: ReadTools *should* be returning some form of errors.NotFound, // however, it just passes back a fmt.Errorf so we live with it // c.Assert(err, jc.Satisfies, errors.IsNotFound) c.Check(err, gc.ErrorMatches, "cannot read tools metadata in tools directory.*no such file or directory") }
func (u *Upgrader) ensureTools(agentTools *coretools.Tools, hostnameVerification utils.SSLHostnameVerification) error { if _, err := agenttools.ReadTools(u.dataDir, agentTools.Version); err == nil { // Tools have already been downloaded return nil } logger.Infof("fetching tools from %q", agentTools.URL) client := utils.GetHTTPClient(hostnameVerification) resp, err := client.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 = agenttools.UnpackTools(u.dataDir, agentTools, resp.Body) if err != nil { return fmt.Errorf("cannot unpack tools: %v", err) } logger.Infof("unpacked tools %s to %s", agentTools.Version, u.dataDir) return nil }
func (s *UpgraderSuite) TestUpgraderAllowsDowngradingPatchVersions(c *gc.C) { stor := s.Environ.Storage() origTools := envtesting.PrimeTools(c, stor, s.DataDir(), version.MustParseBinary("5.4.3-precise-amd64")) s.PatchValue(&version.Current, origTools.Version) downgradeTools := envtesting.AssertUploadFakeToolsVersions( c, stor, version.MustParseBinary("5.4.2-precise-amd64"))[0] err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number) c.Assert(err, gc.IsNil) dummy.SetStorageDelay(coretesting.ShortWait) u := s.makeUpgrader() err = u.Stop() envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ AgentName: s.machine.Tag().String(), OldTools: origTools.Version, NewTools: downgradeTools.Version, DataDir: s.DataDir(), }) foundTools, err := agenttools.ReadTools(s.DataDir(), downgradeTools.Version) c.Assert(err, gc.IsNil) envtesting.CheckTools(c, foundTools, downgradeTools) }
func (s *UpgraderSuite) TestUpgraderAllowsDowngradingPatchVersions(c *gc.C) { stor := s.DefaultToolsStorage origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) s.patchVersion(origTools.Version) downgradeTools := envtesting.AssertUploadFakeToolsVersions( c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.2-precise-amd64"))[0] err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number) c.Assert(err, jc.ErrorIsNil) u := s.makeUpgrader(c) err = u.Stop() s.expectInitialUpgradeCheckNotDone(c) envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ AgentName: s.machine.Tag().String(), OldTools: origTools.Version, NewTools: downgradeTools.Version, DataDir: s.DataDir(), }) foundTools, err := agenttools.ReadTools(s.DataDir(), downgradeTools.Version) c.Assert(err, jc.ErrorIsNil) downgradeTools.URL = fmt.Sprintf("https://%s/model/%s/tools/5.4.2-precise-amd64", s.APIState.Addr(), coretesting.ModelTag.Id()) envtesting.CheckTools(c, foundTools, downgradeTools) }
func (s *UpgraderSuite) TestUpgraderUpgradesImmediately(c *gc.C) { stor := s.DefaultToolsStorage oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) s.patchVersion(oldTools.Version) newTools := envtesting.AssertUploadFakeToolsVersions( c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.5-precise-amd64"))[0] err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) c.Assert(err, jc.ErrorIsNil) u := s.makeUpgrader(c) err = u.Stop() s.expectUpgradeChannelNotClosed(c) envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ AgentName: s.machine.Tag().String(), OldTools: oldTools.Version, NewTools: newTools.Version, DataDir: s.DataDir(), }) foundTools, err := agenttools.ReadTools(s.DataDir(), newTools.Version) c.Assert(err, jc.ErrorIsNil) newTools.URL = fmt.Sprintf("https://%s/environment/%s/tools/5.4.5-precise-amd64", s.APIState.Addr(), coretesting.EnvironmentTag.Id()) envtesting.CheckTools(c, foundTools, newTools) }
func (u *Upgrader) toolsAlreadyDownloaded(wantVersion version.Binary) bool { _, err := agenttools.ReadTools(u.dataDir, wantVersion) return err == nil }