Support for metering FWaaS

Partially-Implements: blueprint ceilometer-meter-fwaas

Change-Id: I3b0e40fa3bbddc304d3adf936626334342288a2d
This commit is contained in:
Pradeep Kilambi 2014-07-14 14:35:40 -07:00
parent 94d6c9a017
commit daf92b6bf4
6 changed files with 304 additions and 0 deletions

View File

@ -101,3 +101,27 @@ class IPSecConnectionsDiscovery(_BaseServicesDiscovery):
conns = self.neutron_cli.ipsec_site_connections_get_all()
return conns
class FirewallDiscovery(_BaseServicesDiscovery):
def __init__(self):
super(FirewallDiscovery, self).__init__()
def discover(self, param=None):
"""Discover resources to monitor."""
fw = self.neutron_cli.firewall_get_all()
return [i for i in fw
if i.get('status', None) != 'error']
class FirewallPolicyDiscovery(_BaseServicesDiscovery):
def __init__(self):
super(FirewallPolicyDiscovery, self).__init__()
def discover(self, param=None):
"""Discover resources to monitor."""
return self.neutron_cli.fw_policy_get_all()

View File

@ -0,0 +1,84 @@
#
# Copyright 2014 Cisco Systems,Inc.
#
# Author: Pradeep Kilambi <pkilambi@cisco.com>
#
# 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.
from ceilometer.network.services import base
from ceilometer.openstack.common import log
from ceilometer.openstack.common import timeutils
from ceilometer import sample
LOG = log.getLogger(__name__)
class FirewallPollster(base.BaseServicesPollster):
"""Pollster to capture firewalls status samples."""
FIELDS = ['admin_state_up',
'description',
'name',
'status',
'firewall_policy_id',
]
def get_samples(self, manager, cache, resources=None):
for fw in resources:
LOG.debug("Firewall : %s" % fw)
status = self.get_status_id(fw['status'])
if status == -1:
# unknown status, skip this sample
LOG.warn("Unknown status %s received on firewall %s, "
"skipping sample" % (fw['status'], fw['id']))
continue
yield sample.Sample(
name='network.services.firewall',
type=sample.TYPE_GAUGE,
unit='firewall',
volume=status,
user_id=None,
project_id=fw['tenant_id'],
resource_id=fw['id'],
timestamp=timeutils.utcnow().isoformat(),
resource_metadata=self.extract_metadata(fw)
)
class FirewallPolicyPollster(base.BaseServicesPollster):
"""Pollster to capture firewalls status samples."""
FIELDS = ['name',
'description',
'name',
'firewall_rules',
'shared',
'audited',
]
def get_samples(self, manager, cache, resources=None):
for fw in resources:
LOG.debug("Firewall Policy: %s" % fw)
yield sample.Sample(
name='network.services.firewall.policy',
type=sample.TYPE_GAUGE,
unit='policy',
volume=1,
user_id=None,
project_id=fw['tenant_id'],
resource_id=fw['id'],
timestamp=timeutils.utcnow().isoformat(),
resource_metadata=self.extract_metadata(fw)
)

View File

@ -106,3 +106,13 @@ class Client(object):
def ipsec_site_connections_get_all(self):
resp = self.client.list_ipsec_site_connections()
return resp.get('ipsec_site_connections')
@logged
def firewall_get_all(self):
resp = self.client.list_firewalls()
return resp.get('firewalls')
@logged
def fw_policy_get_all(self):
resp = self.client.list_firewall_policies()
return resp.get('firewall_policies')

View File

