Пример #1
0
func (s *supportedSeriesSuite) TestOSSupportedSeries(c *gc.C) {
	version.SetSeriesVersions(map[string]string{
		"trusty": "14.04",
		"utopic": "14.10",
		"win7":   "win7",
		"win81":  "win81",
	})
	series := version.OSSupportedSeries(version.Ubuntu)
	c.Assert(series, jc.SameContents, []string{"trusty", "utopic"})
	series = version.OSSupportedSeries(version.Windows)
	c.Assert(series, jc.SameContents, []string{"win7", "win81"})
}
Пример #2
0
func (s *toolsSuite) TestUploadSeriesExpanded(c *gc.C) {
	// Make some fake tools.
	expectedTools, vers, toolPath := s.setupToolsForUpload(c)
	// Now try uploading them. The "series" parameter is accepted
	// but ignored; the API server will expand the tools for all
	// supported series.
	params := "?binaryVersion=" + vers.String() + "&series=nonsense"
	resp, err := s.uploadRequest(c, s.toolsURI(c, params), true, toolPath)
	c.Assert(err, gc.IsNil)

	// Check the response.
	stor := s.Environ.Storage()
	toolsURL, err := stor.URL(tools.StorageName(vers))
	c.Assert(err, gc.IsNil)
	expectedTools[0].URL = toolsURL
	s.assertUploadResponse(c, resp, expectedTools[0])

	// Check the contents.
	for _, series := range version.OSSupportedSeries(version.Ubuntu) {
		toolsVersion := vers
		toolsVersion.Series = series
		r, err := stor.Get(tools.StorageName(toolsVersion))
		c.Assert(err, gc.IsNil)
		uploadedData, err := ioutil.ReadAll(r)
		c.Assert(err, gc.IsNil)
		expectedData, err := ioutil.ReadFile(toolPath)
		c.Assert(err, gc.IsNil)
		c.Assert(uploadedData, gc.DeepEquals, expectedData)
	}
}
Пример #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
// UploadTools uploads tools at the specified location to the API server over HTTPS.
func (c *Client) UploadTools(r io.Reader, vers version.Binary) (*tools.Tools, error) {
	// Older versions of Juju expect to be told which series to expand
	// the uploaded tools to on the server-side. In new versions we
	// do this automatically, and the parameter will be ignored.
	fakeSeries := version.OSSupportedSeries(vers.OS)

	// Prepare the upload request.
	url := fmt.Sprintf("%s/tools?binaryVersion=%s&series=%s", c.st.serverRoot, vers, strings.Join(fakeSeries, ","))
	req, err := http.NewRequest("POST", url, r)
	if err != nil {
		return nil, errors.Annotate(err, "cannot create upload request")
	}
	req.SetBasicAuth(c.st.tag, c.st.password)
	req.Header.Set("Content-Type", "application/x-tar-gz")

	// Send the request.

	// BUG(dimitern) 2013-12-17 bug #1261780
	// Due to issues with go 1.1.2, fixed later, we cannot use a
	// regular TLS client with the CACert here, because we get "x509:
	// cannot validate certificate for 127.0.0.1 because it doesn't
	// contain any IP SANs". Once we use a later go version, this
	// should be changed to connect to the API server with a regular
	// HTTP+TLS enabled client, using the CACert (possily cached, like
	// the tag and password) passed in api.Open()'s info argument.
	resp, err := utils.GetNonValidatingHTTPClient().Do(req)
	if err != nil {
		return nil, errors.Annotate(err, "cannot upload charm")
	}
	defer resp.Body.Close()

	// Now parse the response & return.
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, errors.Annotate(err, "cannot read tools upload response")
	}
	if resp.StatusCode != http.StatusOK {
		return nil, errors.Errorf("tools upload failed: %v (%s)", resp.StatusCode, bytes.TrimSpace(body))
	}

	var jsonResponse params.ToolsResult
	if err := json.Unmarshal(body, &jsonResponse); err != nil {
		return nil, errors.Annotate(err, "cannot unmarshal upload response")
	}
	if err := jsonResponse.Error; err != nil {
		return nil, errors.Annotate(err, "error uploading tools")
	}
	return jsonResponse.Tools, nil
}
Пример #5
0
// uploadToStorage uploads the tools from the specified directory to environment storage.
func (h *toolsUploadHandler) uploadToStorage(uploadedTools *tools.Tools, toolsDir, toolsFilename string) (*tools.Tools, bool, error) {
	// SyncTools requires simplestreams metadata to find the tools to upload.
	stor, err := filestorage.NewFileStorageWriter(toolsDir)
	if err != nil {
		return nil, false, errors.Annotate(err, "cannot create metadata storage")
	}
	// Generate metadata for each series of the same OS as the uploaded tools.
	// The URL for each fake series record points to the same tools tarball.
	allToolsMetadata := []*tools.Tools{uploadedTools}
	osSeries := version.OSSupportedSeries(uploadedTools.Version.OS)
	for _, series := range osSeries {
		vers := uploadedTools.Version
		vers.Series = series
		allToolsMetadata = append(allToolsMetadata, &tools.Tools{
			Version: vers,
			URL:     uploadedTools.URL,
			Size:    uploadedTools.Size,
			SHA256:  uploadedTools.SHA256,
		})
	}
	err = envtools.MergeAndWriteMetadata(stor, allToolsMetadata, false)
	if err != nil {
		return nil, false, errors.Annotate(err, "cannot get environment config")
	}

	// Create the environment so we can get the storage to which we upload the tools.
	envConfig, err := h.state.EnvironConfig()
	if err != nil {
		return nil, false, errors.Annotate(err, "cannot get environment config")
	}
	env, err := environs.New(envConfig)
	if err != nil {
		return nil, false, errors.Annotate(err, "cannot access environment")
	}

	// Now perform the upload.
	builtTools := &sync.BuiltTools{
		Version:     uploadedTools.Version,
		Dir:         toolsDir,
		StorageName: toolsFilename,
		Size:        uploadedTools.Size,
		Sha256Hash:  uploadedTools.SHA256,
	}
	uploadedTools, err = sync.SyncBuiltTools(env.Storage(), builtTools, osSeries...)
	if err != nil {
		return nil, false, err
	}
	return uploadedTools, !envConfig.SSLHostnameVerification(), nil
}
Пример #6
0
// 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()
	tools, err := agenttools.ReadTools(dataDir, version.Current)
	if err != nil {
		return err
	}

	data, err := ioutil.ReadFile(filepath.Join(
		agenttools.SharedToolsDir(dataDir, version.Current),
		"tools.tar.gz",
	))
	if err != nil {
		return err
	}

	storage, err := st.ToolsStorage()
	if err != nil {
		return err
	}
	defer storage.Close()

	var toolsVersions []version.Binary
	if strings.HasPrefix(tools.URL, "file://") {
		// Tools were uploaded: clone for each series of the same OS.
		osSeries := version.OSSupportedSeries(tools.Version.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 := toolstorage.Metadata{
			Version: toolsVersion,
			Size:    tools.Size,
			SHA256:  tools.SHA256,
		}
		logger.Debugf("Adding tools: %v", toolsVersion)
		if err := storage.AddTools(bytes.NewReader(data), metadata); err != nil {
			return err
		}
	}
	return nil
}
Пример #7
0
// uploadTools compiles jujud from $GOPATH and uploads it into the supplied
// storage. If no version has been explicitly chosen, the version number
// reported by the built tools will be based on the client version number.
// In any case, the version number reported will have a build component higher
// than that of any otherwise-matching available envtools.
// uploadTools resets the chosen version and replaces the available tools
// with the ones just uploaded.
func (context *upgradeContext) uploadTools() (err error) {
	// TODO(fwereade): this is kinda crack: we should not assume that
	// version.Current matches whatever source happens to be built. The
	// ideal would be:
	//  1) compile jujud from $GOPATH into some build dir
	//  2) get actual version with `jujud version`
	//  3) check actual version for compatibility with CLI tools
	//  4) generate unique build version with reference to available tools
	//  5) force-version that unique version into the dir directly
	//  6) archive and upload the build dir
	// ...but there's no way we have time for that now. In the meantime,
	// considering the use cases, this should work well enough; but it
	// won't detect an incompatible major-version change, which is a shame.
	if context.chosen == version.Zero {
		context.chosen = context.client
	}
	context.chosen = uploadVersion(context.chosen, context.tools)

	builtTools, err := sync.BuildToolsTarball(&context.chosen, "upgrade")
	if err != nil {
		return err
	}
	defer os.RemoveAll(builtTools.Dir)

	var uploaded *coretools.Tools
	toolsPath := path.Join(builtTools.Dir, builtTools.StorageName)
	logger.Infof("uploading tools %v (%dkB) to Juju state server", builtTools.Version, (builtTools.Size+512)/1024)
	f, err := os.Open(toolsPath)
	if err != nil {
		return err
	}
	defer f.Close()
	additionalSeries := version.OSSupportedSeries(builtTools.Version.OS)
	uploaded, err = context.apiClient.UploadTools(f, builtTools.Version, additionalSeries...)
	if err != nil {
		return err
	}
	context.tools = coretools.List{uploaded}
	return nil
}