github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/commands/main.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package commands
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"os/exec"
    10  	"strings"
    11  
    12  	"github.com/juju/cmd"
    13  	"github.com/juju/loggo"
    14  	"github.com/juju/utils/featureflag"
    15  	utilsos "github.com/juju/utils/os"
    16  	"github.com/juju/utils/series"
    17  	"github.com/juju/version"
    18  
    19  	jujucmd "github.com/juju/juju/cmd"
    20  	"github.com/juju/juju/cmd/juju/action"
    21  	"github.com/juju/juju/cmd/juju/application"
    22  	"github.com/juju/juju/cmd/juju/backups"
    23  	"github.com/juju/juju/cmd/juju/block"
    24  	"github.com/juju/juju/cmd/juju/cachedimages"
    25  	"github.com/juju/juju/cmd/juju/charmcmd"
    26  	"github.com/juju/juju/cmd/juju/cloud"
    27  	"github.com/juju/juju/cmd/juju/controller"
    28  	"github.com/juju/juju/cmd/juju/gui"
    29  	"github.com/juju/juju/cmd/juju/machine"
    30  	"github.com/juju/juju/cmd/juju/metricsdebug"
    31  	"github.com/juju/juju/cmd/juju/model"
    32  	rcmd "github.com/juju/juju/cmd/juju/romulus/commands"
    33  	"github.com/juju/juju/cmd/juju/setmeterstatus"
    34  	"github.com/juju/juju/cmd/juju/space"
    35  	"github.com/juju/juju/cmd/juju/status"
    36  	"github.com/juju/juju/cmd/juju/storage"
    37  	"github.com/juju/juju/cmd/juju/subnet"
    38  	"github.com/juju/juju/cmd/juju/user"
    39  	"github.com/juju/juju/cmd/modelcmd"
    40  	"github.com/juju/juju/feature"
    41  	"github.com/juju/juju/juju"
    42  	"github.com/juju/juju/juju/osenv"
    43  	"github.com/juju/juju/jujuclient"
    44  	jujuversion "github.com/juju/juju/version"
    45  	// Import the providers.
    46  	_ "github.com/juju/juju/provider/all"
    47  )
    48  
    49  var logger = loggo.GetLogger("juju.cmd.juju.commands")
    50  
    51  func init() {
    52  	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
    53  }
    54  
    55  // TODO(ericsnow) Move the following to cmd/juju/main.go:
    56  //  jujuDoc
    57  //  Main
    58  
    59  var jujuDoc = `
    60  juju provides easy, intelligent application orchestration on top of cloud
    61  infrastructure providers such as Amazon EC2, MaaS, OpenStack, Windows, Azure,
    62  or your local machine.
    63  
    64  https://jujucharms.com/
    65  `
    66  
    67  const juju1xCmdName = "juju-1"
    68  
    69  var usageHelp = `
    70  Usage: juju [help] <command>
    71  
    72  Summary:
    73  Juju is model & application management software designed to leverage the power
    74  of existing resource pools, particularly cloud-based ones. It has built-in
    75  support for cloud providers such as Amazon EC2, Google GCE, Microsoft
    76  Azure, OpenStack, and Rackspace. It also works very well with MAAS and
    77  LXD. Juju allows for easy installation and management of workloads on a
    78  chosen resource pool.
    79  
    80  See https://jujucharms.com/docs/stable/help for documentation.
    81  
    82  Common commands:
    83  
    84      add-cloud           Adds a user-defined cloud to Juju.
    85      add-credential      Adds or replaces credentials for a cloud.
    86      add-model           Adds a hosted model.
    87      add-relation        Adds a relation between two applications.
    88      add-unit            Adds extra units of a deployed application.
    89      add-user            Adds a Juju user to a controller.
    90      bootstrap           Initializes a cloud environment.
    91      controllers         Lists all controllers.
    92      deploy              Deploys a new application.
    93      expose              Makes an application publicly available over the network.
    94      models              Lists models a user can access on a controller.
    95      status              Displays the current status of Juju, applications, and units.
    96      switch              Selects or identifies the current controller and model.
    97  
    98  Example help commands:
    99  
   100      `[1:] + "`juju help`" + `          This help page
   101      ` + "`juju help commands`" + ` Lists all commands
   102      ` + "`juju help deploy`" + `   Shows help for command 'deploy'
   103  `
   104  
   105  var x = []byte("\x96\x8c\x99\x8a\x9c\x94\x96\x91\x98\xdf\x9e\x92\x9e\x85\x96\x91\x98\xf5")
   106  
   107  // Main registers subcommands for the juju executable, and hands over control
   108  // to the cmd package. This function is not redundant with main, because it
   109  // provides an entry point for testing with arbitrary command line arguments.
   110  // This function returns the exit code, for main to pass to os.Exit.
   111  func Main(args []string) int {
   112  	return main{
   113  		execCommand: exec.Command,
   114  	}.Run(args)
   115  }
   116  
   117  // main is a type that captures dependencies for running the main function.
   118  type main struct {
   119  	// execCommand abstracts away exec.Command.
   120  	execCommand func(command string, args ...string) *exec.Cmd
   121  }
   122  
   123  // Run is the main entry point for the juju client.
   124  func (m main) Run(args []string) int {
   125  	ctx, err := cmd.DefaultContext()
   126  	if err != nil {
   127  		fmt.Fprintf(os.Stderr, "error: %v\n", err)
   128  		return 2
   129  	}
   130  
   131  	// note that this has to come before we init the juju home directory,
   132  	// since it relies on detecting the lack of said directory.
   133  	newInstall := m.maybeWarnJuju1x()
   134  
   135  	if err = juju.InitJujuXDGDataHome(); err != nil {
   136  		fmt.Fprintf(os.Stderr, "error: %s\n", err)
   137  		return 2
   138  	}
   139  
   140  	if newInstall {
   141  		fmt.Fprintf(ctx.Stderr, "Since Juju %v is being run for the first time, downloading latest cloud information.\n", jujuversion.Current.Major)
   142  		updateCmd := cloud.NewUpdateCloudsCommand()
   143  		if err := updateCmd.Run(ctx); err != nil {
   144  			fmt.Fprintf(ctx.Stderr, "error: %v\n", err)
   145  		}
   146  	}
   147  
   148  	for i := range x {
   149  		x[i] ^= 255
   150  	}
   151  	if len(args) == 2 && args[1] == string(x[0:2]) {
   152  		os.Stdout.Write(x[2:])
   153  		return 0
   154  	}
   155  
   156  	jcmd := NewJujuCommand(ctx)
   157  	return cmd.Main(jcmd, ctx, args[1:])
   158  }
   159  
   160  func (m main) maybeWarnJuju1x() (newInstall bool) {
   161  	newInstall = !juju2xConfigDataExists()
   162  	if !shouldWarnJuju1x() {
   163  		return newInstall
   164  	}
   165  	ver, exists := m.juju1xVersion()
   166  	if !exists {
   167  		return newInstall
   168  	}
   169  	fmt.Fprintf(os.Stderr, `
   170      Welcome to Juju %s. If you meant to use Juju %s you can continue using it
   171      with the command %s e.g. '%s switch'.
   172      See https://jujucharms.com/docs/stable/introducing-2 for more details.
   173  
   174  `[1:], jujuversion.Current, ver, juju1xCmdName, juju1xCmdName)
   175  	return newInstall
   176  }
   177  
   178  func (m main) juju1xVersion() (ver string, exists bool) {
   179  	out, err := m.execCommand(juju1xCmdName, "version").Output()
   180  	if err == exec.ErrNotFound {
   181  		return "", false
   182  	}
   183  	ver = "1.x"
   184  	if err == nil {
   185  		v := strings.TrimSpace(string(out))
   186  		// parse so we can drop the series and arch
   187  		bin, err := version.ParseBinary(v)
   188  		if err == nil {
   189  			ver = bin.Number.String()
   190  		}
   191  	}
   192  	return ver, true
   193  }
   194  
   195  func shouldWarnJuju1x() bool {
   196  	// this code only applies to Ubuntu, where we renamed Juju 1.x to juju-1.
   197  	ostype, err := series.GetOSFromSeries(series.HostSeries())
   198  	if err != nil || ostype != utilsos.Ubuntu {
   199  		return false
   200  	}
   201  	return osenv.Juju1xEnvConfigExists() && !juju2xConfigDataExists()
   202  }
   203  
   204  func juju2xConfigDataExists() bool {
   205  	_, err := os.Stat(osenv.JujuXDGDataHomeDir())
   206  	return err == nil
   207  }
   208  
   209  // NewJujuCommand ...
   210  func NewJujuCommand(ctx *cmd.Context) cmd.Command {
   211  	jcmd := jujucmd.NewSuperCommand(cmd.SuperCommandParams{
   212  		Name:                "juju",
   213  		Doc:                 jujuDoc,
   214  		MissingCallback:     RunPlugin,
   215  		UserAliasesFilename: osenv.JujuXDGDataHomePath("aliases"),
   216  	})
   217  	jcmd.AddHelpTopic("basics", "Basic Help Summary", usageHelp)
   218  	registerCommands(jcmd, ctx)
   219  	return jcmd
   220  }
   221  
   222  type commandRegistry interface {
   223  	Register(cmd.Command)
   224  	RegisterSuperAlias(name, super, forName string, check cmd.DeprecationCheck)
   225  	RegisterDeprecated(subcmd cmd.Command, check cmd.DeprecationCheck)
   226  }
   227  
   228  // TODO(ericsnow) Factor out the commands and aliases into a static
   229  // registry that can be passed to the supercommand separately.
   230  
   231  // registerCommands registers commands in the specified registry.
   232  func registerCommands(r commandRegistry, ctx *cmd.Context) {
   233  	// Creation commands.
   234  	r.Register(newBootstrapCommand())
   235  	r.Register(application.NewAddRelationCommand())
   236  
   237  	// Destruction commands.
   238  	r.Register(application.NewRemoveRelationCommand())
   239  	r.Register(application.NewRemoveServiceCommand())
   240  	r.Register(application.NewRemoveUnitCommand())
   241  
   242  	// Reporting commands.
   243  	r.Register(status.NewStatusCommand())
   244  	r.Register(newSwitchCommand())
   245  	r.Register(status.NewStatusHistoryCommand())
   246  
   247  	// Error resolution and debugging commands.
   248  	r.Register(newRunCommand())
   249  	r.Register(newSCPCommand())
   250  	r.Register(newSSHCommand())
   251  	r.Register(newResolvedCommand())
   252  	r.Register(newDebugLogCommand())
   253  	r.Register(newDebugHooksCommand())
   254  
   255  	// Configuration commands.
   256  	r.Register(model.NewModelGetConstraintsCommand())
   257  	r.Register(model.NewModelSetConstraintsCommand())
   258  	r.Register(newSyncToolsCommand())
   259  	r.Register(newUpgradeJujuCommand(nil))
   260  	r.Register(application.NewUpgradeCharmCommand())
   261  
   262  	// Charm tool commands.
   263  	r.Register(newHelpToolCommand())
   264  	r.Register(charmcmd.NewSuperCommand())
   265  
   266  	// Manage backups.
   267  	r.Register(backups.NewCreateCommand())
   268  	r.Register(backups.NewDownloadCommand())
   269  	r.Register(backups.NewShowCommand())
   270  	r.Register(backups.NewListCommand())
   271  	r.Register(backups.NewRemoveCommand())
   272  	r.Register(backups.NewRestoreCommand())
   273  	r.Register(backups.NewUploadCommand())
   274  
   275  	// Manage authorized ssh keys.
   276  	r.Register(NewAddKeysCommand())
   277  	r.Register(NewRemoveKeysCommand())
   278  	r.Register(NewImportKeysCommand())
   279  	r.Register(NewListKeysCommand())
   280  
   281  	// Manage users and access
   282  	r.Register(user.NewAddCommand())
   283  	r.Register(user.NewChangePasswordCommand())
   284  	r.Register(user.NewShowUserCommand())
   285  	r.Register(user.NewListCommand())
   286  	r.Register(user.NewEnableCommand())
   287  	r.Register(user.NewDisableCommand())
   288  	r.Register(user.NewLoginCommand())
   289  	r.Register(user.NewLogoutCommand())
   290  	r.Register(user.NewRemoveCommand())
   291  	r.Register(user.NewWhoAmICommand())
   292  
   293  	// Manage cached images
   294  	r.Register(cachedimages.NewRemoveCommand())
   295  	r.Register(cachedimages.NewListCommand())
   296  
   297  	// Manage machines
   298  	r.Register(machine.NewAddCommand())
   299  	r.Register(machine.NewRemoveCommand())
   300  	r.Register(machine.NewListMachinesCommand())
   301  	r.Register(machine.NewShowMachineCommand())
   302  
   303  	// Manage model
   304  	r.Register(model.NewConfigCommand())
   305  	r.Register(model.NewDefaultsCommand())
   306  	r.Register(model.NewRetryProvisioningCommand())
   307  	r.Register(model.NewDestroyCommand())
   308  	r.Register(model.NewGrantCommand())
   309  	r.Register(model.NewRevokeCommand())
   310  	r.Register(model.NewShowCommand())
   311  
   312  	if featureflag.Enabled(feature.Migration) {
   313  		r.Register(newMigrateCommand())
   314  	}
   315  	if featureflag.Enabled(feature.DeveloperMode) {
   316  		r.Register(model.NewDumpCommand())
   317  		r.Register(model.NewDumpDBCommand())
   318  	}
   319  
   320  	// Manage and control actions
   321  	r.Register(action.NewStatusCommand())
   322  	r.Register(action.NewRunCommand())
   323  	r.Register(action.NewShowOutputCommand())
   324  	r.Register(action.NewListCommand())
   325  
   326  	// Manage controller availability
   327  	r.Register(newEnableHACommand())
   328  
   329  	// Manage and control services
   330  	r.Register(application.NewAddUnitCommand())
   331  	r.Register(application.NewConfigCommand())
   332  	r.Register(application.NewDefaultDeployCommand())
   333  	r.Register(application.NewExposeCommand())
   334  	r.Register(application.NewUnexposeCommand())
   335  	r.Register(application.NewServiceGetConstraintsCommand())
   336  	r.Register(application.NewServiceSetConstraintsCommand())
   337  
   338  	// Operation protection commands
   339  	r.Register(block.NewDisableCommand())
   340  	r.Register(block.NewListCommand())
   341  	r.Register(block.NewEnableCommand())
   342  
   343  	// Manage storage
   344  	r.Register(storage.NewAddCommand())
   345  	r.Register(storage.NewListCommand())
   346  	r.Register(storage.NewPoolCreateCommand())
   347  	r.Register(storage.NewPoolListCommand())
   348  	r.Register(storage.NewShowCommand())
   349  
   350  	// Manage spaces
   351  	r.Register(space.NewAddCommand())
   352  	r.Register(space.NewListCommand())
   353  	if featureflag.Enabled(feature.PostNetCLIMVP) {
   354  		r.Register(space.NewRemoveCommand())
   355  		r.Register(space.NewUpdateCommand())
   356  		r.Register(space.NewRenameCommand())
   357  	}
   358  
   359  	// Manage subnets
   360  	r.Register(subnet.NewAddCommand())
   361  	r.Register(subnet.NewListCommand())
   362  	if featureflag.Enabled(feature.PostNetCLIMVP) {
   363  		r.Register(subnet.NewCreateCommand())
   364  		r.Register(subnet.NewRemoveCommand())
   365  	}
   366  
   367  	// Manage controllers
   368  	r.Register(controller.NewAddModelCommand())
   369  	r.Register(controller.NewDestroyCommand())
   370  	r.Register(controller.NewListModelsCommand())
   371  	r.Register(controller.NewKillCommand())
   372  	r.Register(controller.NewListControllersCommand())
   373  	r.Register(controller.NewRegisterCommand())
   374  	r.Register(controller.NewUnregisterCommand(jujuclient.NewFileClientStore()))
   375  	r.Register(controller.NewEnableDestroyControllerCommand())
   376  	r.Register(controller.NewShowControllerCommand())
   377  	r.Register(controller.NewGetConfigCommand())
   378  
   379  	// Debug Metrics
   380  	r.Register(metricsdebug.New())
   381  	r.Register(metricsdebug.NewCollectMetricsCommand())
   382  	r.Register(setmeterstatus.New())
   383  
   384  	// Manage clouds and credentials
   385  	r.Register(cloud.NewUpdateCloudsCommand())
   386  	r.Register(cloud.NewListCloudsCommand())
   387  	r.Register(cloud.NewShowCloudCommand())
   388  	r.Register(cloud.NewAddCloudCommand())
   389  	r.Register(cloud.NewRemoveCloudCommand())
   390  	r.Register(cloud.NewListCredentialsCommand())
   391  	r.Register(cloud.NewDetectCredentialsCommand())
   392  	r.Register(cloud.NewSetDefaultRegionCommand())
   393  	r.Register(cloud.NewSetDefaultCredentialCommand())
   394  	r.Register(cloud.NewAddCredentialCommand())
   395  	r.Register(cloud.NewRemoveCredentialCommand())
   396  
   397  	// Juju GUI commands.
   398  	r.Register(gui.NewGUICommand())
   399  	r.Register(gui.NewUpgradeGUICommand())
   400  
   401  	// Commands registered elsewhere.
   402  	for _, newCommand := range registeredCommands {
   403  		command := newCommand()
   404  		r.Register(command)
   405  	}
   406  	for _, newCommand := range registeredEnvCommands {
   407  		command := newCommand()
   408  		r.Register(modelcmd.Wrap(command))
   409  	}
   410  	rcmd.RegisterAll(r)
   411  }