func (s *apiEnvironmentSuite) SetUpTest(c *gc.C) { s.JujuConnSuite.SetUpTest(c) var err error s.client, err = juju.NewAPIClientFromName("", nil) c.Assert(err, jc.ErrorIsNil) c.Assert(s.client, gc.NotNil) }
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 *RemoveServiceCommand) Run(_ *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() return client.ServiceDestroy(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) }
// TODO(jam): 2013-08-27 This should move somewhere in api.* func (s *NewAPIClientSuite) TestMultipleCloseOk(c *gc.C) { coretesting.MakeSampleJujuHome(c) 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 *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) }
// Run connects to the environment specified on the command line and destroys // units therein. func (c *RemoveUnitCommand) 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 *RemoveRelationCommand) Run(_ *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() return client.DestroyRelation(c.Endpoints...) }
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 (s *NewAPIClientSuite) TestNameNotDefault(c *gc.C) { envName := coretesting.SampleCertName + "-2" coretesting.WriteEnvironments(c, coretesting.MultipleEnvConfig, envName) s.bootstrapEnv(c, envName, defaultConfigStore(c)) apiclient, err := juju.NewAPIClientFromName(envName) c.Assert(err, jc.ErrorIsNil) defer apiclient.Close() assertEnvironmentName(c, apiclient, envName) }
func (c *AddRelationCommand) Run(_ *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() _, err = client.AddRelation(c.Endpoints...) return err }
// 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 *RemoveMachineCommand) 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) }
// Run changes the version proposed for the juju envtools. func (c *UpgradeJujuCommand) Run(ctx *cmd.Context) (err error) { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() defer func() { if err == errUpToDate { ctx.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 !c.DryRun { if err := context.uploadTools(series); err != nil { return err } } } if err := context.validate(); err != nil { return err } // TODO(fwereade): this list may be incomplete, pending envtools.Upload change. ctx.Infof("available tools:\n%s", formatTools(context.tools)) ctx.Infof("best version:\n %s", context.chosen) if c.DryRun { ctx.Infof("upgrade to this version by running\n juju upgrade-juju --version=\"%s\"\n", context.chosen) } else { if err := client.SetEnvironAgentVersion(context.chosen); err != nil { return err } logger.Infof("started upgrade to %s", context.chosen) } return nil }
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 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) }
// 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 (s *NewAPIClientSuite) TestNameDefault(c *gc.C) { coretesting.WriteEnvironments(c, coretesting.MultipleEnvConfig) // 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) s.bootstrapEnv(c, coretesting.SampleEnvName, defaultConfigStore(c)) startTime := time.Now() apiclient, err := juju.NewAPIClientFromName("") c.Assert(err, jc.ErrorIsNil) 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) }
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) }
// Run connects to the environment specified on the command line // and calls EnsureAvailability. func (c *EnsureAvailabilityCommand) Run(ctx *cmd.Context) error { client, err := juju.NewAPIClientFromName(c.EnvName) if err != nil { return err } defer client.Close() ensureAvailabilityResult, err := client.EnsureAvailability(c.NumStateServers, c.Constraints, c.Series) if err != nil { return err } result := availabilityInfo{ Added: machineTagsToIds(ensureAvailabilityResult.Added...), Removed: machineTagsToIds(ensureAvailabilityResult.Removed...), Maintained: machineTagsToIds(ensureAvailabilityResult.Maintained...), Promoted: machineTagsToIds(ensureAvailabilityResult.Promoted...), Demoted: machineTagsToIds(ensureAvailabilityResult.Demoted...), } 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) }
// 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 } settings := map[string]string{} for k, v := range c.SettingsStrings { if v[0] != '@' { if !utf8.ValidString(v) { return fmt.Errorf("value for option %q contains non-UTF-8 sequences", k) } settings[k] = v continue } nv, err := readValue(ctx, v[1:]) if err != nil { return err } if !utf8.ValidString(nv) { return fmt.Errorf("value for option %q contains non-UTF-8 sequences", k) } settings[k] = nv } return api.ServiceSet(c.ServiceName, settings) }
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 }
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.") } requestedNetworks, err := networkNamesToTags(parseNetworks(c.Networks)) if err != nil { return err } // We need to ensure network names are valid below, but we don't need them here. _, err = networkNamesToTags(c.Constraints.IncludeNetworks()) if err != nil { return err } _, err = networkNamesToTags(c.Constraints.ExcludeNetworks()) if err != nil { return err } haveNetworks := len(requestedNetworks) > 0 || c.Constraints.HaveNetworks() 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, requestedNetworks, ) if params.IsCodeNotImplemented(err) { if haveNetworks { return errors.New("cannot use --networks/--constraints 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) }
// 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) }