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