@ -0,0 +1,166 @@
#
# Copyright 2014 Cisco Systems,Inc.
#
# Author: Pradeep Kilambi <pkilambi@cisco.com>
#
# 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.
import mock
from ceilometer.central import manager
from ceilometer.network.services import discovery
from ceilometer.network.services import fwaas
from ceilometer.openstack.common import context
from ceilometer.openstack.common.fixture import mockpatch
from ceilometer.openstack.common import test
class _BaseTestFWPollster(test.BaseTestCase):
@mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock())
def setUp(self):
super(_BaseTestFWPollster, self).setUp()
self.addCleanup(mock.patch.stopall)
self.context = context.get_admin_context()
self.manager = manager.AgentManager()
class TestFirewallPollster(_BaseTestFWPollster):
def setUp(self):
super(TestFirewallPollster, self).setUp()
self.pollster = fwaas.FirewallPollster()
fake_fw = self.fake_get_fw_service()
self.useFixture(mockpatch.Patch('ceilometer.neutron_client.Client.'
'firewall_get_all',
return_value=fake_fw))
@staticmethod
def fake_get_fw_service():
return [{'status': 'ACTIVE',
'name': 'myfw',
'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',
'description': '',
'admin_state_up': True,
'id': 'fdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a',
'firewall_policy_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a',
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa'},
{'status': 'PENDING_CREATE',
'name': 'myfw',
'description': '',
'admin_state_up': True,
'id': 'fdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a',
'firewall_policy_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a',
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa'},
{'status': 'error',
'name': 'myfw',
'description': '',
'admin_state_up': True,
'id': 'fdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a',
'firewall_policy_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a',
'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(3, len(samples))
for field in self.pollster.FIELDS:
self.assertEqual(self.fake_get_fw_service()[0][field],
samples[0].resource_metadata[field])
def test_vpn_volume(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_fw_service()))
self.assertEqual(1, samples[0].volume)
self.assertEqual(0, samples[1].volume)
self.assertEqual(2, samples[2].volume)
def test_get_vpn_meter_names(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_fw_service()))
self.assertEqual(set(['network.services.firewall']),
set([s.name for s in samples]))
def test_vpn_discovery(self):
discovered_fws = discovery.FirewallDiscovery().discover()
self.assertEqual(3, len(discovered_fws))
for vpn in self.fake_get_fw_service():
if vpn['status'] == 'error':
self.assertTrue(vpn not in discovered_fws)
else:
self.assertTrue(vpn in discovered_fws)
class TestIPSecConnectionsPollster(_BaseTestFWPollster):
def setUp(self):
super(TestIPSecConnectionsPollster, self).setUp()
self.pollster = fwaas.FirewallPolicyPollster()
fake_fw_policy = self.fake_get_fw_policy()
self.useFixture(mockpatch.Patch('ceilometer.neutron_client.Client.'
'fw_policy_get_all',
return_value=fake_fw_policy))
@staticmethod
def fake_get_fw_policy():
return [{'name': 'my_fw_policy',
'description': 'fw_policy',
'admin_state_up': True,
'tenant_id': 'abe3d818-fdcb-fg4b-de7f-6650dc8a9d7a',
'firewall_rules': [{'enabled': True,
'action': 'allow',
'ip_version': 4,
'protocol': 'tcp',
'destination_port': '80',
'source_ip_address': '10.24.4.2'},
{'enabled': True,
'action': 'deny',
'ip_version': 4,
'protocol': 'tcp',
'destination_port': '22'}],
'shared': True,
'audited': True,
'id': 'fdfbcec-fdcb-fg4b-de7f-6650dc8a9d7a'}
]
def test_policy_get_samples(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_fw_policy()))
self.assertEqual(1, len(samples))
for field in self.pollster.FIELDS:
self.assertEqual(self.fake_get_fw_policy()[0][field],
samples[0].resource_metadata[field])
def test_get_policy_meter_names(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_fw_policy()))
self.assertEqual(set(['network.services.firewall.policy']),
set([s.name for s in samples]))
def test_fw_policy_discovery(self):
discovered_policy = discovery.FirewallPolicyDiscovery().discover()
self.assertEqual(1, len(discovered_policy))
self.assertEqual(self.fake_get_fw_policy(), discovered_policy)

View File

@ -78,6 +78,22 @@ sources:
- "ipsec_connections"
sinks:
- "meter_sink"
- name: firewall_source
interval: 600
meters:
- "network.services.firewall"
discovery:
- "fw_services"
sinks:
- "meter_sink"
- name: fw_policy_source
interval: 600
meters:
- "network.services.firewall.policy"
discovery:
- "fw_policy"
sinks:
- "meter_sink"
sinks:
- name: meter_sink
transformers:

View File

@ -75,6 +75,8 @@ ceilometer.discover =
lb_health_probes = ceilometer.network.services.discovery:LBHealthMonitorsDiscovery
vpn_services = ceilometer.network.services.discovery:VPNServicesDiscovery
ipsec_connections = ceilometer.network.services.discovery:IPSecConnectionsDiscovery
fw_services = ceilometer.network.services.discovery:FirewallDiscovery
fw_policy = ceilometer.network.services.discovery:FirewallPolicyDiscovery
ceilometer.poll.compute =
disk.read.requests = ceilometer.compute.pollsters.disk:ReadRequestsPollster
@ -151,6 +153,8 @@ ceilometer.poll.central =
network.services.lb.outgoing.bytes = ceilometer.network.services.lbaas:LBBytesOutPollster
network.services.vpn = ceilometer.network.services.vpnaas:VPNServicesPollster
network.services.vpn.connections = ceilometer.network.services.vpnaas:IPSecConnectionsPollster
network.services.firewall = ceilometer.network.services.fwaas:FirewallPollster
network.services.firewall.policy = ceilometer.network.services.fwaas:FirewallPolicyPollster
ceilometer.alarm.storage =