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 }