Skip to content
This repository was archived by the owner on Aug 1, 2023. It is now read-only.

Commit 1f02c2b

Browse files
authored
Merge pull request #448 from DSpeichert/telemetry
[RFR] OpenStack Telemetry v2
2 parents b8b50b9 + 3849090 commit 1f02c2b

File tree

8 files changed

+640
-3
lines changed

8 files changed

+640
-3
lines changed

openstack/client.go

+13-3
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,20 @@ func NewClient(endpoint string) (*gophercloud.ProviderClient, error) {
3939
}
4040

4141
parts := strings.Split(path[0:len(path)-1], "/")
42-
for index,version := range(parts) {
42+
for index, version := range parts {
4343
if 2 <= len(version) && len(version) <= 4 && strings.HasPrefix(version, "v") {
4444
_, err := strconv.ParseFloat(version[1:], 64)
4545
if err == nil {
4646
// post version suffixes in path are not supported
4747
// version must be on the last index
48-
if index < len(parts) - 1 {
48+
if index < len(parts)-1 {
4949
return nil, fmt.Errorf("Path suffixes (after version) are not supported.")
5050
}
5151
switch version {
5252
case "v2.0", "v3":
5353
// valid version found, strip from base
5454
return &gophercloud.ProviderClient{
55-
IdentityBase: base[0:len(base)-len(version)-1],
55+
IdentityBase: base[0 : len(base)-len(version)-1],
5656
IdentityEndpoint: endpoint,
5757
}, nil
5858
default:
@@ -356,3 +356,13 @@ func NewImageServiceV2(client *gophercloud.ProviderClient, eo gophercloud.Endpoi
356356
Endpoint: url,
357357
ResourceBase: url + "v2/"}, nil
358358
}
359+
360+
// NewTelemetryV2 creates a ServiceClient that may be used to access the v2 telemetry service.
361+
func NewTelemetryV2(client *gophercloud.ProviderClient, eo gophercloud.EndpointOpts) (*gophercloud.ServiceClient, error) {
362+
eo.ApplyDefaults("metering")
363+
url, err := client.EndpointLocator(eo)
364+
if err != nil {
365+
return nil, err
366+
}
367+
return &gophercloud.ServiceClient{ProviderClient: client, Endpoint: url}, nil
368+
}

openstack/telemetry/v2/meters/doc.go

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package meters
+207
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
// +build fixtures
2+
3+
package meters
4+
5+
import (
6+
"fmt"
7+
"net/http"
8+
"testing"
9+
"time"
10+
11+
th "github.com/rackspace/gophercloud/testhelper"
12+
"github.com/rackspace/gophercloud/testhelper/client"
13+
)
14+
15+
// MeterListBody contains the canned body of a meters.List response.
16+
const MeterListBody = `
17+
[
18+
{
19+
"meter_id": "YmQ5NDMxYzEtOGQ2OS00YWQzLTgwM2EtOGQ0YTZiODlmZDM2K2luc3RhbmNl",
20+
"name": "instance",
21+
"project_id": "35b17138-b364-4e6a-a131-8f3099c5be68",
22+
"resource_id": "bd9431c1-8d69-4ad3-803a-8d4a6b89fd36",
23+
"source": "openstack",
24+
"type": "gauge",
25+
"unit": "instance",
26+
"user_id": "efd87807-12d2-4b38-9c70-5f5c2ac427ff"
27+
},
28+
{
29+
"user_id": "7ya0f7a33717400b951037d55b929c53",
30+
"name": "cpu_util",
31+
"resource_id": "5b88239b-8ba1-44ff-a154-978cbda23479",
32+
"source": "region2",
33+
"meter_id": "NWI4ODIzOWAtOGJhMS00NGZhLWExNTQtOTc4Y2JkYTIzNDc5K2NwdV91dGls",
34+
"project_id": "69e6e7c4ed8b434e92feacbf3d4891fd",
35+
"type": "gauge",
36+
"unit": "%%"
37+
}
38+
]
39+
`
40+
41+
// MeterShowBody is the canned body of a Get request on an existing meter.
42+
const MeterShowBody = `
43+
[
44+
{
45+
"counter_name": "instance",
46+
"counter_type": "gauge",
47+
"counter_unit": "instance",
48+
"counter_volume": 1.0,
49+
"message_id": "5460acce-4fd6-480d-ab18-9735ec7b1996",
50+
"project_id": "35b17138-b364-4e6a-a131-8f3099c5be68",
51+
"resource_id": "bd9431c1-8d69-4ad3-803a-8d4a6b89fd36",
52+
"resource_metadata": {
53+
"name1": "value1",
54+
"name2": "value2"
55+
},
56+
"source": "openstack",
57+
"timestamp": "2013-11-21T12:33:08.323533",
58+
"user_id": "efd87807-12d2-4b38-9c70-5f5c2ac427ff"
59+
}
60+
]
61+
`
62+
63+
// MeterStatisticsBody is the canned body of a Get statistics request on an existing meter.
64+
const MeterStatisticsBody = `
65+
[
66+
{
67+
"avg": 4.5,
68+
"count": 10,
69+
"duration": 300.0,
70+
"duration_end": "2013-01-04T16:47:00",
71+
"duration_start": "2013-01-04T16:42:00",
72+
"max": 9.0,
73+
"min": 1.0,
74+
"period": 7200,
75+
"period_end": "2013-01-04T18:00:00",
76+
"period_start": "2013-01-04T16:00:00",
77+
"sum": 45.0,
78+
"unit": "GiB"
79+
},
80+
{
81+
"count": 28162,
82+
"duration_start": "2015-06-27T20:52:08",
83+
"min": 0.06999999999999999,
84+
"max": 10.06799336650083,
85+
"duration_end": "2015-07-27T20:47:02",
86+
"period": 0,
87+
"sum": 44655.782463977856,
88+
"period_end": "2015-07-17T16:43:31",
89+
"duration": 2591694.0,
90+
"period_start": "2015-07-17T16:43:31",
91+
"avg": 1.5856751105737468,
92+
"groupby": null,
93+
"unit": "%%"
94+
}
95+
]
96+
`
97+
98+
var (
99+
// MeterHerp is a Meter struct that should correspond to the first result in *[]Meter.
100+
MeterHerp = Meter{
101+
MeterId: "YmQ5NDMxYzEtOGQ2OS00YWQzLTgwM2EtOGQ0YTZiODlmZDM2K2luc3RhbmNl",
102+
Name: "instance",
103+
ProjectId: "35b17138-b364-4e6a-a131-8f3099c5be68",
104+
ResourceId: "bd9431c1-8d69-4ad3-803a-8d4a6b89fd36",
105+
Source: "openstack",
106+
Type: "gauge",
107+
Unit: "instance",
108+
UserId: "efd87807-12d2-4b38-9c70-5f5c2ac427ff",
109+
}
110+
111+
// MeterDerp is a Meter struct that should correspond to the second result in *[]Meter.
112+
MeterDerp = Meter{
113+
MeterId: "NWI4ODIzOWAtOGJhMS00NGZhLWExNTQtOTc4Y2JkYTIzNDc5K2NwdV91dGls",
114+
Name: "cpu_util",
115+
ProjectId: "69e6e7c4ed8b434e92feacbf3d4891fd",
116+
ResourceId: "5b88239b-8ba1-44ff-a154-978cbda23479",
117+
Source: "region2",
118+
Type: "gauge",
119+
Unit: "%",
120+
UserId: "7ya0f7a33717400b951037d55b929c53",
121+
}
122+
123+
ShowHerp = OldSample{
124+
Name: "instance",
125+
Type: "gauge",
126+
Unit: "instance",
127+
Volume: 1.0,
128+
MessageId: "5460acce-4fd6-480d-ab18-9735ec7b1996",
129+
ProjectId: "35b17138-b364-4e6a-a131-8f3099c5be68",
130+
ResourceId: "bd9431c1-8d69-4ad3-803a-8d4a6b89fd36",
131+
ResourceMetadata: map[string]string{
132+
"name1": "value1",
133+
"name2": "value2",
134+
},
135+
Source: "openstack",
136+
Timestamp: time.Date(2013, time.November, 21, 12, 33, 8, 323533000, time.UTC),
137+
UserId: "efd87807-12d2-4b38-9c70-5f5c2ac427ff",
138+
}
139+
140+
// StatisticsHerp is a Statistics struct that should correspond to the first result in *[]Statistics.
141+
StatisticsHerp = Statistics{
142+
Avg: 4.5,
143+
Count: 10,
144+
Duration: 300.0,
145+
DurationEnd: "2013-01-04T16:47:00",
146+
DurationStart: "2013-01-04T16:42:00",
147+
Max: 9.0,
148+
Min: 1.0,
149+
Period: 7200,
150+
PeriodEnd: "2013-01-04T18:00:00",
151+
PeriodStart: "2013-01-04T16:00:00",
152+
Sum: 45.0,
153+
Unit: "GiB",
154+
}
155+
156+
// StatisticsDerp is a Statistics struct that should correspond to the second result in *[]Statistics.
157+
StatisticsDerp = Statistics{
158+
Avg: 1.5856751105737468,
159+
Count: 28162,
160+
Duration: 2591694.0,
161+
DurationEnd: "2015-07-27T20:47:02",
162+
DurationStart: "2015-06-27T20:52:08",
163+
Max: 10.06799336650083,
164+
Min: 0.06999999999999999,
165+
Period: 0,
166+
PeriodEnd: "2015-07-17T16:43:31",
167+
PeriodStart: "2015-07-17T16:43:31",
168+
Sum: 44655.782463977856,
169+
Unit: "%",
170+
}
171+
)
172+
173+
// HandleMeterListSuccessfully sets up the test server to respond to a meters List request.
174+
func HandleMeterListSuccessfully(t *testing.T) {
175+
th.Mux.HandleFunc("/v2/meters", func(w http.ResponseWriter, r *http.Request) {
176+
th.TestMethod(t, r, "GET")
177+
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
178+
179+
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
180+
w.WriteHeader(http.StatusOK)
181+
fmt.Fprintf(w, MeterListBody)
182+
})
183+
}
184+
185+
// HandleMeterShowSuccessfully sets up the test server to respond to a show meter request.
186+
func HandleMeterShowSuccessfully(t *testing.T) {
187+
th.Mux.HandleFunc("/v2/meters/instance", func(w http.ResponseWriter, r *http.Request) {
188+
th.TestMethod(t, r, "GET")
189+
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
190+
191+
w.Header().Add("Content-Type", "application/json")
192+
w.WriteHeader(http.StatusOK)
193+
fmt.Fprintf(w, MeterShowBody)
194+
})
195+
}
196+
197+
// HandleMeterStatisticsSuccessfully sets up the test server to respond to a show meter request.
198+
func HandleMeterStatisticsSuccessfully(t *testing.T) {
199+
th.Mux.HandleFunc("/v2/meters/memory/statistics", func(w http.ResponseWriter, r *http.Request) {
200+
th.TestMethod(t, r, "GET")
201+
th.TestHeader(t, r, "X-Auth-Token", client.TokenID)
202+
203+
w.Header().Add("Content-Type", "application/json")
204+
w.WriteHeader(http.StatusOK)
205+
fmt.Fprintf(w, MeterStatisticsBody)
206+
})
207+
}
+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package meters
2+
3+
import (
4+
"github.com/rackspace/gophercloud"
5+
)
6+
7+
// ListOptsBuilder allows extensions to add additional parameters to the
8+
// List request.
9+
type ListOptsBuilder interface {
10+
ToMeterListQuery() (string, error)
11+
}
12+
13+
// ListOpts allows the filtering and sorting of collections through
14+
// the API. Filtering is achieved by passing in struct field values that map to
15+
// the server attributes you want to see returned.
16+
type ListOpts struct {
17+
QueryField string `q:"q.field"`
18+
QueryOp string `q:"q.op"`
19+
QueryValue string `q:"q.value"`
20+
21+
// ID of the last-seen item from the previous response
22+
Marker string `q:"marker"`
23+
24+
// Optional, maximum number of results to return
25+
Limit int `q:"limit"`
26+
}
27+
28+
// ToMeterListQuery formats a ListOpts into a query string.
29+
func (opts ListOpts) ToMeterListQuery() (string, error) {
30+
q, err := gophercloud.BuildQueryString(opts)
31+
if err != nil {
32+
return "", err
33+
}
34+
return q.String(), nil
35+
}
36+
37+
// List makes a request against the API to list meters accessible to you.
38+
func List(client *gophercloud.ServiceClient, opts ListOptsBuilder) ListResult {
39+
var res ListResult
40+
url := listURL(client)
41+
42+
if opts != nil {
43+
query, err := opts.ToMeterListQuery()
44+
if err != nil {
45+
res.Err = err
46+
return res
47+
}
48+
url += query
49+
}
50+
51+
_, res.Err = client.Get(url, &res.Body, &gophercloud.RequestOpts{})
52+
return res
53+
}
54+
55+
// ShowOptsBuilder allows extensions to add additional parameters to the
56+
// Show request.
57+
type ShowOptsBuilder interface {
58+
ToShowQuery() (string, error)
59+
}
60+
61+
// ShowOpts allows the filtering and sorting of collections through
62+
// the API. Filtering is achieved by passing in struct field values that map to
63+
// the server attributes you want to see returned.
64+
type ShowOpts struct {
65+
QueryField string `q:"q.field"`
66+
QueryOp string `q:"q.op"`
67+
QueryValue string `q:"q.value"`
68+
69+
// ID of the last-seen item from the previous response
70+
Marker string `q:"marker"`
71+
72+
// Optional, maximum number of results to return
73+
Limit int `q:"limit"`
74+
}
75+
76+
// ToMeterShowQuery formats a ShowOpts into a query string.
77+
func (opts ShowOpts) ToShowQuery() (string, error) {
78+
q, err := gophercloud.BuildQueryString(opts)
79+
if err != nil {
80+
return "", err
81+
}
82+
return q.String(), nil
83+
}
84+
85+
// Show makes a request against the API to show a specific meter
86+
func Show(client *gophercloud.ServiceClient, meterName string, opts ShowOptsBuilder) ShowResult {
87+
var res ShowResult
88+
url := showURL(client, meterName)
89+
90+
if opts != nil {
91+
query, err := opts.ToShowQuery()
92+
if err != nil {
93+
res.Err = err
94+
return res
95+
}
96+
url += query
97+
}
98+
99+
_, res.Err = client.Get(url, &res.Body, &gophercloud.RequestOpts{})
100+
return res
101+
}
102+
103+
// StatisticsOptsBuilder allows extensions to add additional parameters to the
104+
// List request.
105+
type MeterStatisticsOptsBuilder interface {
106+
ToMeterStatisticsQuery() (string, error)
107+
}
108+
109+
// StatisticsOpts allows the filtering and sorting of collections through
110+
// the API. Filtering is achieved by passing in struct field values that map to
111+
// the server attributes you want to see returned.
112+
type MeterStatisticsOpts struct {
113+
QueryField string `q:"q.field"`
114+
QueryOp string `q:"q.op"`
115+
QueryValue string `q:"q.value"`
116+
117+
// Optional group by
118+
GroupBy string `q:"groupby"`
119+
120+
// Optional number of seconds in a period
121+
Period int `q:"period"`
122+
}
123+
124+
// ToStatisticsQuery formats a StatisticsOpts into a query string.
125+
func (opts MeterStatisticsOpts) ToMeterStatisticsQuery() (string, error) {
126+
q, err := gophercloud.BuildQueryString(opts)
127+
if err != nil {
128+
return "", err
129+
}
130+
return q.String(), nil
131+
}
132+
133+
// List makes a request against the API to list meters accessible to you.
134+
func MeterStatistics(client *gophercloud.ServiceClient, n string, opts MeterStatisticsOptsBuilder) StatisticsResult {
135+
var res StatisticsResult
136+
url := statisticsURL(client, n)
137+
138+
if opts != nil {
139+
query, err := opts.ToMeterStatisticsQuery()
140+
if err != nil {
141+
res.Err = err
142+
return res
143+
}
144+
url += query
145+
}
146+
147+
_, res.Err = client.Get(url, &res.Body, &gophercloud.RequestOpts{})
148+
return res
149+
}

0 commit comments

Comments
 (0)