mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-24 19:30:06 +01:00
cbe62f23ba
- Use promutils.Labels.GetLabels() instead of comparing promutils.Labels.Labels to nil. This make the code more consistent with other places. - Mention the release where the issue has been introduced at docs/CHANGELOG.md. Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/3624
175 lines
5.3 KiB
Go
175 lines
5.3 KiB
Go
package gce
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/logger"
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils"
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutils"
|
|
)
|
|
|
|
// getInstancesLabels returns labels for gce instances obtained from the given cfg
|
|
func getInstancesLabels(cfg *apiConfig) []*promutils.Labels {
|
|
insts := getInstances(cfg)
|
|
var ms []*promutils.Labels
|
|
for _, inst := range insts {
|
|
ms = inst.appendTargetLabels(ms, cfg.project, cfg.tagSeparator, cfg.port)
|
|
}
|
|
return ms
|
|
}
|
|
|
|
func getInstances(cfg *apiConfig) []Instance {
|
|
// Collect instances for each zone in parallel
|
|
type result struct {
|
|
zone string
|
|
insts []Instance
|
|
err error
|
|
}
|
|
ch := make(chan result, len(cfg.zones))
|
|
for _, zone := range cfg.zones {
|
|
go func(zone string) {
|
|
insts, err := getInstancesForProjectAndZone(cfg.client, cfg.project, zone, cfg.filter)
|
|
ch <- result{
|
|
zone: zone,
|
|
insts: insts,
|
|
err: err,
|
|
}
|
|
}(zone)
|
|
}
|
|
var insts []Instance
|
|
for range cfg.zones {
|
|
r := <-ch
|
|
if r.err != nil {
|
|
logger.Errorf("cannot collect instances from zone %q: %s", r.zone, r.err)
|
|
continue
|
|
}
|
|
insts = append(insts, r.insts...)
|
|
}
|
|
return insts
|
|
}
|
|
|
|
func getInstancesForProjectAndZone(client *http.Client, project, zone, filter string) ([]Instance, error) {
|
|
// See https://cloud.google.com/compute/docs/reference/rest/v1/instances/list
|
|
instsURL := fmt.Sprintf("https://compute.googleapis.com/compute/v1/projects/%s/zones/%s/instances", project, zone)
|
|
var insts []Instance
|
|
pageToken := ""
|
|
for {
|
|
data, err := getAPIResponse(client, instsURL, filter, pageToken)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot obtain instances: %w", err)
|
|
}
|
|
il, err := parseInstanceList(data)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot parse instance list from %q: %w", instsURL, err)
|
|
}
|
|
insts = append(insts, il.Items...)
|
|
if len(il.NextPageToken) == 0 {
|
|
return insts, nil
|
|
}
|
|
pageToken = il.NextPageToken
|
|
}
|
|
}
|
|
|
|
// InstanceList is response to https://cloud.google.com/compute/docs/reference/rest/v1/instances/list
|
|
type InstanceList struct {
|
|
Items []Instance
|
|
NextPageToken string
|
|
}
|
|
|
|
// Instance is instance from https://cloud.google.com/compute/docs/reference/rest/v1/instances/list
|
|
type Instance struct {
|
|
ID string `json:"id"`
|
|
Name string
|
|
Status string
|
|
MachineType string
|
|
Zone string
|
|
NetworkInterfaces []NetworkInterface
|
|
Tags TagList
|
|
Metadata MetadataList
|
|
Labels *promutils.Labels
|
|
}
|
|
|
|
// NetworkInterface is network interface from https://cloud.google.com/compute/docs/reference/rest/v1/instances/list
|
|
type NetworkInterface struct {
|
|
Name string
|
|
Network string
|
|
Subnetwork string
|
|
NetworkIP string
|
|
AccessConfigs []AccessConfig
|
|
}
|
|
|
|
// AccessConfig is access config from https://cloud.google.com/compute/docs/reference/rest/v1/instances/list
|
|
type AccessConfig struct {
|
|
Type string
|
|
NatIP string
|
|
}
|
|
|
|
// TagList is tag list from https://cloud.google.com/compute/docs/reference/rest/v1/instances/list
|
|
type TagList struct {
|
|
Items []string
|
|
}
|
|
|
|
// MetadataList is metadataList from https://cloud.google.com/compute/docs/reference/rest/v1/instances/list
|
|
type MetadataList struct {
|
|
Items []MetadataEntry
|
|
}
|
|
|
|
// MetadataEntry is a single entry from metadata
|
|
type MetadataEntry struct {
|
|
Key string
|
|
Value string
|
|
}
|
|
|
|
// parseInstanceList parses InstanceList from data.
|
|
func parseInstanceList(data []byte) (*InstanceList, error) {
|
|
var il InstanceList
|
|
if err := json.Unmarshal(data, &il); err != nil {
|
|
return nil, fmt.Errorf("cannot unmarshal InstanceList from %q: %w", data, err)
|
|
}
|
|
return &il, nil
|
|
}
|
|
|
|
func (inst *Instance) appendTargetLabels(ms []*promutils.Labels, project, tagSeparator string, port int) []*promutils.Labels {
|
|
if len(inst.NetworkInterfaces) == 0 {
|
|
return ms
|
|
}
|
|
iface := inst.NetworkInterfaces[0]
|
|
addr := discoveryutils.JoinHostPort(iface.NetworkIP, port)
|
|
m := promutils.NewLabels(24)
|
|
m.Add("__address__", addr)
|
|
m.Add("__meta_gce_instance_id", inst.ID)
|
|
m.Add("__meta_gce_instance_status", inst.Status)
|
|
m.Add("__meta_gce_instance_name", inst.Name)
|
|
m.Add("__meta_gce_machine_type", inst.MachineType)
|
|
m.Add("__meta_gce_network", iface.Network)
|
|
m.Add("__meta_gce_private_ip", iface.NetworkIP)
|
|
m.Add("__meta_gce_project", project)
|
|
m.Add("__meta_gce_subnetwork", iface.Subnetwork)
|
|
m.Add("__meta_gce_zone", inst.Zone)
|
|
for _, iface := range inst.NetworkInterfaces {
|
|
m.Add(discoveryutils.SanitizeLabelName("__meta_gce_interface_ipv4_"+iface.Name), iface.NetworkIP)
|
|
}
|
|
if len(inst.Tags.Items) > 0 {
|
|
// We surround the separated list with the separator as well. This way regular expressions
|
|
// in relabeling rules don't have to consider tag positions.
|
|
m.Add("__meta_gce_tags", tagSeparator+strings.Join(inst.Tags.Items, tagSeparator)+tagSeparator)
|
|
}
|
|
for _, item := range inst.Metadata.Items {
|
|
m.Add(discoveryutils.SanitizeLabelName("__meta_gce_metadata_"+item.Key), item.Value)
|
|
}
|
|
for _, label := range inst.Labels.GetLabels() {
|
|
m.Add(discoveryutils.SanitizeLabelName("__meta_gce_label_"+label.Name), label.Value)
|
|
}
|
|
if len(iface.AccessConfigs) > 0 {
|
|
ac := iface.AccessConfigs[0]
|
|
if ac.Type == "ONE_TO_ONE_NAT" {
|
|
m.Add("__meta_gce_public_ip", ac.NatIP)
|
|
}
|
|
}
|
|
ms = append(ms, m)
|
|
return ms
|
|
}
|