func (c *RpcCommand) Run(ctx *cmd.Context) error { if c.Value == "error" { return errors.New("blam") } if c.Slow { time.Sleep(testing.ShortWait) return nil } ctx.Stdout.Write([]byte("eye of newt\n")) ctx.Stderr.Write([]byte("toe of frog\n")) return ioutil.WriteFile(ctx.AbsPath("local"), []byte(c.Value), 0644) }
// Run connects to the specified environment and starts the charm // upgrade process. func (c *UpgradeCharmCommand) Run(ctx *cmd.Context) error { conn, err := juju.NewConnFromName(c.EnvName) if err != nil { return err } defer conn.Close() service, err := conn.State.Service(c.ServiceName) if err != nil { return err } oldURL, _ := service.CharmURL() var newURL *charm.URL if c.SwitchURL != "" { // A new charm URL was explicitly specified. conf, err := conn.State.EnvironConfig() if err != nil { return err } newURL, err = charm.InferURL(c.SwitchURL, conf.DefaultSeries()) 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, ctx.AbsPath(c.RepoPath)) if err != nil { return err } // 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 := repo.Latest(newURL) if err != nil { return err } newURL = newURL.WithRevision(latest) } bumpRevision := false if *newURL == *oldURL { if explicitRevision { return fmt.Errorf("already running specified charm %q", newURL) } // Only try bumping the revision when necessary (local dir charm). if _, isLocal := repo.(*charm.LocalRepository); !isLocal { // TODO(dimitern): If the --force flag is set to something // different to before, we might actually want to allow this // case (and the other error below). LP bug #1174287 return fmt.Errorf("already running latest charm %q", newURL) } // This is a local repository. if ch, err := repo.Get(newURL); err != nil { return err } else if _, bumpRevision = ch.(*charm.Dir); !bumpRevision { // Only bump the revision when it's a directory. return fmt.Errorf("cannot increment revision of charm %q: not a directory", newURL) } } sch, err := conn.PutCharm(newURL, repo, bumpRevision) if err != nil { return err } return service.SetCharm(sch, c.Force) }
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, "/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) } log.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 { log.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) } log.Infof("sending charm to the charm store...") err = branch.Push(&bzr.PushAttr{Location: pushLocation, Remember: true}) if err != nil { return err } log.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) } return nil }
func (c *DeployCommand) Run(ctx *cmd.Context) error { conn, err := juju.NewConnFromName(c.EnvName) if err != nil { return err } defer conn.Close() conf, err := conn.State.EnvironConfig() if err != nil { return err } curl, err := charm.InferURL(c.CharmName, conf.DefaultSeries()) if err != nil { return err } repo, err := charm.InferRepository(curl, ctx.AbsPath(c.RepoPath)) if err != nil { return err } // TODO(fwereade) it's annoying to roundtrip the bytes through the client // here, but it's the original behaviour and not convenient to change. // PutCharm will always be required in some form for local charms; and we // will need an EnsureStoreCharm method somewhere that gets the state.Charm // for use in the following checks. ch, err := conn.PutCharm(curl, repo, c.BumpRevision) if err != nil { return err } numUnits := c.NumUnits if ch.Meta().Subordinate { empty := constraints.Value{} if c.Constraints != empty { 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 = ch.Meta().Name } var settings charm.Settings if c.Config.Path != "" { configYAML, err := c.Config.Read(ctx) if err != nil { return err } settings, err = ch.Config().ParseSettingsYAML(configYAML, serviceName) if err != nil { return err } } _, err = conn.DeployService(juju.DeployServiceParams{ ServiceName: serviceName, Charm: ch, NumUnits: numUnits, ConfigSettings: settings, Constraints: c.Constraints, ToMachineSpec: c.ToMachineSpec, }) return err }