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