Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / gophercloud / gophercloud / openstack / client.go
1 package openstack
2
3 import (
4         "fmt"
5         "reflect"
6
7         "github.com/gophercloud/gophercloud"
8         tokens2 "github.com/gophercloud/gophercloud/openstack/identity/v2/tokens"
9         tokens3 "github.com/gophercloud/gophercloud/openstack/identity/v3/tokens"
10         "github.com/gophercloud/gophercloud/openstack/utils"
11 )
12
13 const (
14         // v2 represents Keystone v2.
15         // It should never increase beyond 2.0.
16         v2 = "v2.0"
17
18         // v3 represents Keystone v3.
19         // The version can be anything from v3 to v3.x.
20         v3 = "v3"
21 )
22
23 /*
24 NewClient prepares an unauthenticated ProviderClient instance.
25 Most users will probably prefer using the AuthenticatedClient function
26 instead.
27
28 This is useful if you wish to explicitly control the version of the identity
29 service that's used for authentication explicitly, for example.
30
31 A basic example of using this would be:
32
33         ao, err := openstack.AuthOptionsFromEnv()
34         provider, err := openstack.NewClient(ao.IdentityEndpoint)
35         client, err := openstack.NewIdentityV3(provider, gophercloud.EndpointOpts{})
36 */
37 func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
38         base, err := utils.BaseEndpoint(endpoint)
39         if err != nil {
40                 return nil, err
41         }
42
43         endpoint = gophercloud.NormalizeURL(endpoint)
44         base = gophercloud.NormalizeURL(base)
45
46         p := new(gophercloud.ProviderClient)
47         p.IdentityBase = base
48         p.IdentityEndpoint = endpoint
49         p.UseTokenLock()
50
51         return p, nil
52 }
53
54 /*
55 AuthenticatedClient logs in to an OpenStack cloud found at the identity endpoint
56 specified by the options, acquires a token, and returns a Provider Client
57 instance that's ready to operate.
58
59 If the full path to a versioned identity endpoint was specified  (example:
60 http://example.com:5000/v3), that path will be used as the endpoint to query.
61
62 If a versionless endpoint was specified (example: http://example.com:5000/),
63 the endpoint will be queried to determine which versions of the identity service
64 are available, then chooses the most recent or most supported version.
65
66 Example:
67
68         ao, err := openstack.AuthOptionsFromEnv()
69         provider, err := openstack.AuthenticatedClient(ao)
70         client, err := openstack.NewNetworkV2(client, gophercloud.EndpointOpts{
71                 Region: os.Getenv("OS_REGION_NAME"),
72         })
73 */
74 func AuthenticatedClient(options gophercloud.AuthOptions) (*gophercloud.ProviderClient, error) {
75         client, err := NewClient(options.IdentityEndpoint)
76         if err != nil {
77                 return nil, err
78         }
79
80         err = Authenticate(client, options)
81         if err != nil {
82                 return nil, err
83         }
84         return client, nil
85 }
86
87 // Authenticate or re-authenticate against the most recent identity service
88 // supported at the provided endpoint.
89 func Authenticate(client *gophercloud.ProviderClient, options gophercloud.AuthOptions) error {
90         versions := []*utils.Version{
91                 {ID: v2, Priority: 20, Suffix: "/v2.0/"},
92                 {ID: v3, Priority: 30, Suffix: "/v3/"},
93         }
94
95         chosen, endpoint, err := utils.ChooseVersion(client, versions)
96         if err != nil {
97                 return err
98         }
99
100         switch chosen.ID {
101         case v2:
102                 return v2auth(client, endpoint, options, gophercloud.EndpointOpts{})
103         case v3:
104                 return v3auth(client, endpoint, &options, gophercloud.EndpointOpts{})
105         default:
106                 // The switch statement must be out of date from the versions list.
107                 return fmt.Errorf("Unrecognized identity version: %s", chosen.ID)
108         }
109 }
110
111 // AuthenticateV2 explicitly authenticates against the identity v2 endpoint.
112 func AuthenticateV2(client *gophercloud.ProviderClient, options gophercloud.AuthOptions, eo gophercloud.EndpointOpts) error {
113         return v2auth(client, "", options, eo)
114 }
115
116 func v2auth(client *gophercloud.ProviderClient, endpoint string, options gophercloud.AuthOptions, eo gophercloud.EndpointOpts) error {
117         v2Client, err := NewIdentityV2(client, eo)
118         if err != nil {
119                 return err
120         }
121
122         if endpoint != "" {
123                 v2Client.Endpoint = endpoint
124         }
125
126         v2Opts := tokens2.AuthOptions{
127                 IdentityEndpoint: options.IdentityEndpoint,
128                 Username:         options.Username,
129                 Password:         options.Password,
130                 TenantID:         options.TenantID,
131                 TenantName:       options.TenantName,
132                 AllowReauth:      options.AllowReauth,
133                 TokenID:          options.TokenID,
134         }
135
136         result := tokens2.Create(v2Client, v2Opts)
137
138         err = client.SetTokenAndAuthResult(result)
139         if err != nil {
140                 return err
141         }
142
143         catalog, err := result.ExtractServiceCatalog()
144         if err != nil {
145                 return err
146         }
147
148         if options.AllowReauth {
149                 // here we're creating a throw-away client (tac). it's a copy of the user's provider client, but
150                 // with the token and reauth func zeroed out. combined with setting `AllowReauth` to `false`,
151                 // this should retry authentication only once
152                 tac := *client
153                 tac.SetThrowaway(true)
154                 tac.ReauthFunc = nil
155                 tac.SetTokenAndAuthResult(nil)
156                 tao := options
157                 tao.AllowReauth = false
158                 client.ReauthFunc = func() error {
159                         err := v2auth(&tac, endpoint, tao, eo)
160                         if err != nil {
161                                 return err
162                         }
163                         client.CopyTokenFrom(&tac)
164                         return nil
165                 }
166         }
167         client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
168                 return V2EndpointURL(catalog, opts)
169         }
170
171         return nil
172 }
173
174 // AuthenticateV3 explicitly authenticates against the identity v3 service.
175 func AuthenticateV3(client *gophercloud.ProviderClient, options tokens3.AuthOptionsBuilder, eo gophercloud.EndpointOpts) error {
176         return v3auth(client, "", options, eo)
177 }
178
179 func v3auth(client *gophercloud.ProviderClient, endpoint string, opts tokens3.AuthOptionsBuilder, eo gophercloud.EndpointOpts) error {
180         // Override the generated service endpoint with the one returned by the version endpoint.
181         v3Client, err := NewIdentityV3(client, eo)
182         if err != nil {
183                 return err
184         }
185
186         if endpoint != "" {
187                 v3Client.Endpoint = endpoint
188         }
189
190         result := tokens3.Create(v3Client, opts)
191
192         err = client.SetTokenAndAuthResult(result)
193         if err != nil {
194                 return err
195         }
196
197         catalog, err := result.ExtractServiceCatalog()
198         if err != nil {
199                 return err
200         }
201
202         if opts.CanReauth() {
203                 // here we're creating a throw-away client (tac). it's a copy of the user's provider client, but
204                 // with the token and reauth func zeroed out. combined with setting `AllowReauth` to `false`,
205                 // this should retry authentication only once
206                 tac := *client
207                 tac.SetThrowaway(true)
208                 tac.ReauthFunc = nil
209                 tac.SetTokenAndAuthResult(nil)
210                 var tao tokens3.AuthOptionsBuilder
211                 switch ot := opts.(type) {
212                 case *gophercloud.AuthOptions:
213                         o := *ot
214                         o.AllowReauth = false
215                         tao = &o
216                 case *tokens3.AuthOptions:
217                         o := *ot
218                         o.AllowReauth = false
219                         tao = &o
220                 default:
221                         tao = opts
222                 }
223                 client.ReauthFunc = func() error {
224                         err := v3auth(&tac, endpoint, tao, eo)
225                         if err != nil {
226                                 return err
227                         }
228                         client.CopyTokenFrom(&tac)
229                         return nil
230                 }
231         }
232         client.EndpointLocator = func(opts gophercloud.EndpointOpts) (string, error) {
233                 return V3EndpointURL(catalog, opts)
234         }
235
236         return nil
237 }
238
239 // NewIdentityV2 creates a ServiceClient that may be used to interact with the
240 // v2 identity service.
241 func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
242         endpoint := client.IdentityBase + "v2.0/"
243         clientType := "identity"
244         var err error
245         if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) {
246                 eo.ApplyDefaults(clientType)
247                 endpoint, err = client.EndpointLocator(eo)
248                 if err != nil {
249                         return nil, err
250                 }
251         }
252
253         return &gophercloud.ServiceClient{
254                 ProviderClient: client,
255                 Endpoint:       endpoint,
256                 Type:           clientType,
257         }, nil
258 }
259
260 // NewIdentityV3 creates a ServiceClient that may be used to access the v3
261 // identity service.
262 func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
263         endpoint := client.IdentityBase + "v3/"
264         clientType := "identity"
265         var err error
266         if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) {
267                 eo.ApplyDefaults(clientType)
268                 endpoint, err = client.EndpointLocator(eo)
269                 if err != nil {
270                         return nil, err
271                 }
272         }
273
274         // Ensure endpoint still has a suffix of v3.
275         // This is because EndpointLocator might have found a versionless
276         // endpoint or the published endpoint is still /v2.0. In both
277         // cases, we need to fix the endpoint to point to /v3.
278         base, err := utils.BaseEndpoint(endpoint)
279         if err != nil {
280                 return nil, err
281         }
282
283         base = gophercloud.NormalizeURL(base)
284
285         endpoint = base + "v3/"
286
287         return &gophercloud.ServiceClient{
288                 ProviderClient: client,
289                 Endpoint:       endpoint,
290                 Type:           clientType,
291         }, nil
292 }
293
294 func initClientOpts(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts, clientType string) (*gophercloud.ServiceClient, error) {
295         sc := new(gophercloud.ServiceClient)
296         eo.ApplyDefaults(clientType)
297         url, err := client.EndpointLocator(eo)
298         if err != nil {
299                 return sc, err
300         }
301         sc.ProviderClient = client
302         sc.Endpoint = url
303         sc.Type = clientType
304         return sc, nil
305 }
306
307 // NewBareMetalV1 creates a ServiceClient that may be used with the v1
308 // bare metal package.
309 func NewBareMetalV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
310         return initClientOpts(client, eo, "baremetal")
311 }
312
313 // NewBareMetalIntrospectionV1 creates a ServiceClient that may be used with the v1
314 // bare metal introspection package.
315 func NewBareMetalIntrospectionV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
316         return initClientOpts(client, eo, "baremetal-inspector")
317 }
318
319 // NewObjectStorageV1 creates a ServiceClient that may be used with the v1
320 // object storage package.
321 func NewObjectStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
322         return initClientOpts(client, eo, "object-store")
323 }
324
325 // NewComputeV2 creates a ServiceClient that may be used with the v2 compute
326 // package.
327 func NewComputeV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
328         return initClientOpts(client, eo, "compute")
329 }
330
331 // NewNetworkV2 creates a ServiceClient that may be used with the v2 network
332 // package.
333 func NewNetworkV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
334         sc, err := initClientOpts(client, eo, "network")
335         sc.ResourceBase = sc.Endpoint + "v2.0/"
336         return sc, err
337 }
338
339 // NewBlockStorageV1 creates a ServiceClient that may be used to access the v1
340 // block storage service.
341 func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
342         return initClientOpts(client, eo, "volume")
343 }
344
345 // NewBlockStorageV2 creates a ServiceClient that may be used to access the v2
346 // block storage service.
347 func NewBlockStorageV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
348         return initClientOpts(client, eo, "volumev2")
349 }
350
351 // NewBlockStorageV3 creates a ServiceClient that may be used to access the v3 block storage service.
352 func NewBlockStorageV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
353         return initClientOpts(client, eo, "volumev3")
354 }
355
356 // NewSharedFileSystemV2 creates a ServiceClient that may be used to access the v2 shared file system service.
357 func NewSharedFileSystemV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
358         return initClientOpts(client, eo, "sharev2")
359 }
360
361 // NewCDNV1 creates a ServiceClient that may be used to access the OpenStack v1
362 // CDN service.
363 func NewCDNV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
364         return initClientOpts(client, eo, "cdn")
365 }
366
367 // NewOrchestrationV1 creates a ServiceClient that may be used to access the v1
368 // orchestration service.
369 func NewOrchestrationV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
370         return initClientOpts(client, eo, "orchestration")
371 }
372
373 // NewDBV1 creates a ServiceClient that may be used to access the v1 DB service.
374 func NewDBV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
375         return initClientOpts(client, eo, "database")
376 }
377
378 // NewDNSV2 creates a ServiceClient that may be used to access the v2 DNS
379 // service.
380 func NewDNSV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
381         sc, err := initClientOpts(client, eo, "dns")
382         sc.ResourceBase = sc.Endpoint + "v2/"
383         return sc, err
384 }
385
386 // NewImageServiceV2 creates a ServiceClient that may be used to access the v2
387 // image service.
388 func NewImageServiceV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
389         sc, err := initClientOpts(client, eo, "image")
390         sc.ResourceBase = sc.Endpoint + "v2/"
391         return sc, err
392 }
393
394 // NewLoadBalancerV2 creates a ServiceClient that may be used to access the v2
395 // load balancer service.
396 func NewLoadBalancerV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
397         sc, err := initClientOpts(client, eo, "load-balancer")
398         sc.ResourceBase = sc.Endpoint + "v2.0/"
399         return sc, err
400 }
401
402 // NewClusteringV1 creates a ServiceClient that may be used with the v1 clustering
403 // package.
404 func NewClusteringV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
405         return initClientOpts(client, eo, "clustering")
406 }
407
408 // NewMessagingV2 creates a ServiceClient that may be used with the v2 messaging
409 // service.
410 func NewMessagingV2(client *gophercloud.ProviderClient, clientID string, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
411         sc, err := initClientOpts(client, eo, "messaging")
412         sc.MoreHeaders = map[string]string{"Client-ID": clientID}
413         return sc, err
414 }
415
416 // NewContainerV1 creates a ServiceClient that may be used with v1 container package
417 func NewContainerV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
418         return initClientOpts(client, eo, "container")
419 }
420
421 // NewKeyManagerV1 creates a ServiceClient that may be used with the v1 key
422 // manager service.
423 func NewKeyManagerV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
424         sc, err := initClientOpts(client, eo, "key-manager")
425         sc.ResourceBase = sc.Endpoint + "v1/"
426         return sc, err
427 }
428
429 // NewContainerInfraV1 creates a ServiceClient that may be used with the v1 container infra management
430 // package.
431 func NewContainerInfraV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
432         return initClientOpts(client, eo, "container-infra")
433 }
434
435 // NewWorkflowV2 creates a ServiceClient that may be used with the v2 workflow management package.
436 func NewWorkflowV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
437         return initClientOpts(client, eo, "workflowv2")
438 }