本文整理汇总了Golang中github.com/juju/cmd.Context.Verbosef方法的典型用法代码示例。如果您正苦于以下问题:Golang Context.Verbosef方法的具体用法?Golang Context.Verbosef怎么用?Golang Context.Verbosef使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类github.com/juju/cmd.Context
的用法示例。
在下文中一共展示了Context.Verbosef方法的12个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Golang代码示例。
示例1: WaitForModels
// WaitForModels will wait for the models to bring themselves down nicely.
// It will return the UUIDs of any models that need to be removed forceably.
func (c *killCommand) WaitForModels(ctx *cmd.Context, api destroyControllerAPI, uuid string) error {
thirtySeconds := (time.Second * 30)
updateStatus := newTimedStatusUpdater(ctx, api, uuid, c.clock)
ctrStatus, modelsStatus := updateStatus(0)
lastStatus := ctrStatus
lastChange := c.clock.Now().Truncate(time.Second)
deadline := lastChange.Add(c.timeout)
for ; hasUnDeadModels(modelsStatus) && (deadline.After(c.clock.Now())); ctrStatus, modelsStatus = updateStatus(5 * time.Second) {
now := c.clock.Now().Truncate(time.Second)
if ctrStatus != lastStatus {
lastStatus = ctrStatus
lastChange = now
deadline = lastChange.Add(c.timeout)
}
timeSinceLastChange := now.Sub(lastChange)
timeUntilDestruction := deadline.Sub(now)
warning := ""
// We want to show the warning if it has been more than 30 seconds since
// the last change, or we are within 30 seconds of our timeout.
if timeSinceLastChange > thirtySeconds || timeUntilDestruction < thirtySeconds {
warning = fmt.Sprintf(", will kill machines directly in %s", timeUntilDestruction)
}
ctx.Infof("%s%s", fmtCtrStatus(ctrStatus), warning)
for _, modelStatus := range modelsStatus {
ctx.Verbosef(fmtModelStatus(modelStatus))
}
}
if hasUnDeadModels(modelsStatus) {
return errors.New("timed out")
} else {
ctx.Infof("All hosted models reclaimed, cleaning up controller machines")
}
return nil
}
示例2: Run
// Run implements Command.Run
func (c *destroyCommand) Run(ctx *cmd.Context) error {
store, err := configstore.Default()
if err != nil {
return errors.Annotate(err, "cannot open controller info storage")
}
cfgInfo, err := store.ReadInfo(c.ModelName())
if err != nil {
return errors.Annotate(err, "cannot read controller info")
}
// Verify that we're destroying a controller
apiEndpoint := cfgInfo.APIEndpoint()
if apiEndpoint.ServerUUID != "" && apiEndpoint.ModelUUID != apiEndpoint.ServerUUID {
return errors.Errorf("%q is not a controller; use juju model destroy to destroy it", c.ModelName())
}
if !c.assumeYes {
if err = confirmDestruction(ctx, c.ModelName()); err != nil {
return err
}
}
// Attempt to connect to the API. If we can't, fail the destroy. Users will
// need to use the controller kill command if we can't connect.
api, err := c.getControllerAPI()
if err != nil {
return c.ensureUserFriendlyErrorLog(errors.Annotate(err, "cannot connect to API"), ctx, nil)
}
defer api.Close()
// Obtain bootstrap / controller environ information
controllerEnviron, err := c.getControllerEnviron(cfgInfo, api)
if err != nil {
return errors.Annotate(err, "cannot obtain bootstrap information")
}
// Attempt to destroy the controller.
err = api.DestroyController(c.destroyEnvs)
if err != nil {
return c.ensureUserFriendlyErrorLog(errors.Annotate(err, "cannot destroy controller"), ctx, api)
}
ctx.Infof("Destroying controller %q", c.ModelName())
if c.destroyEnvs {
ctx.Infof("Waiting for hosted model resources to be reclaimed.")
updateStatus := newTimedStatusUpdater(ctx, api, apiEndpoint.ModelUUID)
for ctrStatus, envsStatus := updateStatus(0); hasUnDeadEnvirons(envsStatus); ctrStatus, envsStatus = updateStatus(2 * time.Second) {
ctx.Infof(fmtCtrStatus(ctrStatus))
for _, envStatus := range envsStatus {
ctx.Verbosef(fmtEnvStatus(envStatus))
}
}
ctx.Infof("All hosted models reclaimed, cleaning up controller machines")
}
return environs.Destroy(controllerEnviron, store)
}
示例3: Run
// Run implements Command.Run
func (c *killCommand) Run(ctx *cmd.Context) error {
controllerName := c.ControllerName()
store := c.ClientStore()
if !c.assumeYes {
if err := confirmDestruction(ctx, controllerName); err != nil {
return err
}
}
// Attempt to connect to the API.
api, err := c.getControllerAPI()
switch {
case err == nil:
defer api.Close()
case errors.Cause(err) == common.ErrPerm:
return errors.Annotate(err, "cannot destroy controller")
default:
if errors.Cause(err) != modelcmd.ErrConnTimedOut {
logger.Debugf("unable to open api: %s", err)
}
ctx.Infof("Unable to open API: %s\n", err)
api = nil
}
// Obtain controller environ so we can clean up afterwards.
controllerEnviron, err := c.getControllerEnviron(ctx, store, controllerName, api)
if err != nil {
return errors.Annotate(err, "getting controller environ")
}
// If we were unable to connect to the API, just destroy the controller through
// the environs interface.
if api == nil {
ctx.Infof("Unable to connect to the API server. Destroying through provider.")
return environs.Destroy(controllerName, controllerEnviron, store)
}
// Attempt to destroy the controller and all environments.
err = api.DestroyController(true)
if err != nil {
ctx.Infof("Unable to destroy controller through the API: %s. Destroying through provider.", err)
return environs.Destroy(controllerName, controllerEnviron, store)
}
ctx.Infof("Destroying controller %q\nWaiting for resources to be reclaimed", controllerName)
updateStatus := newTimedStatusUpdater(ctx, api, controllerEnviron.Config().UUID())
for ctrStatus, envsStatus := updateStatus(0); hasUnDeadModels(envsStatus); ctrStatus, envsStatus = updateStatus(2 * time.Second) {
ctx.Infof(fmtCtrStatus(ctrStatus))
for _, envStatus := range envsStatus {
ctx.Verbosef(fmtModelStatus(envStatus))
}
}
ctx.Infof("All hosted models reclaimed, cleaning up controller machines")
return environs.Destroy(controllerName, controllerEnviron, store)
}
示例4: WaitForAgentInitialisation
// WaitForAgentInitialisation polls the bootstrapped controller with a read-only
// command which will fail until the controller is fully initialised.
// TODO(wallyworld) - add a bespoke command to maybe the admin facade for this purpose.
func WaitForAgentInitialisation(ctx *cmd.Context, c *modelcmd.ModelCommandBase, controllerName, hostedModelName string) error {
// TODO(katco): 2016-08-09: lp:1611427
attempts := utils.AttemptStrategy{
Min: bootstrapReadyPollCount,
Delay: bootstrapReadyPollDelay,
}
var (
apiAttempts int
err error
)
// Make a best effort to find the new controller address so we can print it.
addressInfo := ""
controller, err := c.ClientStore().ControllerByName(controllerName)
if err == nil && len(controller.APIEndpoints) > 0 {
addr, err := network.ParseHostPort(controller.APIEndpoints[0])
if err == nil {
addressInfo = fmt.Sprintf(" at %s", addr.Address.Value)
}
}
ctx.Infof("Contacting Juju controller%s to verify accessibility...", addressInfo)
apiAttempts = 1
for attempt := attempts.Start(); attempt.Next(); apiAttempts++ {
err = tryAPI(c)
if err == nil {
ctx.Infof("Bootstrap complete, %q controller now available.", controllerName)
ctx.Infof("Controller machines are in the %q model.", bootstrap.ControllerModelName)
ctx.Infof("Initial model %q added.", hostedModelName)
break
}
// As the API server is coming up, it goes through a number of steps.
// Initially the upgrade steps run, but the api server allows some
// calls to be processed during the upgrade, but not the list blocks.
// Logins are also blocked during space discovery.
// It is also possible that the underlying database causes connections
// to be dropped as it is initialising, or reconfiguring. These can
// lead to EOF or "connection is shut down" error messages. We skip
// these too, hoping that things come back up before the end of the
// retry poll count.
errorMessage := errors.Cause(err).Error()
switch {
case errors.Cause(err) == io.EOF,
strings.HasSuffix(errorMessage, "connection is shut down"),
strings.HasSuffix(errorMessage, "no api connection available"),
strings.Contains(errorMessage, "spaces are still being discovered"):
ctx.Verbosef("Still waiting for API to become available")
continue
case params.ErrCode(err) == params.CodeUpgradeInProgress:
ctx.Verbosef("Still waiting for API to become available: %v", err)
continue
}
break
}
return errors.Annotatef(err, "unable to contact api server after %d attempts", apiAttempts)
}
示例5: Run
// Run implements Command.Run
func (c *destroyCommand) Run(ctx *cmd.Context) error {
controllerName := c.ControllerName()
store := c.ClientStore()
controllerDetails, err := store.ControllerByName(controllerName)
if err != nil {
return errors.Annotate(err, "cannot read controller info")
}
if !c.assumeYes {
if err = confirmDestruction(ctx, c.ControllerName()); err != nil {
return err
}
}
// Attempt to connect to the API. If we can't, fail the destroy. Users will
// need to use the controller kill command if we can't connect.
api, err := c.getControllerAPI()
if err != nil {
return c.ensureUserFriendlyErrorLog(errors.Annotate(err, "cannot connect to API"), ctx, nil)
}
defer api.Close()
// Obtain controller environ so we can clean up afterwards.
controllerEnviron, err := c.getControllerEnviron(store, controllerName, api)
if err != nil {
return errors.Annotate(err, "getting controller environ")
}
// Attempt to destroy the controller.
err = api.DestroyController(c.destroyModels)
if err != nil {
return c.ensureUserFriendlyErrorLog(errors.Annotate(err, "cannot destroy controller"), ctx, api)
}
ctx.Infof("Destroying controller %q", c.ControllerName())
if c.destroyModels {
ctx.Infof("Waiting for hosted model resources to be reclaimed.")
updateStatus := newTimedStatusUpdater(ctx, api, controllerDetails.ControllerUUID)
for ctrStatus, modelsStatus := updateStatus(0); hasUnDeadModels(modelsStatus); ctrStatus, modelsStatus = updateStatus(2 * time.Second) {
ctx.Infof(fmtCtrStatus(ctrStatus))
for _, model := range modelsStatus {
ctx.Verbosef(fmtModelStatus(model))
}
}
ctx.Infof("All hosted models reclaimed, cleaning up controller machines")
}
return environs.Destroy(c.ControllerName(), controllerEnviron, store)
}
示例6: watchDebugLog1dot18
// watchDebugLog1dot18 runs in case of an older API server and uses ssh
// but with server-side grep.
func (c *DebugLogCommand) watchDebugLog1dot18(ctx *cmd.Context) error {
ctx.Infof("Server does not support new stream log, falling back to tail")
ctx.Verbosef("filters are not supported with tail")
sshCmd := &SSHCommand{}
tailCmd := fmt.Sprintf("tail -n -%d -f %s", c.params.Backlog, DefaultLogLocation)
// If the api doesn't support WatchDebugLog, then it won't be running in
// HA either, so machine 0 is where it is all at.
args := []string{"0", tailCmd}
err := sshCmd.Init(args)
if err != nil {
return err
}
sshCmd.EnvName = c.EnvName
return runSSHCommand(sshCmd, ctx)
}
示例7: ReadAuthorizedKeys
// ReadAuthorizedKeys implements the standard juju behaviour for finding
// authorized_keys. It returns a set of keys in in authorized_keys format
// (see sshd(8) for a description). If path is non-empty, it names the
// file to use; otherwise the user's .ssh directory will be searched.
// Home directory expansion will be performed on the path if it starts with
// a ~; if the expanded path is relative, it will be interpreted relative
// to $HOME/.ssh.
//
// The result of utils/ssh.PublicKeyFiles will always be prepended to the
// result. In practice, this means ReadAuthorizedKeys never returns an
// error when the call originates in the CLI.
//
// If no SSH keys are found, ReadAuthorizedKeys returns
// ErrNoAuthorizedKeys.
func ReadAuthorizedKeys(ctx *cmd.Context, path string) (string, error) {
files := ssh.PublicKeyFiles()
if path == "" {
files = append(files, "id_dsa.pub", "id_rsa.pub", "identity.pub")
} else {
files = append(files, path)
}
var firstError error
var keyData []byte
for _, f := range files {
f, err := utils.NormalizePath(f)
if err != nil {
if firstError == nil {
firstError = err
}
continue
}
if !filepath.IsAbs(f) {
f = filepath.Join(utils.Home(), ".ssh", f)
}
data, err := ioutil.ReadFile(f)
if err != nil {
if firstError == nil && !os.IsNotExist(err) {
firstError = err
}
continue
}
keyData = append(keyData, bytes.Trim(data, "\n")...)
keyData = append(keyData, '\n')
ctx.Verbosef("Adding contents of %q to authorized-keys", f)
}
if len(keyData) == 0 {
if firstError == nil {
firstError = ErrNoAuthorizedKeys
}
return "", firstError
}
return string(keyData), nil
}
示例8: Run
// Run connects to the environment specified on the command line and bootstraps
// a juju in that environment if none already exists. If there is as yet no environments.yaml file,
// the user is informed how to create one.
func (c *bootstrapCommand) Run(ctx *cmd.Context) (resultErr error) {
bootstrapFuncs := getBootstrapFuncs()
// Get the cloud definition identified by c.Cloud. If c.Cloud does not
// identify a cloud in clouds.yaml, but is the name of a provider, and
// that provider implements environs.CloudRegionDetector, we'll
// synthesise a Cloud structure with the detected regions and no auth-
// types.
cloud, err := jujucloud.CloudByName(c.Cloud)
if errors.IsNotFound(err) {
ctx.Verbosef("cloud %q not found, trying as a provider name", c.Cloud)
provider, err := environs.Provider(c.Cloud)
if errors.IsNotFound(err) {
return errors.NewNotFound(nil, fmt.Sprintf("unknown cloud %q, please try %q", c.Cloud, "juju update-clouds"))
} else if err != nil {
return errors.Trace(err)
}
detector, ok := provider.(environs.CloudRegionDetector)
if !ok {
ctx.Verbosef(
"provider %q does not support detecting regions",
c.Cloud,
)
return errors.NewNotFound(nil, fmt.Sprintf("unknown cloud %q, please try %q", c.Cloud, "juju update-clouds"))
}
regions, err := detector.DetectRegions()
if err != nil && !errors.IsNotFound(err) {
// It's not an error to have no regions.
return errors.Annotatef(err,
"detecting regions for %q cloud provider",
c.Cloud,
)
}
cloud = &jujucloud.Cloud{
Type: c.Cloud,
Regions: regions,
}
} else if err != nil {
return errors.Trace(err)
}
if err := checkProviderType(cloud.Type); errors.IsNotFound(err) {
// This error will get handled later.
} else if err != nil {
return errors.Trace(err)
}
// Get the credentials and region name.
store := c.ClientStore()
credential, credentialName, regionName, err := modelcmd.GetCredentials(
store, c.Region, c.CredentialName, c.Cloud, cloud.Type,
)
if errors.IsNotFound(err) && c.CredentialName == "" {
// No credential was explicitly specified, and no credential
// was found in credentials.yaml; have the provider detect
// credentials from the environment.
ctx.Verbosef("no credentials found, checking environment")
detected, err := modelcmd.DetectCredential(c.Cloud, cloud.Type)
if errors.Cause(err) == modelcmd.ErrMultipleCredentials {
return ambiguousCredentialError
} else if err != nil {
return errors.Trace(err)
}
// We have one credential so extract it from the map.
var oneCredential jujucloud.Credential
for _, oneCredential = range detected.AuthCredentials {
}
credential = &oneCredential
regionName = c.Region
if regionName == "" {
regionName = detected.DefaultRegion
}
logger.Tracef("authenticating with region %q and %v", regionName, credential)
} else if err != nil {
return errors.Trace(err)
}
region, err := getRegion(cloud, c.Cloud, regionName)
if err != nil {
return errors.Trace(err)
}
hostedModelUUID, err := utils.NewUUID()
if err != nil {
return errors.Trace(err)
}
controllerUUID, err := utils.NewUUID()
if err != nil {
return errors.Trace(err)
}
// Create an environment config from the cloud and credentials.
configAttrs := map[string]interface{}{
"type": cloud.Type,
"name": environs.ControllerModelName,
config.UUIDKey: controllerUUID.String(),
config.ControllerUUIDKey: controllerUUID.String(),
}
//.........这里部分代码省略.........
示例9: Run
//.........这里部分代码省略.........
// Warn of incompatible CLI and filter on the prior major version
// when searching for available tools.
// TODO(cherylj) Add in a suggestion to upgrade to 2.0 if
// no matching tools are found (bug 1532670)
warnCompat = true
break
}
// User requested an upgrade to the next major version.
// Fallthrough to the next case to verify that the upgrade
// conditions are met.
fallthrough
case c.Version.Major > agentVersion.Major:
// User is requesting an upgrade to a new major number
// Only upgrade to a different major number if:
// 1 - Explicitly requested with --agent-version or using --build-agent, and
// 2 - The environment is running a valid version to upgrade from, and
// 3 - The upgrade is to a minor version of 0.
minVer, ok := c.minMajorUpgradeVersion[c.Version.Major]
if !ok {
return errors.Errorf("unknown version %q", c.Version)
}
retErr := false
if c.Version.Minor != 0 {
ctx.Infof("upgrades to %s must first go through juju %d.0",
c.Version, c.Version.Major)
retErr = true
}
if comp := agentVersion.Compare(minVer); comp < 0 {
ctx.Infof("upgrades to a new major version must first go through %s",
minVer)
retErr = true
}
if retErr {
return errors.New("unable to upgrade to requested version")
}
}
context, err := c.initVersions(client, cfg, agentVersion, warnCompat)
if err != nil {
return err
}
// If we're running a custom build or the user has asked for a new agent
// to be built, upload a local jujud binary if possible.
uploadLocalBinary := isControllerModel && c.Version == version.Zero && tryImplicitUpload(agentVersion)
if !warnCompat && (uploadLocalBinary || c.BuildAgent) && !c.DryRun {
if err := context.uploadTools(c.BuildAgent); err != nil {
// If we've explicitly asked to build an agent binary, or the upload failed
// because changes were blocked, we'll return an error.
if err2 := block.ProcessBlockedError(err, block.BlockChange); c.BuildAgent || err2 == cmd.ErrSilent {
return err2
}
}
builtMsg := ""
if c.BuildAgent {
builtMsg = " (built from source)"
}
fmt.Fprintf(ctx.Stdout, "no prepackaged tools available, using local agent binary %v%s\n", context.chosen, builtMsg)
}
// If there was an error implicitly uploading a binary, we'll still look for any packaged binaries
// since there may still be a valid upgrade and the user didn't ask for any local binary.
if err := context.validate(); err != nil {
return err
}
// TODO(fwereade): this list may be incomplete, pending envtools.Upload change.
ctx.Verbosef("available tools:\n%s", formatTools(context.tools))
ctx.Verbosef("best version:\n %s", context.chosen)
if warnCompat {
fmt.Fprintf(ctx.Stderr, "version %s incompatible with this client (%s)\n", context.chosen, jujuversion.Current)
}
if c.DryRun {
fmt.Fprintf(ctx.Stderr, "upgrade to this version by running\n juju upgrade-juju --agent-version=\"%s\"\n", context.chosen)
} else {
if c.ResetPrevious {
if ok, err := c.confirmResetPreviousUpgrade(ctx); !ok || err != nil {
const message = "previous upgrade not reset and no new upgrade triggered"
if err != nil {
return errors.Annotate(err, message)
}
return errors.New(message)
}
if err := client.AbortCurrentUpgrade(); err != nil {
return block.ProcessBlockedError(err, block.BlockChange)
}
}
if err := client.SetModelAgentVersion(context.chosen); err != nil {
if params.IsCodeUpgradeInProgress(err) {
return errors.Errorf("%s\n\n"+
"Please wait for the upgrade to complete or if there was a problem with\n"+
"the last upgrade that has been resolved, consider running the\n"+
"upgrade-juju command with the --reset-previous-upgrade flag.", err,
)
} else {
return block.ProcessBlockedError(err, block.BlockChange)
}
}
fmt.Fprintf(ctx.Stdout, "started upgrade to %s\n", context.chosen)
}
return nil
}
示例10: Run
// Run connects to the environment specified on the command line and bootstraps
// a juju in that environment if none already exists. If there is as yet no environments.yaml file,
// the user is informed how to create one.
func (c *bootstrapCommand) Run(ctx *cmd.Context) (resultErr error) {
if err := c.parseConstraints(ctx); err != nil {
return err
}
if c.BootstrapImage != "" {
if c.BootstrapSeries == "" {
return errors.Errorf("--bootstrap-image must be used with --bootstrap-series")
}
cons, err := constraints.Merge(c.Constraints, c.BootstrapConstraints)
if err != nil {
return errors.Trace(err)
}
if !cons.HasArch() {
return errors.Errorf("--bootstrap-image must be used with --bootstrap-constraints, specifying architecture")
}
}
if c.interactive {
if err := c.runInteractive(ctx); err != nil {
return errors.Trace(err)
}
// now run normal bootstrap using info gained above.
}
if c.showClouds {
return printClouds(ctx, c.ClientStore())
}
if c.showRegionsForCloud != "" {
return printCloudRegions(ctx, c.showRegionsForCloud)
}
bootstrapFuncs := getBootstrapFuncs()
// Get the cloud definition identified by c.Cloud. If c.Cloud does not
// identify a cloud in clouds.yaml, but is the name of a provider, and
// that provider implements environs.CloudRegionDetector, we'll
// synthesise a Cloud structure with the detected regions and no auth-
// types.
cloud, err := jujucloud.CloudByName(c.Cloud)
if errors.IsNotFound(err) {
ctx.Verbosef("cloud %q not found, trying as a provider name", c.Cloud)
provider, err := environs.Provider(c.Cloud)
if errors.IsNotFound(err) {
return errors.NewNotFound(nil, fmt.Sprintf("unknown cloud %q, please try %q", c.Cloud, "juju update-clouds"))
} else if err != nil {
return errors.Trace(err)
}
detector, ok := bootstrapFuncs.CloudRegionDetector(provider)
if !ok {
ctx.Verbosef(
"provider %q does not support detecting regions",
c.Cloud,
)
return errors.NewNotFound(nil, fmt.Sprintf("unknown cloud %q, please try %q", c.Cloud, "juju update-clouds"))
}
var cloudEndpoint string
regions, err := detector.DetectRegions()
if errors.IsNotFound(err) {
// It's not an error to have no regions. If the
// provider does not support regions, then we
// reinterpret the supplied region name as the
// cloud's endpoint. This enables the user to
// supply, for example, maas/<IP> or manual/<IP>.
if c.Region != "" {
ctx.Verbosef("interpreting %q as the cloud endpoint", c.Region)
cloudEndpoint = c.Region
c.Region = ""
}
} else if err != nil {
return errors.Annotatef(err,
"detecting regions for %q cloud provider",
c.Cloud,
)
}
schemas := provider.CredentialSchemas()
authTypes := make([]jujucloud.AuthType, 0, len(schemas))
for authType := range schemas {
authTypes = append(authTypes, authType)
}
// Since we are iterating over a map, lets sort the authTypes so
// they are always in a consistent order.
sort.Sort(jujucloud.AuthTypes(authTypes))
cloud = &jujucloud.Cloud{
Type: c.Cloud,
AuthTypes: authTypes,
Endpoint: cloudEndpoint,
Regions: regions,
}
} else if err != nil {
return errors.Trace(err)
}
if err := checkProviderType(cloud.Type); errors.IsNotFound(err) {
// This error will get handled later.
} else if err != nil {
return errors.Trace(err)
}
provider, err := environs.Provider(cloud.Type)
if err != nil {
//.........这里部分代码省略.........
示例11: Run
// Run implements Command.Run
func (c *killCommand) Run(ctx *cmd.Context) error {
store, err := configstore.Default()
if err != nil {
return errors.Annotate(err, "cannot open controller info storage")
}
cfgInfo, err := store.ReadInfo(c.ModelName())
if err != nil {
return errors.Annotate(err, "cannot read controller info")
}
// Verify that we're destroying a controller
apiEndpoint := cfgInfo.APIEndpoint()
if apiEndpoint.ServerUUID != "" && apiEndpoint.ModelUUID != apiEndpoint.ServerUUID {
return errors.Errorf("%q is not a controller; use juju model destroy to destroy it", c.ModelName())
}
if !c.assumeYes {
if err = confirmDestruction(ctx, c.ModelName()); err != nil {
return err
}
}
// Attempt to connect to the API.
api, err := c.getControllerAPI()
switch {
case err == nil:
defer api.Close()
case errors.Cause(err) == common.ErrPerm:
return errors.Annotate(err, "cannot destroy controller")
default:
if errors.Cause(err) != modelcmd.ErrConnTimedOut {
logger.Debugf("unable to open api: %s", err)
}
ctx.Infof("Unable to open API: %s\n", err)
api = nil
}
// Obtain bootstrap / controller environ information
controllerEnviron, err := c.getControllerEnviron(cfgInfo, api)
if err != nil {
return errors.Annotate(err, "cannot obtain bootstrap information")
}
// If we were unable to connect to the API, just destroy the controller through
// the environs interface.
if api == nil {
ctx.Infof("Unable to connect to the API server. Destroying through provider.")
return environs.Destroy(controllerEnviron, store)
}
// Attempt to destroy the controller and all environments.
err = api.DestroyController(true)
if err != nil {
ctx.Infof("Unable to destroy controller through the API: %s. Destroying through provider.", err)
return environs.Destroy(controllerEnviron, store)
}
ctx.Infof("Destroying controller %q\nWaiting for resources to be reclaimed", c.ModelName())
updateStatus := newTimedStatusUpdater(ctx, api, apiEndpoint.ModelUUID)
for ctrStatus, envsStatus := updateStatus(0); hasUnDeadEnvirons(envsStatus); ctrStatus, envsStatus = updateStatus(2 * time.Second) {
ctx.Infof(fmtCtrStatus(ctrStatus))
for _, envStatus := range envsStatus {
ctx.Verbosef(fmtEnvStatus(envStatus))
}
}
ctx.Infof("All hosted models reclaimed, cleaning up controller machines")
return environs.Destroy(controllerEnviron, store)
}
示例12: Run
// Run implements Command.Run
func (c *destroyCommand) Run(ctx *cmd.Context) error {
controllerName := c.ControllerName()
store := c.ClientStore()
if !c.assumeYes {
if err := confirmDestruction(ctx, c.ControllerName()); err != nil {
return err
}
}
// Attempt to connect to the API. If we can't, fail the destroy. Users will
// need to use the controller kill command if we can't connect.
api, err := c.getControllerAPI()
if err != nil {
return c.ensureUserFriendlyErrorLog(errors.Annotate(err, "cannot connect to API"), ctx, nil)
}
defer api.Close()
// Obtain controller environ so we can clean up afterwards.
controllerEnviron, err := c.getControllerEnviron(ctx, store, controllerName, api)
if err != nil {
return errors.Annotate(err, "getting controller environ")
}
for {
// Attempt to destroy the controller.
ctx.Infof("Destroying controller")
var hasHostedModels bool
err = api.DestroyController(c.destroyModels)
if err != nil {
if params.IsCodeHasHostedModels(err) {
hasHostedModels = true
} else {
return c.ensureUserFriendlyErrorLog(
errors.Annotate(err, "cannot destroy controller"),
ctx, api,
)
}
}
updateStatus := newTimedStatusUpdater(ctx, api, controllerEnviron.Config().UUID(), clock.WallClock)
ctrStatus, modelsStatus := updateStatus(0)
if !c.destroyModels {
if err := c.checkNoAliveHostedModels(ctx, modelsStatus); err != nil {
return errors.Trace(err)
}
if hasHostedModels && !hasUnDeadModels(modelsStatus) {
// When we called DestroyController before, we were
// informed that there were hosted models remaining.
// When we checked just now, there were none. We should
// try destroying again.
continue
}
}
// Even if we've not just requested for hosted models to be destroyed,
// there may be some being destroyed already. We need to wait for them.
ctx.Infof("Waiting for hosted model resources to be reclaimed")
for ; hasUnDeadModels(modelsStatus); ctrStatus, modelsStatus = updateStatus(2 * time.Second) {
ctx.Infof(fmtCtrStatus(ctrStatus))
for _, model := range modelsStatus {
ctx.Verbosef(fmtModelStatus(model))
}
}
ctx.Infof("All hosted models reclaimed, cleaning up controller machines")
return environs.Destroy(c.ControllerName(), controllerEnviron, store)
}
}