Example #1
0
func (s *StoreSuite) TestNilAuthorization(c *gc.C) {
	config := testing.EnvironConfig(c)
	store := env_config.SpecializeCharmRepo(s.store, config)

	base := "cs:series/good"
	charmURL := charm.MustParseURL(base)
	_, err := store.Get(charmURL)

	c.Assert(err, gc.IsNil)
	c.Assert(s.server.Authorizations, gc.HasLen, 0)
}
Example #2
0
func (s *StoreSuite) TestAuthorization(c *gc.C) {
	config := testing.CustomEnvironConfig(c,
		testing.Attrs{"charm-store-auth": "token=value"})
	store := env_config.SpecializeCharmRepo(s.store, config)

	base := "cs:series/good"
	charmURL := charm.MustParseURL(base)
	_, err := store.Get(charmURL)

	c.Assert(err, gc.IsNil)

	c.Assert(s.server.Authorizations, gc.HasLen, 1)
	c.Assert(s.server.Authorizations[0], gc.Equals, "charmstore token=value")
}
Example #3
0
func (c *Client) ResolveCharms(args params.ResolveCharms) (params.ResolveCharmResults, error) {
	var results params.ResolveCharmResults

	envConfig, err := c.api.state.EnvironConfig()
	if err != nil {
		return params.ResolveCharmResults{}, err
	}
	repo := config.SpecializeCharmRepo(CharmStore, envConfig)

	for _, ref := range args.References {
		result := params.ResolveCharmResult{}
		curl, err := c.resolveCharm(ref, repo)
		if err != nil {
			result.Error = err.Error()
		} else {
			result.URL = curl
		}
		results.URLs = append(results.URLs, result)
	}
	return results, nil
}
Example #4
0
// AddCharm adds the given charm URL (which must include revision) to
// the environment, if it does not exist yet. Local charms are not
// supported, only charm store URLs. See also AddLocalCharm().
func (c *Client) AddCharm(args params.CharmURL) error {
	charmURL, err := charm.ParseURL(args.URL)
	if err != nil {
		return err
	}
	if charmURL.Schema != "cs" {
		return fmt.Errorf("only charm store charm URLs are supported, with cs: schema")
	}
	if charmURL.Revision < 0 {
		return fmt.Errorf("charm URL must include revision")
	}

	// First, check if a pending or a real charm exists in state.
	stateCharm, err := c.api.state.PrepareStoreCharmUpload(charmURL)
	if err == nil && stateCharm.IsUploaded() {
		// Charm already in state (it was uploaded already).
		return nil
	} else if err != nil {
		return err
	}

	// Get the charm and its information from the store.
	envConfig, err := c.api.state.EnvironConfig()
	if err != nil {
		return err
	}
	store := config.SpecializeCharmRepo(CharmStore, envConfig)
	downloadedCharm, err := store.Get(charmURL)
	if err != nil {
		return errgo.Annotatef(err, "cannot download charm %q", charmURL.String())
	}

	// Open it and calculate the SHA256 hash.
	downloadedBundle, ok := downloadedCharm.(*charm.Bundle)
	if !ok {
		return errgo.New("expected a charm archive, got %T", downloadedCharm)
	}
	archive, err := os.Open(downloadedBundle.Path)
	if err != nil {
		return errgo.Annotate(err, "cannot read downloaded charm")
	}
	defer archive.Close()
	bundleSHA256, size, err := utils.ReadSHA256(archive)
	if err != nil {
		return errgo.Annotate(err, "cannot calculate SHA256 hash of charm")
	}
	if _, err := archive.Seek(0, 0); err != nil {
		return errgo.Annotate(err, "cannot rewind charm archive")
	}

	// Get the environment storage and upload the charm.
	env, err := environs.New(envConfig)
	if err != nil {
		return errgo.Annotate(err, "cannot access environment")
	}
	storage := env.Storage()
	archiveName, err := CharmArchiveName(charmURL.Name, charmURL.Revision)
	if err != nil {
		return errgo.Annotate(err, "cannot generate charm archive name")
	}
	if err := storage.Put(archiveName, archive, size); err != nil {
		return errgo.Annotate(err, "cannot upload charm to provider storage")
	}
	storageURL, err := storage.URL(archiveName)
	if err != nil {
		return errgo.Annotate(err, "cannot get storage URL for charm")
	}
	bundleURL, err := url.Parse(storageURL)
	if err != nil {
		return errgo.Annotate(err, "cannot parse storage URL")
	}

	// Finally, update the charm data in state and mark it as no longer pending.
	_, err = c.api.state.UpdateUploadedCharm(downloadedCharm, charmURL, bundleURL, bundleSHA256)
	if err == state.ErrCharmRevisionAlreadyModified ||
		state.IsCharmAlreadyUploadedError(err) {
		// This is not an error, it just signifies somebody else
		// managed to upload and update the charm in state before
		// us. This means we have to delete what we just uploaded
		// to storage.
		if err := storage.Remove(archiveName); err != nil {
			errgo.Annotate(err, "cannot remove duplicated charm from storage")
		}
		return nil
	}
	return err
}
Example #5
0
func (c *DeployCommand) Run(ctx *cmd.Context) error {
	client, err := juju.NewAPIClientFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()

	attrs, err := client.EnvironmentGet()
	if err != nil {
		return err
	}
	conf, err := config.New(config.NoDefaults, attrs)
	if err != nil {
		return err
	}

	curl, err := resolveCharmURL(c.CharmName, client, conf)
	if err != nil {
		return err
	}

	repo, err := charm.InferRepository(curl.Reference, ctx.AbsPath(c.RepoPath))
	if err != nil {
		return err
	}

	repo = config.SpecializeCharmRepo(repo, conf)

	curl, err = addCharmViaAPI(client, ctx, curl, repo)
	if err != nil {
		return err
	}

	if c.BumpRevision {
		ctx.Infof("--upgrade (or -u) is deprecated and ignored; charms are always deployed with a unique revision.")
	}
	var includeNetworks []string
	var excludeNetworks []string
	haveNetworks := false
	if c.Networks != "" {
		includeNetworks = parseNetworks(c.Networks)
		haveNetworks = true
	}
	if c.ExcludeNetworks != "" {
		excludeNetworks = parseNetworks(c.ExcludeNetworks)
		haveNetworks = true
	}
	if haveNetworks {
		env, err := environs.New(conf)
		if err != nil {
			return err
		}
		if !env.SupportNetworks() {
			return errors.New("cannot use --networks/--exclude-networks: not supported by the environment")
		}
	}

	charmInfo, err := client.CharmInfo(curl.String())
	if err != nil {
		return err
	}

	numUnits := c.NumUnits
	if charmInfo.Meta.Subordinate {
		if !constraints.IsEmpty(&c.Constraints) {
			return errors.New("cannot use --constraints with subordinate service")
		}
		if numUnits == 1 && c.ToMachineSpec == "" {
			numUnits = 0
		} else {
			return errors.New("cannot use --num-units or --to with subordinate service")
		}
	}
	serviceName := c.ServiceName
	if serviceName == "" {
		serviceName = charmInfo.Meta.Name
	}

	var configYAML []byte
	if c.Config.Path != "" {
		configYAML, err = c.Config.Read(ctx)
		if err != nil {
			return err
		}
	}
	err = client.ServiceDeployWithNetworks(
		curl.String(),
		serviceName,
		numUnits,
		string(configYAML),
		c.Constraints,
		c.ToMachineSpec,
		includeNetworks,
		excludeNetworks,
	)
	if params.IsCodeNotImplemented(err) {
		if haveNetworks {
			return errors.New("cannot use --networks/--exclude-networks: not supported by the API server")
		}
		err = client.ServiceDeploy(
			curl.String(),
			serviceName,
			numUnits,
			string(configYAML),
			c.Constraints,
			c.ToMachineSpec)
	}
	return err
}
Example #6
0
// Run connects to the specified environment and starts the charm
// upgrade process.
func (c *UpgradeCharmCommand) Run(ctx *cmd.Context) error {
	client, err := juju.NewAPIClientFromName(c.EnvName)
	if err != nil {
		return err
	}
	defer client.Close()
	oldURL, err := client.ServiceGetCharmURL(c.ServiceName)
	if err != nil {
		return err
	}

	attrs, err := client.EnvironmentGet()
	if err != nil {
		return err
	}
	conf, err := config.New(config.NoDefaults, attrs)
	if err != nil {
		return err
	}

	var newURL *charm.URL
	if c.SwitchURL != "" {
		newURL, err = resolveCharmURL(c.SwitchURL, client, conf)
		if err != nil {
			return err
		}
	} else {
		// No new URL specified, but revision might have been.
		newURL = oldURL.WithRevision(c.Revision)
	}

	repo, err := charm.InferRepository(newURL.Reference, ctx.AbsPath(c.RepoPath))
	if err != nil {
		return err
	}
	repo = config.SpecializeCharmRepo(repo, conf)

	// If no explicit revision was set with either SwitchURL
	// or Revision flags, discover the latest.
	explicitRevision := true
	if newURL.Revision == -1 {
		explicitRevision = false
		latest, err := charm.Latest(repo, newURL)
		if err != nil {
			return err
		}
		newURL = newURL.WithRevision(latest)
	}
	if *newURL == *oldURL {
		if explicitRevision {
			return fmt.Errorf("already running specified charm %q", newURL)
		} else if newURL.Schema == "cs" {
			// No point in trying to upgrade a charm store charm when
			// we just determined that's the latest revision
			// available.
			return fmt.Errorf("already running latest charm %q", newURL)
		}
	}

	addedURL, err := addCharmViaAPI(client, ctx, newURL, repo)
	if err != nil {
		return err
	}

	return client.ServiceSetCharm(c.ServiceName, addedURL.String(), c.Force)
}