github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/cmd/envcmd/systemcommand.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package envcmd 5 6 import ( 7 "github.com/juju/cmd" 8 "github.com/juju/errors" 9 "launchpad.net/gnuflag" 10 11 "github.com/juju/juju/api" 12 "github.com/juju/juju/api/environmentmanager" 13 "github.com/juju/juju/api/systemmanager" 14 "github.com/juju/juju/api/usermanager" 15 "github.com/juju/juju/environs/configstore" 16 "github.com/juju/juju/juju" 17 ) 18 19 // ErrNoSystemSpecified is returned by commands that operate on 20 // a system if there is no current system, no system has been 21 // explicitly specified, and there is no default system. 22 var ErrNoSystemSpecified = errors.New("no system specified") 23 24 // SystemCommand is intended to be a base for all commands 25 // that need to operate on systems as opposed to environments. 26 type SystemCommand interface { 27 cmd.Command 28 29 // SetSystemName is called prior to the wrapped command's Init method with 30 // the active system name. The system name is guaranteed to be non-empty 31 // at entry of Init. 32 SetSystemName(systemName string) 33 34 // SystemName returns the name of the system or environment used to 35 // determine that API end point. 36 SystemName() string 37 } 38 39 // SysCommandBase is a convenience type for embedding in commands 40 // that wish to implement SystemCommand. 41 type SysCommandBase struct { 42 cmd.CommandBase 43 systemName string 44 } 45 46 // SetSystemName records the current environment name in the SysCommandBase 47 func (c *SysCommandBase) SetSystemName(systemName string) { 48 c.systemName = systemName 49 } 50 51 // SystemName returns the name of the system or environment used to determine 52 // that API end point. 53 func (c *SysCommandBase) SystemName() string { 54 return c.systemName 55 } 56 57 // NewEnvironmentManagerAPIClient returns an API client for the 58 // EnvironmentManager on the current system using the current credentials. 59 func (c *SysCommandBase) NewEnvironmentManagerAPIClient() (*environmentmanager.Client, error) { 60 root, err := c.newAPIRoot() 61 if err != nil { 62 return nil, errors.Trace(err) 63 } 64 return environmentmanager.NewClient(root), nil 65 } 66 67 // NewSystemManagerAPIClient returns an API client for the SystemManager on 68 // the current system using the current credentials. 69 func (c *SysCommandBase) NewSystemManagerAPIClient() (*systemmanager.Client, error) { 70 root, err := c.newAPIRoot() 71 if err != nil { 72 return nil, errors.Trace(err) 73 } 74 return systemmanager.NewClient(root), nil 75 } 76 77 // NewUserManagerAPIClient returns an API client for the UserManager on the 78 // current system using the current credentials. 79 func (c *SysCommandBase) NewUserManagerAPIClient() (*usermanager.Client, error) { 80 root, err := c.newAPIRoot() 81 if err != nil { 82 return nil, errors.Trace(err) 83 } 84 return usermanager.NewClient(root), nil 85 } 86 87 // newAPIRoot returns a restricted API for the current system using the current 88 // credentials. Only the UserManager and EnvironmentManager may be accessed 89 // through this API connection. 90 func (c *SysCommandBase) newAPIRoot() (api.Connection, error) { 91 if c.systemName == "" { 92 return nil, errors.Trace(ErrNoSystemSpecified) 93 } 94 return juju.NewAPIFromName(c.systemName) 95 } 96 97 // ConnectionCredentials returns the credentials used to connect to the API for 98 // the specified system. 99 func (c *SysCommandBase) ConnectionCredentials() (configstore.APICredentials, error) { 100 // TODO: the user may soon be specified through the command line 101 // or through an environment setting, so return these when they are ready. 102 var emptyCreds configstore.APICredentials 103 info, err := c.ConnectionInfo() 104 if err != nil { 105 return emptyCreds, errors.Trace(err) 106 } 107 return info.APICredentials(), nil 108 } 109 110 // ConnectionEndpoint returns the endpoint details used to connect to the API for 111 // the specified system. 112 func (c *SysCommandBase) ConnectionEndpoint() (configstore.APIEndpoint, error) { 113 // TODO: the user may soon be specified through the command line 114 // or through an environment setting, so return these when they are ready. 115 var empty configstore.APIEndpoint 116 info, err := c.ConnectionInfo() 117 if err != nil { 118 return empty, errors.Trace(err) 119 } 120 return info.APIEndpoint(), nil 121 } 122 123 // ConnectionInfo returns the environ info from the cached config store. 124 func (c *SysCommandBase) ConnectionInfo() (configstore.EnvironInfo, error) { 125 // TODO: the user may soon be specified through the command line 126 // or through an environment setting, so return these when they are ready. 127 if c.systemName == "" { 128 return nil, errors.Trace(ErrNoSystemSpecified) 129 } 130 info, err := ConnectionInfoForName(c.systemName) 131 if err != nil { 132 return nil, errors.Trace(err) 133 } 134 return info, nil 135 } 136 137 // Wrap wraps the specified SystemCommand, returning a Command 138 // that proxies to each of the SystemCommand methods. 139 func WrapSystem(c SystemCommand) cmd.Command { 140 return &sysCommandWrapper{SystemCommand: c} 141 } 142 143 type sysCommandWrapper struct { 144 SystemCommand 145 systemName string 146 } 147 148 // SetFlags implements Command.SetFlags, then calls the wrapped command's SetFlags. 149 func (w *sysCommandWrapper) SetFlags(f *gnuflag.FlagSet) { 150 f.StringVar(&w.systemName, "s", "", "juju system to operate in") 151 f.StringVar(&w.systemName, "system", "", "") 152 w.SystemCommand.SetFlags(f) 153 } 154 155 func (w *sysCommandWrapper) getDefaultSystemName() (string, error) { 156 if currentSystem, err := ReadCurrentSystem(); err != nil { 157 return "", errors.Trace(err) 158 } else if currentSystem != "" { 159 return currentSystem, nil 160 } 161 if currentEnv, err := ReadCurrentEnvironment(); err != nil { 162 return "", errors.Trace(err) 163 } else if currentEnv != "" { 164 return currentEnv, nil 165 } 166 return "", errors.Trace(ErrNoSystemSpecified) 167 } 168 169 // Init implements Command.Init, then calls the wrapped command's Init. 170 func (w *sysCommandWrapper) Init(args []string) error { 171 if w.systemName == "" { 172 name, err := w.getDefaultSystemName() 173 if err != nil { 174 return errors.Trace(err) 175 } 176 w.systemName = name 177 } 178 w.SetSystemName(w.systemName) 179 return w.SystemCommand.Init(args) 180 }