-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
metadata.go
102 lines (85 loc) · 2.85 KB
/
metadata.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
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
// This file contains code based on the Azure IMDS samples, https://github.com/microsoft/azureimds
// under the Apache License 2.0
package azure // import "github.com/open-telemetry/opentelemetry-collector-contrib/internal/metadataproviders/azure"
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
)
const (
// Azure IMDS compute endpoint, see https://aka.ms/azureimds
metadataEndpoint = "http://169.254.169.254/metadata/instance/compute"
)
// Provider gets metadata from the Azure IMDS.
type Provider interface {
Metadata(context.Context) (*ComputeMetadata, error)
}
type azureProviderImpl struct {
endpoint string
client *http.Client
}
// NewProvider creates a new metadata provider
func NewProvider() Provider {
return &azureProviderImpl{
endpoint: metadataEndpoint,
client: &http.Client{},
}
}
type ComputeTagsListMetadata struct {
Name string `json:"name"`
Value string `json:"value"`
}
// ComputeMetadata is the Azure IMDS compute metadata response format
type ComputeMetadata struct {
Location string `json:"location"`
Name string `json:"name"`
VMID string `json:"vmID"`
VMSize string `json:"vmSize"`
SubscriptionID string `json:"subscriptionID"`
ResourceGroupName string `json:"resourceGroupName"`
VMScaleSetName string `json:"vmScaleSetName"`
TagsList []ComputeTagsListMetadata `json:"tagsList"`
}
// Metadata queries a given endpoint and parses the output to the Azure IMDS format
func (p *azureProviderImpl) Metadata(ctx context.Context) (*ComputeMetadata, error) {
const (
// API version used
apiVersionKey = "api-version"
apiVersion = "2020-09-01"
// format used
formatKey = "format"
jsonFormat = "json"
)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, p.endpoint, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Add("Metadata", "True")
q := req.URL.Query()
q.Add(formatKey, jsonFormat)
q.Add(apiVersionKey, apiVersion)
req.URL.RawQuery = q.Encode()
resp, err := p.client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to query Azure IMDS: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
//lint:ignore ST1005 Azure is a capitalized proper noun here
return nil, fmt.Errorf("Azure IMDS replied with status code: %s", resp.Status)
}
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read Azure IMDS reply: %w", err)
}
var metadata *ComputeMetadata
err = json.Unmarshal(respBody, &metadata)
if err != nil {
return nil, fmt.Errorf("failed to decode Azure IMDS reply: %w", err)
}
return metadata, nil
}