Skip to content

Commit 5acaa3c

Browse files
authored
fix microversion header (#355)
* fix microversion header; refactor common operations in client.go and service_client.go * don't add microversion header for nil client type
1 parent d8ccf0f commit 5acaa3c

File tree

2 files changed

+77
-137
lines changed

2 files changed

+77
-137
lines changed

openstack/client.go

Lines changed: 35 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,10 @@ func v3auth(client *gophercloud.ProviderClient, endpoint string, opts tokens3.Au
182182
// NewIdentityV2 creates a ServiceClient that may be used to interact with the v2 identity service.
183183
func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
184184
endpoint := client.IdentityBase + "v2.0/"
185+
clientType := "identity"
185186
var err error
186187
if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) {
187-
eo.ApplyDefaults("identity")
188+
eo.ApplyDefaults(clientType)
188189
endpoint, err = client.EndpointLocator(eo)
189190
if err != nil {
190191
return nil, err
@@ -194,15 +195,17 @@ func NewIdentityV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOp
194195
return &gophercloud.ServiceClient{
195196
ProviderClient: client,
196197
Endpoint: endpoint,
198+
Type: clientType,
197199
}, nil
198200
}
199201

200202
// NewIdentityV3 creates a ServiceClient that may be used to access the v3 identity service.
201203
func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
202204
endpoint := client.IdentityBase + "v3/"
205+
clientType := "identity"
203206
var err error
204207
if !reflect.DeepEqual(eo, gophercloud.EndpointOpts{}) {
205-
eo.ApplyDefaults("identity")
208+
eo.ApplyDefaults(clientType)
206209
endpoint, err = client.EndpointLocator(eo)
207210
if err != nil {
208211
return nil, err
@@ -212,125 +215,81 @@ func NewIdentityV3(client *gophercloud.ProviderClient, eo gophercloud.EndpointOp
212215
return &gophercloud.ServiceClient{
213216
ProviderClient: client,
214217
Endpoint: endpoint,
218+
Type: clientType,
215219
}, nil
216220
}
217221

218-
// NewObjectStorageV1 creates a ServiceClient that may be used with the v1 object storage package.
219-
func NewObjectStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
220-
eo.ApplyDefaults("object-store")
222+
func initClientOpts(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts, clientType string) (*gophercloud.ServiceClient, error) {
223+
sc := new(gophercloud.ServiceClient)
224+
eo.ApplyDefaults(clientType)
221225
url, err := client.EndpointLocator(eo)
222226
if err != nil {
223-
return nil, err
227+
return sc, err
224228
}
225-
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
229+
sc.ProviderClient = client
230+
sc.Endpoint = url
231+
sc.Type = clientType
232+
return sc, nil
233+
}
234+
235+
// NewObjectStorageV1 creates a ServiceClient that may be used with the v1 object storage package.
236+
func NewObjectStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
237+
return initClientOpts(client, eo, "object-store")
226238
}
227239

228240
// NewComputeV2 creates a ServiceClient that may be used with the v2 compute package.
229241
func NewComputeV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
230-
eo.ApplyDefaults("compute")
231-
url, err := client.EndpointLocator(eo)
232-
if err != nil {
233-
return nil, err
234-
}
235-
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
242+
return initClientOpts(client, eo, "compute")
236243
}
237244

238245
// NewNetworkV2 creates a ServiceClient that may be used with the v2 network package.
239246
func NewNetworkV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
240-
eo.ApplyDefaults("network")
241-
url, err := client.EndpointLocator(eo)
242-
if err != nil {
243-
return nil, err
244-
}
245-
return &gophercloud.ServiceClient{
246-
ProviderClient: client,
247-
Endpoint: url,
248-
ResourceBase: url + "v2.0/",
249-
}, nil
247+
sc, err := initClientOpts(client, eo, "network")
248+
sc.ResourceBase = sc.Endpoint + "v2.0/"
249+
return sc, err
250250
}
251251

252252
// NewBlockStorageV1 creates a ServiceClient that may be used to access the v1 block storage service.
253253
func NewBlockStorageV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
254-
eo.ApplyDefaults("volume")
255-
url, err := client.EndpointLocator(eo)
256-
if err != nil {
257-
return nil, err
258-
}
259-
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
254+
return initClientOpts(client, eo, "volume")
260255
}
261256

