Add supports for stats in ACI provider
This adds a new, optional, interface for providers that want to provide stats.
This commit is contained in:
@@ -18,6 +18,7 @@ const (
|
||||
containerGroupListByResourceGroupURLPath = "subscriptions/{{.subscriptionId}}/resourceGroups/{{.resourceGroup}}/providers/Microsoft.ContainerInstance/containerGroups"
|
||||
containerLogsURLPath = containerGroupURLPath + "/containers/{{.containerName}}/logs"
|
||||
containerExecURLPath = containerGroupURLPath + "/containers/{{.containerName}}/exec"
|
||||
containerGroupMetricsURLPath = containerGroupURLPath + "/providers/microsoft.Insights/metrics"
|
||||
)
|
||||
|
||||
// Client is a client for interacting with Azure Container Instances.
|
||||
|
||||
97
providers/azure/client/aci/metrics.go
Normal file
97
providers/azure/client/aci/metrics.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package aci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/azure/client/api"
|
||||
)
|
||||
|
||||
// GetContainerGroupMetrics gets metrics for the provided container group
|
||||
func (c *Client) GetContainerGroupMetrics(ctx context.Context, resourceGroup, containerGroup string, options MetricsRequest) (*ContainerGroupMetricsResult, error) {
|
||||
if len(options.Types) == 0 {
|
||||
return nil, errors.New("must provide metrics types to fetch")
|
||||
}
|
||||
if options.Start.After(options.End) || options.Start.Equal(options.End) && !options.Start.IsZero() {
|
||||
return nil, errors.Errorf("end parameter must be after start: start=%s, end=%s", options.Start, options.End)
|
||||
}
|
||||
|
||||
var metricNames string
|
||||
for _, t := range options.Types {
|
||||
if len(metricNames) > 0 {
|
||||
metricNames += ","
|
||||
}
|
||||
metricNames += string(t)
|
||||
}
|
||||
|
||||
var ag string
|
||||
for _, a := range options.Aggregations {
|
||||
if len(ag) > 0 {
|
||||
ag += ","
|
||||
}
|
||||
ag += string(a)
|
||||
}
|
||||
|
||||
urlParams := url.Values{
|
||||
"api-version": []string{"2018-01-01"},
|
||||
"aggregation": []string{ag},
|
||||
"metricnames": []string{metricNames},
|
||||
"interval": []string{"PT1M"}, // TODO: make configurable?
|
||||
}
|
||||
|
||||
if options.Dimension != "" {
|
||||
urlParams.Add("$filter", options.Dimension)
|
||||
}
|
||||
|
||||
if !options.Start.IsZero() || !options.End.IsZero() {
|
||||
urlParams.Add("timespan", path.Join(options.Start.Format(time.RFC3339), options.End.Format(time.RFC3339)))
|
||||
}
|
||||
|
||||
// Create the url.
|
||||
uri := api.ResolveRelative(c.auth.ResourceManagerEndpoint, containerGroupMetricsURLPath)
|
||||
uri += "?" + url.Values(urlParams).Encode()
|
||||
|
||||
// Create the request.
|
||||
req, err := http.NewRequest("GET", uri, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "creating get container group metrics uri request failed")
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
// Add the parameters to the url.
|
||||
if err := api.ExpandURL(req.URL, map[string]string{
|
||||
"subscriptionId": c.auth.SubscriptionID,
|
||||
"resourceGroup": resourceGroup,
|
||||
"containerGroupName": containerGroup,
|
||||
}); err != nil {
|
||||
return nil, errors.Wrap(err, "expanding URL with parameters failed")
|
||||
}
|
||||
|
||||
// SEnd the request.
|
||||
resp, err := c.hc.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "sending get container group metrics request failed")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 200 (OK) is a success response.
|
||||
if err := api.CheckResponse(resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Decode the body from the response.
|
||||
if resp.Body == nil {
|
||||
return nil, errors.New("container group metrics returned an empty body in the response")
|
||||
}
|
||||
var metrics ContainerGroupMetricsResult
|
||||
if err := json.NewDecoder(resp.Body).Decode(&metrics); err != nil {
|
||||
return nil, errors.Wrap(err, "decoding get container group metrics response body failed")
|
||||
}
|
||||
|
||||
return &metrics, nil
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package aci
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/azure/client/api"
|
||||
)
|
||||
|
||||
@@ -332,3 +334,85 @@ type LogAnalyticsWorkspace struct {
|
||||
WorkspaceID string `json:"workspaceID,omitempty"`
|
||||
WorkspaceKey string `json:"workspaceKey,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerGroupMetricsResult stores all the results for a container group metrics request.
|
||||
type ContainerGroupMetricsResult struct {
|
||||
Value []MetricValue `json:"value"`
|
||||
}
|
||||
|
||||
// MetricValue stores metrics results
|
||||
type MetricValue struct {
|
||||
ID string `json:"id"`
|
||||
Desc MetricDescriptor `json:"name"`
|
||||
Timeseries []MetricTimeSeries `json:"timeseries"`
|
||||
Type string `json:"type"`
|
||||
Unit string `json:"unit"`
|
||||
}
|
||||
|
||||
// MetricDescriptor stores the name for a given metric and the localized version of that name.
|
||||
type MetricDescriptor struct {
|
||||
Value MetricType `json:"value"`
|
||||
LocalizedValue string `json:"localizedValue"`
|
||||
}
|
||||
|
||||
// MetricTimeSeries is the time series for a given metric
|
||||
// It contains all the metrics values and other details for the dimension the metrics are aggregated on.
|
||||
type MetricTimeSeries struct {
|
||||
Data []TimeSeriesEntry `json:"data"`
|
||||
MetadataValues []MetricMetadataValue `json:"metadatavalues,omitempty"`
|
||||
}
|
||||
|
||||
// MetricMetadataValue stores extra metadata about a metric
|
||||
// In particular it is used to provide details about the breakdown of a metric dimension.
|
||||
type MetricMetadataValue struct {
|
||||
Name ValueDescriptor `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// ValueDescriptor describes a generic value.
|
||||
// It is used to describe metadata fields.
|
||||
type ValueDescriptor struct {
|
||||
Value string `json:"value"`
|
||||
LocalizedValue string `json:"localizedValue"`
|
||||
}
|
||||
|
||||
// TimeSeriesEntry is the metric data for a given timestamp/metric type
|
||||
type TimeSeriesEntry struct {
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Average float64 `json:"average"`
|
||||
Total float64 `json:"total"`
|
||||
Count float64 `json:"count"`
|
||||
}
|
||||
|
||||
// MetricsRequest is an options struct used when getting container group metrics
|
||||
type MetricsRequest struct {
|
||||
Start time.Time
|
||||
End time.Time
|
||||
Types []MetricType
|
||||
Aggregations []AggregationType
|
||||
|
||||
// Note that a dimension may not be available for certain metrics.
|
||||
// In such cases, you will need to make separate requests.
|
||||
Dimension string
|
||||
}
|
||||
|
||||
// MetricType is an enum type for defining supported metric types.
|
||||
type MetricType string
|
||||
|
||||
// Supported metric types
|
||||
const (
|
||||
MetricTypeCPUUsage MetricType = "CpuUsage"
|
||||
MetricTypeMemoryUsage MetricType = "MemoryUsage"
|
||||
MetricTyperNetworkBytesRecievedPerSecond MetricType = "NetworkBytesReceivedPerSecond"
|
||||
MetricTyperNetworkBytesTransmittedPerSecond MetricType = "NetworkBytesTransmittedPerSecond"
|
||||
)
|
||||
|
||||
// AggregationType is an enum type for defining supported aggregation types
|
||||
type AggregationType string
|
||||
|
||||
// Supported metric aggregation types
|
||||
const (
|
||||
AggregationTypeCount AggregationType = "count"
|
||||
AggregationTypeAverage AggregationType = "average"
|
||||
AggregationTypeTotal AggregationType = "total"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user