github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/api/interface.go (about) 1 // Copyright 2012-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package api 5 6 import ( 7 "net/url" 8 "time" 9 10 "github.com/juju/errors" 11 "github.com/juju/version" 12 "gopkg.in/juju/names.v2" 13 "gopkg.in/macaroon-bakery.v1/httpbakery" 14 "gopkg.in/macaroon.v1" 15 16 "github.com/juju/juju/api/base" 17 "github.com/juju/juju/api/charmrevisionupdater" 18 "github.com/juju/juju/api/cleaner" 19 "github.com/juju/juju/api/discoverspaces" 20 "github.com/juju/juju/api/imagemetadata" 21 "github.com/juju/juju/api/instancepoller" 22 "github.com/juju/juju/api/reboot" 23 "github.com/juju/juju/api/unitassigner" 24 "github.com/juju/juju/api/uniter" 25 "github.com/juju/juju/api/upgrader" 26 "github.com/juju/juju/network" 27 "github.com/juju/utils/set" 28 ) 29 30 // Info encapsulates information about a server holding juju state and 31 // can be used to make a connection to it. 32 type Info struct { 33 34 // This block of fields is sufficient to connect: 35 36 // Addrs holds the addresses of the controllers. 37 Addrs []string 38 39 // CACert holds the CA certificate that will be used 40 // to validate the controller's certificate, in PEM format. 41 // If this is empty, the standard system root certificates 42 // will be used. 43 CACert string 44 45 // ModelTag holds the model tag for the model we are 46 // trying to connect to. If this is empty, a controller-only 47 // login will be made. 48 ModelTag names.ModelTag 49 50 // ...but this block of fields is all about the authentication mechanism 51 // to use after connecting -- if any -- and should probably be extracted. 52 53 // SkipLogin, if true, skips the Login call on connection. It is an 54 // error to set Tag, Password, or Macaroons if SkipLogin is true. 55 SkipLogin bool `yaml:"-"` 56 57 // Tag holds the name of the entity that is connecting. 58 // If this is nil, and the password is empty, macaroon authentication 59 // will be used to log in unless SkipLogin is true. 60 Tag names.Tag 61 62 // Password holds the password for the administrator or connecting entity. 63 Password string 64 65 // Macaroons holds a slice of macaroon.Slice that may be used to 66 // authenticate with the API server. 67 Macaroons []macaroon.Slice `yaml:",omitempty"` 68 69 // Nonce holds the nonce used when provisioning the machine. Used 70 // only by the machine agent. 71 Nonce string `yaml:",omitempty"` 72 } 73 74 // Ports returns the unique ports for the api addresses. 75 func (info *Info) Ports() []int { 76 ports := set.NewInts() 77 hostPorts, err := network.ParseHostPorts(info.Addrs...) 78 if err != nil { 79 // Addresses have already been validated. 80 panic(err) 81 } 82 for _, hp := range hostPorts { 83 ports.Add(hp.Port) 84 } 85 return ports.Values() 86 } 87 88 // Validate validates the API info. 89 func (info *Info) Validate() error { 90 if len(info.Addrs) == 0 { 91 return errors.NotValidf("missing addresses") 92 } 93 if _, err := network.ParseHostPorts(info.Addrs...); err != nil { 94 return errors.NotValidf("host addresses: %v", err) 95 } 96 if info.SkipLogin { 97 if info.Tag != nil { 98 return errors.NotValidf("specifying Tag and SkipLogin") 99 } 100 if info.Password != "" { 101 return errors.NotValidf("specifying Password and SkipLogin") 102 } 103 if len(info.Macaroons) > 0 { 104 return errors.NotValidf("specifying Macaroons and SkipLogin") 105 } 106 } 107 return nil 108 } 109 110 // DialOpts holds configuration parameters that control the 111 // Dialing behavior when connecting to a controller. 112 type DialOpts struct { 113 // DialAddressInterval is the amount of time to wait 114 // before starting to dial another address. 115 DialAddressInterval time.Duration 116 117 // Timeout is the amount of time to wait contacting 118 // a controller. 119 Timeout time.Duration 120 121 // RetryDelay is the amount of time to wait between 122 // unsuccessful connection attempts. 123 RetryDelay time.Duration 124 125 // BakeryClient is the httpbakery Client, which 126 // is used to do the macaroon-based authorization. 127 // This and the *http.Client inside it are copied 128 // by Open, and any RoundTripper field 129 // the HTTP client is ignored. 130 BakeryClient *httpbakery.Client 131 132 // InsecureSkipVerify skips TLS certificate verification 133 // when connecting to the controller. This should only 134 // be used in tests, or when verification cannot be 135 // performed and the communication need not be secure. 136 InsecureSkipVerify bool 137 } 138 139 // DefaultDialOpts returns a DialOpts representing the default 140 // parameters for contacting a controller. 141 func DefaultDialOpts() DialOpts { 142 return DialOpts{ 143 DialAddressInterval: 50 * time.Millisecond, 144 Timeout: 10 * time.Minute, 145 RetryDelay: 2 * time.Second, 146 } 147 } 148 149 // OpenFunc is the usual form of a function that opens an API connection. 150 type OpenFunc func(*Info, DialOpts) (Connection, error) 151 152 // Connection exists purely to make api-opening funcs mockable. It's just a 153 // dumb copy of all the methods on api.state; we can and should be extracting 154 // smaller and more relevant interfaces (and dropping some of them too). 155 156 // Connection represents a connection to a Juju API server. 157 type Connection interface { 158 159 // This first block of methods is pretty close to a sane Connection interface. 160 Close() error 161 Broken() <-chan struct{} 162 Addr() string 163 APIHostPorts() [][]network.HostPort 164 165 // These are a bit off -- ServerVersion is apparently not known until after 166 // Login()? Maybe evidence of need for a separate AuthenticatedConnection..? 167 Login(name names.Tag, password, nonce string, ms []macaroon.Slice) error 168 ServerVersion() (version.Number, bool) 169 170 // APICaller provides the facility to make API calls directly. 171 // This should not be used outside the api/* packages or tests. 172 base.APICaller 173 174 // ControllerTag returns the tag of the controller. 175 // This could be defined on base.APICaller. 176 ControllerTag() names.ControllerTag 177 178 // All the rest are strange and questionable and deserve extra attention 179 // and/or discussion. 180 181 // Something-or-other expects Ping to exist, and *maybe* the heartbeat 182 // *should* be handled outside the State type, but it's also handled 183 // inside it as well. We should figure this out sometime -- we should 184 // either expose Ping() or Broken() but not both. 185 Ping() error 186 187 // I think this is actually dead code. It's tested, at least, so I'm 188 // keeping it for now, but it's not apparently used anywhere else. 189 AllFacadeVersions() map[string][]int 190 191 // AuthTag returns the tag of the authorized user of the state API 192 // connection. 193 AuthTag() names.Tag 194 195 // ModelAccess returns the access level of authorized user to the model. 196 ModelAccess() string 197 198 // ControllerAccess returns the access level of authorized user to the controller. 199 ControllerAccess() string 200 201 // CookieURL returns the URL that HTTP cookies for the API will be 202 // associated with. 203 CookieURL() *url.URL 204 205 // These methods expose a bunch of worker-specific facades, and basically 206 // just should not exist; but removing them is too noisy for a single CL. 207 // Client in particular is intimately coupled with State -- and the others 208 // will be easy to remove, but until we're using them via manifolds it's 209 // prohibitively ugly to do so. 210 Client() *Client 211 Uniter() (*uniter.State, error) 212 Upgrader() *upgrader.State 213 Reboot() (reboot.State, error) 214 DiscoverSpaces() *discoverspaces.API 215 InstancePoller() *instancepoller.API 216 CharmRevisionUpdater() *charmrevisionupdater.State 217 Cleaner() *cleaner.API 218 MetadataUpdater() *imagemetadata.Client 219 UnitAssigner() unitassigner.API 220 }