262257
// NewBlockStorageV2 creates a ServiceClient that may be used to access the v2 block storage service.
263258
func NewBlockStorageV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
264-
eo.ApplyDefaults("volumev2")
265-
url, err := client.EndpointLocator(eo)
266-
if err != nil {
267-
return nil, err
268-
}
269-
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
259+
return initClientOpts(client, eo, "volumev2")
270260
}
271261

272262
// NewSharedFileSystemV2 creates a ServiceClient that may be used to access the v2 shared file system service.
273263
func NewSharedFileSystemV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
274-
eo.ApplyDefaults("sharev2")
275-
url, err := client.EndpointLocator(eo)
276-
if err != nil {
277-
return nil, err
278-
}
279-
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
264+
return initClientOpts(client, eo, "sharev2")
280265
}
281266

282267
// NewCDNV1 creates a ServiceClient that may be used to access the OpenStack v1
283268
// CDN service.
284269
func NewCDNV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
285-
eo.ApplyDefaults("cdn")
286-
url, err := client.EndpointLocator(eo)
287-
if err != nil {
288-
return nil, err
289-
}
290-
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
270+
return initClientOpts(client, eo, "cdn")
291271
}
292272

293273
// NewOrchestrationV1 creates a ServiceClient that may be used to access the v1 orchestration service.
294274
func NewOrchestrationV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
295-
eo.ApplyDefaults("orchestration")
296-
url, err := client.EndpointLocator(eo)
297-
if err != nil {
298-
return nil, err
299-
}
300-
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
275+
return initClientOpts(client, eo, "orchestration")
301276
}
302277

303278
// NewDBV1 creates a ServiceClient that may be used to access the v1 DB service.
304279
func NewDBV1(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
305-
eo.ApplyDefaults("database")
306-
url, err := client.EndpointLocator(eo)
307-
if err != nil {
308-
return nil, err
309-
}
310-
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
280+
return initClientOpts(client, eo, "database")
311281
}
312282

313283
// NewDNSV2 creates a ServiceClient that may be used to access the v2 DNS service.
314284
func NewDNSV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
315-
eo.ApplyDefaults("dns")
316-
url, err := client.EndpointLocator(eo)
317-
if err != nil {
318-
return nil, err
319-
}
320-
return &gophercloud.ServiceClient{
321-
ProviderClient: client,
322-
Endpoint: url,
323-
ResourceBase: url + "v2/"}, nil
285+
sc, err := initClientOpts(client, eo, "dns")
286+
sc.ResourceBase = sc.Endpoint + "v2/"
287+
return sc, err
324288
}
325289

326290
// NewImageServiceV2 creates a ServiceClient that may be used to access the v2 image service.
327291
func NewImageServiceV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
328-
eo.ApplyDefaults("image")
329-
url, err := client.EndpointLocator(eo)
330-
if err != nil {
331-
return nil, err
332-
}
333-
return &gophercloud.ServiceClient{ProviderClient: client,
334-
Endpoint: url,
335-
ResourceBase: url + "v2/"}, nil
292+
sc, err := initClientOpts(client, eo, "image")
293+
sc.ResourceBase = sc.Endpoint + "v2/"
294+
return sc, err
336295
}

service_client.go

Lines changed: 42 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ type ServiceClient struct {
2121
// as-is, instead.
2222
ResourceBase string
2323

24+
// This is the service client type (e.g. compute, sharev2).
25+
// NOTE: FOR INTERNAL USE ONLY. DO NOT SET. GOPHERCLOUD WILL SET THIS.
26+
// It is only exported because it gets set in a different package.
27+
Type string
28+
29+
// The microversion of the service to use. Set this to use a particular microversion.
2430
Microversion string
2531
}
2632

@@ -37,105 +43,80 @@ func (client *ServiceClient) ServiceURL(parts ...string) string {
3743
return client.ResourceBaseURL() + strings.Join(parts, "/")
3844
}
3945

