Merge "Do not drop floating IPs/VPNs with unknown status"

This commit is contained in:
Zuul
2025-04-25 08:08:56 +00:00
committed by Gerrit Code Review
7 changed files with 116 additions and 44 deletions
+9 -4
View File
@@ -18,6 +18,7 @@
from oslo_log import log
from ceilometer.i18n import _
from ceilometer.network.services import base
from ceilometer import sample
@@ -41,11 +42,15 @@ class FloatingIPPollster(base.BaseServicesPollster):
def get_samples(self, manager, cache, resources):
for fip in resources or []:
if fip['status'] is None:
LOG.warning("Invalid status, skipping IP address %s" %
fip['floating_ip_address'])
continue
LOG.debug("FLOATING IP : %s", fip)
status = self.get_status_id(fip['status'])
if status == -1:
LOG.warning(
_("Unknown status %(status)s for floating IP address "
"%(address)s (%(id)s), setting volume to -1") % {
"status": fip['status'],
"address": fip['floating_ip_address'],
"id": fip['id']})
yield sample.Sample(
name='ip.floating',
type=sample.TYPE_GAUGE,
+2
View File
@@ -38,5 +38,7 @@ class BaseServicesPollster(plugin_base.PollsterBase):
@staticmethod
def get_status_id(value):
if not value:
return -1
status = value.lower()
return STATUS.get(status, -1)
+1 -3
View File
@@ -29,9 +29,7 @@ class VPNServicesDiscovery(_BaseServicesDiscovery):
def discover(self, manager, param=None):
"""Discover resources to monitor."""
vpnservices = self.neutron_cli.vpn_get_all()
return [i for i in vpnservices
if i.get('status', None) != 'error']
return self.neutron_cli.vpn_get_all()
class IPSecConnectionsDiscovery(_BaseServicesDiscovery):
+8 -8
View File
@@ -41,15 +41,15 @@ class VPNServicesPollster(base.BaseServicesPollster):
resources = resources or []
for vpn in resources:
LOG.debug("VPN : %s" % vpn)
LOG.debug("VPN : %s", vpn)
status = self.get_status_id(vpn['status'])
if status == -1:
# unknown status, skip this sample
LOG.warning(_("Unknown status %(stat)s received on vpn "
"%(id)s, skipping sample")
% {'stat': vpn['status'], 'id': vpn['id']})
continue
LOG.warning(
_("Unknown status %(status)s for VPN %(name)s (%(id)s), "
"setting volume to -1") % {
"status": vpn['status'],
"name": vpn['name'],
"id": vpn['id']})
yield sample.Sample(
name='network.services.vpn',
type=sample.TYPE_GAUGE,
@@ -90,7 +90,7 @@ class IPSecConnectionsPollster(base.BaseServicesPollster):
resources = resources or []
for conn in resources:
LOG.debug("IPSec Connection Info: %s" % conn)
LOG.debug("IPSec Connection Info: %s", conn)
yield sample.Sample(
name='network.services.vpn.connections',
@@ -43,15 +43,15 @@ class TestVPNServicesPollster(_BaseTestVPNPollster):
def setUp(self):
super(TestVPNServicesPollster, self).setUp()
self.pollster = vpnaas.VPNServicesPollster(self.CONF)
fake_vpn = self.fake_get_vpn_service()
self.fake_vpn = self.fake_get_vpn_service()
self.useFixture(fixtures.MockPatch('ceilometer.neutron_client.Client.'
'vpn_get_all',
return_value=fake_vpn))
return_value=self.fake_vpn))
@staticmethod
def fake_get_vpn_service():
return [{'status': 'ACTIVE',
'name': 'myvpn',
'name': 'myvpn1',
'description': '',
'admin_state_up': True,
'id': 'fdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a',
@@ -59,7 +59,7 @@ class TestVPNServicesPollster(_BaseTestVPNPollster):
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa',
'router_id': 'ade3d818-fdcb-fg4b-de7f-6750dc8a9d7a'},
{'status': 'INACTIVE',
'name': 'myvpn',
'name': 'myvpn2',
'description': '',
'admin_state_up': True,
'id': 'cdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a',
@@ -67,7 +67,7 @@ class TestVPNServicesPollster(_BaseTestVPNPollster):
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa',
'router_id': 'ade3d818-fdcb-fg4b-de7f-6750dc8a9d7a'},
{'status': 'PENDING_CREATE',
'name': 'myvpn',
'name': 'myvpn3',
'description': '',
'id': 'bdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a',
'admin_state_up': True,
@@ -75,49 +75,70 @@ class TestVPNServicesPollster(_BaseTestVPNPollster):
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa',
'router_id': 'ade3d818-fdcb-fg4b-de7f-6750dc8a9d7a'},
{'status': 'error',
'name': 'myvpn',
'name': 'myvpn4',
'description': '',
'id': 'edde3d818-fdcb-fg4b-de7f-6750dc8a9d7a',
'admin_state_up': False,
'subnet_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a',
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa',
'router_id': 'ade3d818-fdcb-fg4b-de7f-6750dc8a9d7a'},
{'status': 'UNKNOWN',
'name': 'myvpn5',
'description': '',
'id': '34e6383a-b1ab-4602-b26a-a1ae7b759212',
'admin_state_up': False,
'subnet_id': '8c20bbbf-1409-4bc4-b652-3aeda66746c1',
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa',
'router_id': '0e5c9333-2ef5-4c90-9cca-5cc898515da4'},
{'status': None,
'name': 'myvpn6',
'description': '',
'id': '6e94ff61-8dea-4154-98f1-4020e4b2cecd',
'admin_state_up': False,
'subnet_id': '5e2a20c3-547a-43e4-90c5-26d32ea42d10',
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa',
'router_id': '5b14df87-60c1-4fc7-8ad5-7811b2199c7f'},
]
def test_vpn_get_samples(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_vpn_service()))
self.assertEqual(4, len(samples))
for field in self.pollster.FIELDS:
self.assertEqual(self.fake_get_vpn_service()[0][field],
samples[0].resource_metadata[field])
resources=self.fake_vpn))
self.assertEqual(len(self.fake_vpn), len(samples))
self.assertEqual(set(vpn['id'] for vpn in self.fake_vpn),
set(sample.resource_id for sample in samples))
samples_dict = {sample.resource_id: sample for sample in samples}
for vpn in self.fake_vpn:
sample = samples_dict[vpn['id']]
for field in self.pollster.FIELDS:
self.assertEqual(vpn[field],
sample.resource_metadata[field])
def test_vpn_volume(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_vpn_service()))
resources=self.fake_vpn))
self.assertEqual(1, samples[0].volume)
self.assertEqual(0, samples[1].volume)
self.assertEqual(2, samples[2].volume)
self.assertEqual(7, samples[3].volume)
self.assertEqual(-1, samples[4].volume)
self.assertEqual(-1, samples[5].volume)
def test_get_vpn_meter_names(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_vpn_service()))
resources=self.fake_vpn))
self.assertEqual(set(['network.services.vpn']),
set([s.name for s in samples]))
def test_vpn_discovery(self):
discovered_vpns = discovery.VPNServicesDiscovery(
self.CONF).discover(self.manager)
self.assertEqual(3, len(discovered_vpns))
self.assertEqual(len(self.fake_vpn), len(discovered_vpns))
for vpn in self.fake_get_vpn_service():
if vpn['status'] == 'error':
self.assertNotIn(vpn, discovered_vpns)
else:
self.assertIn(vpn, discovered_vpns)
self.assertIn(vpn, discovered_vpns)
class TestIPSecConnectionsPollster(_BaseTestVPNPollster):
@@ -39,10 +39,10 @@ class TestFloatingIPPollster(_BaseTestFloatingIPPollster):
def setUp(self):
super(TestFloatingIPPollster, self).setUp()
self.pollster = floatingip.FloatingIPPollster(self.CONF)
fake_fip = self.fake_get_fip_service()
self.fake_fip = self.fake_get_fip_service()
self.useFixture(fixtures.MockPatch('ceilometer.neutron_client.Client.'
'fip_get_all',
return_value=fake_fip))
return_value=self.fake_fip))
@staticmethod
def fake_get_fip_service():
@@ -72,31 +72,60 @@ class TestFloatingIPPollster(_BaseTestFloatingIPPollster):
'fixed_ip_address': '10.0.0.8',
'floating_ip_address': '65.79.162.13',
'port_id': '67a0d2c7-a397-444c-9d75-d2ac89b6f209',
'id': '90ca27bf-72bc-40c8-9c13-414d564ea367'}]
'id': '90ca27bf-72bc-40c8-9c13-414d564ea367'},
{'router_id': 'a27ac630-939f-4e2e-bbc3-09a6b4f19a77',
'status': 'UNKNOWN',
'tenant_id': '54a0gggg50ee4c4396b2f8dc220a2bed57',
'floating_network_id':
'4d0c3f4f-79c7-40ff-9b0d-6e3a396547db',
'fixed_ip_address': '10.0.0.9',
'floating_ip_address': '65.79.162.14',
'port_id': '59cc6efa-7c89-4730-b051-b15f594e6728',
'id': 'a8a11884-7666-4f35-901e-dbb84e7111b5'},
{'router_id': '7eb0adde-6c3b-4a77-9714-f718a17afb83',
'status': None,
'tenant_id': '54a0gggg50ee4c4396b2f8dc220a2bed57',
'floating_network_id':
'bd6290e6-b014-4cd3-91f0-7e8a1b4c26ab',
'fixed_ip_address': '10.0.0.10',
'floating_ip_address': '65.79.162.15',
'port_id': 'd3b9436d-4b2b-4832-852b-34df7513c935',
'id': '27c539ca-94ce-42fc-a639-1bf2c8690d76'}]
def test_fip_get_samples(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_fip_service()))
self.assertEqual(3, len(samples))
for field in self.pollster.FIELDS:
self.assertEqual(self.fake_get_fip_service()[0][field],
samples[0].resource_metadata[field])
resources=self.fake_fip))
self.assertEqual(len(self.fake_fip), len(samples))
self.assertEqual(set(fip['id'] for fip in self.fake_fip),
set(sample.resource_id for sample in samples))
samples_dict = {sample.resource_id: sample for sample in samples}
for fip in self.fake_fip:
sample = samples_dict[fip['id']]
for field in self.pollster.FIELDS:
self.assertEqual(fip[field],
sample.resource_metadata[field])
def test_fip_volume(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_fip_service()))
resources=self.fake_fip))
self.assertEqual(1, samples[0].volume)
self.assertEqual(3, samples[1].volume)
self.assertEqual(7, samples[2].volume)
self.assertEqual(-1, samples[3].volume)
self.assertEqual(-1, samples[4].volume)
def test_get_fip_meter_names(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_fip_service()))
resources=self.fake_fip))
self.assertEqual(set(['ip.floating']),
set([s.name for s in samples]))
def test_fip_discovery(self):
discovered_fips = discovery.FloatingIPDiscovery(
self.CONF).discover(self.manager)
self.assertEqual(3, len(discovered_fips))
self.assertEqual(len(self.fake_fip), len(discovered_fips))
for fip in self.fake_fip:
self.assertIn(fip, discovered_fips)
@@ -0,0 +1,17 @@
---
upgrade:
- |
The ``ip.floating`` and ``network.services.vpn`` pollsters now publish
samples for all found floating IPs and VPNs, even if they are known
to have an unknown state, when they would previously be dropped.
The volume of samples for such floating IPs and VPNs will be set to
``-1``.
This improves visibility of floating IPs and VPNs with unknown states,
allowing them to be monitored via samples and the Gnocchi metrics,
making it easier to discover such resources for troubleshooting.
It also moves some of the "business logic" for downstream rating/billing
services such as CloudKitty out of Ceilometer itself.
- |
The ``network.services.vpn`` now publishes samples for VPNs with
status ``ERROR``, when they would previously be dropped.
The sample volume for VPNs in ``ERROR`` state is ``7``.