1package gophercloud
2
3import (
4	"io"
5	"net/http"
6	"strings"
7)
8
9// ServiceClient stores details required to interact with a specific service API implemented by a provider.
10// Generally, you'll acquire these by calling the appropriate `New` method on a ProviderClient.
11type ServiceClient struct {
12	// ProviderClient is a reference to the provider that implements this service.
13	*ProviderClient
14
15	// Endpoint is the base URL of the service's API, acquired from a service catalog.
16	// It MUST end with a /.
17	Endpoint string
18
19	// ResourceBase is the base URL shared by the resources within a service's API. It should include
20	// the API version and, like Endpoint, MUST end with a / if set. If not set, the Endpoint is used
21	// as-is, instead.
22	ResourceBase string
23
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.
30	Microversion string
31
32	// MoreHeaders allows users (or Gophercloud) to set service-wide headers on requests. Put another way,
33	// values set in this field will be set on all the HTTP requests the service client sends.
34	MoreHeaders map[string]string
35}
36
37// ResourceBaseURL returns the base URL of any resources used by this service. It MUST end with a /.
38func (client *ServiceClient) ResourceBaseURL() string {
39	if client.ResourceBase != "" {
40		return client.ResourceBase
41	}
42	return client.Endpoint
43}
44
45// ServiceURL constructs a URL for a resource belonging to this provider.
46func (client *ServiceClient) ServiceURL(parts ...string) string {
47	return client.ResourceBaseURL() + strings.Join(parts, "/")
48}
49
50func (client *ServiceClient) initReqOpts(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) {
51	if v, ok := (JSONBody).(io.Reader); ok {
52		opts.RawBody = v
53	} else if JSONBody != nil {
54		opts.JSONBody = JSONBody
55	}
56
57	if JSONResponse != nil {
58		opts.JSONResponse = JSONResponse
59	}
60
61	if opts.MoreHeaders == nil {
62		opts.MoreHeaders = make(map[string]string)
63	}
64
65	if client.Microversion != "" {
66		client.setMicroversionHeader(opts)
67	}
68}
69
70// Get calls `Request` with the "GET" HTTP verb.
71func (client *ServiceClient) Get(url string, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
72	if opts == nil {
73		opts = new(RequestOpts)
74	}
75	client.initReqOpts(url, nil, JSONResponse, opts)
76	return client.Request("GET", url, opts)
77}
78
79// Post calls `Request` with the "POST" HTTP verb.
80func (client *ServiceClient) Post(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
81	if opts == nil {
82		opts = new(RequestOpts)
83	}
84	client.initReqOpts(url, JSONBody, JSONResponse, opts)
85	return client.Request("POST", url, opts)
86}
87
88// Put calls `Request` with the "PUT" HTTP verb.
89func (client *ServiceClient) Put(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
90	if opts == nil {
91		opts = new(RequestOpts)
92	}
93	client.initReqOpts(url, JSONBody, JSONResponse, opts)
94	return client.Request("PUT", url, opts)
95}
96
97// Patch calls `Request` with the "PATCH" HTTP verb.
98func (client *ServiceClient) Patch(url string, JSONBody interface{}, JSONResponse interface{}, opts *RequestOpts) (*http.Response, error) {
99	if opts == nil {
100		opts = new(RequestOpts)
101	}
102	client.initReqOpts(url, JSONBody, JSONResponse, opts)
103	return client.Request("PATCH", url, opts)
104}
105
106// Delete calls `Request` with the "DELETE" HTTP verb.
107func (client *ServiceClient) Delete(url string, opts *RequestOpts) (*http.Response, error) {
108	if opts == nil {
109		opts = new(RequestOpts)
110	}
111	client.initReqOpts(url, nil, nil, opts)
112	return client.Request("DELETE", url, opts)
113}
114
115// Head calls `Request` with the "HEAD" HTTP verb.
116func (client *ServiceClient) Head(url string, opts *RequestOpts) (*http.Response, error) {
117	if opts == nil {
118		opts = new(RequestOpts)
119	}
120	client.initReqOpts(url, nil, nil, opts)
121	return client.Request("HEAD", url, opts)
122}
123
124func (client *ServiceClient) setMicroversionHeader(opts *RequestOpts) {
125	switch client.Type {
126	case "compute":
127		opts.MoreHeaders["X-OpenStack-Nova-API-Version"] = client.Microversion
128	case "sharev2":
129		opts.MoreHeaders["X-OpenStack-Manila-API-Version"] = client.Microversion
130	case "volume":
131		opts.MoreHeaders["X-OpenStack-Volume-API-Version"] = client.Microversion
132	case "baremetal":
133		opts.MoreHeaders["X-OpenStack-Ironic-API-Version"] = client.Microversion
134	}
135
136	if client.Type != "" {
137		opts.MoreHeaders["OpenStack-API-Version"] = client.Type + " " + client.Microversion
138	}
139}
140
141// Request carries out the HTTP operation for the service client
142func (client *ServiceClient) Request(method, url string, options *RequestOpts) (*http.Response, error) {
143	if len(client.MoreHeaders) > 0 {
144		if options == nil {
145			options = new(RequestOpts)
146		}
147		for k, v := range client.MoreHeaders {
148			options.MoreHeaders[k] = v
149		}
150	}
151	return client.ProviderClient.Request(method, url, options)
152}
153