discovery/openstack: discover all interfaces (#4649)
* discovery/openstack: discover all interfaces * Add address pool label Signed-off-by: Simon Pasquier <spasquie@redhat.com>
This commit is contained in:
parent
33c97d73e4
commit
a2a78d0a09
|
@ -34,6 +34,7 @@ import (
|
|||
|
||||
const (
|
||||
openstackLabelPrefix = model.MetaLabelPrefix + "openstack_"
|
||||
openstackLabelAddressPool = openstackLabelPrefix + "address_pool"
|
||||
openstackLabelInstanceID = openstackLabelPrefix + "instance_id"
|
||||
openstackLabelInstanceName = openstackLabelPrefix + "instance_name"
|
||||
openstackLabelInstanceStatus = openstackLabelPrefix + "instance_status"
|
||||
|
@ -100,6 +101,11 @@ func (i *InstanceDiscovery) Run(ctx context.Context, ch chan<- []*targetgroup.Gr
|
|||
}
|
||||
}
|
||||
|
||||
type floatingIPKey struct {
|
||||
id string
|
||||
fixed string
|
||||
}
|
||||
|
||||
func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
||||
var err error
|
||||
t0 := time.Now()
|
||||
|
@ -124,7 +130,8 @@ func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
|||
// OpenStack API reference
|
||||
// https://developer.openstack.org/api-ref/compute/#list-floating-ips
|
||||
pagerFIP := floatingips.List(client)
|
||||
floatingIPList := make(map[string][]string)
|
||||
floatingIPList := make(map[floatingIPKey]string)
|
||||
floatingIPPresent := make(map[string]struct{})
|
||||
err = pagerFIP.EachPage(func(page pagination.Page) (bool, error) {
|
||||
result, err := floatingips.ExtractFloatingIPs(page)
|
||||
if err != nil {
|
||||
|
@ -132,9 +139,11 @@ func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
|||
}
|
||||
for _, ip := range result {
|
||||
// Skip not associated ips
|
||||
if ip.InstanceID != "" {
|
||||
floatingIPList[ip.InstanceID] = append(floatingIPList[ip.InstanceID], ip.IP)
|
||||
if ip.InstanceID == "" || ip.FixedIP == "" {
|
||||
continue
|
||||
}
|
||||
floatingIPList[floatingIPKey{id: ip.InstanceID, fixed: ip.FixedIP}] = ip.IP
|
||||
floatingIPPresent[ip.IP] = struct{}{}
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
@ -156,14 +165,28 @@ func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
|||
}
|
||||
|
||||
for _, s := range instanceList {
|
||||
labels := model.LabelSet{
|
||||
openstackLabelInstanceID: model.LabelValue(s.ID),
|
||||
}
|
||||
if len(s.Addresses) == 0 {
|
||||
level.Info(i.logger).Log("msg", "Got no IP address", "instance", s.ID)
|
||||
continue
|
||||
}
|
||||
for _, address := range s.Addresses {
|
||||
|
||||
labels := model.LabelSet{
|
||||
openstackLabelInstanceID: model.LabelValue(s.ID),
|
||||
openstackLabelInstanceStatus: model.LabelValue(s.Status),
|
||||
openstackLabelInstanceName: model.LabelValue(s.Name),
|
||||
}
|
||||
|
||||
id, ok := s.Flavor["id"].(string)
|
||||
if !ok {
|
||||
level.Warn(i.logger).Log("msg", "Invalid type for flavor id, expected string")
|
||||
continue
|
||||
}
|
||||
labels[openstackLabelInstanceFlavor] = model.LabelValue(id)
|
||||
for k, v := range s.Metadata {
|
||||
name := strutil.SanitizeLabelName(k)
|
||||
labels[openstackLabelTagPrefix+model.LabelName(name)] = model.LabelValue(v)
|
||||
}
|
||||
for pool, address := range s.Addresses {
|
||||
md, ok := address.([]interface{})
|
||||
if !ok {
|
||||
level.Warn(i.logger).Log("msg", "Invalid type for address, expected array")
|
||||
|
@ -173,7 +196,8 @@ func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
|||
level.Debug(i.logger).Log("msg", "Got no IP address", "instance", s.ID)
|
||||
continue
|
||||
}
|
||||
md1, ok := md[0].(map[string]interface{})
|
||||
for _, address := range md {
|
||||
md1, ok := address.(map[string]interface{})
|
||||
if !ok {
|
||||
level.Warn(i.logger).Log("msg", "Invalid type for address, expected dict")
|
||||
continue
|
||||
|
@ -183,28 +207,24 @@ func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
|||
level.Warn(i.logger).Log("msg", "Invalid type for address, expected string")
|
||||
continue
|
||||
}
|
||||
labels[openstackLabelPrivateIP] = model.LabelValue(addr)
|
||||
addr = net.JoinHostPort(addr, fmt.Sprintf("%d", i.port))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
// Only use first private IP
|
||||
break
|
||||
}
|
||||
if val, ok := floatingIPList[s.ID]; ok && len(val) > 0 {
|
||||
labels[openstackLabelPublicIP] = model.LabelValue(val[0])
|
||||
}
|
||||
labels[openstackLabelInstanceStatus] = model.LabelValue(s.Status)
|
||||
labels[openstackLabelInstanceName] = model.LabelValue(s.Name)
|
||||
id, ok := s.Flavor["id"].(string)
|
||||
if !ok {
|
||||
level.Warn(i.logger).Log("msg", "Invalid type for instance id, excepted string")
|
||||
if _, ok := floatingIPPresent[addr]; ok {
|
||||
continue
|
||||
}
|
||||
labels[openstackLabelInstanceFlavor] = model.LabelValue(id)
|
||||
for k, v := range s.Metadata {
|
||||
name := strutil.SanitizeLabelName(k)
|
||||
labels[openstackLabelTagPrefix+model.LabelName(name)] = model.LabelValue(v)
|
||||
lbls := make(model.LabelSet, len(labels))
|
||||
for k, v := range labels {
|
||||
lbls[k] = v
|
||||
}
|
||||
lbls[openstackLabelAddressPool] = model.LabelValue(pool)
|
||||
lbls[openstackLabelPrivateIP] = model.LabelValue(addr)
|
||||
if val, ok := floatingIPList[floatingIPKey{id: s.ID, fixed: addr}]; ok {
|
||||
lbls[openstackLabelPublicIP] = model.LabelValue(val)
|
||||
}
|
||||
addr = net.JoinHostPort(addr, fmt.Sprintf("%d", i.port))
|
||||
lbls[model.AddressLabel] = model.LabelValue(addr)
|
||||
|
||||
tg.Targets = append(tg.Targets, lbls)
|
||||
}
|
||||
}
|
||||
tg.Targets = append(tg.Targets, labels)
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
package openstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
|
@ -56,28 +57,62 @@ func TestOpenstackSDInstanceRefresh(t *testing.T) {
|
|||
mock := &OpenstackSDInstanceTestSuite{}
|
||||
mock.SetupTest(t)
|
||||
|
||||
instance, _ := mock.openstackAuthSuccess()
|
||||
instance, err := mock.openstackAuthSuccess()
|
||||
testutil.Ok(t, err)
|
||||
|
||||
tg, err := instance.refresh()
|
||||
|
||||
testutil.Ok(t, err)
|
||||
testutil.Assert(t, tg != nil, "")
|
||||
testutil.Assert(t, tg.Targets != nil, "")
|
||||
testutil.Assert(t, len(tg.Targets) == 3, "")
|
||||
testutil.Equals(t, 4, len(tg.Targets))
|
||||
|
||||
testutil.Equals(t, tg.Targets[0]["__address__"], model.LabelValue("10.0.0.32:0"))
|
||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_instance_flavor"], model.LabelValue("1"))
|
||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_instance_id"], model.LabelValue("ef079b0c-e610-4dfb-b1aa-b49f07ac48e5"))
|
||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_instance_name"], model.LabelValue("herp"))
|
||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_instance_status"], model.LabelValue("ACTIVE"))
|
||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_private_ip"], model.LabelValue("10.0.0.32"))
|
||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_public_ip"], model.LabelValue("10.10.10.2"))
|
||||
|
||||
testutil.Equals(t, tg.Targets[1]["__address__"], model.LabelValue("10.0.0.31:0"))
|
||||
testutil.Equals(t, tg.Targets[1]["__meta_openstack_instance_flavor"], model.LabelValue("1"))
|
||||
testutil.Equals(t, tg.Targets[1]["__meta_openstack_instance_id"], model.LabelValue("9e5476bd-a4ec-4653-93d6-72c93aa682ba"))
|
||||
testutil.Equals(t, tg.Targets[1]["__meta_openstack_instance_name"], model.LabelValue("derp"))
|
||||
testutil.Equals(t, tg.Targets[1]["__meta_openstack_instance_status"], model.LabelValue("ACTIVE"))
|
||||
testutil.Equals(t, tg.Targets[1]["__meta_openstack_private_ip"], model.LabelValue("10.0.0.31"))
|
||||
for i, lbls := range []model.LabelSet{
|
||||
model.LabelSet{
|
||||
"__address__": model.LabelValue("10.0.0.32:0"),
|
||||
"__meta_openstack_instance_flavor": model.LabelValue("1"),
|
||||
"__meta_openstack_instance_id": model.LabelValue("ef079b0c-e610-4dfb-b1aa-b49f07ac48e5"),
|
||||
"__meta_openstack_instance_status": model.LabelValue("ACTIVE"),
|
||||
"__meta_openstack_instance_name": model.LabelValue("herp"),
|
||||
"__meta_openstack_private_ip": model.LabelValue("10.0.0.32"),
|
||||
"__meta_openstack_public_ip": model.LabelValue("10.10.10.2"),
|
||||
"__meta_openstack_address_pool": model.LabelValue("private"),
|
||||
},
|
||||
model.LabelSet{
|
||||
"__address__": model.LabelValue("10.0.0.31:0"),
|
||||
"__meta_openstack_instance_flavor": model.LabelValue("1"),
|
||||
"__meta_openstack_instance_id": model.LabelValue("9e5476bd-a4ec-4653-93d6-72c93aa682ba"),
|
||||
"__meta_openstack_instance_status": model.LabelValue("ACTIVE"),
|
||||
"__meta_openstack_instance_name": model.LabelValue("derp"),
|
||||
"__meta_openstack_private_ip": model.LabelValue("10.0.0.31"),
|
||||
"__meta_openstack_address_pool": model.LabelValue("private"),
|
||||
},
|
||||
model.LabelSet{
|
||||
"__address__": model.LabelValue("10.0.0.33:0"),
|
||||
"__meta_openstack_instance_flavor": model.LabelValue("4"),
|
||||
"__meta_openstack_instance_id": model.LabelValue("9e5476bd-a4ec-4653-93d6-72c93aa682bb"),
|
||||
"__meta_openstack_instance_status": model.LabelValue("ACTIVE"),
|
||||
"__meta_openstack_instance_name": model.LabelValue("merp"),
|
||||
"__meta_openstack_private_ip": model.LabelValue("10.0.0.33"),
|
||||
"__meta_openstack_address_pool": model.LabelValue("private"),
|
||||
"__meta_openstack_tag_env": model.LabelValue("prod"),
|
||||
},
|
||||
model.LabelSet{
|
||||
"__address__": model.LabelValue("10.0.0.34:0"),
|
||||
"__meta_openstack_instance_flavor": model.LabelValue("4"),
|
||||
"__meta_openstack_instance_id": model.LabelValue("9e5476bd-a4ec-4653-93d6-72c93aa682bb"),
|
||||
"__meta_openstack_instance_status": model.LabelValue("ACTIVE"),
|
||||
"__meta_openstack_instance_name": model.LabelValue("merp"),
|
||||
"__meta_openstack_private_ip": model.LabelValue("10.0.0.34"),
|
||||
"__meta_openstack_address_pool": model.LabelValue("private"),
|
||||
"__meta_openstack_tag_env": model.LabelValue("prod"),
|
||||
"__meta_openstack_public_ip": model.LabelValue("10.10.10.4"),
|
||||
},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("item %d", i), func(t *testing.T) {
|
||||
testutil.Equals(t, lbls, tg.Targets[i])
|
||||
})
|
||||
}
|
||||
|
||||
mock.TearDownSuite()
|
||||
}
|
||||
|
|
|
@ -327,6 +327,11 @@ const serverListBody = `
|
|||
"version": 4,
|
||||
"addr": "10.0.0.32",
|
||||
"OS-EXT-IPS:type": "fixed"
|
||||
},
|
||||
{
|
||||
"version": 4,
|
||||
"addr": "10.10.10.2",
|
||||
"OS-EXT-IPS:type": "floating"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -463,10 +468,19 @@ const serverListBody = `
|
|||
"addresses": {
|
||||
"private": [
|
||||
{
|
||||
"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:9e:89:be",
|
||||
"version": 4,
|
||||
"addr": "10.0.0.31",
|
||||
"addr": "10.0.0.33",
|
||||
"OS-EXT-IPS:type": "fixed"
|
||||
},
|
||||
{
|
||||
"version": 4,
|
||||
"addr": "10.0.0.34",
|
||||
"OS-EXT-IPS:type": "fixed"
|
||||
},
|
||||
{
|
||||
"version": 4,
|
||||
"addr": "10.10.10.4",
|
||||
"OS-EXT-IPS:type": "floating"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -488,7 +502,7 @@ const serverListBody = `
|
|||
"OS-SRV-USG:launched_at": "2014-09-25T13:04:49.000000",
|
||||
"OS-EXT-SRV-ATTR:hypervisor_hostname": "devstack",
|
||||
"flavor": {
|
||||
"id": "1",
|
||||
"id": "4",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/flavors/1",
|
||||
|
@ -515,7 +529,9 @@ const serverListBody = `
|
|||
"progress": 0,
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"config_drive": "",
|
||||
"metadata": {}
|
||||
"metadata": {
|
||||
"env": "prod"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -543,11 +559,18 @@ const listOutput = `
|
|||
"pool": "nova"
|
||||
},
|
||||
{
|
||||
"fixed_ip": "166.78.185.201",
|
||||
"fixed_ip": "10.0.0.32",
|
||||
"id": "2",
|
||||
"instance_id": "ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
|
||||
"ip": "10.10.10.2",
|
||||
"pool": "nova"
|
||||
},
|
||||
{
|
||||
"fixed_ip": "10.0.0.34",
|
||||
"id": "3",
|
||||
"instance_id": "9e5476bd-a4ec-4653-93d6-72c93aa682bb",
|
||||
"ip": "10.10.10.4",
|
||||
"pool": "nova"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -477,8 +477,9 @@ The following meta labels are available on targets during [relabeling](#relabel_
|
|||
|
||||
#### `instance`
|
||||
|
||||
The `instance` role discovers one target per Nova instance. The target
|
||||
address defaults to the first private IP address of the instance.
|
||||
The `instance` role discovers one target per network interface of Nova
|
||||
instance. The target address defaults to the private IP address of the network
|
||||
interface.
|
||||
|
||||
The following meta labels are available on targets during [relabeling](#relabel_config):
|
||||
|
||||
|
@ -488,6 +489,7 @@ The following meta labels are available on targets during [relabeling](#relabel_
|
|||
* `__meta_openstack_instance_flavor`: the flavor of the OpenStack instance.
|
||||
* `__meta_openstack_public_ip`: the public IP of the OpenStack instance.
|
||||
* `__meta_openstack_private_ip`: the private IP of the OpenStack instance.
|
||||
* `__meta_openstack_address_pool`: the pool of the private IP.
|
||||
* `__meta_openstack_tag_<tagkey>`: each tag value of the instance.
|
||||
|
||||
See below for the configuration options for OpenStack discovery:
|
||||
|
|
Loading…
Reference in New Issue