Add support for metering VPNaaS

Change-Id: Ida9e04b13d54ab4853a4ba30d2148ac7bc8ba244
Partially-Implements: blueprint ceilometer-meter-vpnaas
This commit is contained in:
Pradeep Kilambi 2014-07-16 07:39:11 -07:00
parent 6840237574
commit 94d6c9a017
6 changed files with 320 additions and 1 deletions

View File

@ -76,3 +76,28 @@ class LBHealthMonitorsDiscovery(_BaseServicesDiscovery):
probes = self.neutron_cli.health_monitor_get_all()
return probes
class VPNServicesDiscovery(_BaseServicesDiscovery):
def __init__(self):
super(VPNServicesDiscovery, self).__init__()
def discover(self, 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']
class IPSecConnectionsDiscovery(_BaseServicesDiscovery):
def __init__(self):
super(IPSecConnectionsDiscovery, self).__init__()
def discover(self, param=None):
"""Discover resources to monitor."""
conns = self.neutron_cli.ipsec_site_connections_get_all()
return conns

View File

@ -0,0 +1,93 @@
#
# 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 VPNServicesPollster(base.BaseServicesPollster):
"""Pollster to capture VPN status samples."""
FIELDS = ['admin_state_up',
'description',
'name',
'status',
'subnet_id',
'router_id'
]
def get_samples(self, manager, cache, resources=None):
for vpn in resources:
LOG.debug("VPN : %s" % vpn)
status = self.get_status_id(vpn['status'])
if status == -1:
# unknown status, skip this sample
LOG.warn("Unknown status %s received on vpn %s, "
"skipping sample" % (vpn['status'], vpn['id']))
continue
yield sample.Sample(
name='network.services.vpn',
type=sample.TYPE_GAUGE,
unit='vpn',
volume=status,
user_id=None,
project_id=vpn['tenant_id'],
resource_id=vpn['id'],
timestamp=timeutils.utcnow().isoformat(),
resource_metadata=self.extract_metadata(vpn)
)
class IPSecConnectionsPollster(base.BaseServicesPollster):
"""Pollster to capture VPN status samples."""
FIELDS = ['name',
'description',
'peer_address',
'peer_id',
'peer_cidrs',
'psk',
'initiator',
'ikepolicy_id',
'dpd',
'ipsecpolicy_id',
'vpnservice_id',
'mtu',
'admin_state_up',
'tenant_id'
]
def get_samples(self, manager, cache, resources=None):
for conn in resources:
LOG.debug("IPSec Connection Info: %s" % conn)
yield sample.Sample(
name='network.services.vpn.connections',
type=sample.TYPE_GAUGE,
unit='vpn',
volume=1,
user_id=None,
project_id=conn['tenant_id'],
resource_id=conn['id'],
timestamp=timeutils.utcnow().isoformat(),
resource_metadata=self.extract_metadata(conn)
)

View File

@ -96,3 +96,13 @@ class Client(object):
@logged
def pool_stats(self, pool):
return self.client.retrieve_pool_stats(pool)
@logged
def vpn_get_all(self):
resp = self.client.list_vpnservices()
return resp.get('vpnservices')
@logged
def ipsec_site_connections_get_all(self):
resp = self.client.list_ipsec_site_connections()
return resp.get('ipsec_site_connections')

View File

@ -0,0 +1,171 @@
#
# 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 vpnaas
from ceilometer.openstack.common import context
from ceilometer.openstack.common.fixture import mockpatch
from ceilometer.openstack.common import test
class _BaseTestVPNPollster(test.BaseTestCase):
@mock.patch('ceilometer.pipeline.setup_pipeline', mock.MagicMock())
def setUp(self):
super(_BaseTestVPNPollster, self).setUp()
self.addCleanup(mock.patch.stopall)
self.context = context.get_admin_context()
self.manager = manager.AgentManager()
class TestVPNServicesPollster(_BaseTestVPNPollster):
def setUp(self):
super(TestVPNServicesPollster, self).setUp()
self.pollster = vpnaas.VPNServicesPollster()
fake_vpn = self.fake_get_vpn_service()
self.useFixture(mockpatch.Patch('ceilometer.neutron_client.Client.'
'vpn_get_all',
return_value=fake_vpn))
@staticmethod
def fake_get_vpn_service():
return [{'status': 'ACTIVE',
'name': 'myvpn',
'description': '',
'admin_state_up': True,
'id': 'fdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a',
'subnet_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a',
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa',
'router_id': 'ade3d818-fdcb-fg4b-de7f-6750dc8a9d7a'},
{'status': 'INACTIVE',
'name': 'myvpn',
'description': '',
'admin_state_up': True,
'id': 'cdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a',
'subnet_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a',
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa',
'router_id': 'ade3d818-fdcb-fg4b-de7f-6750dc8a9d7a'},
{'status': 'PENDING_CREATE',
'name': 'myvpn',
'description': '',
'id': 'bdde3d818-fdcb-fg4b-de7f-6750dc8a9d7a',
'admin_state_up': True,
'subnet_id': 'bbe3d818-bdcb-4e4b-b47f-5650dc8a9d7a',
'tenant_id': 'a4eb9f4938bb418bbc4f8eb31802fefa',
'router_id': 'ade3d818-fdcb-fg4b-de7f-6750dc8a9d7a'},
{'status': 'error',
'name': 'myvpn',
'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'},
]
def test_vpn_get_samples(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_vpn_service()))
self.assertEqual(3, len(samples))
for field in self.pollster.FIELDS:
self.assertEqual(self.fake_get_vpn_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_vpn_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_vpn_service()))
self.assertEqual(set(['network.services.vpn']),
set([s.name for s in samples]))
def test_vpn_discovery(self):
discovered_vpns = discovery.VPNServicesDiscovery().discover()
self.assertEqual(3, len(discovered_vpns))
for vpn in self.fake_get_vpn_service():
if vpn['status'] == 'error':
self.assertTrue(vpn not in discovered_vpns)
else:
self.assertTrue(vpn in discovered_vpns)
class TestIPSecConnectionsPollster(_BaseTestVPNPollster):
def setUp(self):
super(TestIPSecConnectionsPollster, self).setUp()
self.pollster = vpnaas.IPSecConnectionsPollster()
fake_conns = self.fake_get_ipsec_connections()
self.useFixture(mockpatch.Patch('ceilometer.neutron_client.Client.'
'ipsec_site_connections_get_all',
return_value=fake_conns))
@staticmethod
def fake_get_ipsec_connections():
return [{'name': 'connection1',
'description': 'Remote-connection1',
'peer_address': '192.168.1.10',
'peer_id': '192.168.1.10',
'peer_cidrs': ['192.168.2.0/24',
'192.168.3.0/24'],
'mtu': 1500,
'psk': 'abcd',
'initiator': 'bi-directional',
'dpd': {
'action': 'hold',
'interval': 30,
'timeout': 120},
'ikepolicy_id': 'ade3d818-fdcb-fg4b-de7f-4550dc8a9d7a',
'ipsecpolicy_id': 'fce3d818-fdcb-fg4b-de7f-7850dc8a9d7a',
'vpnservice_id': 'dce3d818-fdcb-fg4b-de7f-5650dc8a9d7a',
'admin_state_up': True,
'tenant_id': 'abe3d818-fdcb-fg4b-de7f-6650dc8a9d7a',
'id': 'fdfbcec-fdcb-fg4b-de7f-6650dc8a9d7a'}
]
def test_conns_get_samples(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_ipsec_connections()))
self.assertEqual(1, len(samples))
for field in self.pollster.FIELDS:
self.assertEqual(self.fake_get_ipsec_connections()[0][field],
samples[0].resource_metadata[field])
def test_get_conns_meter_names(self):
samples = list(self.pollster.get_samples(
self.manager, {},
resources=self.fake_get_ipsec_connections()))
self.assertEqual(set(['network.services.vpn.connections']),
set([s.name for s in samples]))
def test_conns_discovery(self):
discovered_conns = discovery.IPSecConnectionsDiscovery().discover()
self.assertEqual(1, len(discovered_conns))
self.assertEqual(self.fake_get_ipsec_connections(), discovered_conns)

