mirror of
https://github.com/prometheus/prometheus.git
synced 2025-02-02 08:31:11 -08:00
Merge pull request #15539 from paulojmdias/openstack-loadbalancer-discovery
discovery(openstack): add load balancer discovery
This commit is contained in:
commit
ffea9f005b
201
discovery/openstack/loadbalancer.go
Normal file
201
discovery/openstack/loadbalancer.go
Normal file
|
@ -0,0 +1,201 @@
|
|||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/openstack"
|
||||
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/listeners"
|
||||
"github.com/gophercloud/gophercloud/openstack/loadbalancer/v2/loadbalancers"
|
||||
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/prometheus/common/promslog"
|
||||
|
||||
"github.com/prometheus/prometheus/discovery/targetgroup"
|
||||
)
|
||||
|
||||
const (
|
||||
openstackLabelLoadBalancerID = openstackLabelPrefix + "loadbalancer_id"
|
||||
openstackLabelLoadBalancerName = openstackLabelPrefix + "loadbalancer_name"
|
||||
openstackLabelLoadBalancerOperatingStatus = openstackLabelPrefix + "loadbalancer_operating_status"
|
||||
openstackLabelLoadBalancerProvisioningStatus = openstackLabelPrefix + "loadbalancer_provisioning_status"
|
||||
openstackLabelLoadBalancerAvailabilityZone = openstackLabelPrefix + "loadbalancer_availability_zone"
|
||||
openstackLabelLoadBalancerFloatingIP = openstackLabelPrefix + "loadbalancer_floating_ip"
|
||||
openstackLabelLoadBalancerVIP = openstackLabelPrefix + "loadbalancer_vip"
|
||||
openstackLabelLoadBalancerProvider = openstackLabelPrefix + "loadbalancer_provider"
|
||||
openstackLabelLoadBalancerTags = openstackLabelPrefix + "loadbalancer_tags"
|
||||
)
|
||||
|
||||
// LoadBalancerDiscovery discovers OpenStack load balancers.
|
||||
type LoadBalancerDiscovery struct {
|
||||
provider *gophercloud.ProviderClient
|
||||
authOpts *gophercloud.AuthOptions
|
||||
region string
|
||||
logger *slog.Logger
|
||||
availability gophercloud.Availability
|
||||
}
|
||||
|
||||
// NewLoadBalancerDiscovery returns a new loadbalancer discovery.
|
||||
func newLoadBalancerDiscovery(provider *gophercloud.ProviderClient, opts *gophercloud.AuthOptions,
|
||||
region string, availability gophercloud.Availability, l *slog.Logger,
|
||||
) *LoadBalancerDiscovery {
|
||||
if l == nil {
|
||||
l = promslog.NewNopLogger()
|
||||
}
|
||||
return &LoadBalancerDiscovery{
|
||||
provider: provider, authOpts: opts,
|
||||
region: region, availability: availability, logger: l,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *LoadBalancerDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) {
|
||||
i.provider.Context = ctx
|
||||
err := openstack.Authenticate(i.provider, *i.authOpts)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not authenticate to OpenStack: %w", err)
|
||||
}
|
||||
|
||||
client, err := openstack.NewLoadBalancerV2(i.provider, gophercloud.EndpointOpts{
|
||||
Region: i.region, Availability: i.availability,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create OpenStack load balancer session: %w", err)
|
||||
}
|
||||
|
||||
networkClient, err := openstack.NewNetworkV2(i.provider, gophercloud.EndpointOpts{
|
||||
Region: i.region, Availability: i.availability,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create OpenStack network session: %w", err)
|
||||
}
|
||||
|
||||
allPages, err := loadbalancers.List(client, loadbalancers.ListOpts{}).AllPages()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list load balancers: %w", err)
|
||||
}
|
||||
|
||||
allLBs, err := loadbalancers.ExtractLoadBalancers(allPages)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to extract load balancers: %w", err)
|
||||
}
|
||||
|
||||
// Fetch all listeners in one API call
|
||||
listenerPages, err := listeners.List(client, listeners.ListOpts{}).AllPages()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list all listeners: %w", err)
|
||||
}
|
||||
|
||||
allListeners, err := listeners.ExtractListeners(listenerPages)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to extract all listeners: %w", err)
|
||||
}
|
||||
|
||||
// Create a map to group listeners by Load Balancer ID
|
||||
listenerMap := make(map[string][]listeners.Listener)
|
||||
for _, listener := range allListeners {
|
||||
// Iterate through each associated Load Balancer ID in the Loadbalancers array
|
||||
for _, lb := range listener.Loadbalancers {
|
||||
listenerMap[lb.ID] = append(listenerMap[lb.ID], listener)
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch all floating IPs
|
||||
fipPages, err := floatingips.List(networkClient, floatingips.ListOpts{}).AllPages()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list all fips: %w", err)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list floating IPs: %w", err)
|
||||
}
|
||||
|
||||
allFIPs, err := floatingips.ExtractFloatingIPs(fipPages)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to extract floating IPs: %w", err)
|
||||
}
|
||||
|
||||
// Create a map to associate floating IPs with their resource IDs
|
||||
fipMap := make(map[string]string) // Key: LoadBalancerID/PortID, Value: Floating IP
|
||||
for _, fip := range allFIPs {
|
||||
if fip.PortID != "" {
|
||||
fipMap[fip.PortID] = fip.FloatingIP
|
||||
}
|
||||
}
|
||||
|
||||
tg := &targetgroup.Group{
|
||||
Source: "OS_" + i.region,
|
||||
}
|
||||
|
||||
for _, lb := range allLBs {
|
||||
// Retrieve listeners for this load balancer from the map
|
||||
lbListeners, exists := listenerMap[lb.ID]
|
||||
if !exists || len(lbListeners) == 0 {
|
||||
i.logger.Debug("Got no listener", "loadbalancer", lb.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
// Variable to store the port of the first PROMETHEUS listener
|
||||
var listenerPort int
|
||||
hasPrometheusListener := false
|
||||
|
||||
// Check if any listener has the PROMETHEUS protocol
|
||||
for _, listener := range lbListeners {
|
||||
if listener.Protocol == "PROMETHEUS" {
|
||||
hasPrometheusListener = true
|
||||
listenerPort = listener.ProtocolPort
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Skip LBs without PROMETHEUS listener protocol
|
||||
if !hasPrometheusListener {
|
||||
i.logger.Debug("Got no PROMETHEUS listener", "loadbalancer", lb.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
labels := model.LabelSet{}
|
||||
addr := net.JoinHostPort(lb.VipAddress, strconv.Itoa(listenerPort))
|
||||
labels[model.AddressLabel] = model.LabelValue(addr)
|
||||
labels[openstackLabelLoadBalancerID] = model.LabelValue(lb.ID)
|
||||
labels[openstackLabelLoadBalancerName] = model.LabelValue(lb.Name)
|
||||
labels[openstackLabelLoadBalancerOperatingStatus] = model.LabelValue(lb.OperatingStatus)
|
||||
labels[openstackLabelLoadBalancerProvisioningStatus] = model.LabelValue(lb.ProvisioningStatus)
|
||||
labels[openstackLabelLoadBalancerAvailabilityZone] = model.LabelValue(lb.AvailabilityZone)
|
||||
labels[openstackLabelLoadBalancerVIP] = model.LabelValue(lb.VipAddress)
|
||||
labels[openstackLabelLoadBalancerProvider] = model.LabelValue(lb.Provider)
|
||||
labels[openstackLabelProjectID] = model.LabelValue(lb.ProjectID)
|
||||
|
||||
if len(lb.Tags) > 0 {
|
||||
labels[openstackLabelLoadBalancerTags] = model.LabelValue(strings.Join(lb.Tags, ","))
|
||||
}
|
||||
|
||||
if floatingIP, exists := fipMap[lb.VipPortID]; exists {
|
||||
labels[openstackLabelLoadBalancerFloatingIP] = model.LabelValue(floatingIP)
|
||||
}
|
||||
|
||||
tg.Targets = append(tg.Targets, labels)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []*targetgroup.Group{tg}, nil
|
||||
}
|
137
discovery/openstack/loadbalancer_test.go
Normal file
137
discovery/openstack/loadbalancer_test.go
Normal file
|
@ -0,0 +1,137 @@
|
|||
// Copyright 2017 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package openstack
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type OpenstackSDLoadBalancerTestSuite struct {
|
||||
Mock *SDMock
|
||||
}
|
||||
|
||||
func (s *OpenstackSDLoadBalancerTestSuite) SetupTest(t *testing.T) {
|
||||
s.Mock = NewSDMock(t)
|
||||
s.Mock.Setup()
|
||||
|
||||
s.Mock.HandleLoadBalancerListSuccessfully()
|
||||
s.Mock.HandleListenersListSuccessfully()
|
||||
s.Mock.HandleFloatingIPListSuccessfully()
|
||||
|
||||
s.Mock.HandleVersionsSuccessfully()
|
||||
s.Mock.HandleAuthSuccessfully()
|
||||
}
|
||||
|
||||
func (s *OpenstackSDLoadBalancerTestSuite) openstackAuthSuccess() (refresher, error) {
|
||||
conf := SDConfig{
|
||||
IdentityEndpoint: s.Mock.Endpoint(),
|
||||
Password: "test",
|
||||
Username: "test",
|
||||
DomainName: "12345",
|
||||
Region: "RegionOne",
|
||||
Role: "loadbalancer",
|
||||
}
|
||||
return newRefresher(&conf, nil)
|
||||
}
|
||||
|
||||
func TestOpenstackSDLoadBalancerRefresh(t *testing.T) {
|
||||
mock := &OpenstackSDLoadBalancerTestSuite{}
|
||||
mock.SetupTest(t)
|
||||
|
||||
instance, err := mock.openstackAuthSuccess()
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
tgs, err := instance.refresh(ctx)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Len(t, tgs, 1)
|
||||
|
||||
tg := tgs[0]
|
||||
require.NotNil(t, tg)
|
||||
require.NotNil(t, tg.Targets)
|
||||
require.Len(t, tg.Targets, 4)
|
||||
|
||||
for i, lbls := range []model.LabelSet{
|
||||
{
|
||||
"__address__": model.LabelValue("10.0.0.32:9273"),
|
||||
"__meta_openstack_loadbalancer_id": model.LabelValue("ef079b0c-e610-4dfb-b1aa-b49f07ac48e5"),
|
||||
"__meta_openstack_loadbalancer_name": model.LabelValue("lb1"),
|
||||
"__meta_openstack_loadbalancer_operating_status": model.LabelValue("ONLINE"),
|
||||
"__meta_openstack_loadbalancer_provisioning_status": model.LabelValue("ACTIVE"),
|
||||
"__meta_openstack_loadbalancer_availability_zone": model.LabelValue("az1"),
|
||||
"__meta_openstack_loadbalancer_floating_ip": model.LabelValue("192.168.1.2"),
|
||||
"__meta_openstack_loadbalancer_vip": model.LabelValue("10.0.0.32"),
|
||||
"__meta_openstack_loadbalancer_provider": model.LabelValue("amphora"),
|
||||
"__meta_openstack_loadbalancer_tags": model.LabelValue("tag1,tag2"),
|
||||
"__meta_openstack_project_id": model.LabelValue("fcad67a6189847c4aecfa3c81a05783b"),
|
||||
},
|
||||
{
|
||||
"__address__": model.LabelValue("10.0.2.78:8080"),
|
||||
"__meta_openstack_loadbalancer_id": model.LabelValue("d92c471e-8d3e-4b9f-b2b5-9c72a9e3ef54"),
|
||||
"__meta_openstack_loadbalancer_name": model.LabelValue("lb3"),
|
||||
"__meta_openstack_loadbalancer_operating_status": model.LabelValue("ONLINE"),
|
||||
"__meta_openstack_loadbalancer_provisioning_status": model.LabelValue("ACTIVE"),
|
||||
"__meta_openstack_loadbalancer_availability_zone": model.LabelValue("az3"),
|
||||
"__meta_openstack_loadbalancer_floating_ip": model.LabelValue("192.168.3.4"),
|
||||
"__meta_openstack_loadbalancer_vip": model.LabelValue("10.0.2.78"),
|
||||
"__meta_openstack_loadbalancer_provider": model.LabelValue("amphora"),
|
||||
"__meta_openstack_loadbalancer_tags": model.LabelValue("tag5,tag6"),
|
||||
"__meta_openstack_project_id": model.LabelValue("ac57f03dba1a4fdebff3e67201bc7a85"),
|
||||
},
|
||||
{
|
||||
"__address__": model.LabelValue("10.0.3.99:9090"),
|
||||
"__meta_openstack_loadbalancer_id": model.LabelValue("f5c7e918-df38-4a5a-a7d4-d9c27ab2cf67"),
|
||||
"__meta_openstack_loadbalancer_name": model.LabelValue("lb4"),
|
||||
"__meta_openstack_loadbalancer_operating_status": model.LabelValue("ONLINE"),
|
||||
"__meta_openstack_loadbalancer_provisioning_status": model.LabelValue("ACTIVE"),
|
||||
"__meta_openstack_loadbalancer_availability_zone": model.LabelValue("az1"),
|
||||
"__meta_openstack_loadbalancer_floating_ip": model.LabelValue("192.168.4.5"),
|
||||
"__meta_openstack_loadbalancer_vip": model.LabelValue("10.0.3.99"),
|
||||
"__meta_openstack_loadbalancer_provider": model.LabelValue("amphora"),
|
||||
"__meta_openstack_project_id": model.LabelValue("fa8c372dfe4d4c92b0c4e3a2d9b3c9fa"),
|
||||
},
|
||||
{
|
||||
"__address__": model.LabelValue("10.0.4.88:9876"),
|
||||
"__meta_openstack_loadbalancer_id": model.LabelValue("e83a6d92-7a3e-4567-94b3-20c83b32a75e"),
|
||||
"__meta_openstack_loadbalancer_name": model.LabelValue("lb5"),
|
||||
"__meta_openstack_loadbalancer_operating_status": model.LabelValue("ONLINE"),
|
||||
"__meta_openstack_loadbalancer_provisioning_status": model.LabelValue("ACTIVE"),
|
||||
"__meta_openstack_loadbalancer_availability_zone": model.LabelValue("az4"),
|
||||
"__meta_openstack_loadbalancer_vip": model.LabelValue("10.0.4.88"),
|
||||
"__meta_openstack_loadbalancer_provider": model.LabelValue("amphora"),
|
||||
"__meta_openstack_project_id": model.LabelValue("a5d3b2e1e6f34cd9a5f7c2f01a6b8e29"),
|
||||
},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("item %d", i), func(t *testing.T) {
|
||||
require.Equal(t, lbls, tg.Targets[i])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenstackSDLoadBalancerRefreshWithDoneContext(t *testing.T) {
|
||||
mock := &OpenstackSDLoadBalancerTestSuite{}
|
||||
mock.SetupTest(t)
|
||||
|
||||
loadbalancer, _ := mock.openstackAuthSuccess()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
_, err := loadbalancer.refresh(ctx)
|
||||
require.ErrorContains(t, err, context.Canceled.Error(), "%q doesn't contain %q", err, context.Canceled)
|
||||
}
|
|
@ -149,7 +149,20 @@ func (m *SDMock) HandleAuthSuccessfully() {
|
|||
],
|
||||
"id": "589f3d99a3d94f5f871e9f5cf206d2e8",
|
||||
"type": "network"
|
||||
}
|
||||
},
|
||||
{
|
||||
"endpoints": [
|
||||
{
|
||||
"id": "39dc322ce86c1234b4f06c2eeae0841b",
|
||||
"interface": "public",
|
||||
"region": "RegionOne",
|
||||
"region_id": "RegionOne",
|
||||
"url": "%s"
|
||||
}
|
||||
],
|
||||
"id": "26968f704a68417bbddd29508455ff90",
|
||||
"type": "load-balancer"
|
||||
}
|
||||
],
|
||||
"expires_at": "2013-02-27T18:30:59.999999Z",
|
||||
"is_domain": false,
|
||||
|
@ -186,7 +199,7 @@ func (m *SDMock) HandleAuthSuccessfully() {
|
|||
}
|
||||
}
|
||||
}
|
||||
`, m.Endpoint(), m.Endpoint())
|
||||
`, m.Endpoint(), m.Endpoint(), m.Endpoint())
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -711,6 +724,63 @@ const listOutput = `
|
|||
"tags": [],
|
||||
"created_at": "2024-01-24T13:30:50Z",
|
||||
"updated_at": "2024-01-24T13:30:51Z"
|
||||
},
|
||||
{
|
||||
"id": "fea7332d-9027-4cf9-bf62-c3c4c6ebaf84",
|
||||
"tenant_id": "fcad67a6189847c4aecfa3c81a05783b",
|
||||
"floating_ip_address": "192.168.1.2",
|
||||
"floating_network_id": "d02c4f18-d606-4864-b12a-1c9b39a46be2",
|
||||
"router_id": "f03af93b-4e8f-4f55-adcf-a0317782ede2",
|
||||
"port_id": "b47c39f5-238d-4b17-ae87-9b5d19af8a2e",
|
||||
"fixed_ip_address": "10.0.0.32",
|
||||
"status": "ACTIVE",
|
||||
"description": "",
|
||||
"dns_domain": "",
|
||||
"dns_name": "",
|
||||
"port_forwardings": [],
|
||||
"tags": [],
|
||||
"created_at": "2023-08-30T15:11:37Z",
|
||||
"updated_at": "2023-08-30T15:11:38Z",
|
||||
"revision_number": 1,
|
||||
"project_id": "fcad67a6189847c4aecfa3c81a05783b"
|
||||
},
|
||||
{
|
||||
"id": "febb9554-cf83-4f9b-94d9-1b3c34be357f",
|
||||
"tenant_id": "ac57f03dba1a4fdebff3e67201bc7a85",
|
||||
"floating_ip_address": "192.168.3.4",
|
||||
"floating_network_id": "d02c4f18-d606-4864-b12a-1c9b39a46be2",
|
||||
"router_id": "f03af93b-4e8f-4f55-adcf-a0317782ede2",
|
||||
"port_id": "c83b6e12-4e5d-4673-a4b3-5bc72a7f3ef9",
|
||||
"fixed_ip_address": "10.0.2.78",
|
||||
"status": "ACTIVE",
|
||||
"description": "",
|
||||
"dns_domain": "",
|
||||
"dns_name": "",
|
||||
"port_forwardings": [],
|
||||
"tags": [],
|
||||
"created_at": "2023-08-30T15:11:37Z",
|
||||
"updated_at": "2023-08-30T15:11:38Z",
|
||||
"revision_number": 1,
|
||||
"project_id": "ac57f03dba1a4fdebff3e67201bc7a85"
|
||||
},
|
||||
{
|
||||
"id": "febb9554-cf83-4f9b-94d9-1b3c34be357f",
|
||||
"tenant_id": "fa8c372dfe4d4c92b0c4e3a2d9b3c9fa",
|
||||
"floating_ip_address": "192.168.4.5",
|
||||
"floating_network_id": "d02c4f18-d606-4864-b12a-1c9b39a46be2",
|
||||
"router_id": "f03af93b-4e8f-4f55-adcf-a0317782ede2",
|
||||
"port_id": "f9e8b6e12-7e4d-4963-a5b3-6cd82a7f3ff6",
|
||||
"fixed_ip_address": "10.0.3.99",
|
||||
"status": "ACTIVE",
|
||||
"description": "",
|
||||
"dns_domain": "",
|
||||
"dns_name": "",
|
||||
"port_forwardings": [],
|
||||
"tags": [],
|
||||
"created_at": "2023-08-30T15:11:37Z",
|
||||
"updated_at": "2023-08-30T15:11:38Z",
|
||||
"revision_number": 1,
|
||||
"project_id": "fa8c372dfe4d4c92b0c4e3a2d9b3c9fa"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -863,3 +933,471 @@ func (m *SDMock) HandlePortsListSuccessfully() {
|
|||
fmt.Fprint(w, portsListBody)
|
||||
})
|
||||
}
|
||||
|
||||
const lbListBody = `
|
||||
{
|
||||
"loadbalancers": [
|
||||
{
|
||||
"id": "ef079b0c-e610-4dfb-b1aa-b49f07ac48e5",
|
||||
"name": "lb1",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"project_id": "fcad67a6189847c4aecfa3c81a05783b",
|
||||
"created_at": "2024-12-01T10:00:00",
|
||||
"updated_at": "2024-12-01T10:30:00",
|
||||
"vip_address": "10.0.0.32",
|
||||
"vip_port_id": "b47c39f5-238d-4b17-ae87-9b5d19af8a2e",
|
||||
"vip_subnet_id": "14a4c6a5-fe71-4a94-9071-4cd12fb8337f",
|
||||
"vip_network_id": "d02c4f18-d606-4864-b12a-1c9b39a46be2",
|
||||
"tags": ["tag1", "tag2"],
|
||||
"availability_zone": "az1",
|
||||
"vip_vnic_type": "normal",
|
||||
"provider": "amphora",
|
||||
"listeners": [
|
||||
{
|
||||
"id": "c4146b54-febc-4caf-a53f-ed1cab6faba5"
|
||||
},
|
||||
{
|
||||
"id": "a058d20e-82de-4eff-bb65-5c76a8554435"
|
||||
}
|
||||
],
|
||||
"tenant_id": "fcad67a6189847c4aecfa3c81a05783b"
|
||||
},
|
||||
{
|
||||
"id": "d92c471e-8d3e-4b9f-b2b5-9c72a9e3ef54",
|
||||
"name": "lb3",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"project_id": "ac57f03dba1a4fdebff3e67201bc7a85",
|
||||
"created_at": "2024-12-01T12:00:00",
|
||||
"updated_at": "2024-12-01T12:45:00",
|
||||
"vip_address": "10.0.2.78",
|
||||
"vip_port_id": "c83b6e12-4e5d-4673-a4b3-5bc72a7f3ef9",
|
||||
"vip_subnet_id": "36c5e9f6-e7a2-4975-a8c6-3b8e4f93cf45",
|
||||
"vip_network_id": "g03c6f27-e617-4975-c8f7-4c9f3f94cf68",
|
||||
"tags": ["tag5", "tag6"],
|
||||
"availability_zone": "az3",
|
||||
"vip_vnic_type": "normal",
|
||||
"provider": "amphora",
|
||||
"listeners": [
|
||||
{
|
||||
"id": "5b9529a4-6cbf-48f8-a006-d99cbc717da0"
|
||||
},
|
||||
{
|
||||
"id": "5d26333b-74d1-4b2a-90ab-2b2c0f5a8048"
|
||||
}
|
||||
],
|
||||
"tenant_id": "ac57f03dba1a4fdebff3e67201bc7a85"
|
||||
},
|
||||
{
|
||||
"id": "f5c7e918-df38-4a5a-a7d4-d9c27ab2cf67",
|
||||
"name": "lb4",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"project_id": "fa8c372dfe4d4c92b0c4e3a2d9b3c9fa",
|
||||
"created_at": "2024-12-01T13:00:00",
|
||||
"updated_at": "2024-12-01T13:20:00",
|
||||
"vip_address": "10.0.3.99",
|
||||
"vip_port_id": "f9e8b6e12-7e4d-4963-a5b3-6cd82a7f3ff6",
|
||||
"vip_subnet_id": "47d6f8f9-f7b2-4876-a9d8-4e8f4g95df79",
|
||||
"vip_network_id": "h04d7f38-f718-4876-d9g8-5d8g5h95df89",
|
||||
"tags": [],
|
||||
"availability_zone": "az1",
|
||||
"vip_vnic_type": "normal",
|
||||
"provider": "amphora",
|
||||
"listeners": [
|
||||
{
|
||||
"id": "84c87596-1ff0-4f6d-b151-0a78e1f407a3"
|
||||
},
|
||||
{
|
||||
"id": "fe460a7c-16a9-4984-9fe6-f6e5153ebab1"
|
||||
}
|
||||
],
|
||||
"tenant_id": "fa8c372dfe4d4c92b0c4e3a2d9b3c9fa"
|
||||
},
|
||||
{
|
||||
"id": "e83a6d92-7a3e-4567-94b3-20c83b32a75e",
|
||||
"name": "lb5",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"project_id": "a5d3b2e1e6f34cd9a5f7c2f01a6b8e29",
|
||||
"created_at": "2024-12-01T11:00:00",
|
||||
"updated_at": "2024-12-01T11:15:00",
|
||||
"vip_address": "10.0.4.88",
|
||||
"vip_port_id": "d83a6d92-7a3e-4567-94b3-20c83b32a75e",
|
||||
"vip_subnet_id": "25b4d8e5-fe81-4a87-9071-4cc12fb8337f",
|
||||
"vip_network_id": "f02c5e19-c507-4864-b16e-2b7a39e56be3",
|
||||
"tags": [],
|
||||
"availability_zone": "az4",
|
||||
"vip_vnic_type": "normal",
|
||||
"provider": "amphora",
|
||||
"listeners": [
|
||||
{
|
||||
"id": "50902e62-34b8-46b2-9ed4-9053e7ad46dc"
|
||||
},
|
||||
{
|
||||
"id": "98a867ad-ff07-4880-b05f-32088866a68a"
|
||||
}
|
||||
],
|
||||
"tenant_id": "a5d3b2e1e6f34cd9a5f7c2f01a6b8e29"
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
// HandleLoadBalancerListSuccessfully mocks the load balancer list API.
|
||||
func (m *SDMock) HandleLoadBalancerListSuccessfully() {
|
||||
m.Mux.HandleFunc("/v2.0/lbaas/loadbalancers", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(m.t, r, http.MethodGet)
|
||||
testHeader(m.t, r, "X-Auth-Token", tokenID)
|
||||
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
fmt.Fprint(w, lbListBody)
|
||||
})
|
||||
}
|
||||
|
||||
const listenerListBody = `
|
||||
{
|
||||
"listeners": [
|
||||
{
|
||||
"id": "c4146b54-febc-4caf-a53f-ed1cab6faba5",
|
||||
"name": "stats-listener",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"protocol": "PROMETHEUS",
|
||||
"protocol_port": 9273,
|
||||
"connection_limit": -1,
|
||||
"default_tls_container_ref": null,
|
||||
"sni_container_refs": [],
|
||||
"project_id": "fcad67a6189847c4aecfa3c81a05783b",
|
||||
"default_pool_id": null,
|
||||
"l7policies": [],
|
||||
"insert_headers": {},
|
||||
"created_at": "2024-08-29T18:05:24",
|
||||
"updated_at": "2024-12-04T21:21:10",
|
||||
"loadbalancers": [
|
||||
{
|
||||
"id": "ef079b0c-e610-4dfb-b1aa-b49f07ac48e5"
|
||||
}
|
||||
],
|
||||
"timeout_client_data": 50000,
|
||||
"timeout_member_connect": 5000,
|
||||
"timeout_member_data": 50000,
|
||||
"timeout_tcp_inspect": 0,
|
||||
"tags": [],
|
||||
"client_ca_tls_container_ref": null,
|
||||
"client_authentication": "NONE",
|
||||
"client_crl_container_ref": null,
|
||||
"allowed_cidrs": null,
|
||||
"tls_ciphers": null,
|
||||
"tls_versions": null,
|
||||
"alpn_protocols": null,
|
||||
"hsts_max_age": null,
|
||||
"hsts_include_subdomains": null,
|
||||
"hsts_preload": null,
|
||||
"tenant_id": "fcad67a6189847c4aecfa3c81a05783b"
|
||||
},
|
||||
{
|
||||
"id": "5b9529a4-6cbf-48f8-a006-d99cbc717da0",
|
||||
"name": "stats-listener2",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"protocol": "PROMETHEUS",
|
||||
"protocol_port": 8080,
|
||||
"connection_limit": -1,
|
||||
"default_tls_container_ref": null,
|
||||
"sni_container_refs": [],
|
||||
"project_id": "ac57f03dba1a4fdebff3e67201bc7a85",
|
||||
"default_pool_id": null,
|
||||
"l7policies": [],
|
||||
"insert_headers": {},
|
||||
"created_at": "2024-08-29T18:05:24",
|
||||
"updated_at": "2024-12-04T21:21:10",
|
||||
"loadbalancers": [
|
||||
{
|
||||
"id": "d92c471e-8d3e-4b9f-b2b5-9c72a9e3ef54"
|
||||
}
|
||||
],
|
||||
"timeout_client_data": 50000,
|
||||
"timeout_member_connect": 5000,
|
||||
"timeout_member_data": 50000,
|
||||
"timeout_tcp_inspect": 0,
|
||||
"tags": [],
|
||||
"client_ca_tls_container_ref": null,
|
||||
"client_authentication": "NONE",
|
||||
"client_crl_container_ref": null,
|
||||
"allowed_cidrs": null,
|
||||
"tls_ciphers": null,
|
||||
"tls_versions": null,
|
||||
"alpn_protocols": null,
|
||||
"hsts_max_age": null,
|
||||
"hsts_include_subdomains": null,
|
||||
"hsts_preload": null,
|
||||
"tenant_id": "ac57f03dba1a4fdebff3e67201bc7a85"
|
||||
},
|
||||
{
|
||||
"id": "84c87596-1ff0-4f6d-b151-0a78e1f407a3",
|
||||
"name": "stats-listener3",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"protocol": "PROMETHEUS",
|
||||
"protocol_port": 9090,
|
||||
"connection_limit": -1,
|
||||
"default_tls_container_ref": null,
|
||||
"sni_container_refs": [],
|
||||
"project_id": "fa8c372dfe4d4c92b0c4e3a2d9b3c9fa",
|
||||
"default_pool_id": null,
|
||||
"l7policies": [],
|
||||
"insert_headers": {},
|
||||
"created_at": "2024-08-29T18:05:24",
|
||||
"updated_at": "2024-12-04T21:21:10",
|
||||
"loadbalancers": [
|
||||
{
|
||||
"id": "f5c7e918-df38-4a5a-a7d4-d9c27ab2cf67"
|
||||
}
|
||||
],
|
||||
"timeout_client_data": 50000,
|
||||
"timeout_member_connect": 5000,
|
||||
"timeout_member_data": 50000,
|
||||
"timeout_tcp_inspect": 0,
|
||||
"tags": [],
|
||||
"client_ca_tls_container_ref": null,
|
||||
"client_authentication": "NONE",
|
||||
"client_crl_container_ref": null,
|
||||
"allowed_cidrs": null,
|
||||
"tls_ciphers": null,
|
||||
"tls_versions": null,
|
||||
"alpn_protocols": null,
|
||||
"hsts_max_age": null,
|
||||
"hsts_include_subdomains": null,
|
||||
"hsts_preload": null,
|
||||
"tenant_id": "fa8c372dfe4d4c92b0c4e3a2d9b3c9fa"
|
||||
},
|
||||
{
|
||||
"id": "50902e62-34b8-46b2-9ed4-9053e7ad46dc",
|
||||
"name": "stats-listener4",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"protocol": "PROMETHEUS",
|
||||
"protocol_port": 9876,
|
||||
"connection_limit": -1,
|
||||
"default_tls_container_ref": null,
|
||||
"sni_container_refs": [],
|
||||
"project_id": "a5d3b2e1e6f34cd9a5f7c2f01a6b8e29",
|
||||
"default_pool_id": null,
|
||||
"l7policies": [],
|
||||
"insert_headers": {},
|
||||
"created_at": "2024-08-29T18:05:24",
|
||||
"updated_at": "2024-12-04T21:21:10",
|
||||
"loadbalancers": [
|
||||
{
|
||||
"id": "e83a6d92-7a3e-4567-94b3-20c83b32a75e"
|
||||
}
|
||||
],
|
||||
"timeout_client_data": 50000,
|
||||
"timeout_member_connect": 5000,
|
||||
"timeout_member_data": 50000,
|
||||
"timeout_tcp_inspect": 0,
|
||||
"tags": [],
|
||||
"client_ca_tls_container_ref": null,
|
||||
"client_authentication": "NONE",
|
||||
"client_crl_container_ref": null,
|
||||
"allowed_cidrs": null,
|
||||
"tls_ciphers": null,
|
||||
"tls_versions": null,
|
||||
"alpn_protocols": null,
|
||||
"hsts_max_age": null,
|
||||
"hsts_include_subdomains": null,
|
||||
"hsts_preload": null,
|
||||
"tenant_id": "a5d3b2e1e6f34cd9a5f7c2f01a6b8e29"
|
||||
},
|
||||
{
|
||||
"id": "a058d20e-82de-4eff-bb65-5c76a8554435",
|
||||
"name": "port6443",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"protocol": "TCP",
|
||||
"protocol_port": 6443,
|
||||
"connection_limit": -1,
|
||||
"default_tls_container_ref": null,
|
||||
"sni_container_refs": [],
|
||||
"project_id": "a5d3b2e1e6f34cd9a5f7c2f01a6b8e29",
|
||||
"default_pool_id": "5643208b-b691-4b1f-a6b8-356f14903e56",
|
||||
"l7policies": [],
|
||||
"insert_headers": {},
|
||||
"created_at": "2024-10-02T19:32:48",
|
||||
"updated_at": "2024-12-04T21:44:34",
|
||||
"loadbalancers": [
|
||||
{
|
||||
"id": "ef079b0c-e610-4dfb-b1aa-b49f07ac48e5"
|
||||
}
|
||||
],
|
||||
"timeout_client_data": 50000,
|
||||
"timeout_member_connect": 5000,
|
||||
"timeout_member_data": 50000,
|
||||
"timeout_tcp_inspect": 0,
|
||||
"tags": [],
|
||||
"client_ca_tls_container_ref": null,
|
||||
"client_authentication": "NONE",
|
||||
"client_crl_container_ref": null,
|
||||
"allowed_cidrs": null,
|
||||
"tls_ciphers": null,
|
||||
"tls_versions": null,
|
||||
"alpn_protocols": null,
|
||||
"hsts_max_age": null,
|
||||
"hsts_include_subdomains": null,
|
||||
"hsts_preload": null,
|
||||
"tenant_id": "a5d3b2e1e6f34cd9a5f7c2f01a6b8e29"
|
||||
},
|
||||
{
|
||||
"id": "5d26333b-74d1-4b2a-90ab-2b2c0f5a8048",
|
||||
"name": "port6444",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"protocol": "TCP",
|
||||
"protocol_port": 6444,
|
||||
"connection_limit": -1,
|
||||
"default_tls_container_ref": null,
|
||||
"sni_container_refs": [],
|
||||
"project_id": "ac57f03dba1a4fdebff3e67201bc7a85",
|
||||
"default_pool_id": "5643208b-b691-4b1f-a6b8-356f14903e56",
|
||||
"l7policies": [],
|
||||
"insert_headers": {},
|
||||
"created_at": "2024-10-02T19:32:48",
|
||||
"updated_at": "2024-12-04T21:44:34",
|
||||
"loadbalancers": [
|
||||
{
|
||||
"id": "d92c471e-8d3e-4b9f-b2b5-9c72a9e3ef54"
|
||||
}
|
||||
],
|
||||
"timeout_client_data": 50000,
|
||||
"timeout_member_connect": 5000,
|
||||
"timeout_member_data": 50000,
|
||||
"timeout_tcp_inspect": 0,
|
||||
"tags": [],
|
||||
"client_ca_tls_container_ref": null,
|
||||
"client_authentication": "NONE",
|
||||
"client_crl_container_ref": null,
|
||||
"allowed_cidrs": null,
|
||||
"tls_ciphers": null,
|
||||
"tls_versions": null,
|
||||
"alpn_protocols": null,
|
||||
"hsts_max_age": null,
|
||||
"hsts_include_subdomains": null,
|
||||
"hsts_preload": null,
|
||||
"tenant_id": "ac57f03dba1a4fdebff3e67201bc7a85"
|
||||
},
|
||||
{
|
||||
"id": "fe460a7c-16a9-4984-9fe6-f6e5153ebab1",
|
||||
"name": "port6445",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"protocol": "TCP",
|
||||
"protocol_port": 6445,
|
||||
"connection_limit": -1,
|
||||
"default_tls_container_ref": null,
|
||||
"sni_container_refs": [],
|
||||
"project_id": "fa8c372dfe4d4c92b0c4e3a2d9b3c9fa",
|
||||
"default_pool_id": "5643208b-b691-4b1f-a6b8-356f14903e56",
|
||||
"l7policies": [],
|
||||
"insert_headers": {},
|
||||
"created_at": "2024-10-02T19:32:48",
|
||||
"updated_at": "2024-12-04T21:44:34",
|
||||
"loadbalancers": [
|
||||
{
|
||||
"id": "f5c7e918-df38-4a5a-a7d4-d9c27ab2cf67"
|
||||
}
|
||||
],
|
||||
"timeout_client_data": 50000,
|
||||
"timeout_member_connect": 5000,
|
||||
"timeout_member_data": 50000,
|
||||
"timeout_tcp_inspect": 0,
|
||||
"tags": [],
|
||||
"client_ca_tls_container_ref": null,
|
||||
"client_authentication": "NONE",
|
||||
"client_crl_container_ref": null,
|
||||
"allowed_cidrs": null,
|
||||
"tls_ciphers": null,
|
||||
"tls_versions": null,
|
||||
"alpn_protocols": null,
|
||||
"hsts_max_age": null,
|
||||
"hsts_include_subdomains": null,
|
||||
"hsts_preload": null,
|
||||
"tenant_id": "fa8c372dfe4d4c92b0c4e3a2d9b3c9fa"
|
||||
},
|
||||
{
|
||||
"id": "98a867ad-ff07-4880-b05f-32088866a68a",
|
||||
"name": "port6446",
|
||||
"description": "",
|
||||
"provisioning_status": "ACTIVE",
|
||||
"operating_status": "ONLINE",
|
||||
"admin_state_up": true,
|
||||
"protocol": "TCP",
|
||||
"protocol_port": 6446,
|
||||
"connection_limit": -1,
|
||||
"default_tls_container_ref": null,
|
||||
"sni_container_refs": [],
|
||||
"project_id": "a5d3b2e1e6f34cd9a5f7c2f01a6b8e29",
|
||||
"default_pool_id": "5643208b-b691-4b1f-a6b8-356f14903e56",
|
||||
"l7policies": [],
|
||||
"insert_headers": {},
|
||||
"created_at": "2024-10-02T19:32:48",
|
||||
"updated_at": "2024-12-04T21:44:34",
|
||||
"loadbalancers": [
|
||||
{
|
||||
"id": "e83a6d92-7a3e-4567-94b3-20c83b32a75e"
|
||||
}
|
||||
],
|
||||
"timeout_client_data": 50000,
|
||||
"timeout_member_connect": 5000,
|
||||
"timeout_member_data": 50000,
|
||||
"timeout_tcp_inspect": 0,
|
||||
"tags": [],
|
||||
"client_ca_tls_container_ref": null,
|
||||
"client_authentication": "NONE",
|
||||
"client_crl_container_ref": null,
|
||||
"allowed_cidrs": null,
|
||||
"tls_ciphers": null,
|
||||
"tls_versions": null,
|
||||
"alpn_protocols": null,
|
||||
"hsts_max_age": null,
|
||||
"hsts_include_subdomains": null,
|
||||
"hsts_preload": null,
|
||||
"tenant_id": "a5d3b2e1e6f34cd9a5f7c2f01a6b8e29"
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
// HandleListenersListSuccessfully mocks the listeners endpoint.
|
||||
func (m *SDMock) HandleListenersListSuccessfully() {
|
||||
m.Mux.HandleFunc("/v2.0/lbaas/listeners", func(w http.ResponseWriter, r *http.Request) {
|
||||
testMethod(m.t, r, http.MethodGet)
|
||||
testHeader(m.t, r, "X-Auth-Token", tokenID)
|
||||
|
||||
w.Header().Add("Content-Type", "application/json")
|
||||
fmt.Fprint(w, listenerListBody)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -97,6 +97,9 @@ const (
|
|||
// OpenStack document reference
|
||||
// https://docs.openstack.org/horizon/pike/user/launch-instances.html
|
||||
OpenStackRoleInstance Role = "instance"
|
||||
// Openstack document reference
|
||||
// https://docs.openstack.org/openstacksdk/rocky/user/resources/load_balancer/index.html
|
||||
OpenStackRoleLoadBalancer Role = "loadbalancer"
|
||||
)
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
|
@ -105,7 +108,7 @@ func (c *Role) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
return err
|
||||
}
|
||||
switch *c {
|
||||
case OpenStackRoleHypervisor, OpenStackRoleInstance:
|
||||
case OpenStackRoleHypervisor, OpenStackRoleInstance, OpenStackRoleLoadBalancer:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown OpenStack SD role %q", *c)
|
||||
|
@ -128,7 +131,7 @@ func (c *SDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
}
|
||||
|
||||
if c.Role == "" {
|
||||
return errors.New("role missing (one of: instance, hypervisor)")
|
||||
return errors.New("role missing (one of: instance, hypervisor, loadbalancer)")
|
||||
}
|
||||
if c.Region == "" {
|
||||
return errors.New("openstack SD configuration requires a region")
|
||||
|
@ -211,6 +214,8 @@ func newRefresher(conf *SDConfig, l *slog.Logger) (refresher, error) {
|
|||
return newHypervisorDiscovery(client, &opts, conf.Port, conf.Region, availability, l), nil
|
||||
case OpenStackRoleInstance:
|
||||
return newInstanceDiscovery(client, &opts, conf.Port, conf.Region, conf.AllTenants, availability, l), nil
|
||||
case OpenStackRoleLoadBalancer:
|
||||
return newLoadBalancerDiscovery(client, &opts, conf.Region, availability, l), nil
|
||||
}
|
||||
return nil, errors.New("unknown OpenStack discovery role")
|
||||
}
|
||||
|
|
|
@ -1208,6 +1208,25 @@ The following meta labels are available on targets during [relabeling](#relabel_
|
|||
* `__meta_openstack_tag_<key>`: each metadata item of the instance, with any unsupported characters converted to an underscore.
|
||||
* `__meta_openstack_user_id`: the user account owning the tenant.
|
||||
|
||||
#### `loadbalancer`
|
||||
|
||||
The `loadbalancer` role discovers one target per Octavia loadbalancer with a
|
||||
`PROMETHEUS` listener. The target address defaults to the VIP address
|
||||
of the load balancer.
|
||||
|
||||
The following meta labels are available on targets during [relabeling](#relabel_config):
|
||||
|
||||
* `__meta_openstack_loadbalancer_availability_zone`: the availability zone of the OpenStack load balancer.
|
||||
* `__meta_openstack_loadbalancer_floating_ip`: the floating IP of the OpenStack load balancer.
|
||||
* `__meta_openstack_loadbalancer_id`: the OpenStack load balancer ID.
|
||||
* `__meta_openstack_loadbalancer_name`: the OpenStack load balancer name.
|
||||
* `__meta_openstack_loadbalancer_provider`: the Octavia provider of the OpenStack load balancer.
|
||||
* `__meta_openstack_loadbalancer_operating_status`: the operating status of the OpenStack load balancer.
|
||||
* `__meta_openstack_loadbalancer_provisioning_status`: the provisioning status of the OpenStack load balancer.
|
||||
* `__meta_openstack_loadbalancer_tags`: comma separated list of the OpenStack load balancer.
|
||||
* `__meta_openstack_loadbalancer_vip`: the VIP of the OpenStack load balancer.
|
||||
* `__meta_openstack_project_id`: the project (tenant) owning this load balancer.
|
||||
|
||||
See below for the configuration options for OpenStack discovery:
|
||||
|
||||
```yaml
|
||||
|
|
Loading…
Reference in a new issue