forked from RobustPerception/azure_metrics_exporter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
azure.go
176 lines (159 loc) · 5.62 KB
/
azure.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
)
// AzureMetricDefinitionResponse represents metric definition response for a given resource from Azure.
type AzureMetricDefinitionResponse struct {
MetricDefinitionResponses []metricDefinitionResponse `json:"value"`
}
type metricDefinitionResponse struct {
Dimensions []struct {
LocalizedValue string `json:"localizedValue"`
Value string `json:"value"`
} `json:"dimensions"`
ID string `json:"id"`
IsDimensionRequired bool `json:"isDimensionRequired"`
MetricAvailabilities []struct {
Retention string `json:"retention"`
TimeGrain string `json:"timeGrain"`
} `json:"metricAvailabilities"`
Name struct {
LocalizedValue string `json:"localizedValue"`
Value string `json:"value"`
} `json:"name"`
PrimaryAggregationType string `json:"primaryAggregationType"`
ResourceID string `json:"resourceId"`
Unit string `json:"unit"`
}
// AzureMetricValueResponse represents a metric value response for a given metric definition.
type AzureMetricValueResponse struct {
Value []struct {
Data []struct {
TimeStamp string `json:"timeStamp"`
Total float64 `json:"total"`
Average float64 `json:"average"`
Minimum float64 `json:"minimum"`
Maximum float64 `json:"maximum"`
} `json:"data"`
ID string `json:"id"`
Name struct {
LocalizedValue string `json:"localizedValue"`
Value string `json:"value"`
} `json:"name"`
Type string `json:"type"`
Unit string `json:"unit"`
} `json:"value"`
APIError struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
// AzureClient represents our client to talk to the Azure api
type AzureClient struct {
client *http.Client
accessToken string
}
// NewAzureClient returns an Azure client to talk the Azure API
func NewAzureClient() *AzureClient {
return &AzureClient{
client: &http.Client{},
accessToken: "",
}
}
func (ac *AzureClient) getAccessToken() {
target := fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/token", sc.C.Credentials.TenantID)
form := url.Values{
"grant_type": {"client_credentials"},
"resource": {"https://management.azure.com/"},
"client_id": {sc.C.Credentials.ClientID},
"client_secret": {sc.C.Credentials.ClientSecret},
}
resp, err := ac.client.PostForm(target, form)
if err != nil {
log.Fatalf("Error authenticating against Azure API: %v", err)
}
if resp.StatusCode != 200 {
log.Fatalf("Did not get status code 200, got: %d", resp.StatusCode)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("Error reading body of response: %v", err)
}
var data map[string]interface{}
err = json.Unmarshal(body, &data)
if err != nil {
log.Fatalf("Error unmarshalling response body: %v", err)
}
ac.accessToken = data["access_token"].(string)
}
// Loop through all specified resource targets and get their respective metric definitions.
func (ac *AzureClient) getMetricDefinitions() map[string]AzureMetricDefinitionResponse {
apiVersion := "2016-03-01"
definitions := make(map[string]AzureMetricDefinitionResponse)
for _, target := range sc.C.Targets {
metricsResource := fmt.Sprintf("subscriptions/%s%s", sc.C.Credentials.SubscriptionID, target.Resource)
metricsTarget := fmt.Sprintf("https://management.azure.com/%s/providers/microsoft.insights/metricDefinitions?api-version=%s", metricsResource, apiVersion)
req, err := http.NewRequest("GET", metricsTarget, nil)
if err != nil {
log.Fatalf("Error creating HTTP request: %v", err)
}
req.Header.Set("Authorization", "Bearer "+ac.accessToken)
resp, err := ac.client.Do(req)
if err != nil {
log.Fatalf("Error: %v", err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("Error reading body of response: %v", err)
}
def := AzureMetricDefinitionResponse{}
err = json.Unmarshal(body, &def)
if err != nil {
log.Fatalf("Error unmarshalling response body: %v", err)
}
definitions[target.Resource] = def
}
return definitions
}
func (ac *AzureClient) getMetricValue(metricName string, target string) AzureMetricValueResponse {
apiVersion := "2016-09-01"
metricsResource := fmt.Sprintf("subscriptions/%s%s", sc.C.Credentials.SubscriptionID, target)
endTime, startTime := GetTimes()
filter := fmt.Sprintf("(name.value eq '%s') and (aggregationType eq 'Total' or aggregationType eq 'Average' or aggregationType eq 'Minimum' or aggregationType eq 'Maximum') and startTime eq %s and endTime eq %s", metricName, startTime, endTime)
filter = strings.Replace(filter, " ", "%20", -1)
metricValueEndpoint := fmt.Sprintf("https://management.azure.com/%s/providers/microsoft.insights/metrics?$filter=%s&api-version=%s", metricsResource, filter, apiVersion)
req, err := http.NewRequest("GET", metricValueEndpoint, nil)
if err != nil {
log.Fatalf("Error creating HTTP request: %v", err)
}
req.Header.Set("Authorization", "Bearer "+ac.accessToken)
log.Printf("GET %s", metricValueEndpoint)
resp, err := ac.client.Do(req)
if err != nil {
log.Fatalf("Error: %v", err)
}
if resp.StatusCode != 200 {
log.Fatalf("Unable to query metrics API with status code: %d", resp.StatusCode)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("Error reading body of response: %v", err)
}
var data AzureMetricValueResponse
err = json.Unmarshal(body, &data)
if err != nil {
log.Fatalf("Error unmarshalling response body: %v", err)
}
if data.APIError.Code == "ExpiredAuthenticationToken" {
log.Printf("Access token expired. Reathenticating...")
ac.getAccessToken()
}
return data
}