diff --git a/ceilometer/network/services/fwaas.py b/ceilometer/network/services/fwaas.py index 830707dce5..58a622bd2f 100644 --- a/ceilometer/network/services/fwaas.py +++ b/ceilometer/network/services/fwaas.py @@ -42,12 +42,12 @@ class FirewallPollster(base.BaseServicesPollster): LOG.debug("Firewall : %s", fw) status = self.get_status_id(fw['status']) if status == -1: - # unknown status, skip this sample - LOG.warning("Unknown status %(stat)s received on fw %(id)s," - "skipping sample", - {'stat': fw['status'], 'id': fw['id']}) - continue - + LOG.warning( + "Unknown status %(status)s for firewall %(name)s " + "(%(id)s), setting volume to -1", + {"status": fw['status'], + "name": fw['name'], + "id": fw['id']}) yield sample.Sample( name='network.services.firewall', type=sample.TYPE_GAUGE, diff --git a/ceilometer/tests/unit/network/services/test_fwaas.py b/ceilometer/tests/unit/network/services/test_fwaas.py index 28e9910c06..faf79b7ae2 100644 --- a/ceilometer/tests/unit/network/services/test_fwaas.py +++ b/ceilometer/tests/unit/network/services/test_fwaas.py @@ -43,77 +43,96 @@ class TestFirewallPollster(_BaseTestFWPollster): def setUp(self): super().setUp() self.pollster = fwaas.FirewallPollster(self.CONF) - fake_fw = self.fake_get_fw_service() + self.fake_fw = self.fake_get_fw_service() self.useFixture(fixtures.MockPatch('ceilometer.neutron_client.Client.' 'firewall_get_all', - return_value=fake_fw)) + return_value=self.fake_fw)) @staticmethod def fake_get_fw_service(): return [{'status': 'ACTIVE', - 'name': 'myfw', + 'name': 'myfw1', 'description': '', 'admin_state_up': True, 'id': 'fdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a', 'firewall_policy_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a', 'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa'}, {'status': 'INACTIVE', - 'name': 'myfw', + 'name': 'myfw2', 'description': '', 'admin_state_up': True, - 'id': 'fdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a', - 'firewall_policy_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a', + 'id': 'e0d707dc-6194-4471-8286-0635bf65a055', + 'firewall_policy_id': 'e0d707dc-6194-4471-8286-0635bf65a055', 'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa'}, {'status': 'PENDING_CREATE', - 'name': 'myfw', + 'name': 'myfw3', 'description': '', 'admin_state_up': True, - 'id': 'fdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a', + 'id': 'e538d353-31e9-4581-a511-0a487ff71d0d', 'firewall_policy_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a', 'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa'}, - {'status': 'error', - 'name': 'myfw', + {'status': 'ERROR', + 'name': 'myfw4', 'description': '', 'admin_state_up': True, - 'id': 'fdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a', - 'firewall_policy_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a', + 'id': '06f698c4-dc63-43c4-a2d9-7b978e80f09a', + 'firewall_policy_id': 'bef98f97-789f-418e-82ad-3e5d69618916', + 'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa'}, + {'status': 'UNKNOWN', + 'name': 'myfw5', + 'description': '', + 'admin_state_up': True, + 'id': 'c65a1bec-ab59-44ce-b784-1c725f427998', + 'firewall_policy_id': 'd45b975e-738f-42c3-a4b3-760d3a58ab51', + 'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa'}, + {'status': None, + 'name': 'myfw6', + 'description': '', + 'admin_state_up': True, + 'id': 'ab5d19ff-32a8-49e5-aa2b-d008157359d9', + 'firewall_policy_id': '79b9c933-2a7c-4f93-bbf9-d165f0326581', 'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa'}, ] def test_fw_get_samples(self): samples = list(self.pollster.get_samples( self.manager, {}, - resources=self.fake_get_fw_service())) - self.assertEqual(4, len(samples)) - for field in self.pollster.FIELDS: - self.assertEqual(self.fake_get_fw_service()[0][field], - samples[0].resource_metadata[field]) + resources=self.fake_fw)) + self.assertEqual(len(self.fake_fw), len(samples)) + self.assertEqual({fw['id'] for fw in self.fake_fw}, + {sample.resource_id for sample in samples}) + samples_dict = {sample.resource_id: sample for sample in samples} + for fw in self.fake_fw: + sample = samples_dict[fw['id']] + for field in self.pollster.FIELDS: + self.assertEqual(fw[field], + sample.resource_metadata[field]) def test_vpn_volume(self): samples = list(self.pollster.get_samples( self.manager, {}, - resources=self.fake_get_fw_service())) + resources=self.fake_fw)) 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_fw_service())) + resources=self.fake_fw)) self.assertEqual({'network.services.firewall'}, {s.name for s in samples}) def test_vpn_discovery(self): discovered_fws = discovery.FirewallDiscovery( self.CONF).discover(self.manager) - self.assertEqual(3, len(discovered_fws)) + self.assertEqual(len(self.fake_fw), len(discovered_fws)) - for vpn in self.fake_get_fw_service(): - if vpn['status'] == 'error': - self.assertNotIn(vpn, discovered_fws) - else: - self.assertIn(vpn, discovered_fws) + for vpn in self.fake_fw: + self.assertIn(vpn, discovered_fws) class TestIPSecConnectionsPollster(_BaseTestFWPollster): diff --git a/releasenotes/notes/publish-fw-with-invalid-state-e961372c95791bcd.yaml b/releasenotes/notes/publish-fw-with-invalid-state-e961372c95791bcd.yaml new file mode 100644 index 0000000000..cdd3e916d0 --- /dev/null +++ b/releasenotes/notes/publish-fw-with-invalid-state-e961372c95791bcd.yaml @@ -0,0 +1,12 @@ +--- +upgrade: + - | + The ``network.services.firewall`` pollster now publishes samples for all + found firewalls, even if they are known to have an unknown state, when + they would previously be dropped. The volume of samples for such firewalls + will be set to ``-1``. This improves visibility of firewalls with unknown + states, allowing them to be monitored via samples and the + Gnocchi/Prometheus 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.