Example #1
0
func (s *JujuConnSuite) AddTestingCharm(c *gc.C, name string) *state.Charm {
	ch := testing.Charms.Dir(name)
	ident := fmt.Sprintf("%s-%d", ch.Meta().Name, ch.Revision())
	curl := charm.MustParseURL("local:quantal/" + ident)
	repo, err := charm.InferRepository(curl.Reference, testing.Charms.Path())
	c.Assert(err, gc.IsNil)
	sch, err := s.Conn.PutCharm(curl, repo, false)
	c.Assert(err, gc.IsNil)
	return sch
}
Example #2
0
func (s *CharmSuite) TestInferRepository(c *gc.C) {
	for i, t := range inferRepoTests {
		c.Logf("test %d", i)
		curl, err := charm.InferURL(t.url, "precise")
		c.Assert(err, gc.IsNil)
		repo, err := charm.InferRepository(curl.Reference, "/some/path")
		c.Assert(err, gc.IsNil)
		switch repo := repo.(type) {
		case *charm.LocalRepository:
			c.Assert(repo.Path, gc.Equals, t.path)
		default:
			c.Assert(repo, gc.Equals, charm.Store)
		}
	}
	curl, err := charm.InferURL("local:whatever", "precise")
	c.Assert(err, gc.IsNil)
	_, err = charm.InferRepository(curl.Reference, "")
	c.Assert(err, gc.ErrorMatches, "path to local repository not specified")
	curl.Schema = "foo"
	_, err = charm.InferRepository(curl.Reference, "")
	c.Assert(err, gc.ErrorMatches, "unknown schema for charm reference.*")
}
Example #3
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 #4
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)
}
Example #5
0
func (c *PublishCommand) Run(ctx *cmd.Context) (err error) {
	branch := bzr.New(ctx.AbsPath(c.CharmPath))
	if _, err := os.Stat(branch.Join(".bzr")); err != nil {
		return fmt.Errorf("not a charm branch: %s", branch.Location())
	}
	if err := branch.CheckClean(); err != nil {
		return err
	}

	var curl *charm.URL
	if c.URL == "" {
		if err == nil {
			loc, err := branch.PushLocation()
			if err != nil {
				return fmt.Errorf("no charm URL provided and cannot infer from current directory (no push location)")
			}
			curl, err = charm.Store.CharmURL(loc)
			if err != nil {
				return fmt.Errorf("cannot infer charm URL from branch location: %q", loc)
			}
		}
	} else {
		curl, err = charm.InferURL(c.URL, "")
		if err != nil {
			return err
		}
	}

	pushLocation := charm.Store.BranchLocation(curl)
	if c.changePushLocation != nil {
		pushLocation = c.changePushLocation(pushLocation)
	}

	repo, err := charm.InferRepository(curl.Reference, "/not/important")
	if err != nil {
		return err
	}
	if repo != charm.Store {
		return fmt.Errorf("charm URL must reference the juju charm store")
	}

	localDigest, err := branch.RevisionId()
	if err != nil {
		return fmt.Errorf("cannot obtain local digest: %v", err)
	}
	logger.Infof("local digest is %s", localDigest)

	ch, err := charm.ReadDir(branch.Location())
	if err != nil {
		return err
	}
	if ch.Meta().Name != curl.Name {
		return fmt.Errorf("charm name in metadata must match name in URL: %q != %q", ch.Meta().Name, curl.Name)
	}

	oldEvent, err := charm.Store.Event(curl, localDigest)
	if _, ok := err.(*charm.NotFoundError); ok {
		oldEvent, err = charm.Store.Event(curl, "")
		if _, ok := err.(*charm.NotFoundError); ok {
			logger.Infof("charm %s is not yet in the store", curl)
			err = nil
		}
	}
	if err != nil {
		return fmt.Errorf("cannot obtain event details from the store: %s", err)
	}

	if oldEvent != nil && oldEvent.Digest == localDigest {
		return handleEvent(ctx, curl, oldEvent)
	}

	logger.Infof("sending charm to the charm store...")

	err = branch.Push(&bzr.PushAttr{Location: pushLocation, Remember: true})
	if err != nil {
		return err
	}
	logger.Infof("charm sent; waiting for it to be published...")
	for {
		time.Sleep(c.pollDelay)
		newEvent, err := charm.Store.Event(curl, "")
		if _, ok := err.(*charm.NotFoundError); ok {
			continue
		}
		if err != nil {
			return fmt.Errorf("cannot obtain event details from the store: %s", err)
		}
		if oldEvent != nil && oldEvent.Digest == newEvent.Digest {
			continue
		}
		if newEvent.Digest != localDigest {
			// TODO Check if the published digest is in the local history.
			return fmt.Errorf("charm changed but not to local charm digest; publishing race?")
		}
		return handleEvent(ctx, curl, newEvent)
	}
}