| Samuel A. Falvo II | fd78c30 | 2013-06-25 16:35:32 -0700 | [diff] [blame] | 1 | package gophercloud | 
 | 2 |  | 
| Samuel A. Falvo II | 5d0d74c | 2013-06-25 17:23:18 -0700 | [diff] [blame] | 3 | import ( | 
 | 4 | 	"net/http" | 
 | 5 | ) | 
 | 6 |  | 
| Samuel A. Falvo II | 2e2b877 | 2013-07-04 15:40:15 -0700 | [diff] [blame] | 7 | // 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. | 
 | 11 | type Provider struct { | 
 | 12 | 	AuthEndpoint string | 
 | 13 | } | 
 | 14 |  | 
| Samuel A. Falvo II | 1206f85 | 2013-07-15 17:56:51 -0700 | [diff] [blame^] | 15 | // ReauthHandlerFunc functions are responsible for somehow performing the task of | 
 | 16 | // reauthentication. | 
 | 17 | type ReauthHandlerFunc func() error | 
 | 18 |  | 
| Samuel A. Falvo II | 4e89518 | 2013-06-26 15:44:18 -0700 | [diff] [blame] | 19 | // 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 II | fd78c30 | 2013-06-25 16:35:32 -0700 | [diff] [blame] | 22 | type Context struct { | 
| Samuel A. Falvo II | 5d0d74c | 2013-06-25 17:23:18 -0700 | [diff] [blame] | 23 | 	// providerMap serves as a directory of supported providers. | 
| Samuel A. Falvo II | 4e89518 | 2013-06-26 15:44:18 -0700 | [diff] [blame] | 24 | 	providerMap map[string]Provider | 
| Samuel A. Falvo II | 5d0d74c | 2013-06-25 17:23:18 -0700 | [diff] [blame] | 25 |  | 
 | 26 | 	// httpClient refers to the current HTTP client interface to use. | 
 | 27 | 	httpClient *http.Client | 
| Samuel A. Falvo II | 1206f85 | 2013-07-15 17:56:51 -0700 | [diff] [blame^] | 28 |  | 
 | 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 II | fd78c30 | 2013-06-25 16:35:32 -0700 | [diff] [blame] | 39 | } | 
 | 40 |  | 
| Samuel A. Falvo II | 4e89518 | 2013-06-26 15:44:18 -0700 | [diff] [blame] | 41 | // 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 II | fd78c30 | 2013-06-25 16:35:32 -0700 | [diff] [blame] | 48 | func TestContext() *Context { | 
 | 49 | 	return &Context{ | 
| Samuel A. Falvo II | 4e89518 | 2013-06-26 15:44:18 -0700 | [diff] [blame] | 50 | 		providerMap: make(map[string]Provider), | 
| Samuel A. Falvo II | 839428e | 2013-06-25 18:02:24 -0700 | [diff] [blame] | 51 | 		httpClient:  &http.Client{}, | 
| Samuel A. Falvo II | fd78c30 | 2013-06-25 16:35:32 -0700 | [diff] [blame] | 52 | 	} | 
 | 53 | } | 
| Samuel A. Falvo II | 5d0d74c | 2013-06-25 17:23:18 -0700 | [diff] [blame] | 54 |  | 
| Samuel A. Falvo II | 4e89518 | 2013-06-26 15:44:18 -0700 | [diff] [blame] | 55 | // UseCustomClient configures the context to use a customized HTTP client | 
 | 56 | // instance.  By default, TestContext() will return a Context which uses | 
| Samuel A. Falvo II | fca35b7 | 2013-07-02 18:30:28 -0700 | [diff] [blame] | 57 | // the net/http package's default client instance. | 
| Samuel A. Falvo II | 2e2b877 | 2013-07-04 15:40:15 -0700 | [diff] [blame] | 58 | func (c *Context) UseCustomClient(hc *http.Client) *Context { | 
| Samuel A. Falvo II | 839428e | 2013-06-25 18:02:24 -0700 | [diff] [blame] | 59 | 	c.httpClient = hc | 
| Samuel A. Falvo II | 2e2b877 | 2013-07-04 15:40:15 -0700 | [diff] [blame] | 60 | 	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. | 
 | 66 | func (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. | 
 | 76 | func (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. | 
 | 86 | func (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 II | 1dd740a | 2013-07-08 15:48:40 -0700 | [diff] [blame] | 95 | // Instantiates a Cloud Servers API for the provider given. | 
 | 96 | func (c *Context) ServersApi(acc AccessProvider, criteria ApiCriteria) (CloudServersProvider, error) { | 
| Samuel A. Falvo II | 2e2b877 | 2013-07-04 15:40:15 -0700 | [diff] [blame] | 97 | 	url := acc.FirstEndpointUrlByCriteria(criteria) | 
 | 98 | 	if url == "" { | 
 | 99 | 		return nil, ErrEndpoint | 
 | 100 | 	} | 
 | 101 |  | 
| Samuel A. Falvo II | 1dd740a | 2013-07-08 15:48:40 -0700 | [diff] [blame] | 102 | 	gcp := &genericServersProvider{ | 
| Samuel A. Falvo II | 2e2b877 | 2013-07-04 15:40:15 -0700 | [diff] [blame] | 103 | 		endpoint: url, | 
 | 104 | 		context:  c, | 
| Samuel A. Falvo II | bc0d54a | 2013-07-08 14:45:21 -0700 | [diff] [blame] | 105 | 		access:   acc, | 
| Samuel A. Falvo II | 2e2b877 | 2013-07-04 15:40:15 -0700 | [diff] [blame] | 106 | 	} | 
 | 107 |  | 
 | 108 | 	return gcp, nil | 
| Samuel A. Falvo II | 5d0d74c | 2013-06-25 17:23:18 -0700 | [diff] [blame] | 109 | } | 
| Samuel A. Falvo II | 1206f85 | 2013-07-15 17:56:51 -0700 | [diff] [blame^] | 110 |  | 
 | 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. | 
 | 118 | func (c *Context) WithReauthHandler(f ReauthHandlerFunc) *Context { | 
 | 119 | 	c.reauthHandler = f | 
 | 120 | 	return c | 
 | 121 | } |