func (c *DestroyEnvironmentCommand) Run(ctx *cmd.Context) (result error) { store, err := configstore.Default() if err != nil { return fmt.Errorf("cannot open environment info storage: %v", err) } environ, err := environs.NewFromName(c.envName, store) if err != nil { if environs.IsEmptyConfig(err) { // Delete the .jenv file and call it done. ctx.Infof("removing empty environment file") return environs.DestroyInfo(c.envName, store) } return err } if !c.assumeYes { fmt.Fprintf(ctx.Stdout, destroyEnvMsg, environ.Name(), environ.Config().Type()) scanner := bufio.NewScanner(ctx.Stdin) scanner.Scan() err := scanner.Err() if err != nil && err != io.EOF { return fmt.Errorf("Environment destruction aborted: %s", err) } answer := strings.ToLower(scanner.Text()) if answer != "y" && answer != "yes" { return errors.New("environment destruction aborted") } } // If --force is supplied, then don't attempt to use the API. // This is necessary to destroy broken environments, where the // API server is inaccessible or faulty. if !c.force { defer func() { if result == nil { return } logger.Errorf(`failed to destroy environment %q If the environment is unusable, then you may run juju destroy-environment --force to forcefully destroy the environment. Upon doing so, review your environment provider console for any resources that need to be cleaned up. `, c.envName) }() apiclient, err := juju.NewAPIClientFromName(c.envName) if err != nil { return fmt.Errorf("cannot connect to API: %v", err) } defer apiclient.Close() err = apiclient.DestroyEnvironment() if err != nil && !params.IsCodeNotImplemented(err) { return fmt.Errorf("destroying environment: %v", err) } } return environs.Destroy(environ, store) }
func (c *ResolvedCommand) Run(_ *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() return client.Resolved(c.UnitName, c.Retry) }
// Run connects to the environment specified on the command line // and calls EnsureAvailability. func (c *EnsureAvailabilityCommand) Run(_ *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() return client.EnsureAvailability(c.NumStateServers, c.Constraints, c.Series) }
// TODO(jam): 2013-08-27 This should move somewhere in api.* func (*NewAPIClientSuite) TestMultipleCloseOk(c *gc.C) { defer coretesting.MakeSampleHome(c).Restore() bootstrapEnv(c, "", defaultConfigStore(c)) client, _ := juju.NewAPIClientFromName("") c.Assert(client.Close(), gc.IsNil) c.Assert(client.Close(), gc.IsNil) c.Assert(client.Close(), gc.IsNil) }
func (c *DestroyRelationCommand) Run(_ *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() return client.DestroyRelation(c.Endpoints...) }
// Run changes the juju-managed firewall to hide any // ports that were also explicitly marked by units as closed. func (c *UnexposeCommand) Run(_ *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() return client.ServiceUnexpose(c.ServiceName) }
// Run resets the configuration of a service. func (c *UnsetCommand) Run(ctx *cmd.Context) error { apiclient, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer apiclient.Close() return apiclient.ServiceUnset(c.ServiceName, c.Options) }
// Run connects to the environment specified on the command line and destroys // units therein. func (c *DestroyUnitCommand) Run(_ *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() return client.DestroyServiceUnits(c.UnitNames...) }
func (c *UnsetEnvironmentCommand) Run(ctx *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() return client.EnvironmentUnset(c.keys...) }
func (*NewAPIClientSuite) TestNameNotDefault(c *gc.C) { defer coretesting.MakeMultipleEnvHome(c).Restore() envName := coretesting.SampleCertName + "-2" bootstrapEnv(c, envName, defaultConfigStore(c)) apiclient, err := juju.NewAPIClientFromName(envName) c.Assert(err, gc.IsNil) defer apiclient.Close() assertEnvironmentName(c, apiclient, envName) }
// Run connects to the environment specified on the command line // and calls AddServiceUnits for the given service. func (c *AddUnitCommand) Run(_ *cmd.Context) error { apiclient, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer apiclient.Close() _, err = apiclient.AddServiceUnits(c.ServiceName, c.NumUnits, c.ToMachineSpec) return err }
func (c *DestroyMachineCommand) Run(_ *cmd.Context) error { apiclient, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer apiclient.Close() if c.Force { return apiclient.ForceDestroyMachines(c.MachineIds...) } return apiclient.DestroyMachines(c.MachineIds...) }
// ProvisionMachine provisions a machine agent to an existing host, via // an SSH connection to the specified host. The host may optionally be preceded // with a login username, as in [user@]host. // // On successful completion, this function will return the id of the state.Machine // that was entered into state. func ProvisionMachine(args ProvisionMachineArgs) (machineId string, err error) { client, err := juju.NewAPIClientFromName(args.EnvName) if err != nil { return "", err } defer func() { if machineId != "" && err != nil { logger.Errorf("provisioning failed, removing machine %v: %v", machineId, err) if cleanupErr := client.DestroyMachines(machineId); cleanupErr != nil { logger.Warningf("error cleaning up machine: %s", cleanupErr) } machineId = "" } client.Close() }() // Create the "ubuntu" user and initialise passwordless sudo. We populate // the ubuntu user's authorized_keys file with the public keys in the current // user's ~/.ssh directory. The authenticationworker will later update the // ubuntu user's authorized_keys. user, hostname := splitUserHost(args.Host) authorizedKeys, err := config.ReadAuthorizedKeys("") if err := InitUbuntuUser(hostname, user, authorizedKeys, args.Stdin, args.Stdout); err != nil { return "", err } machineParams, err := gatherMachineParams(hostname) if err != nil { return "", err } // Inform Juju that the machine exists. machineId, err = recordMachineInState(client, *machineParams) if err != nil { return "", err } provisioningScript, err := client.ProvisioningScript(params.ProvisioningScriptParams{ MachineId: machineId, Nonce: machineParams.Nonce, }) if err != nil { return "", err } // Finally, provision the machine agent. err = runProvisionScript(provisioningScript, hostname, args.Stderr) if err != nil { return machineId, err } logger.Infof("Provisioned machine %v", machineId) return machineId, nil }
func (c *SetConstraintsCommand) Run(_ *cmd.Context) (err error) { apiclient, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer apiclient.Close() if c.ServiceName == "" { return apiclient.SetEnvironmentConstraints(c.Constraints) } return apiclient.SetServiceConstraints(c.ServiceName, c.Constraints) }
func (c *RetryProvisioningCommand) Run(context *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() results, err := client.RetryProvisioning(c.Machines...) if err != nil { return err } for i, result := range results { if result.Error != nil { fmt.Fprintf(context.Stderr, "cannot retry provisioning %q: %v\n", c.Machines[i], result.Error) } } return nil }
// Run changes the version proposed for the juju envtools. func (c *UpgradeJujuCommand) Run(_ *cmd.Context) (err error) { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() defer func() { if err == errUpToDate { logger.Infof(err.Error()) err = nil } }() // Determine the version to upgrade to, uploading tools if necessary. attrs, err := client.EnvironmentGet() if err != nil { return err } cfg, err := config.New(config.NoDefaults, attrs) if err != nil { return err } context, err := c.initVersions(client, cfg) if err != nil { return err } if c.UploadTools { series := bootstrap.SeriesToUpload(cfg, c.Series) if err := context.uploadTools(series); err != nil { return err } } if err := context.validate(); err != nil { return err } logger.Infof("upgrade version chosen: %s", context.chosen) // TODO(fwereade): this list may be incomplete, pending envtools.Upload change. logger.Infof("available tools: %s", context.tools) if err := client.SetEnvironAgentVersion(context.chosen); err != nil { return err } logger.Infof("started upgrade to %s", context.chosen) return nil }
// Run updates the configuration of a service. func (c *SetCommand) Run(ctx *cmd.Context) error { api, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer api.Close() if c.SettingsYAML.Path != "" { b, err := c.SettingsYAML.Read(ctx) if err != nil { return err } return api.ServiceSetYAML(c.ServiceName, string(b)) } else if len(c.SettingsStrings) == 0 { return nil } return api.ServiceSet(c.ServiceName, c.SettingsStrings) }
func (c *GetConstraintsCommand) Run(ctx *cmd.Context) error { apiclient, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer apiclient.Close() var cons constraints.Value if c.ServiceName == "" { cons, err = apiclient.GetEnvironmentConstraints() } else { cons, err = apiclient.GetServiceConstraints(c.ServiceName) } if err != nil { return err } return c.out.Write(ctx, cons) }
func (s *NewAPIClientSuite) TestNameDefault(c *gc.C) { defer coretesting.MakeMultipleEnvHome(c).Restore() // The connection logic should not delay the config connection // at all when there is no environment info available. // Make sure of that by providing a suitably long delay // and checking that the connection happens within that // time. s.PatchValue(juju.ProviderConnectDelay, coretesting.LongWait) bootstrapEnv(c, coretesting.SampleEnvName, defaultConfigStore(c)) startTime := time.Now() apiclient, err := juju.NewAPIClientFromName("") c.Assert(err, gc.IsNil) defer apiclient.Close() c.Assert(time.Since(startTime), jc.LessThan, coretesting.LongWait) // We should get the default sample environment if we ask for "" assertEnvironmentName(c, apiclient, coretesting.SampleEnvName) }
// Run fetches the configuration of the service and formats // the result as a YAML string. func (c *GetCommand) Run(ctx *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() results, err := client.ServiceGet(c.ServiceName) if err != nil { return err } resultsMap := map[string]interface{}{ "service": results.Service, "charm": results.Charm, "settings": results.Config, } return c.out.Write(ctx, resultsMap) }
func (c *StatusCommand) Run(ctx *cmd.Context) error { // Just verify the pattern validity client side, do not use the matcher _, err := client.NewUnitMatcher(c.patterns) if err != nil { return err } apiclient, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return fmt.Errorf(connectionError, c.EnvName, err) } defer apiclient.Close() status, err := apiclient.Status(c.patterns) // Display any error, but continue to print status if some was returned if err != nil { fmt.Fprintf(ctx.Stderr, "%v\n", err) } result := formatStatus(status) return c.out.Write(ctx, result) }
func (c *GetEnvironmentCommand) 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 } if c.key != "" { if value, found := attrs[c.key]; found { return c.out.Write(ctx, value) } return fmt.Errorf("Key %q not found in %q environment.", c.key, attrs["name"]) } // If key is empty, write out the whole lot. return c.out.Write(ctx, attrs) }
func (c *AddMachineCommand) Run(ctx *cmd.Context) error { if c.Placement != nil && c.Placement.Scope == "ssh" { args := manual.ProvisionMachineArgs{ Host: c.Placement.Directive, EnvName: c.EnvName, Stdin: ctx.Stdin, Stdout: ctx.Stdout, Stderr: ctx.Stderr, } _, err := manual.ProvisionMachine(args) return err } client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() if c.Placement != nil && c.Placement.Scope == instance.MachineScope { // It does not make sense to add-machine <id>. return fmt.Errorf("machine-id cannot be specified when adding machines") } machineParams := params.AddMachineParams{ Placement: c.Placement, Series: c.Series, Constraints: c.Constraints, Jobs: []params.MachineJob{params.JobHostUnits}, } results, err := client.AddMachines([]params.AddMachineParams{machineParams}) if params.IsCodeNotImplemented(err) { if c.Placement != nil { containerType, parseErr := instance.ParseContainerType(c.Placement.Scope) if parseErr != nil { // The user specified a non-container placement directive: // return original API not implemented error. return err } machineParams.ContainerType = containerType machineParams.ParentId = c.Placement.Directive machineParams.Placement = nil } logger.Infof( "AddMachinesWithPlacement not supported by the API server, " + "falling back to 1.18 compatibility mode", ) results, err = client.AddMachines1dot18([]params.AddMachineParams{machineParams}) } if err != nil { return err } // Currently, only one machine is added, but in future there may be several added in one call. machineInfo := results[0] if machineInfo.Error != nil { return machineInfo.Error } machineId := machineInfo.Machine if names.IsContainerMachine(machineId) { ctx.Infof("created container %v", machineId) } else { ctx.Infof("created machine %v", machineId) } return nil }
// 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) }
if !ok || level < loggo.TRACE || level > loggo.ERROR { return fmt.Errorf("level value %q is not one of %q, %q, %q, %q, %q", c.level, loggo.TRACE, loggo.DEBUG, loggo.INFO, loggo.WARNING, loggo.ERROR) } c.params.Level = level } return cmd.CheckEmpty(args) } type DebugLogAPI interface { WatchDebugLog(params api.DebugLogParams) (io.ReadCloser, error) Close() error } var getDebugLogAPI = func(envName string) (DebugLogAPI, error) { return juju.NewAPIClientFromName(envName) } // Run retrieves the debug log via the API. func (c *DebugLogCommand) Run(ctx *cmd.Context) (err error) { client, err := getDebugLogAPI(c.EnvName) if err != nil { return err } defer client.Close() debugLog, err := client.WatchDebugLog(c.params) if err != nil { if errors.IsNotSupported(err) { return c.watchDebugLog1dot18(ctx) } return err
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 }
result := runResults[0] ctx.Stdout.Write(result.Stdout) ctx.Stderr.Write(result.Stderr) if result.Error != "" { // Convert the error string back into an error object. return fmt.Errorf("%s", result.Error) } if result.Code != 0 { return cmd.NewRcPassthroughError(result.Code) } return nil } c.out.Write(ctx, ConvertRunResults(runResults)) return nil } // In order to be able to easily mock out the API side for testing, // the API client is got using a function. type RunClient interface { Close() error RunOnAllMachines(commands string, timeout time.Duration) ([]params.RunResult, error) Run(run params.RunParams) ([]params.RunResult, error) } // Here we need the signature to be correct for the interface. var getAPIClient = func(name string) (RunClient, error) { return juju.NewAPIClientFromName(name) }