github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/controller/showcontroller.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package controller 5 6 import ( 7 "fmt" 8 9 "github.com/juju/cmd" 10 "github.com/juju/errors" 11 "launchpad.net/gnuflag" 12 13 "github.com/juju/juju/cmd/modelcmd" 14 "github.com/juju/juju/environs/config" 15 "github.com/juju/juju/jujuclient" 16 ) 17 18 var usageShowControllerSummary = ` 19 Shows detailed information of a controller.`[1:] 20 21 var usageShowControllerDetails = ` 22 Shows extended information about a controller(s) as well as related models 23 and accounts. The active model and user accounts are also displayed. 24 25 Examples: 26 juju show-controller 27 juju show-controller aws google 28 29 See also: 30 list-controllers`[1:] 31 32 // NewShowControllerCommand returns a command to show details of the desired controllers. 33 func NewShowControllerCommand() cmd.Command { 34 cmd := &showControllerCommand{ 35 store: jujuclient.NewFileClientStore(), 36 } 37 return modelcmd.WrapBase(cmd) 38 } 39 40 // Init implements Command.Init. 41 func (c *showControllerCommand) Init(args []string) (err error) { 42 c.controllerNames = args 43 return nil 44 } 45 46 // Info implements Command.Info 47 func (c *showControllerCommand) Info() *cmd.Info { 48 return &cmd.Info{ 49 Name: "show-controller", 50 Args: "[<controller name> ...]", 51 Purpose: usageShowControllerSummary, 52 Doc: usageShowControllerDetails, 53 Aliases: []string{"show-controllers"}, 54 } 55 } 56 57 // SetFlags implements Command.SetFlags. 58 func (c *showControllerCommand) SetFlags(f *gnuflag.FlagSet) { 59 c.JujuCommandBase.SetFlags(f) 60 f.BoolVar(&c.showPasswords, "show-passwords", false, "Show passwords for displayed accounts") 61 c.out.AddFlags(f, "yaml", map[string]cmd.Formatter{ 62 "yaml": cmd.FormatYaml, 63 "json": cmd.FormatJson, 64 }) 65 } 66 67 // Run implements Command.Run 68 func (c *showControllerCommand) Run(ctx *cmd.Context) error { 69 controllerNames := c.controllerNames 70 if len(controllerNames) == 0 { 71 currentController, err := modelcmd.ReadCurrentController() 72 if err != nil { 73 return errors.Trace(err) 74 } 75 if currentController == "" { 76 return errors.New("there is no active controller") 77 } 78 controllerNames = []string{currentController} 79 } 80 controllers := make(map[string]ShowControllerDetails) 81 for _, name := range controllerNames { 82 actualName, err := modelcmd.ResolveControllerName(c.store, name) 83 if err != nil { 84 return err 85 } 86 one, err := c.store.ControllerByName(actualName) 87 if err != nil { 88 return err 89 } 90 controllers[name] = c.convertControllerForShow(actualName, one) 91 } 92 return c.out.Write(ctx, controllers) 93 } 94 95 type ShowControllerDetails struct { 96 // Details contains the same details that client store caches for this controller. 97 Details ControllerDetails `yaml:"details,omitempty" json:"details,omitempty"` 98 99 // Accounts is a collection of accounts for this controller. 100 Accounts map[string]*AccountDetails `yaml:"accounts,omitempty" json:"accounts,omitempty"` 101 102 // CurrentAccount is the name of the current account for this controller. 103 CurrentAccount string `yaml:"current-account,omitempty" json:"current-account,omitempty"` 104 105 // BootstrapConfig contains the bootstrap configuration for this controller. 106 // This is only available on the client that bootstrapped the controller. 107 BootstrapConfig *BootstrapConfig `yaml:"bootstrap-config,omitempty" json:"bootstrap-config,omitempty"` 108 109 // Errors is a collection of errors related to accessing this controller details. 110 Errors []string `yaml:"errors,omitempty" json:"errors,omitempty"` 111 } 112 113 // ControllerDetails holds details of a controller to show. 114 type ControllerDetails struct { 115 // ControllerUUID is the unique ID for the controller. 116 ControllerUUID string `yaml:"uuid" json:"uuid"` 117 118 // APIEndpoints is the collection of API endpoints running in this controller. 119 APIEndpoints []string `yaml:"api-endpoints,flow" json:"api-endpoints"` 120 121 // CACert is a security certificate for this controller. 122 CACert string `yaml:"ca-cert" json:"ca-cert"` 123 } 124 125 // ModelDetails holds details of a model to show. 126 type ModelDetails struct { 127 // ModelUUID holds the details of a model. 128 ModelUUID string `yaml:"uuid" json:"uuid"` 129 } 130 131 // AccountDetails holds details of an account to show. 132 type AccountDetails struct { 133 // User is the username for the account. 134 User string `yaml:"user" json:"user"` 135 136 // Password is the password for the account. 137 Password string `yaml:"password,omitempty" json:"password,omitempty"` 138 139 // Models is a collection of all models for this controller. 140 Models map[string]ModelDetails `yaml:"models,omitempty" json:"models,omitempty"` 141 142 // CurrentModel is the name of the current model for this controller 143 CurrentModel string `yaml:"current-model,omitempty" json:"current-model,omitempty"` 144 } 145 146 // BootstrapConfig holds the configuration used to bootstrap a controller. 147 type BootstrapConfig struct { 148 Config map[string]interface{} `yaml:"config,omitempty" json:"config,omitempty"` 149 Cloud string `yaml:"cloud" json:"cloud"` 150 CloudType string `yaml:"cloud-type" json:"cloud-type"` 151 CloudRegion string `yaml:"region,omitempty" json:"region,omitempty"` 152 CloudEndpoint string `yaml:"endpoint,omitempty" json:"endpoint,omitempty"` 153 CloudStorageEndpoint string `yaml:"storage-endpoint,omitempty" json:"storage-endpoint,omitempty"` 154 Credential string `yaml:"credential,omitempty" json:"credential,omitempty"` 155 } 156 157 func (c *showControllerCommand) convertControllerForShow(controllerName string, details *jujuclient.ControllerDetails) ShowControllerDetails { 158 controller := ShowControllerDetails{ 159 Details: ControllerDetails{ 160 ControllerUUID: details.ControllerUUID, 161 APIEndpoints: details.APIEndpoints, 162 CACert: details.CACert, 163 }, 164 } 165 c.convertAccountsForShow(controllerName, &controller) 166 c.convertBootstrapConfigForShow(controllerName, &controller) 167 return controller 168 } 169 170 func (c *showControllerCommand) convertAccountsForShow(controllerName string, controller *ShowControllerDetails) { 171 accounts, err := c.store.AllAccounts(controllerName) 172 if err != nil && !errors.IsNotFound(err) { 173 controller.Errors = append(controller.Errors, err.Error()) 174 } 175 176 if len(accounts) > 0 { 177 controller.Accounts = make(map[string]*AccountDetails) 178 for accountName, account := range accounts { 179 details := &AccountDetails{User: account.User} 180 controller.Accounts[accountName] = details 181 if c.showPasswords { 182 details.Password = account.Password 183 } 184 if err := c.convertModelsForShow(controllerName, accountName, details); err != nil { 185 controller.Errors = append(controller.Errors, err.Error()) 186 } 187 } 188 } 189 190 controller.CurrentAccount, err = c.store.CurrentAccount(controllerName) 191 if err != nil && !errors.IsNotFound(err) { 192 controller.Errors = append(controller.Errors, err.Error()) 193 } 194 } 195 196 func (c *showControllerCommand) convertModelsForShow(controllerName, accountName string, account *AccountDetails) error { 197 models, err := c.store.AllModels(controllerName, accountName) 198 if errors.IsNotFound(err) { 199 return nil 200 } else if err != nil { 201 return err 202 } 203 if len(models) > 0 { 204 account.Models = make(map[string]ModelDetails) 205 for modelName, model := range models { 206 account.Models[modelName] = ModelDetails{model.ModelUUID} 207 } 208 } 209 account.CurrentModel, err = c.store.CurrentModel(controllerName, accountName) 210 if err != nil && !errors.IsNotFound(err) { 211 return err 212 } 213 return nil 214 } 215 216 func (c *showControllerCommand) convertBootstrapConfigForShow(controllerName string, controller *ShowControllerDetails) { 217 bootstrapConfig, err := c.store.BootstrapConfigForController(controllerName) 218 if errors.IsNotFound(err) { 219 return 220 } else if err != nil { 221 controller.Errors = append(controller.Errors, err.Error()) 222 return 223 } 224 cfg := make(map[string]interface{}) 225 var cloudType string 226 for k, v := range bootstrapConfig.Config { 227 switch k { 228 case config.NameKey: 229 // Name is always "admin" for the admin model, 230 // which is not interesting to us here. 231 case config.TypeKey: 232 // Pull Type up to the top level. 233 cloudType = fmt.Sprint(v) 234 default: 235 cfg[k] = v 236 } 237 } 238 controller.BootstrapConfig = &BootstrapConfig{ 239 Config: cfg, 240 Cloud: bootstrapConfig.Cloud, 241 CloudType: cloudType, 242 CloudRegion: bootstrapConfig.CloudRegion, 243 CloudEndpoint: bootstrapConfig.CloudEndpoint, 244 CloudStorageEndpoint: bootstrapConfig.CloudStorageEndpoint, 245 Credential: bootstrapConfig.Credential, 246 } 247 } 248 249 type showControllerCommand struct { 250 modelcmd.JujuCommandBase 251 252 out cmd.Output 253 store jujuclient.ClientStore 254 255 controllerNames []string 256 showPasswords bool 257 }