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 }