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 (
|
const (
|
||||||
openstackLabelPrefix = model.MetaLabelPrefix + "openstack_"
|
openstackLabelPrefix = model.MetaLabelPrefix + "openstack_"
|
||||||
|
openstackLabelAddressPool = openstackLabelPrefix + "address_pool"
|
||||||
openstackLabelInstanceID = openstackLabelPrefix + "instance_id"
|
openstackLabelInstanceID = openstackLabelPrefix + "instance_id"
|
||||||
openstackLabelInstanceName = openstackLabelPrefix + "instance_name"
|
openstackLabelInstanceName = openstackLabelPrefix + "instance_name"
|
||||||
openstackLabelInstanceStatus = openstackLabelPrefix + "instance_status"
|
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) {
|
func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
||||||
var err error
|
var err error
|
||||||
t0 := time.Now()
|
t0 := time.Now()
|
||||||
|
@ -124,7 +130,8 @@ func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
||||||
// OpenStack API reference
|
// OpenStack API reference
|
||||||
// https://developer.openstack.org/api-ref/compute/#list-floating-ips
|
// https://developer.openstack.org/api-ref/compute/#list-floating-ips
|
||||||
pagerFIP := floatingips.List(client)
|
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) {
|
err = pagerFIP.EachPage(func(page pagination.Page) (bool, error) {
|
||||||
result, err := floatingips.ExtractFloatingIPs(page)
|
result, err := floatingips.ExtractFloatingIPs(page)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -132,9 +139,11 @@ func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
||||||
}
|
}
|
||||||
for _, ip := range result {
|
for _, ip := range result {
|
||||||
// Skip not associated ips
|
// Skip not associated ips
|
||||||
if ip.InstanceID != "" {
|
if ip.InstanceID == "" || ip.FixedIP == "" {
|
||||||
floatingIPList[ip.InstanceID] = append(floatingIPList[ip.InstanceID], ip.IP)
|
continue
|
||||||
}
|
}
|
||||||
|
floatingIPList[floatingIPKey{id: ip.InstanceID, fixed: ip.FixedIP}] = ip.IP
|
||||||
|
floatingIPPresent[ip.IP] = struct{}{}
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
})
|
})
|
||||||
|
@ -156,14 +165,28 @@ func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range instanceList {
|
for _, s := range instanceList {
|
||||||
labels := model.LabelSet{
|
|
||||||
openstackLabelInstanceID: model.LabelValue(s.ID),
|
|
||||||
}
|
|
||||||
if len(s.Addresses) == 0 {
|
if len(s.Addresses) == 0 {
|
||||||
level.Info(i.logger).Log("msg", "Got no IP address", "instance", s.ID)
|
level.Info(i.logger).Log("msg", "Got no IP address", "instance", s.ID)
|
||||||
continue
|
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{})
|
md, ok := address.([]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
level.Warn(i.logger).Log("msg", "Invalid type for address, expected array")
|
level.Warn(i.logger).Log("msg", "Invalid type for address, expected array")
|
||||||
|
@ -173,38 +196,35 @@ func (i *InstanceDiscovery) refresh() (*targetgroup.Group, error) {
|
||||||
level.Debug(i.logger).Log("msg", "Got no IP address", "instance", s.ID)
|
level.Debug(i.logger).Log("msg", "Got no IP address", "instance", s.ID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
md1, ok := md[0].(map[string]interface{})
|
for _, address := range md {
|
||||||
if !ok {
|
md1, ok := address.(map[string]interface{})
|
||||||
level.Warn(i.logger).Log("msg", "Invalid type for address, expected dict")
|
if !ok {
|
||||||
continue
|
level.Warn(i.logger).Log("msg", "Invalid type for address, expected dict")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
addr, ok := md1["addr"].(string)
|
||||||
|
if !ok {
|
||||||
|
level.Warn(i.logger).Log("msg", "Invalid type for address, expected string")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := floatingIPPresent[addr]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
addr, ok := md1["addr"].(string)
|
|
||||||
if !ok {
|
|
||||||
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")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
labels[openstackLabelInstanceFlavor] = model.LabelValue(id)
|
|
||||||
for k, v := range s.Metadata {
|
|
||||||
name := strutil.SanitizeLabelName(k)
|
|
||||||
labels[openstackLabelTagPrefix+model.LabelName(name)] = model.LabelValue(v)
|
|
||||||
}
|
|
||||||
tg.Targets = append(tg.Targets, labels)
|
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
package openstack
|
package openstack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/prometheus/common/model"
|
"github.com/prometheus/common/model"
|
||||||
|
@ -56,28 +57,62 @@ func TestOpenstackSDInstanceRefresh(t *testing.T) {
|
||||||
mock := &OpenstackSDInstanceTestSuite{}
|
mock := &OpenstackSDInstanceTestSuite{}
|
||||||
mock.SetupTest(t)
|
mock.SetupTest(t)
|
||||||
|
|
||||||
instance, _ := mock.openstackAuthSuccess()
|
instance, err := mock.openstackAuthSuccess()
|
||||||
|
testutil.Ok(t, err)
|
||||||
|
|
||||||
tg, err := instance.refresh()
|
tg, err := instance.refresh()
|
||||||
|
|
||||||
testutil.Ok(t, err)
|
testutil.Ok(t, err)
|
||||||
testutil.Assert(t, tg != nil, "")
|
testutil.Assert(t, tg != nil, "")
|
||||||
testutil.Assert(t, tg.Targets != 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"))
|
for i, lbls := range []model.LabelSet{
|
||||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_instance_flavor"], model.LabelValue("1"))
|
model.LabelSet{
|
||||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_instance_id"], model.LabelValue("ef079b0c-e610-4dfb-b1aa-b49f07ac48e5"))
|
"__address__": model.LabelValue("10.0.0.32:0"),
|
||||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_instance_name"], model.LabelValue("herp"))
|
"__meta_openstack_instance_flavor": model.LabelValue("1"),
|
||||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_instance_status"], model.LabelValue("ACTIVE"))
|
"__meta_openstack_instance_id": model.LabelValue("ef079b0c-e610-4dfb-b1aa-b49f07ac48e5"),
|
||||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_private_ip"], model.LabelValue("10.0.0.32"))
|
"__meta_openstack_instance_status": model.LabelValue("ACTIVE"),
|
||||||
testutil.Equals(t, tg.Targets[0]["__meta_openstack_public_ip"], model.LabelValue("10.10.10.2"))
|
"__meta_openstack_instance_name": model.LabelValue("herp"),
|
||||||
|
"__meta_openstack_private_ip": model.LabelValue("10.0.0.32"),
|
||||||
testutil.Equals(t, tg.Targets[1]["__address__"], model.LabelValue("10.0.0.31:0"))
|
"__meta_openstack_public_ip": model.LabelValue("10.10.10.2"),
|
||||||
testutil.Equals(t, tg.Targets[1]["__meta_openstack_instance_flavor"], model.LabelValue("1"))
|
"__meta_openstack_address_pool": model.LabelValue("private"),
|
||||||
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"))
|
model.LabelSet{
|
||||||
testutil.Equals(t, tg.Targets[1]["__meta_openstack_instance_status"], model.LabelValue("ACTIVE"))
|
"__address__": model.LabelValue("10.0.0.31:0"),
|
||||||
testutil.Equals(t, tg.Targets[1]["__meta_openstack_private_ip"], model.LabelValue("10.0.0.31"))
|
"__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()
|
mock.TearDownSuite()
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,6 +327,11 @@ const serverListBody = `
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"addr": "10.0.0.32",
|
"addr": "10.0.0.32",
|
||||||
"OS-EXT-IPS:type": "fixed"
|
"OS-EXT-IPS:type": "fixed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": 4,
|
||||||
|
"addr": "10.10.10.2",
|
||||||
|
"OS-EXT-IPS:type": "floating"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -463,10 +468,19 @@ const serverListBody = `
|
||||||
"addresses": {
|
"addresses": {
|
||||||
"private": [
|
"private": [
|
||||||
{
|
{
|
||||||
"OS-EXT-IPS-MAC:mac_addr": "fa:16:3e:9e:89:be",
|
|
||||||
"version": 4,
|
"version": 4,
|
||||||
"addr": "10.0.0.31",
|
"addr": "10.0.0.33",
|
||||||
"OS-EXT-IPS:type": "fixed"
|
"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-SRV-USG:launched_at": "2014-09-25T13:04:49.000000",
|
||||||
"OS-EXT-SRV-ATTR:hypervisor_hostname": "devstack",
|
"OS-EXT-SRV-ATTR:hypervisor_hostname": "devstack",
|
||||||
"flavor": {
|
"flavor": {
|
||||||
"id": "1",
|
"id": "4",
|
||||||
"links": [
|
"links": [
|
||||||
{
|
{
|
||||||
"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/flavors/1",
|
"href": "http://104.130.131.164:8774/fcad67a6189847c4aecfa3c81a05783b/flavors/1",
|
||||||
|
@ -515,7 +529,9 @@ const serverListBody = `
|
||||||
"progress": 0,
|
"progress": 0,
|
||||||
"OS-EXT-STS:power_state": 1,
|
"OS-EXT-STS:power_state": 1,
|
||||||
"config_drive": "",
|
"config_drive": "",
|
||||||
"metadata": {}
|
"metadata": {
|
||||||
|
"env": "prod"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -543,11 +559,18 @@ const listOutput = `
|
||||||
"pool": "nova"
|
"pool": "nova"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"fixed_ip": "166.78.185.201",
|
"fixed_ip": "10.0.0.32",
|
||||||
"id": "2",
|
"id": "2",
|
||||||
"instance_id": "ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
|
"instance_id": "ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
|
||||||
"ip": "10.10.10.2",
|
"ip": "10.10.10.2",
|
||||||
"pool": "nova"
|
"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`
|
#### `instance`
|
||||||
|
|
||||||
The `instance` role discovers one target per Nova instance. The target
|
The `instance` role discovers one target per network interface of Nova
|
||||||
address defaults to the first private IP address of the instance.
|
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):
|
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_instance_flavor`: the flavor of the OpenStack instance.
|
||||||
* `__meta_openstack_public_ip`: the public IP 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_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.
|
* `__meta_openstack_tag_<tagkey>`: each tag value of the instance.
|
||||||
|
|
||||||
See below for the configuration options for OpenStack discovery:
|
See below for the configuration options for OpenStack discovery:
|
||||||
|
|
Loading…
Reference in New Issue