View File

@ -62,6 +62,22 @@ sources:
- "lb_members"
sinks:
- meter_sink
- name: vpn_services_source
interval: 600
meters:
- "network.services.vpn"
discovery:
- "vpn_services"
sinks:
- "meter_sink"
- name: vpn_conns_source
interval: 600
meters:
- "network.services.vpn.connections"
discovery:
- "ipsec_connections"
sinks:
- "meter_sink"
sinks:
- name: meter_sink
transformers:

View File

@ -73,7 +73,8 @@ ceilometer.discover =
lb_vips = ceilometer.network.services.discovery:LBVipsDiscovery
lb_members = ceilometer.network.services.discovery:LBMembersDiscovery
lb_health_probes = ceilometer.network.services.discovery:LBHealthMonitorsDiscovery
vpn_services = ceilometer.network.services.discovery:VPNServicesDiscovery
ipsec_connections = ceilometer.network.services.discovery:IPSecConnectionsDiscovery
ceilometer.poll.compute =
disk.read.requests = ceilometer.compute.pollsters.disk:ReadRequestsPollster
@ -148,6 +149,9 @@ ceilometer.poll.central =
network.services.lb.active.connections = ceilometer.network.services.lbaas:LBActiveConnectionsPollster
network.services.lb.incoming.bytes = ceilometer.network.services.lbaas:LBBytesInPollster
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
ceilometer.alarm.storage =
log = ceilometer.storage.impl_log:Connection