-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathhttpclient.go
154 lines (121 loc) · 4.45 KB
/
httpclient.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package httpclient
import (
"crypto/tls"
"fmt"
"net/http"
"strings"
httptransport "github.com/go-openapi/runtime/client"
"github.com/hashicorp/go-cleanhttp"
"golang.org/x/oauth2"
"github.com/hashicorp/hcp-sdk-go/config"
"github.com/hashicorp/hcp-sdk-go/version"
)
// Config contains the client's configuration options
type Config struct {
// HCPConfig contains values that allow to interact with HCP APIs.
config.HCPConfig
// HostPath is the host name of the HCP API, without a scheme prefix.
//
// Deprecated: HCPConfig should be used instead
HostPath string `json:"host_path"`
// AuthURL is the URL of the authentication provider, inclusive of the 'https' scheme prefix.
//
// Deprecated: HCPConfig should be used instead
AuthURL string `json:"auth_url"`
// ClientID is the client ID of a Service Principal Key.
//
// Deprecated: HCPConfig should be used instead
ClientID string `json:"client_id"`
// ClientSecret is the client secret of a Service Principal Key, only provided on creation.
//
// Deprecated: HCPConfig should be used instead
ClientSecret string `json:"client_secret"`
// SourceChannel denotes the client (channel) that originiated the request.
// This is synonymous to a user-agent.
SourceChannel string `json:"source_channel"`
// Client allows passing a custom http.Client to be used instead of the
// cleanhttp default one for both Auth and API requests. This should be used only for testing
// in testing to provide the httptest.Server's custom client that will trust
// its TLS cert.
//
// Deprecated: HCPConfig should be used instead
Client *http.Client
}
// New creates a client with the right base path to connect to any HCP API
func New(cfg Config) (runtime *httptransport.Runtime, err error) {
// Populate default values where possible.
if err = cfg.Canonicalize(); err != nil {
return nil, fmt.Errorf("invalid config: %w", err)
}
// Create a transport using the API TLS config.
tlsTransport := cleanhttp.DefaultPooledTransport()
tlsTransport.TLSClientConfig = cfg.APITLSConfig()
// Wrap the transport in an oauth2.Transport.
var transport http.RoundTripper = &oauth2.Transport{
Base: tlsTransport,
Source: cfg,
}
var opts []MiddlewareOption
if cfg.SourceChannel != "" {
// Use custom transport in order to set the source channel header when it is present.
sc := fmt.Sprintf("%s hcp-go-sdk/%s", cfg.SourceChannel, version.Version)
opts = append(opts, withSourceChannel(sc))
}
if cfg.Profile().OrganizationID != "" && cfg.Profile().ProjectID != "" {
opts = append(opts, withOrgAndProjectIDs(cfg.Profile().OrganizationID, cfg.Profile().ProjectID))
}
transport = &roundTripperWithMiddleware{
OriginalRoundTripper: transport,
MiddlewareOptions: opts,
}
// Set the scheme based on the TLS configuration.
scheme := "https"
if cfg.APITLSConfig() == nil {
scheme = "http"
}
// Create a runtime that can be used by the generated clients.
runtime = httptransport.New(cfg.APIAddress(), "", []string{scheme})
runtime.Transport = transport
return runtime, nil
}
// Canonicalize populates default values for config fields that are otherwise unset.
func (c *Config) Canonicalize() error {
// When a HCPConfig is provided it is expected to be canonical and
// deprecated configuration values will be ignored.
if c.HCPConfig != nil {
return nil
}
tlsConfig := &tls.Config{}
// Use the test client's TLS configuration, if one was provided
if c.Client != nil {
httpTransport, ok := c.Client.Transport.(*http.Transport)
if ok {
tlsConfig = httpTransport.TLSClientConfig
}
}
// Otherwise, construct a HCPConfig
options := []config.HCPConfigOption{config.FromEnv()}
if c.HostPath != "" {
// Allow https:// prefix on HostPath even though it's the only scheme we allow
// as it's more natural to support the URL. Any other scheme we don't strip
// which will fail validation.
if strings.HasPrefix(strings.ToLower(c.HostPath), "https://") {
c.HostPath = c.HostPath[8:]
}
options = append(options, config.WithAPI(c.HostPath, tlsConfig))
}
if c.AuthURL != "" {
options = append(options, config.WithAuth(c.AuthURL, tlsConfig))
}
if c.ClientID != "" && c.ClientSecret != "" {
options = append(options, config.WithClientCredentials(c.ClientID, c.ClientSecret))
}
var err error
c.HCPConfig, err = config.NewHCPConfig(options...)
if err != nil {
return fmt.Errorf("failed to construct HCP config: %w", err)
}
return nil
}