github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/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  
    10  	"github.com/juju/cmd"
    11  	"github.com/juju/utils/featureflag"
    12  
    13  	jujucmd "github.com/juju/juju/cmd"
    14  	"github.com/juju/juju/cmd/envcmd"
    15  	"github.com/juju/juju/cmd/juju/action"
    16  	"github.com/juju/juju/cmd/juju/backups"
    17  	"github.com/juju/juju/cmd/juju/block"
    18  	"github.com/juju/juju/cmd/juju/cachedimages"
    19  	"github.com/juju/juju/cmd/juju/common"
    20  	"github.com/juju/juju/cmd/juju/environment"
    21  	"github.com/juju/juju/cmd/juju/helptopics"
    22  	"github.com/juju/juju/cmd/juju/machine"
    23  	"github.com/juju/juju/cmd/juju/service"
    24  	"github.com/juju/juju/cmd/juju/space"
    25  	"github.com/juju/juju/cmd/juju/status"
    26  	"github.com/juju/juju/cmd/juju/storage"
    27  	"github.com/juju/juju/cmd/juju/subnet"
    28  	"github.com/juju/juju/cmd/juju/system"
    29  	"github.com/juju/juju/cmd/juju/user"
    30  	"github.com/juju/juju/environs"
    31  	"github.com/juju/juju/feature"
    32  	"github.com/juju/juju/juju"
    33  	"github.com/juju/juju/juju/osenv"
    34  	// Import the providers.
    35  	_ "github.com/juju/juju/provider/all"
    36  	"github.com/juju/juju/version"
    37  )
    38  
    39  func init() {
    40  	featureflag.SetFlagsFromEnvironment(osenv.JujuFeatureFlagEnvKey)
    41  }
    42  
    43  var jujuDoc = `
    44  juju provides easy, intelligent service orchestration on top of cloud
    45  infrastructure providers such as Amazon EC2, HP Cloud, MaaS, OpenStack, Windows
    46  Azure, or your local machine.
    47  
    48  https://juju.ubuntu.com/
    49  `
    50  
    51  var x = []byte("\x96\x8c\x99\x8a\x9c\x94\x96\x91\x98\xdf\x9e\x92\x9e\x85\x96\x91\x98\xf5")
    52  
    53  // Main registers subcommands for the juju executable, and hands over control
    54  // to the cmd package. This function is not redundant with main, because it
    55  // provides an entry point for testing with arbitrary command line arguments.
    56  func Main(args []string) {
    57  	ctx, err := cmd.DefaultContext()
    58  	if err != nil {
    59  		fmt.Fprintf(os.Stderr, "error: %v\n", err)
    60  		os.Exit(2)
    61  	}
    62  	if err = juju.InitJujuHome(); err != nil {
    63  		fmt.Fprintf(os.Stderr, "error: %s\n", err)
    64  		os.Exit(2)
    65  	}
    66  	for i := range x {
    67  		x[i] ^= 255
    68  	}
    69  	if len(args) == 2 && args[1] == string(x[0:2]) {
    70  		os.Stdout.Write(x[2:])
    71  		os.Exit(0)
    72  	}
    73  	jcmd := NewJujuCommand(ctx)
    74  	os.Exit(cmd.Main(jcmd, ctx, args[1:]))
    75  }
    76  
    77  func NewJujuCommand(ctx *cmd.Context) cmd.Command {
    78  	jcmd := jujucmd.NewSuperCommand(cmd.SuperCommandParams{
    79  		Name:            "juju",
    80  		Doc:             jujuDoc,
    81  		MissingCallback: RunPlugin,
    82  	})
    83  	jcmd.AddHelpTopic("basics", "Basic commands", helptopics.Basics)
    84  	jcmd.AddHelpTopic("local-provider", "How to configure a local (LXC) provider",
    85  		helptopics.LocalProvider)
    86  	jcmd.AddHelpTopic("openstack-provider", "How to configure an OpenStack provider",
    87  		helptopics.OpenstackProvider, "openstack")
    88  	jcmd.AddHelpTopic("ec2-provider", "How to configure an Amazon EC2 provider",
    89  		helptopics.EC2Provider, "ec2", "aws", "amazon")
    90  	jcmd.AddHelpTopic("hpcloud-provider", "How to configure an HP Cloud provider",
    91  		helptopics.HPCloud, "hpcloud", "hp-cloud")
    92  	jcmd.AddHelpTopic("azure-provider", "How to configure a Windows Azure provider",
    93  		helptopics.AzureProvider, "azure")
    94  	jcmd.AddHelpTopic("maas-provider", "How to configure a MAAS provider",
    95  		helptopics.MAASProvider, "maas")
    96  	jcmd.AddHelpTopic("constraints", "How to use commands with constraints", helptopics.Constraints)
    97  	jcmd.AddHelpTopic("placement", "How to use placement directives", helptopics.Placement)
    98  	jcmd.AddHelpTopic("glossary", "Glossary of terms", helptopics.Glossary)
    99  	jcmd.AddHelpTopic("logging", "How Juju handles logging", helptopics.Logging)
   100  	jcmd.AddHelpTopic("juju", "What is Juju?", helptopics.Juju)
   101  	jcmd.AddHelpTopic("juju-systems", "About Juju Environment Systems (JES)", helptopics.JujuSystems)
   102  	jcmd.AddHelpTopic("users", "About users in Juju", helptopics.Users)
   103  	jcmd.AddHelpTopicCallback("plugins", "Show Juju plugins", PluginHelpTopic)
   104  
   105  	registerCommands(jcmd, ctx)
   106  	return jcmd
   107  }
   108  
   109  type commandRegistry interface {
   110  	Register(cmd.Command)
   111  	RegisterSuperAlias(name, super, forName string, check cmd.DeprecationCheck)
   112  	RegisterDeprecated(subcmd cmd.Command, check cmd.DeprecationCheck)
   113  }
   114  
   115  // registerCommands registers commands in the specified registry.
   116  // EnvironCommands must be wrapped with an envCmdWrapper.
   117  func registerCommands(r commandRegistry, ctx *cmd.Context) {
   118  	wrapEnvCommand := func(c envcmd.EnvironCommand) cmd.Command {
   119  		return envCmdWrapper{envcmd.Wrap(c), ctx}
   120  	}
   121  
   122  	// Creation commands.
   123  	r.Register(wrapEnvCommand(&BootstrapCommand{}))
   124  	r.Register(wrapEnvCommand(&DeployCommand{}))
   125  	r.Register(wrapEnvCommand(&AddRelationCommand{}))
   126  
   127  	// Destruction commands.
   128  	r.Register(wrapEnvCommand(&RemoveRelationCommand{}))
   129  	r.Register(wrapEnvCommand(&RemoveServiceCommand{}))
   130  	r.Register(wrapEnvCommand(&RemoveUnitCommand{}))
   131  	r.Register(&DestroyEnvironmentCommand{})
   132  
   133  	// Reporting commands.
   134  	r.Register(wrapEnvCommand(&status.StatusCommand{}))
   135  	r.Register(&SwitchCommand{})
   136  	r.Register(wrapEnvCommand(&EndpointCommand{}))
   137  	r.Register(wrapEnvCommand(&APIInfoCommand{}))
   138  	r.Register(wrapEnvCommand(&status.StatusHistoryCommand{}))
   139  
   140  	// Error resolution and debugging commands.
   141  	r.Register(wrapEnvCommand(&RunCommand{}))
   142  	r.Register(wrapEnvCommand(&SCPCommand{}))
   143  	r.Register(wrapEnvCommand(&SSHCommand{}))
   144  	r.Register(wrapEnvCommand(&ResolvedCommand{}))
   145  	r.Register(wrapEnvCommand(&DebugLogCommand{}))
   146  	r.Register(wrapEnvCommand(&DebugHooksCommand{}))
   147  
   148  	// Configuration commands.
   149  	r.Register(&InitCommand{})
   150  	r.RegisterDeprecated(wrapEnvCommand(&common.GetConstraintsCommand{}),
   151  		twoDotOhDeprecation("environment get-constraints or service get-constraints"))
   152  	r.RegisterDeprecated(wrapEnvCommand(&common.SetConstraintsCommand{}),
   153  		twoDotOhDeprecation("environment set-constraints or service set-constraints"))
   154  	r.Register(wrapEnvCommand(&ExposeCommand{}))
   155  	r.Register(wrapEnvCommand(&SyncToolsCommand{}))
   156  	r.Register(wrapEnvCommand(&UnexposeCommand{}))
   157  	r.Register(wrapEnvCommand(&UpgradeJujuCommand{}))
   158  	r.Register(wrapEnvCommand(&UpgradeCharmCommand{}))
   159  
   160  	// Charm publishing commands.
   161  	r.Register(wrapEnvCommand(&PublishCommand{}))
   162  
   163  	// Charm tool commands.
   164  	r.Register(&HelpToolCommand{})
   165  
   166  	// Manage backups.
   167  	r.Register(backups.NewCommand())
   168  
   169  	// Manage authorized ssh keys.
   170  	r.Register(NewAuthorizedKeysCommand())
   171  
   172  	// Manage users and access
   173  	r.Register(user.NewSuperCommand())
   174  
   175  	// Manage cached images
   176  	r.Register(cachedimages.NewSuperCommand())
   177  
   178  	// Manage machines
   179  	r.Register(machine.NewSuperCommand())
   180  	r.RegisterSuperAlias("add-machine", "machine", "add", twoDotOhDeprecation("machine add"))
   181  	r.RegisterSuperAlias("remove-machine", "machine", "remove", twoDotOhDeprecation("machine remove"))
   182  	r.RegisterSuperAlias("destroy-machine", "machine", "remove", twoDotOhDeprecation("machine remove"))
   183  	r.RegisterSuperAlias("terminate-machine", "machine", "remove", twoDotOhDeprecation("machine remove"))
   184  
   185  	// Mangage environment
   186  	r.Register(environment.NewSuperCommand())
   187  	r.RegisterSuperAlias("get-environment", "environment", "get", twoDotOhDeprecation("environment get"))
   188  	r.RegisterSuperAlias("get-env", "environment", "get", twoDotOhDeprecation("environment get"))
   189  	r.RegisterSuperAlias("set-environment", "environment", "set", twoDotOhDeprecation("environment set"))
   190  	r.RegisterSuperAlias("set-env", "environment", "set", twoDotOhDeprecation("environment set"))
   191  	r.RegisterSuperAlias("unset-environment", "environment", "unset", twoDotOhDeprecation("environment unset"))
   192  	r.RegisterSuperAlias("unset-env", "environment", "unset", twoDotOhDeprecation("environment unset"))
   193  	r.RegisterSuperAlias("retry-provisioning", "environment", "retry-provisioning", twoDotOhDeprecation("environment retry-provisioning"))
   194  
   195  	// Manage and control actions
   196  	r.Register(action.NewSuperCommand())
   197  
   198  	// Manage state server availability
   199  	r.Register(wrapEnvCommand(&EnsureAvailabilityCommand{}))
   200  
   201  	// Manage and control services
   202  	r.Register(service.NewSuperCommand())
   203  	r.RegisterSuperAlias("add-unit", "service", "add-unit", twoDotOhDeprecation("service add-unit"))
   204  	r.RegisterSuperAlias("get", "service", "get", twoDotOhDeprecation("service get"))
   205  	r.RegisterSuperAlias("set", "service", "set", twoDotOhDeprecation("service set"))
   206  	r.RegisterSuperAlias("unset", "service", "unset", twoDotOhDeprecation("service unset"))
   207  
   208  	// Operation protection commands
   209  	r.Register(block.NewSuperBlockCommand())
   210  	r.Register(wrapEnvCommand(&block.UnblockCommand{}))
   211  
   212  	// Manage storage
   213  	r.Register(storage.NewSuperCommand())
   214  
   215  	// Manage spaces
   216  	r.Register(space.NewSuperCommand())
   217  
   218  	// Manage subnets
   219  	r.Register(subnet.NewSuperCommand())
   220  
   221  	// Manage systems
   222  	if featureflag.Enabled(feature.JES) {
   223  		r.Register(system.NewSuperCommand())
   224  		r.RegisterSuperAlias("systems", "system", "list", nil)
   225  
   226  		// Add top level aliases of the same name as the subcommands.
   227  		r.RegisterSuperAlias("environments", "system", "environments", nil)
   228  		r.RegisterSuperAlias("login", "system", "login", nil)
   229  		r.RegisterSuperAlias("create-environment", "system", "create-environment", nil)
   230  		r.RegisterSuperAlias("create-env", "system", "create-env", nil)
   231  	}
   232  }
   233  
   234  // envCmdWrapper is a struct that wraps an environment command and lets us handle
   235  // errors returned from Init before they're returned to the main function.
   236  type envCmdWrapper struct {
   237  	cmd.Command
   238  	ctx *cmd.Context
   239  }
   240  
   241  func (w envCmdWrapper) Init(args []string) error {
   242  	err := w.Command.Init(args)
   243  	if environs.IsNoEnv(err) {
   244  		fmt.Fprintln(w.ctx.Stderr, "No juju environment configuration file exists.")
   245  		fmt.Fprintln(w.ctx.Stderr, err)
   246  		fmt.Fprintln(w.ctx.Stderr, "Please create a configuration by running:")
   247  		fmt.Fprintln(w.ctx.Stderr, "    juju init")
   248  		fmt.Fprintln(w.ctx.Stderr, "then edit the file to configure your juju environment.")
   249  		fmt.Fprintln(w.ctx.Stderr, "You can then re-run the command.")
   250  		return cmd.ErrSilent
   251  	}
   252  	return err
   253  }
   254  
   255  func main() {
   256  	Main(os.Args)
   257  }
   258  
   259  type versionDeprecation struct {
   260  	replacement string
   261  	deprecate   version.Number
   262  	obsolete    version.Number
   263  }
   264  
   265  // Deprecated implements cmd.DeprecationCheck.
   266  // If the current version is after the deprecate version number,
   267  // the command is deprecated and the replacement should be used.
   268  func (v *versionDeprecation) Deprecated() (bool, string) {
   269  	if version.Current.Number.Compare(v.deprecate) > 0 {
   270  		return true, v.replacement
   271  	}
   272  	return false, ""
   273  }
   274  
   275  // Obsolete implements cmd.DeprecationCheck.
   276  // If the current version is after the obsolete version number,
   277  // the command is obsolete and shouldn't be registered.
   278  func (v *versionDeprecation) Obsolete() bool {
   279  	return version.Current.Number.Compare(v.obsolete) > 0
   280  }
   281  
   282  func twoDotOhDeprecation(replacement string) cmd.DeprecationCheck {
   283  	return &versionDeprecation{
   284  		replacement: replacement,
   285  		deprecate:   version.MustParse("2.0-00"),
   286  		obsolete:    version.MustParse("3.0-00"),
   287  	}
   288  }