-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
instance.go
140 lines (132 loc) · 3.92 KB
/
instance.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
package openstack
import (
"encoding/json"
"fmt"
"path"
"sort"
"strconv"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
)
// See https://docs.openstack.org/api-ref/compute/#list-servers
type serversDetail struct {
Servers []server `json:"servers"`
Links []struct {
HREF string `json:"href"`
Rel string `json:"rel"`
} `json:"servers_links,omitempty"`
}
type server struct {
ID string `json:"id"`
TenantID string `json:"tenant_id"`
UserID string `json:"user_id"`
Name string `json:"name"`
HostID string `json:"hostid"`
Status string `json:"status"`
Addresses map[string][]struct {
Address string `json:"addr"`
Version int `json:"version"`
Type string `json:"OS-EXT-IPS:type"`
} `json:"addresses"`
Metadata map[string]string `json:"metadata,omitempty"`
Flavor struct {
ID string `json:"id"`
} `json:"flavor"`
}
func parseServersDetail(data []byte) (*serversDetail, error) {
var srvd serversDetail
if err := json.Unmarshal(data, &srvd); err != nil {
return nil, fmt.Errorf("cannot parse serversDetail: %w", err)
}
return &srvd, nil
}
func addInstanceLabels(servers []server, port int) []*promutils.Labels {
var ms []*promutils.Labels
for _, server := range servers {
commonLabels := promutils.NewLabels(16)
commonLabels.Add("__meta_openstack_instance_id", server.ID)
commonLabels.Add("__meta_openstack_instance_status", server.Status)
commonLabels.Add("__meta_openstack_instance_name", server.Name)
commonLabels.Add("__meta_openstack_project_id", server.TenantID)
commonLabels.Add("__meta_openstack_user_id", server.UserID)
commonLabels.Add("__meta_openstack_instance_flavor", server.Flavor.ID)
for k, v := range server.Metadata {
commonLabels.Add(discoveryutils.SanitizeLabelName("__meta_openstack_tag_"+k), v)
}
// Traverse server.Addresses in alphabetical order of pool name
// in order to return targets in deterministic order.
sortedPools := make([]string, 0, len(server.Addresses))
for pool := range server.Addresses {
sortedPools = append(sortedPools, pool)
}
sort.Strings(sortedPools)
for _, pool := range sortedPools {
addresses := server.Addresses[pool]
if len(addresses) == 0 {
// skip pool with zero addresses
continue
}
var publicIP string
// its possible to have only one floating ip per pool
for _, ip := range addresses {
if ip.Type != "floating" {
continue
}
publicIP = ip.Address
break
}
for _, ip := range addresses {
// fast return
if len(ip.Address) == 0 || ip.Type == "floating" {
continue
}
// copy labels
m := promutils.NewLabels(20)
m.AddFrom(commonLabels)
m.Add("__meta_openstack_address_pool", pool)
m.Add("__meta_openstack_private_ip", ip.Address)
if len(publicIP) > 0 {
m.Add("__meta_openstack_public_ip", publicIP)
}
m.Add("__address__", discoveryutils.JoinHostPort(ip.Address, port))
ms = append(ms, m)
}
}
}
return ms
}
func (cfg *apiConfig) getServers() ([]server, error) {
creds, err := cfg.getFreshAPICredentials()
if err != nil {
return nil, err
}
computeURL := *creds.computeURL
computeURL.Path = path.Join(computeURL.Path, "servers", "detail")
q := computeURL.Query()
q.Set("all_tenants", strconv.FormatBool(cfg.allTenants))
computeURL.RawQuery = q.Encode()
nextLink := computeURL.String()
var servers []server
for {
resp, err := getAPIResponse(nextLink, cfg)
if err != nil {
return nil, err
}
serversDetail, err := parseServersDetail(resp)
if err != nil {
return nil, err
}
servers = append(servers, serversDetail.Servers...)
if len(serversDetail.Links) == 0 {
return servers, nil
}
nextLink = serversDetail.Links[0].HREF
}
}
func getInstancesLabels(cfg *apiConfig) ([]*promutils.Labels, error) {
srv, err := cfg.getServers()
if err != nil {
return nil, err
}
return addInstanceLabels(srv, cfg.port), nil
}