40-
// Get calls `Request` with the "GET" HTTP verb.
41-
func (client *ServiceClient) Get(url string, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
42-
if opts == nil {
43-
opts = &RequestOpts{}
46+
func (client *ServiceClient) initReqOpts(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) {
47+
if v, ok := (JSONBody).(io.Reader); ok {
48+
opts.RawBody = v
49+
} else if JSONBody != nil {
50+
opts.JSONBody = JSONBody
4451
}
52+
4553
if JSONResponse != nil {
4654
opts.JSONResponse = JSONResponse
4755
}
4856

4957
if opts.MoreHeaders == nil {
5058
opts.MoreHeaders = make(map[string]string)
5159
}
52-
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
5360

61+
if client.Microversion != "" {
62+
client.setMicroversionHeader(opts)
63+
}
64+
}
65+
66+
// Get calls `Request` with the "GET" HTTP verb.
67+
func (client *ServiceClient) Get(url string, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
68+
if opts == nil {
69+
opts = new(RequestOpts)
70+
}
71+
client.initReqOpts(url, nil, JSONResponse, opts)
5472
return client.Request("GET", url, opts)
5573
}
5674

5775
// Post calls `Request` with the "POST" HTTP verb.
5876
func (client *ServiceClient) Post(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
5977
if opts == nil {
60-
opts = &RequestOpts{}
61-
}
62-
63-
if v, ok := (JSONBody).(io.Reader); ok {
64-
opts.RawBody = v
65-
} else if JSONBody != nil {
66-
opts.JSONBody = JSONBody
67-
}
68-
69-
if JSONResponse != nil {
70-
opts.JSONResponse = JSONResponse
78+
opts = new(RequestOpts)
7179
}
72-
73-
if opts.MoreHeaders == nil {
74-
opts.MoreHeaders = make(map[string]string)
75-
}
76-
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
77-
80+
client.initReqOpts(url, JSONBody, JSONResponse, opts)
7881
return client.Request("POST", url, opts)
7982
}
8083

8184
// Put calls `Request` with the "PUT" HTTP verb.
8285
func (client *ServiceClient) Put(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
8386
if opts == nil {
84-
opts = &RequestOpts{}
87+
opts = new(RequestOpts)
8588
}
86-
87-
if v, ok := (JSONBody).(io.Reader); ok {
88-
opts.RawBody = v
89-
} else if JSONBody != nil {
90-
opts.JSONBody = JSONBody
91-
}
92-
93-
if JSONResponse != nil {
94-
opts.JSONResponse = JSONResponse
95-
}
96-
97-
if opts.MoreHeaders == nil {
98-
opts.MoreHeaders = make(map[string]string)
99-
}
100-
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
101-
89+
client.initReqOpts(url, JSONBody, JSONResponse, opts)
10290
return client.Request("PUT", url, opts)
10391
}
10492

10593
// Patch calls `Request` with the "PATCH" HTTP verb.
10694
func (client *ServiceClient) Patch(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
10795
if opts == nil {
108-
opts = &RequestOpts{}
96+
opts = new(RequestOpts)
10997
}
110-
111-
if v, ok := (JSONBody).(io.Reader); ok {
112-
opts.RawBody = v
113-
} else if JSONBody != nil {
114-
opts.JSONBody = JSONBody
115-
}
116-
117-
if JSONResponse != nil {
118-
opts.JSONResponse = JSONResponse
119-
}
120-
121-
if opts.MoreHeaders == nil {
122-
opts.MoreHeaders = make(map[string]string)
123-
}
124-
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
125-
98+
client.initReqOpts(url, JSONBody, JSONResponse, opts)
12699
return client.Request("PATCH", url, opts)
127100
}
128101

129102
// Delete calls `Request` with the "DELETE" HTTP verb.
130103
func (client *ServiceClient) Delete(url string, opts *RequestOpts) (*http.Response, error) {
131104
if opts == nil {
132-
opts = &RequestOpts{}
105+
opts = new(RequestOpts)
133106
}
107+
client.initReqOpts(url, nil, nil, opts)
108+
return client.Request("DELETE", url, opts)
109+
}
134110

135-
if opts.MoreHeaders == nil {
136-
opts.MoreHeaders = make(map[string]string)
111+
func (client *ServiceClient) setMicroversionHeader(opts *RequestOpts) {
112+
switch client.Type {
113+
case "compute":
114+
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
115+
case "sharev2":
116+
opts.MoreHeaders["X-OpenStack-Manila-API-Version"] = client.Microversion
137117
}
138-
opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
139118

140-
return client.Request("DELETE", url, opts)
119+
if client.Type != "" {
120+
opts.MoreHeaders["OpenStack-API-Version"] = client.Type + " " + client.Microversion
121+
}
141122
}

0 commit comments

Comments
 (0)