client.go raw
1 // Package v3 provides primitives to interact with the openapi HTTP API.
2 //
3 // Code generated by github.com/egoscale/v3/generator version v0.0.1 DO NOT EDIT.
4 package v3
5
6 import (
7 "context"
8 "fmt"
9 "io"
10 "log"
11 "net/http"
12 "runtime"
13 "time"
14
15 "github.com/exoscale/egoscale/v3/credentials"
16 "github.com/go-playground/validator/v10"
17 "github.com/hashicorp/go-retryablehttp"
18 )
19
20 // Endpoint represents a zone endpoint.
21 type Endpoint string
22
23 const (
24 CHGva2 Endpoint = "https://api-ch-gva-2.exoscale.com/v2"
25 CHDk2 Endpoint = "https://api-ch-dk-2.exoscale.com/v2"
26 DEFra1 Endpoint = "https://api-de-fra-1.exoscale.com/v2"
27 DEMuc1 Endpoint = "https://api-de-muc-1.exoscale.com/v2"
28 ATVie1 Endpoint = "https://api-at-vie-1.exoscale.com/v2"
29 ATVie2 Endpoint = "https://api-at-vie-2.exoscale.com/v2"
30 BGSof1 Endpoint = "https://api-bg-sof-1.exoscale.com/v2"
31 HrZag1 Endpoint = "https://api-hr-zag-1.exoscale.com/v2"
32 )
33
34 // defaultHTTPClient is HTTP client with retry logic.
35 // Default retry configuration can be found in go-retryablehttp repo.
36 var defaultHTTPClient = func() *http.Client {
37 rc := retryablehttp.NewClient()
38 // silence client by default
39 rc.Logger = log.New(io.Discard, "", 0)
40 return rc.StandardClient()
41 }()
42
43 func (c Client) GetZoneName(ctx context.Context, endpoint Endpoint) (ZoneName, error) {
44 resp, err := c.ListZones(ctx)
45 if err != nil {
46 return "", fmt.Errorf("get zone name: list zones: %w", err)
47 }
48
49 zone, err := resp.FindZone(string(endpoint))
50 if err != nil {
51 return "", fmt.Errorf("get zone name: find zone: %w", err)
52 }
53
54 return zone.Name, nil
55 }
56
57 func (c Client) GetZoneAPIEndpoint(ctx context.Context, zoneName ZoneName) (Endpoint, error) {
58 resp, err := c.ListZones(ctx)
59 if err != nil {
60 return "", fmt.Errorf("get zone api endpoint: list zones: %w", err)
61 }
62
63 zone, err := resp.FindZone(string(zoneName))
64 if err != nil {
65 return "", fmt.Errorf("get zone api endpoint: find zone: %w", err)
66 }
67
68 return zone.APIEndpoint, nil
69 }
70
71 // Client represents an Exoscale API client.
72 type Client struct {
73 apiKey string
74 apiSecret string
75 userAgent string
76 serverEndpoint string
77 httpClient *http.Client
78 waitTimeout time.Duration
79 validate *validator.Validate
80 trace bool
81
82 // A list of callbacks for modifying requests which are generated before sending over
83 // the network.
84 requestInterceptors []RequestInterceptorFn
85 }
86
87 // RequestInterceptorFn is the function signature for the RequestInterceptor callback function
88 type RequestInterceptorFn func(ctx context.Context, req *http.Request) error
89
90 // Deprecated: use ClientOptWithUserAgent instead.
91 var UserAgent = getDefaultUserAgent()
92
93 // ClientOpt represents a function setting Exoscale API client option.
94 type ClientOpt func(*Client) error
95
96 // ClientOptWithTrace returns a ClientOpt enabling HTTP request/response tracing.
97 func ClientOptWithTrace() ClientOpt {
98 return func(c *Client) error {
99 c.trace = true
100 return nil
101 }
102 }
103
104 // ClientOptWithUserAgent returns a ClientOpt setting the user agent header.
105 func ClientOptWithUserAgent(ua string) ClientOpt {
106 return func(c *Client) error {
107 c.userAgent = ua + " " + getDefaultUserAgent()
108 return nil
109 }
110 }
111
112 // ClientOptWithValidator returns a ClientOpt with a given validator.
113 func ClientOptWithValidator(validate *validator.Validate) ClientOpt {
114 return func(c *Client) error {
115 c.validate = validate
116 return nil
117 }
118 }
119
120 // ClientOptWithEndpoint returns a ClientOpt With a given zone Endpoint.
121 func ClientOptWithEndpoint(endpoint Endpoint) ClientOpt {
122 return func(c *Client) error {
123 c.serverEndpoint = string(endpoint)
124 return nil
125 }
126 }
127
128 // ClientOptWithWaitTimeout returns a ClientOpt With a given wait timeout.
129 func ClientOptWithWaitTimeout(t time.Duration) ClientOpt {
130 return func(c *Client) error {
131 c.waitTimeout = t
132 return nil
133 }
134 }
135
136 // ClientOptWithRequestInterceptors returns a ClientOpt With given RequestInterceptors.
137 func ClientOptWithRequestInterceptors(f ...RequestInterceptorFn) ClientOpt {
138 return func(c *Client) error {
139 c.requestInterceptors = append(c.requestInterceptors, f...)
140 return nil
141 }
142 }
143
144 // ClientOptWithHTTPClient returns a ClientOpt overriding the default http.Client.
145 // Note: the Exoscale API client will chain additional middleware
146 // (http.RoundTripper) on the HTTP client internally, which can alter the HTTP
147 // requests and responses. If you don't want any other middleware than the ones
148 // currently set to your HTTP client, you should duplicate it and pass a copy
149 // instead.
150 func ClientOptWithHTTPClient(v *http.Client) ClientOpt {
151 return func(c *Client) error {
152 c.httpClient = v
153
154 return nil
155 }
156 }
157
158 // getDefaultUserAgent returns the "User-Agent" HTTP request header added to outgoing HTTP requests.
159 func getDefaultUserAgent() string {
160 return fmt.Sprintf("egoscale/%s (%s; %s/%s)",
161 Version,
162 runtime.Version(),
163 runtime.GOOS,
164 runtime.GOARCH)
165 }
166
167 // NewClient returns a new Exoscale API client.
168 func NewClient(credentials *credentials.Credentials, opts ...ClientOpt) (*Client, error) {
169 values, err := credentials.Get()
170 if err != nil {
171 return nil, err
172 }
173
174 client := &Client{
175 apiKey: values.APIKey,
176 apiSecret: values.APISecret,
177 serverEndpoint: string(CHGva2),
178 httpClient: defaultHTTPClient,
179 validate: validator.New(),
180 userAgent: getDefaultUserAgent(),
181 }
182
183 for _, opt := range opts {
184 if err := opt(client); err != nil {
185 return nil, fmt.Errorf("client configuration error: %s", err)
186 }
187 }
188
189 return client, nil
190 }
191
192 // getUserAgent only for compatibility with UserAgent.
193 func (c *Client) getUserAgent() string {
194 defaultUA := getDefaultUserAgent()
195
196 if c.userAgent != defaultUA {
197 return c.userAgent
198 }
199
200 if UserAgent != defaultUA {
201 return UserAgent
202 }
203
204 return c.userAgent
205 }
206
207 // WithEndpoint returns a copy of Client with new zone Endpoint.
208 func (c *Client) WithEndpoint(endpoint Endpoint) *Client {
209 clone := cloneClient(c)
210
211 clone.serverEndpoint = string(endpoint)
212
213 return clone
214 }
215
216 // WithWaitTimeout returns a copy of Client with new wait timeout.
217 func (c *Client) WithWaitTimeout(t time.Duration) *Client {
218 clone := cloneClient(c)
219
220 clone.waitTimeout = t
221
222 return clone
223 }
224
225 // WithUserAgent returns a copy of Client with new User-Agent.
226 func (c *Client) WithUserAgent(ua string) *Client {
227 clone := cloneClient(c)
228
229 clone.userAgent = ua + " " + getDefaultUserAgent()
230
231 return clone
232 }
233
234 // WithTrace returns a copy of Client with tracing enabled.
235 func (c *Client) WithTrace() *Client {
236 clone := cloneClient(c)
237
238 clone.trace = true
239
240 return clone
241 }
242
243 // WithHttpClient returns a copy of Client with new http.Client.
244 // Deprecated: use WithHTTPClient instead.
245 func (c *Client) WithHttpClient(client *http.Client) *Client {
246 clone := cloneClient(c)
247
248 clone.httpClient = client
249
250 return clone
251 }
252
253 // WithHTTPClient returns a copy of Client with new http.Client.
254 func (c *Client) WithHTTPClient(client *http.Client) *Client {
255 clone := cloneClient(c)
256
257 clone.httpClient = client
258
259 return clone
260 }
261
262 // WithRequestInterceptor returns a copy of Client with new RequestInterceptors.
263 func (c *Client) WithRequestInterceptor(f ...RequestInterceptorFn) *Client {
264 clone := cloneClient(c)
265
266 clone.requestInterceptors = append(clone.requestInterceptors, f...)
267
268 return clone
269 }
270
271 func (c *Client) executeRequestInterceptors(ctx context.Context, req *http.Request) error {
272 for _, fn := range c.requestInterceptors {
273 if err := fn(ctx, req); err != nil {
274 return err
275 }
276 }
277
278 return nil
279 }
280
281 func cloneClient(c *Client) *Client {
282 return &Client{
283 apiKey: c.apiKey,
284 apiSecret: c.apiSecret,
285 userAgent: c.userAgent,
286 serverEndpoint: c.serverEndpoint,
287 httpClient: c.httpClient,
288 requestInterceptors: c.requestInterceptors,
289 waitTimeout: c.waitTimeout,
290 trace: c.trace,
291 validate: c.validate,
292 }
293 }
294