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  }