serviceclient.go raw
1 package clientservices
2
3 import (
4 "fmt"
5 "net"
6 "net/http"
7 "time"
8
9 "github.com/gophercloud/gophercloud"
10 "github.com/gophercloud/gophercloud/openstack"
11 )
12
13 type ServiceClientOptions struct {
14 // The name of the domain in which the token will be issued.
15 DomainName string
16
17 // Credentials to auth with.
18 Username string
19 Password string
20
21 // Optional field for setting project scope.
22 ProjectID string
23
24 // Optional field. The name of the domain where the user resides (Identity v3).
25 UserDomainName string
26
27 // Field for setting Identity endpoint.
28 AuthURL string
29
30 // Field for setting location for endpoints like ResellAPI or Keystone.
31 AuthRegion string
32
33 // Optional field.
34 HTTPClient *http.Client
35
36 // Optional field.
37 UserAgent string
38 }
39
40 func NewServiceClient(options *ServiceClientOptions) (*gophercloud.ServiceClient, error) {
41 // UserDomainName field to specify the domain name where the user is located.
42 // If this field is not specified, then we will think that the token will be
43 // issued in the same domain where the user is located.
44 if options.UserDomainName == "" {
45 options.UserDomainName = options.DomainName
46 }
47
48 authOptions := gophercloud.AuthOptions{
49 AllowReauth: true,
50 IdentityEndpoint: options.AuthURL,
51 Username: options.Username,
52 Password: options.Password,
53 DomainName: options.UserDomainName,
54 Scope: &gophercloud.AuthScope{
55 ProjectID: options.ProjectID,
56 },
57 }
58
59 // If project scope is not set, we use domain scope.
60 if authOptions.Scope.ProjectID == "" {
61 authOptions.Scope.DomainName = options.DomainName
62 }
63
64 authProvider, err := openstack.AuthenticatedClient(authOptions)
65 if err != nil {
66 return nil, fmt.Errorf("failed to create auth provider, err: %w", err)
67 }
68
69 serviceClient, err := openstack.NewIdentityV3(authProvider, gophercloud.EndpointOpts{
70 Availability: gophercloud.AvailabilityPublic,
71 Region: options.AuthRegion,
72 })
73 if err != nil {
74 return nil, fmt.Errorf("failed to create service client, err: %w", err)
75 }
76
77 httpClient := options.HTTPClient
78 if httpClient == nil {
79 httpClient = NewHTTPClient()
80 }
81 serviceClient.HTTPClient = *httpClient
82
83 if options.UserAgent != "" {
84 userAgent := gophercloud.UserAgent{}
85 userAgent.Prepend(options.UserAgent)
86 serviceClient.UserAgent = userAgent
87 }
88
89 return serviceClient, nil
90 }
91
92 // ---------------------------------------------------------------------------------------------------------------------
93
94 const (
95 // httpTimeout represents the default timeout (in seconds) for HTTP
96 // requests.
97 httpTimeout = 120
98
99 // dialTimeout represents the default timeout (in seconds) for HTTP
100 // connection establishments.
101 dialTimeout = 60
102
103 // keepaliveTimeout represents the default keep-alive period for an active
104 // network connection.
105 keepaliveTimeout = 60
106
107 // maxIdleConns represents the maximum number of idle (keep-alive)
108 // connections.
109 maxIdleConns = 100
110
111 // idleConnTimeout represents the maximum amount of time an idle
112 // (keep-alive) connection will remain idle before closing itself.
113 idleConnTimeout = 100
114
115 // tlsHandshakeTimeout represents the default timeout (in seconds)
116 // for TLS handshake.
117 tlsHandshakeTimeout = 60
118
119 // expectContinueTimeout represents the default amount of time to
120 // wait for a server's first response headers.
121 expectContinueTimeout = 1
122 )
123
124 func NewHTTPClient() *http.Client {
125 return &http.Client{
126 Timeout: time.Second * httpTimeout,
127 Transport: &http.Transport{
128 Proxy: http.ProxyFromEnvironment,
129 DialContext: (&net.Dialer{
130 Timeout: dialTimeout * time.Second,
131 KeepAlive: keepaliveTimeout * time.Second,
132 }).DialContext,
133 MaxIdleConns: maxIdleConns,
134 IdleConnTimeout: idleConnTimeout * time.Second,
135 TLSHandshakeTimeout: tlsHandshakeTimeout * time.Second,
136 ExpectContinueTimeout: expectContinueTimeout * time.Second,
137 },
138 }
139 }
140