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 }