blob: 86f4ef5cde9fae79718b23cdc9c365938a34d7a1 [file] [log] [blame]
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -07001package gophercloud
2
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -07003import (
4 "net/http"
5)
6
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -07007// Provider structures exist for each tangible provider of OpenStack service.
8// For example, Rackspace, Hewlett-Packard, and NASA might have their own instance of this structure.
9//
10// At a minimum, a provider must expose an authentication endpoint.
11type Provider struct {
12 AuthEndpoint string
13}
14
Samuel A. Falvo II1206f852013-07-15 17:56:51 -070015// ReauthHandlerFunc functions are responsible for somehow performing the task of
16// reauthentication.
17type ReauthHandlerFunc func() error
18
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070019// Context structures encapsulate Gophercloud-global state in a manner which
20// facilitates easier unit testing. As a user of this SDK, you'll never
21// have to use this structure, except when contributing new code to the SDK.
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -070022type Context struct {
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070023 // providerMap serves as a directory of supported providers.
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070024 providerMap map[string]Provider
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070025
26 // httpClient refers to the current HTTP client interface to use.
27 httpClient *http.Client
Samuel A. Falvo II1206f852013-07-15 17:56:51 -070028
29 // reauthHandler provides the functionality needed to re-authenticate
30 // if that feature is enabled. Note: in order to allow for automatic
31 // re-authentication, the Context object will need to remember your
32 // username, password, and tenant ID as provided in the initial call
33 // to Authenticate(). If you do not desire this, you'll need to handle
34 // reauthentication yourself through other means. Two methods exist:
35 // the first approach is to just handle errors yourself at the application
36 // layer, and the other is through a custom reauthentication handler
37 // set through the WithReauthHandler() method.
38 reauthHandler ReauthHandlerFunc
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -070039}
40
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070041// TestContext yields a new Context instance, pre-initialized with a barren
42// state suitable for per-unit-test customization. This configuration consists
43// of:
44//
45// * An empty provider map.
46//
47// * An HTTP client built by the net/http package (see http://godoc.org/net/http#Client).
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -070048func TestContext() *Context {
49 return &Context{
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070050 providerMap: make(map[string]Provider),
Samuel A. Falvo II839428e2013-06-25 18:02:24 -070051 httpClient: &http.Client{},
Samuel A. Falvo IIfd78c302013-06-25 16:35:32 -070052 }
53}
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -070054
Samuel A. Falvo II4e895182013-06-26 15:44:18 -070055// UseCustomClient configures the context to use a customized HTTP client
56// instance. By default, TestContext() will return a Context which uses
Samuel A. Falvo IIfca35b72013-07-02 18:30:28 -070057// the net/http package's default client instance.
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -070058func (c *Context) UseCustomClient(hc *http.Client) *Context {
Samuel A. Falvo II839428e2013-06-25 18:02:24 -070059 c.httpClient = hc
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -070060 return c
61}
62
63// RegisterProvider allows a unit test to register a mythical provider convenient for testing.
64// If the provider structure lacks adequate configuration, or the configuration given has some
65// detectable error, an ErrConfiguration error will result.
66func (c *Context) RegisterProvider(name string, p Provider) error {
67 if p.AuthEndpoint == "" {
68 return ErrConfiguration
69 }
70
71 c.providerMap[name] = p
72 return nil
73}
74
75// WithProvider offers convenience for unit tests.
76func (c *Context) WithProvider(name string, p Provider) *Context {
77 err := c.RegisterProvider(name, p)
78 if err != nil {
79 panic(err)
80 }
81 return c
82}
83
84// ProviderByName will locate a provider amongst those previously registered, if it exists.
85// If the named provider has not been registered, an ErrProvider error will result.
86func (c *Context) ProviderByName(name string) (p Provider, err error) {
87 for provider, descriptor := range c.providerMap {
88 if name == provider {
89 return descriptor, nil
90 }
91 }
92 return Provider{}, ErrProvider
93}
94
Samuel A. Falvo II1dd740a2013-07-08 15:48:40 -070095// Instantiates a Cloud Servers API for the provider given.
96func (c *Context) ServersApi(acc AccessProvider, criteria ApiCriteria) (CloudServersProvider, error) {
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -070097 url := acc.FirstEndpointUrlByCriteria(criteria)
98 if url == "" {
99 return nil, ErrEndpoint
100 }
101
Samuel A. Falvo II1dd740a2013-07-08 15:48:40 -0700102 gcp := &genericServersProvider{
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -0700103 endpoint: url,
104 context: c,
Samuel A. Falvo IIbc0d54a2013-07-08 14:45:21 -0700105 access: acc,
Samuel A. Falvo II2e2b8772013-07-04 15:40:15 -0700106 }
107
108 return gcp, nil
Samuel A. Falvo II5d0d74c2013-06-25 17:23:18 -0700109}
Samuel A. Falvo II1206f852013-07-15 17:56:51 -0700110
111// WithReauthHandler configures the context to handle reauthentication attempts using the supplied
112// funtion. By default, reauthentication happens by invoking Authenticate(), which is unlikely to be
113// useful in a unit test.
114//
115// Do not confuse this function with WithReauth()! Although they work together to support reauthentication,
116// WithReauth() actually contains the decision-making logic to determine when to perform a reauth,
117// while WithReauthHandler() is used to configure what a reauth actually entails.
118func (c *Context) WithReauthHandler(f ReauthHandlerFunc) *Context {
119 c.reauthHandler = f
120 return c
121}