Пример #1
0
func (s *UpgradeCharmSuccessStateSuite) TestForcedSeriesUpgrade(c *gc.C) {
	path := testcharms.Repo.ClonedDirPath(c.MkDir(), "multi-series")
	err := runDeploy(c, path, "multi-series", "--series", "precise")
	c.Assert(err, jc.ErrorIsNil)
	application, err := s.State.Application("multi-series")
	c.Assert(err, jc.ErrorIsNil)
	ch, _, err := application.Charm()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(ch.Revision(), gc.Equals, 1)

	// Copy files from a charm supporting a different set of series
	// so we can try an upgrade requiring --force-series.
	for _, f := range []string{"metadata.yaml", "revision"} {
		err = utils.CopyFile(
			filepath.Join(path, f),
			filepath.Join(testcharms.Repo.CharmDirPath("multi-series2"), f))
		c.Assert(err, jc.ErrorIsNil)
	}
	err = runUpgradeCharm(c, "multi-series", "--path", path, "--force-series")
	c.Assert(err, jc.ErrorIsNil)

	err = application.Refresh()
	c.Assert(err, jc.ErrorIsNil)
	ch, force, err := application.Charm()
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(ch.Revision(), gc.Equals, 8)
	c.Assert(force, gc.Equals, false)
	s.AssertCharmUploaded(c, ch.URL())
	c.Assert(ch.URL().String(), gc.Equals, "local:precise/multi-series2-8")
}
Пример #2
0
// Clone creates a copy of the container, giving the copy the specified name.
func (mock *mockContainer) Clone(name string, extraArgs []string, templateArgs []string) (golxc.Container, error) {
	state := mock.getState()
	if state == golxc.StateUnknown {
		return nil, fmt.Errorf("container has not been created")
	} else if state == golxc.StateRunning {
		return nil, fmt.Errorf("container is running, clone not possible")
	}

	container := &mockContainer{
		factory:  mock.factory,
		name:     name,
		state:    golxc.StateStopped,
		logLevel: golxc.LogWarning,
	}
	mock.factory.instances[name] = container

	// Create the container directory.
	containerDir := filepath.Join(mock.factory.containerDir, name)
	if err := os.MkdirAll(containerDir, 0755); err != nil {
		return nil, errors.Trace(err)
	}
	if err := utils.CopyFile(container.configFilename(), mock.configFilename()); err != nil {
		return nil, errors.Trace(err)
	}

	mock.factory.notify(eventArgs(Cloned, mock.name, extraArgs, templateArgs, nil))
	return container, nil
}
Пример #3
0
// 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
}
Пример #4
0
// buildToolsTarball bundles a tools tarball and places it in a temp directory in
// the expected tools path.
func buildToolsTarball(forceVersion *version.Number) (builtTools *BuiltTools, err error) {
	// TODO(rog) find binaries from $PATH when not using a development
	// version of juju within a $GOPATH.

	logger.Debugf("Building tools")
	// We create the entire archive before asking the environment to
	// start uploading so that we can be sure we have archived
	// correctly.
	f, err := ioutil.TempFile("", "juju-tgz")
	if err != nil {
		return nil, err
	}
	defer f.Close()
	defer os.Remove(f.Name())
	toolsVersion, sha256Hash, err := envtools.BundleTools(f, forceVersion)
	if err != nil {
		return nil, err
	}
	fileInfo, err := f.Stat()
	if err != nil {
		return nil, fmt.Errorf("cannot stat newly made tools archive: %v", err)
	}
	size := fileInfo.Size()
	logger.Infof("built tools %v (%dkB)", toolsVersion, (size+512)/1024)
	baseToolsDir, err := ioutil.TempDir("", "juju-tools")
	if err != nil {
		return nil, err
	}

	// If we exit with an error, clean up the built tools directory.
	defer func() {
		if err != nil {
			os.RemoveAll(baseToolsDir)
		}
	}()

	err = os.MkdirAll(filepath.Join(baseToolsDir, storage.BaseToolsPath, "releases"), 0755)
	if err != nil {
		return nil, err
	}
	storageName := envtools.StorageName(toolsVersion)
	err = utils.CopyFile(filepath.Join(baseToolsDir, storageName), f.Name())
	if err != nil {
		return nil, err
	}
	return &BuiltTools{
		Version:     toolsVersion,
		Dir:         baseToolsDir,
		StorageName: storageName,
		Size:        size,
		Sha256Hash:  sha256Hash,
	}, nil
}
Пример #5
0
// cloneToolsForSeries copies the built tools tarball into a tarball for the specified
// stream and series and generates corresponding metadata.
func cloneToolsForSeries(toolsInfo *BuiltTools, stream string, series ...string) error {
	// Copy the tools to the target storage, recording a Tools struct for each one.
	var targetTools coretools.List
	targetTools = append(targetTools, &coretools.Tools{
		Version: toolsInfo.Version,
		Size:    toolsInfo.Size,
		SHA256:  toolsInfo.Sha256Hash,
	})
	putTools := func(vers version.Binary) (string, error) {
		name := envtools.StorageName(vers, stream)
		src := filepath.Join(toolsInfo.Dir, toolsInfo.StorageName)
		dest := filepath.Join(toolsInfo.Dir, name)
		destDir := filepath.Dir(dest)
		if err := os.MkdirAll(destDir, 0755); err != nil {
			return "", err
		}
		if err := utils.CopyFile(dest, src); err != nil {
			return "", err
		}
		// Append to targetTools the attributes required to write out tools metadata.
		targetTools = append(targetTools, &coretools.Tools{
			Version: vers,
			Size:    toolsInfo.Size,
			SHA256:  toolsInfo.Sha256Hash,
		})
		return name, nil
	}
	logger.Debugf("generating tarballs for %v", series)
	for _, series := range series {
		_, err := jujuseries.SeriesVersion(series)
		if err != nil {
			return err
		}
		if series != toolsInfo.Version.Series {
			fakeVersion := toolsInfo.Version
			fakeVersion.Series = series
			if _, err := putTools(fakeVersion); err != nil {
				return err
			}
		}
	}
	// The tools have been copied to a temp location from which they will be uploaded,
	// now write out the matching simplestreams metadata so that SyncTools can find them.
	metadataStore, err := filestorage.NewFileStorageWriter(toolsInfo.Dir)
	if err != nil {
		return err
	}
	logger.Debugf("generating tools metadata")
	return envtools.MergeAndWriteMetadata(metadataStore, stream, stream, targetTools, false)
}
Пример #6
0
func (*fileSuite) TestCopyFile(c *gc.C) {
	dir := c.MkDir()
	f, err := ioutil.TempFile(dir, "source")
	c.Assert(err, gc.IsNil)
	defer f.Close()
	_, err = f.Write([]byte("hello world"))
	c.Assert(err, gc.IsNil)
	dest := filepath.Join(dir, "dest")

	err = utils.CopyFile(dest, f.Name())
	c.Assert(err, gc.IsNil)
	data, err := ioutil.ReadFile(dest)
	c.Assert(err, gc.IsNil)
	c.Assert(string(data), gc.Equals, "hello world")
}
Пример #7
0
// Create creates a new container based on the given template.
func (mock *mockContainer) Create(configFile, template string, extraArgs []string, templateArgs []string, envArgs []string) error {
	if mock.getState() != golxc.StateUnknown {
		return fmt.Errorf("container is already created")
	}
	mock.factory.instances[mock.name] = mock
	// Create the container directory.
	containerDir := filepath.Join(mock.factory.containerDir, mock.name)
	if err := os.MkdirAll(containerDir, 0755); err != nil {
		return errors.Trace(err)
	}
	if err := utils.CopyFile(mock.configFilename(), configFile); err != nil {
		return errors.Trace(err)
	}
	mock.setState(golxc.StateStopped)
	mock.factory.notify(eventArgs(Created, mock.name, extraArgs, templateArgs, envArgs))
	return nil
}
Пример #8
0
Файл: sync.go Проект: bac/juju
// BuildAgentTarball bundles an agent tarball and places it in a temp directory in
// the expected agent path.
func buildAgentTarball(build bool, forceVersion *version.Number, stream string) (_ *BuiltAgent, err error) {
	// TODO(rog) find binaries from $PATH when not using a development
	// version of juju within a $GOPATH.

	logger.Debugf("Making agent binary tarball")
	// We create the entire archive before asking the environment to
	// start uploading so that we can be sure we have archived
	// correctly.
	f, err := ioutil.TempFile("", "juju-tgz")
	if err != nil {
		return nil, err
	}
	defer f.Close()
	defer os.Remove(f.Name())
	toolsVersion, sha256Hash, err := envtools.BundleTools(build, f, forceVersion)
	if err != nil {
		return nil, err
	}
	// Built agent version needs to match the client used to bootstrap.
	builtVersion := toolsVersion
	builtVersion.Build = 0
	clientVersion := jujuversion.Current
	clientVersion.Build = 0
	if builtVersion.Number.Compare(clientVersion) != 0 {
		return nil, errors.Errorf("agent binary %v not compatibile with bootstrap client %v", toolsVersion.Number, jujuversion.Current)
	}
	fileInfo, err := f.Stat()
	if err != nil {
		return nil, errors.Errorf("cannot stat newly made tools archive: %v", err)
	}
	size := fileInfo.Size()
	reportedVersion := toolsVersion
	if forceVersion != nil {
		reportedVersion.Number = *forceVersion
	}
	logger.Infof("using agent binary %v aliased to %v (%dkB)", toolsVersion, reportedVersion, (size+512)/1024)
	baseToolsDir, err := ioutil.TempDir("", "juju-tools")
	if err != nil {
		return nil, err
	}

	// If we exit with an error, clean up the built tools directory.
	defer func() {
		if err != nil {
			os.RemoveAll(baseToolsDir)
		}
	}()

	err = os.MkdirAll(filepath.Join(baseToolsDir, storage.BaseToolsPath, stream), 0755)
	if err != nil {
		return nil, err
	}
	storageName := envtools.StorageName(toolsVersion, stream)
	err = utils.CopyFile(filepath.Join(baseToolsDir, storageName), f.Name())
	if err != nil {
		return nil, err
	}
	return &BuiltAgent{
		Version:     toolsVersion,
		Dir:         baseToolsDir,
		StorageName: storageName,
		Size:        size,
		Sha256Hash:  sha256Hash,
	}, nil
}