1// Package clients contains functions for creating OpenStack service clients
2// for use in acceptance tests. It also manages the required environment
3// variables to run the tests.
4package clients
5
6import (
7	"fmt"
8	"net/http"
9	"os"
10	"strings"
11
12	"github.com/gophercloud/gophercloud"
13	"github.com/gophercloud/gophercloud/openstack"
14	baremetalNoAuth "github.com/gophercloud/gophercloud/openstack/baremetal/noauth"
15	blockstorageNoAuth "github.com/gophercloud/gophercloud/openstack/blockstorage/noauth"
16)
17
18// AcceptanceTestChoices contains image and flavor selections for use by the acceptance tests.
19type AcceptanceTestChoices struct {
20	// ImageID contains the ID of a valid image.
21	ImageID string
22
23	// FlavorID contains the ID of a valid flavor.
24	FlavorID string
25
26	// FlavorIDResize contains the ID of a different flavor available on the same OpenStack installation, that is distinct
27	// from FlavorID.
28	FlavorIDResize string
29
30	// FloatingIPPool contains the name of the pool from where to obtain floating IPs.
31	FloatingIPPoolName string
32
33	// MagnumKeypair contains the ID of a valid key pair.
34	MagnumKeypair string
35
36	// MagnumImageID contains the ID of a valid magnum image.
37	MagnumImageID string
38
39	// NetworkName is the name of a network to launch the instance on.
40	NetworkName string
41
42	// NetworkID is the ID of a network to launch the instance on.
43	NetworkID string
44
45	// SubnetID is the ID of a subnet to launch the instance on.
46	SubnetID string
47
48	// ExternalNetworkID is the network ID of the external network.
49	ExternalNetworkID string
50
51	// DBDatastoreType is the datastore type for DB tests.
52	DBDatastoreType string
53
54	// DBDatastoreTypeID is the datastore type version for DB tests.
55	DBDatastoreVersion string
56}
57
58// AcceptanceTestChoicesFromEnv populates a ComputeChoices struct from environment variables.
59// If any required state is missing, an `error` will be returned that enumerates the missing properties.
60func AcceptanceTestChoicesFromEnv() (*AcceptanceTestChoices, error) {
61	imageID := os.Getenv("OS_IMAGE_ID")
62	flavorID := os.Getenv("OS_FLAVOR_ID")
63	flavorIDResize := os.Getenv("OS_FLAVOR_ID_RESIZE")
64	magnumImageID := os.Getenv("OS_MAGNUM_IMAGE_ID")
65	magnumKeypair := os.Getenv("OS_MAGNUM_KEYPAIR")
66	networkName := os.Getenv("OS_NETWORK_NAME")
67	networkID := os.Getenv("OS_NETWORK_ID")
68	subnetID := os.Getenv("OS_SUBNET_ID")
69	floatingIPPoolName := os.Getenv("OS_POOL_NAME")
70	externalNetworkID := os.Getenv("OS_EXTGW_ID")
71	dbDatastoreType := os.Getenv("OS_DB_DATASTORE_TYPE")
72	dbDatastoreVersion := os.Getenv("OS_DB_DATASTORE_VERSION")
73
74	missing := make([]string, 0, 3)
75	if imageID == "" {
76		missing = append(missing, "OS_IMAGE_ID")
77	}
78	if flavorID == "" {
79		missing = append(missing, "OS_FLAVOR_ID")
80	}
81	if flavorIDResize == "" {
82		missing = append(missing, "OS_FLAVOR_ID_RESIZE")
83	}
84	if floatingIPPoolName == "" {
85		missing = append(missing, "OS_POOL_NAME")
86	}
87	if externalNetworkID == "" {
88		missing = append(missing, "OS_EXTGW_ID")
89	}
90
91	/* // Temporarily disabled, see https://github.com/gophercloud/gophercloud/issues/1345
92	if networkID == "" {
93		missing = append(missing, "OS_NETWORK_ID")
94	}
95	if subnetID == "" {
96		missing = append(missing, "OS_SUBNET_ID")
97	}
98	*/
99
100	if networkName == "" {
101		networkName = "private"
102	}
103	notDistinct := ""
104	if flavorID == flavorIDResize {
105		notDistinct = "OS_FLAVOR_ID and OS_FLAVOR_ID_RESIZE must be distinct."
106	}
107
108	if len(missing) > 0 || notDistinct != "" {
109		text := "You're missing some important setup:\n"
110		if len(missing) > 0 {
111			text += " * These environment variables must be provided: " + strings.Join(missing, ", ") + "\n"
112		}
113		if notDistinct != "" {
114			text += " * " + notDistinct + "\n"
115		}
116
117		return nil, fmt.Errorf(text)
118	}
119
120	return &AcceptanceTestChoices{
121		ImageID:            imageID,
122		FlavorID:           flavorID,
123		FlavorIDResize:     flavorIDResize,
124		FloatingIPPoolName: floatingIPPoolName,
125		MagnumImageID:      magnumImageID,
126		MagnumKeypair:      magnumKeypair,
127		NetworkName:        networkName,
128		NetworkID:          networkID,
129		SubnetID:           subnetID,
130		ExternalNetworkID:  externalNetworkID,
131		DBDatastoreType:    dbDatastoreType,
132		DBDatastoreVersion: dbDatastoreVersion,
133	}, nil
134}
135
136// NewBlockStorageV1Client returns a *ServiceClient for making calls
137// to the OpenStack Block Storage v1 API. An error will be returned
138// if authentication or client creation was not possible.
139func NewBlockStorageV1Client() (*gophercloud.ServiceClient, error) {
140	ao, err := openstack.AuthOptionsFromEnv()
141	if err != nil {
142		return nil, err
143	}
144
145	client, err := openstack.AuthenticatedClient(ao)
146	if err != nil {
147		return nil, err
148	}
149
150	client = configureDebug(client)
151
152	return openstack.NewBlockStorageV1(client, gophercloud.EndpointOpts{
153		Region: os.Getenv("OS_REGION_NAME"),
154	})
155}
156
157// NewBlockStorageV2Client returns a *ServiceClient for making calls
158// to the OpenStack Block Storage v2 API. An error will be returned
159// if authentication or client creation was not possible.
160func NewBlockStorageV2Client() (*gophercloud.ServiceClient, error) {
161	ao, err := openstack.AuthOptionsFromEnv()
162	if err != nil {
163		return nil, err
164	}
165
166	client, err := openstack.AuthenticatedClient(ao)
167	if err != nil {
168		return nil, err
169	}
170
171	client = configureDebug(client)
172
173	return openstack.NewBlockStorageV2(client, gophercloud.EndpointOpts{
174		Region: os.Getenv("OS_REGION_NAME"),
175	})
176}
177
178// NewBlockStorageV3Client returns a *ServiceClient for making calls
179// to the OpenStack Block Storage v3 API. An error will be returned
180// if authentication or client creation was not possible.
181func NewBlockStorageV3Client() (*gophercloud.ServiceClient, error) {
182	ao, err := openstack.AuthOptionsFromEnv()
183	if err != nil {
184		return nil, err
185	}
186
187	client, err := openstack.AuthenticatedClient(ao)
188	if err != nil {
189		return nil, err
190	}
191
192	client = configureDebug(client)
193
194	return openstack.NewBlockStorageV3(client, gophercloud.EndpointOpts{
195		Region: os.Getenv("OS_REGION_NAME"),
196	})
197}
198
199// NewBlockStorageV2NoAuthClient returns a noauth *ServiceClient for
200// making calls to the OpenStack Block Storage v2 API. An error will be
201// returned if client creation was not possible.
202func NewBlockStorageV2NoAuthClient() (*gophercloud.ServiceClient, error) {
203	client, err := blockstorageNoAuth.NewClient(gophercloud.AuthOptions{
204		Username:   os.Getenv("OS_USERNAME"),
205		TenantName: os.Getenv("OS_TENANT_NAME"),
206	})
207	if err != nil {
208		return nil, err
209	}
210
211	client = configureDebug(client)
212
213	return blockstorageNoAuth.NewBlockStorageNoAuth(client, blockstorageNoAuth.EndpointOpts{
214		CinderEndpoint: os.Getenv("CINDER_ENDPOINT"),
215	})
216}
217
218// NewBlockStorageV3NoAuthClient returns a noauth *ServiceClient for
219// making calls to the OpenStack Block Storage v2 API. An error will be
220// returned if client creation was not possible.
221func NewBlockStorageV3NoAuthClient() (*gophercloud.ServiceClient, error) {
222	client, err := blockstorageNoAuth.NewClient(gophercloud.AuthOptions{
223		Username:   os.Getenv("OS_USERNAME"),
224		TenantName: os.Getenv("OS_TENANT_NAME"),
225	})
226	if err != nil {
227		return nil, err
228	}
229
230	client = configureDebug(client)
231
232	return blockstorageNoAuth.NewBlockStorageNoAuth(client, blockstorageNoAuth.EndpointOpts{
233		CinderEndpoint: os.Getenv("CINDER_ENDPOINT"),
234	})
235}
236
237// NewComputeV2Client returns a *ServiceClient for making calls
238// to the OpenStack Compute v2 API. An error will be returned
239// if authentication or client creation was not possible.
240func NewComputeV2Client() (*gophercloud.ServiceClient, error) {
241	ao, err := openstack.AuthOptionsFromEnv()
242	if err != nil {
243		return nil, err
244	}
245
246	client, err := openstack.AuthenticatedClient(ao)
247	if err != nil {
248		return nil, err
249	}
250
251	client = configureDebug(client)
252
253	return openstack.NewComputeV2(client, gophercloud.EndpointOpts{
254		Region: os.Getenv("OS_REGION_NAME"),
255	})
256}
257
258// NewBareMetalV1Client returns a *ServiceClient for making calls
259// to the OpenStack Bare Metal v1 API. An error will be returned
260// if authentication or client creation was not possible.
261func NewBareMetalV1Client() (*gophercloud.ServiceClient, error) {
262	ao, err := openstack.AuthOptionsFromEnv()
263	if err != nil {
264		return nil, err
265	}
266
267	client, err := openstack.AuthenticatedClient(ao)
268	if err != nil {
269		return nil, err
270	}
271
272	client = configureDebug(client)
273
274	return openstack.NewBareMetalV1(client, gophercloud.EndpointOpts{
275		Region: os.Getenv("OS_REGION_NAME"),
276	})
277}
278
279// NewBareMetalV1NoAuthClient returns a *ServiceClient for making calls
280// to the OpenStack Bare Metal v1 API. An error will be returned
281// if authentication or client creation was not possible.
282func NewBareMetalV1NoAuthClient() (*gophercloud.ServiceClient, error) {
283	return baremetalNoAuth.NewBareMetalNoAuth(baremetalNoAuth.EndpointOpts{
284		IronicEndpoint: os.Getenv("IRONIC_ENDPOINT"),
285	})
286}
287
288// NewBareMetalIntrospectionV1Client returns a *ServiceClient for making calls
289// to the OpenStack Bare Metal Introspection v1 API. An error will be returned
290// if authentication or client creation was not possible.
291func NewBareMetalIntrospectionV1Client() (*gophercloud.ServiceClient, error) {
292	ao, err := openstack.AuthOptionsFromEnv()
293	if err != nil {
294		return nil, err
295	}
296
297	client, err := openstack.AuthenticatedClient(ao)
298	if err != nil {
299		return nil, err
300	}
301
302	client = configureDebug(client)
303
304	return openstack.NewBareMetalIntrospectionV1(client, gophercloud.EndpointOpts{
305		Region: os.Getenv("OS_REGION_NAME"),
306	})
307}
308
309// NewDBV1Client returns a *ServiceClient for making calls
310// to the OpenStack Database v1 API. An error will be returned
311// if authentication or client creation was not possible.
312func NewDBV1Client() (*gophercloud.ServiceClient, error) {
313	ao, err := openstack.AuthOptionsFromEnv()
314	if err != nil {
315		return nil, err
316	}
317
318	client, err := openstack.AuthenticatedClient(ao)
319	if err != nil {
320		return nil, err
321	}
322
323	client = configureDebug(client)
324
325	return openstack.NewDBV1(client, gophercloud.EndpointOpts{
326		Region: os.Getenv("OS_REGION_NAME"),
327	})
328}
329
330// NewDNSV2Client returns a *ServiceClient for making calls
331// to the OpenStack Compute v2 API. An error will be returned
332// if authentication or client creation was not possible.
333func NewDNSV2Client() (*gophercloud.ServiceClient, error) {
334	ao, err := openstack.AuthOptionsFromEnv()
335	if err != nil {
336		return nil, err
337	}
338
339	client, err := openstack.AuthenticatedClient(ao)
340	if err != nil {
341		return nil, err
342	}
343
344	client = configureDebug(client)
345
346	return openstack.NewDNSV2(client, gophercloud.EndpointOpts{
347		Region: os.Getenv("OS_REGION_NAME"),
348	})
349}
350
351// NewIdentityV2Client returns a *ServiceClient for making calls
352// to the OpenStack Identity v2 API. An error will be returned
353// if authentication or client creation was not possible.
354func NewIdentityV2Client() (*gophercloud.ServiceClient, error) {
355	ao, err := openstack.AuthOptionsFromEnv()
356	if err != nil {
357		return nil, err
358	}
359
360	client, err := openstack.AuthenticatedClient(ao)
361	if err != nil {
362		return nil, err
363	}
364
365	client = configureDebug(client)
366
367	return openstack.NewIdentityV2(client, gophercloud.EndpointOpts{
368		Region: os.Getenv("OS_REGION_NAME"),
369	})
370}
371
372// NewIdentityV2AdminClient returns a *ServiceClient for making calls
373// to the Admin Endpoint of the OpenStack Identity v2 API. An error
374// will be returned if authentication or client creation was not possible.
375func NewIdentityV2AdminClient() (*gophercloud.ServiceClient, error) {
376	ao, err := openstack.AuthOptionsFromEnv()
377	if err != nil {
378		return nil, err
379	}
380
381	client, err := openstack.AuthenticatedClient(ao)
382	if err != nil {
383		return nil, err
384	}
385
386	client = configureDebug(client)
387
388	return openstack.NewIdentityV2(client, gophercloud.EndpointOpts{
389		Region:       os.Getenv("OS_REGION_NAME"),
390		Availability: gophercloud.AvailabilityAdmin,
391	})
392}
393
394// NewIdentityV2UnauthenticatedClient returns an unauthenticated *ServiceClient
395// for the OpenStack Identity v2 API. An error  will be returned if
396// authentication or client creation was not possible.
397func NewIdentityV2UnauthenticatedClient() (*gophercloud.ServiceClient, error) {
398	ao, err := openstack.AuthOptionsFromEnv()
399	if err != nil {
400		return nil, err
401	}
402
403	client, err := openstack.NewClient(ao.IdentityEndpoint)
404	if err != nil {
405		return nil, err
406	}
407
408	client = configureDebug(client)
409
410	return openstack.NewIdentityV2(client, gophercloud.EndpointOpts{})
411}
412
413// NewIdentityV3Client returns a *ServiceClient for making calls
414// to the OpenStack Identity v3 API. An error will be returned
415// if authentication or client creation was not possible.
416func NewIdentityV3Client() (*gophercloud.ServiceClient, error) {
417	ao, err := openstack.AuthOptionsFromEnv()
418	if err != nil {
419		return nil, err
420	}
421
422	client, err := openstack.AuthenticatedClient(ao)
423	if err != nil {
424		return nil, err
425	}
426
427	client = configureDebug(client)
428
429	return openstack.NewIdentityV3(client, gophercloud.EndpointOpts{
430		Region: os.Getenv("OS_REGION_NAME"),
431	})
432}
433
434// NewIdentityV3UnauthenticatedClient returns an unauthenticated *ServiceClient
435// for the OpenStack Identity v3 API. An error  will be returned if
436// authentication or client creation was not possible.
437func NewIdentityV3UnauthenticatedClient() (*gophercloud.ServiceClient, error) {
438	ao, err := openstack.AuthOptionsFromEnv()
439	if err != nil {
440		return nil, err
441	}
442
443	client, err := openstack.NewClient(ao.IdentityEndpoint)
444	if err != nil {
445		return nil, err
446	}
447
448	client = configureDebug(client)
449
450	return openstack.NewIdentityV3(client, gophercloud.EndpointOpts{})
451}
452
453// NewImageServiceV2Client returns a *ServiceClient for making calls to the
454// OpenStack Image v2 API. An error will be returned if authentication or
455// client creation was not possible.
456func NewImageServiceV2Client() (*gophercloud.ServiceClient, error) {
457	ao, err := openstack.AuthOptionsFromEnv()
458	if err != nil {
459		return nil, err
460	}
461
462	client, err := openstack.AuthenticatedClient(ao)
463	if err != nil {
464		return nil, err
465	}
466
467	client = configureDebug(client)
468
469	return openstack.NewImageServiceV2(client, gophercloud.EndpointOpts{
470		Region: os.Getenv("OS_REGION_NAME"),
471	})
472}
473
474// NewNetworkV2Client returns a *ServiceClient for making calls to the
475// OpenStack Networking v2 API. An error will be returned if authentication
476// or client creation was not possible.
477func NewNetworkV2Client() (*gophercloud.ServiceClient, error) {
478	ao, err := openstack.AuthOptionsFromEnv()
479	if err != nil {
480		return nil, err
481	}
482
483	client, err := openstack.AuthenticatedClient(ao)
484	if err != nil {
485		return nil, err
486	}
487
488	client = configureDebug(client)
489
490	return openstack.NewNetworkV2(client, gophercloud.EndpointOpts{
491		Region: os.Getenv("OS_REGION_NAME"),
492	})
493}
494
495// NewObjectStorageV1Client returns a *ServiceClient for making calls to the
496// OpenStack Object Storage v1 API. An error will be returned if authentication
497// or client creation was not possible.
498func NewObjectStorageV1Client() (*gophercloud.ServiceClient, error) {
499	ao, err := openstack.AuthOptionsFromEnv()
500	if err != nil {
501		return nil, err
502	}
503
504	client, err := openstack.AuthenticatedClient(ao)
505	if err != nil {
506		return nil, err
507	}
508
509	client = configureDebug(client)
510
511	return openstack.NewObjectStorageV1(client, gophercloud.EndpointOpts{
512		Region: os.Getenv("OS_REGION_NAME"),
513	})
514}
515
516// NewSharedFileSystemV2Client returns a *ServiceClient for making calls
517// to the OpenStack Shared File System v2 API. An error will be returned
518// if authentication or client creation was not possible.
519func NewSharedFileSystemV2Client() (*gophercloud.ServiceClient, error) {
520	ao, err := openstack.AuthOptionsFromEnv()
521	if err != nil {
522		return nil, err
523	}
524
525	client, err := openstack.AuthenticatedClient(ao)
526	if err != nil {
527		return nil, err
528	}
529
530	client = configureDebug(client)
531
532	return openstack.NewSharedFileSystemV2(client, gophercloud.EndpointOpts{
533		Region: os.Getenv("OS_REGION_NAME"),
534	})
535}
536
537// NewLoadBalancerV2Client returns a *ServiceClient for making calls to the
538// OpenStack Octavia v2 API. An error will be returned if authentication
539// or client creation was not possible.
540func NewLoadBalancerV2Client() (*gophercloud.ServiceClient, error) {
541	ao, err := openstack.AuthOptionsFromEnv()
542	if err != nil {
543		return nil, err
544	}
545
546	client, err := openstack.AuthenticatedClient(ao)
547	if err != nil {
548		return nil, err
549	}
550
551	client = configureDebug(client)
552
553	return openstack.NewLoadBalancerV2(client, gophercloud.EndpointOpts{
554		Region: os.Getenv("OS_REGION_NAME"),
555	})
556}
557
558// NewClusteringV1Client returns a *ServiceClient for making calls
559// to the OpenStack Clustering v1 API. An error will be returned
560// if authentication or client creation was not possible.
561func NewClusteringV1Client() (*gophercloud.ServiceClient, error) {
562	ao, err := openstack.AuthOptionsFromEnv()
563	if err != nil {
564		return nil, err
565	}
566
567	client, err := openstack.AuthenticatedClient(ao)
568	if err != nil {
569		return nil, err
570	}
571
572	client = configureDebug(client)
573
574	return openstack.NewClusteringV1(client, gophercloud.EndpointOpts{
575		Region: os.Getenv("OS_REGION_NAME"),
576	})
577}
578
579// NewMessagingV2Client returns a *ServiceClient for making calls
580// to the OpenStack Messaging (Zaqar) v2 API. An error will be returned
581// if authentication or client creation was not possible.
582func NewMessagingV2Client(clientID string) (*gophercloud.ServiceClient, error) {
583	ao, err := openstack.AuthOptionsFromEnv()
584	if err != nil {
585		return nil, err
586	}
587
588	client, err := openstack.AuthenticatedClient(ao)
589	if err != nil {
590		return nil, err
591	}
592
593	client = configureDebug(client)
594
595	return openstack.NewMessagingV2(client, clientID, gophercloud.EndpointOpts{
596		Region: os.Getenv("OS_REGION_NAME"),
597	})
598}
599
600// NewContainerV1Client returns a *ServiceClient for making calls
601// to the OpenStack Container V1 API. An error will be returned
602// if authentication or client creation was not possible.
603func NewContainerV1Client() (*gophercloud.ServiceClient, error) {
604	ao, err := openstack.AuthOptionsFromEnv()
605	if err != nil {
606		return nil, err
607	}
608
609	client, err := openstack.AuthenticatedClient(ao)
610	if err != nil {
611		return nil, err
612	}
613
614	client = configureDebug(client)
615
616	return openstack.NewContainerV1(client, gophercloud.EndpointOpts{
617		Region: os.Getenv("OS_REGION_NAME"),
618	})
619}
620
621// NewKeyManagerV1Client returns a *ServiceClient for making calls
622// to the OpenStack Key Manager (Barbican) v1 API. An error will be
623// returned if authentication or client creation was not possible.
624func NewKeyManagerV1Client() (*gophercloud.ServiceClient, error) {
625	ao, err := openstack.AuthOptionsFromEnv()
626	if err != nil {
627		return nil, err
628	}
629
630	client, err := openstack.AuthenticatedClient(ao)
631	if err != nil {
632		return nil, err
633	}
634
635	client = configureDebug(client)
636
637	return openstack.NewKeyManagerV1(client, gophercloud.EndpointOpts{
638		Region: os.Getenv("OS_REGION_NAME"),
639	})
640}
641
642// configureDebug will configure the provider client to print the API
643// requests and responses if OS_DEBUG is enabled.
644func configureDebug(client *gophercloud.ProviderClient) *gophercloud.ProviderClient {
645	if os.Getenv("OS_DEBUG") != "" {
646		client.HTTPClient = http.Client{
647			Transport: &LogRoundTripper{
648				Rt: &http.Transport{},
649			},
650		}
651	}
652
653	return client
654}
655
656// NewContainerInfraV1Client returns a *ServiceClient for making calls
657// to the OpenStack Container Infra Management v1 API. An error will be returned
658// if authentication or client creation was not possible.
659func NewContainerInfraV1Client() (*gophercloud.ServiceClient, error) {
660	ao, err := openstack.AuthOptionsFromEnv()
661	if err != nil {
662		return nil, err
663	}
664
665	client, err := openstack.AuthenticatedClient(ao)
666	if err != nil {
667		return nil, err
668	}
669
670	client = configureDebug(client)
671
672	return openstack.NewContainerInfraV1(client, gophercloud.EndpointOpts{
673		Region: os.Getenv("OS_REGION_NAME"),
674	})
675}
676
677// NewWorkflowV2Client returns a *ServiceClient for making calls
678// to the OpenStack Workflow v2 API (Mistral). An error will be returned if
679// authentication or client creation failed.
680func NewWorkflowV2Client() (*gophercloud.ServiceClient, error) {
681	ao, err := openstack.AuthOptionsFromEnv()
682	if err != nil {
683		return nil, err
684	}
685
686	client, err := openstack.AuthenticatedClient(ao)
687	if err != nil {
688		return nil, err
689	}
690
691	client = configureDebug(client)
692
693	return openstack.NewWorkflowV2(client, gophercloud.EndpointOpts{
694		Region: os.Getenv("OS_REGION_NAME"),
695	})
696}
697
698// NewOrchestrationV1Client returns a *ServiceClient for making calls
699// to the OpenStack Orchestration v1 API. An error will be returned
700// if authentication or client creation was not possible.
701func NewOrchestrationV1Client() (*gophercloud.ServiceClient, error) {
702	ao, err := openstack.AuthOptionsFromEnv()
703	if err != nil {
704		return nil, err
705	}
706
707	client, err := openstack.AuthenticatedClient(ao)
708	if err != nil {
709		return nil, err
710	}
711
712	client = configureDebug(client)
713
714	return openstack.NewOrchestrationV1(client, gophercloud.EndpointOpts{
715		Region: os.Getenv("OS_REGION_NAME"),
716	})
717}
718
719// NewPlacementV1Client returns a *ServiceClient for making calls
720// to the OpenStack Placement API. An error will be returned
721// if authentication or client creation was not possible.
722func NewPlacementV1Client() (*gophercloud.ServiceClient, error) {
723	ao, err := openstack.AuthOptionsFromEnv()
724	if err != nil {
725		return nil, err
726	}
727
728	client, err := openstack.AuthenticatedClient(ao)
729	if err != nil {
730		return nil, err
731	}
732
733	client = configureDebug(client)
734
735	return openstack.NewPlacementV1(client, gophercloud.EndpointOpts{
736		Region: os.Getenv("OS_REGION_NAME"),
737	})
738}
739