Merge "Remove List events API from Cisco N1kv Neutron"
This commit is contained in:
commit
48e9a73f64
@ -852,6 +852,13 @@ def get_policy_profile(db_session, id):
|
||||
raise c_exc.PolicyProfileIdNotFound(profile_id=id)
|
||||
|
||||
|
||||
def get_policy_profiles():
|
||||
"""Retrieve all policy profiles."""
|
||||
db_session = db.get_session()
|
||||
with db_session.begin(subtransactions=True):
|
||||
return db_session.query(n1kv_models_v2.PolicyProfile)
|
||||
|
||||
|
||||
def create_profile_binding(db_session, tenant_id, profile_id, profile_type):
|
||||
"""Create Network/Policy Profile association with a tenant."""
|
||||
db_session = db_session or db.get_session()
|
||||
|
@ -156,18 +156,6 @@ class Client(object):
|
||||
"""
|
||||
return self._get(self.port_profiles_path)
|
||||
|
||||
def list_events(self, event_type=None, epoch=None):
|
||||
"""
|
||||
Fetch all events of event_type from the VSM.
|
||||
|
||||
:param event_type: type of event to be listed.
|
||||
:param epoch: timestamp after which the events occurred to be listed.
|
||||
:returns: XML string
|
||||
"""
|
||||
if event_type:
|
||||
self.events_path = self.events_path + '?type=' + event_type
|
||||
return self._get(self.events_path)
|
||||
|
||||
def create_bridge_domain(self, network, overlay_subtype):
|
||||
"""
|
||||
Create a bridge domain on VSM.
|
||||
|
@ -154,15 +154,13 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
"""
|
||||
LOG.debug(_('_setup_vsm'))
|
||||
self.agent_vsm = True
|
||||
# Retrieve all the policy profiles from VSM.
|
||||
self._populate_policy_profiles()
|
||||
# Continue to poll VSM for any create/delete of policy profiles.
|
||||
# Poll VSM for create/delete of policy profile.
|
||||
eventlet.spawn(self._poll_policy_profiles)
|
||||
|
||||
def _poll_policy_profiles(self):
|
||||
"""Start a green thread to pull policy profiles from VSM."""
|
||||
while True:
|
||||
self._poll_policies(event_type='port_profile')
|
||||
self._populate_policy_profiles()
|
||||
eventlet.sleep(int(c_conf.CISCO_N1K.poll_duration))
|
||||
|
||||
def _populate_policy_profiles(self):
|
||||
@ -177,53 +175,35 @@ class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
try:
|
||||
n1kvclient = n1kv_client.Client()
|
||||
policy_profiles = n1kvclient.list_port_profiles()
|
||||
LOG.debug(_('_populate_policy_profiles %s'), policy_profiles)
|
||||
vsm_profiles = {}
|
||||
plugin_profiles = {}
|
||||
# Fetch policy profiles from VSM
|
||||
if policy_profiles:
|
||||
for profile in policy_profiles['body'][c_const.SET]:
|
||||
if c_const.ID and c_const.NAME in profile:
|
||||
profile_id = profile[c_const.PROPERTIES][c_const.ID]
|
||||
profile_name = profile[c_const.
|
||||
PROPERTIES][c_const.NAME]
|
||||
self._add_policy_profile(profile_name, profile_id)
|
||||
profile_name = (profile[c_const.PROPERTIES].
|
||||
get(c_const.NAME, None))
|
||||
profile_id = (profile[c_const.PROPERTIES].
|
||||
get(c_const.ID, None))
|
||||
if profile_id and profile_name:
|
||||
vsm_profiles[profile_id] = profile_name
|
||||
# Fetch policy profiles previously populated
|
||||
for profile in n1kv_db_v2.get_policy_profiles():
|
||||
plugin_profiles[profile.id] = profile.name
|
||||
vsm_profiles_set = set(vsm_profiles)
|
||||
plugin_profiles_set = set(plugin_profiles)
|
||||
# Update database if the profile sets differ.
|
||||
if vsm_profiles_set ^ plugin_profiles_set:
|
||||
# Add profiles in database if new profiles were created in VSM
|
||||
for pid in vsm_profiles_set - plugin_profiles_set:
|
||||
self._add_policy_profile(vsm_profiles[pid], pid)
|
||||
# Delete profiles from database if profiles were deleted in VSM
|
||||
for pid in plugin_profiles_set - vsm_profiles_set:
|
||||
self._delete_policy_profile(pid)
|
||||
self._remove_all_fake_policy_profiles()
|
||||
except (cisco_exceptions.VSMError,
|
||||
cisco_exceptions.VSMConnectionFailed):
|
||||
LOG.warning(_('No policy profile populated from VSM'))
|
||||
|
||||
def _poll_policies(self, event_type=None, epoch=None, tenant_id=None):
|
||||
"""
|
||||
Poll for Policy Profiles from Cisco Nexus1000V for any update/delete.
|
||||
"""
|
||||
LOG.debug(_('_poll_policies'))
|
||||
try:
|
||||
n1kvclient = n1kv_client.Client()
|
||||
policy_profiles = n1kvclient.list_events(event_type, epoch)
|
||||
if policy_profiles:
|
||||
for profile in policy_profiles['body'][c_const.SET]:
|
||||
if c_const.NAME in profile:
|
||||
# Extract commands from the events XML.
|
||||
cmd = profile[c_const.PROPERTIES]['cmd']
|
||||
cmds = cmd.split(';')
|
||||
cmdwords = cmds[1].split()
|
||||
profile_name = profile[c_const.
|
||||
PROPERTIES][c_const.NAME]
|
||||
# Delete the policy profile from db if deleted on VSM
|
||||
if 'no' in cmdwords[0]:
|
||||
p = self._get_policy_profile_by_name(profile_name)
|
||||
if p:
|
||||
self._delete_policy_profile(p['id'])
|
||||
# Add policy profile to neutron DB idempotently
|
||||
elif c_const.ID in profile[c_const.PROPERTIES]:
|
||||
profile_id = profile[c_const.
|
||||
PROPERTIES][c_const.ID]
|
||||
self._add_policy_profile(
|
||||
profile_name, profile_id, tenant_id)
|
||||
# Replace tenant-id for profile bindings with admin's tenant-id
|
||||
self._remove_all_fake_policy_profiles()
|
||||
except (cisco_exceptions.VSMError,
|
||||
cisco_exceptions.VSMConnectionFailed):
|
||||
LOG.warning(_('No policy profile updated from VSM'))
|
||||
|
||||
def _extend_network_dict_provider(self, context, network):
|
||||
"""Add extended network parameters."""
|
||||
binding = n1kv_db_v2.get_network_binding(context.session,
|
||||
|
@ -18,7 +18,7 @@
|
||||
# @author: Sourabh Patwardhan, Cisco Systems Inc.
|
||||
|
||||
from neutron.openstack.common import log as logging
|
||||
from neutron.plugins.cisco.common import cisco_exceptions
|
||||
from neutron.plugins.cisco.common import cisco_exceptions as c_exc
|
||||
from neutron.plugins.cisco.n1kv.n1kv_client import Client as n1kv_client
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -36,15 +36,26 @@ class TestClient(n1kv_client):
|
||||
def __init__(self, **kwargs):
|
||||
self.broken = False
|
||||
self.inject_params = False
|
||||
self.total_profiles = 2
|
||||
super(TestClient, self).__init__()
|
||||
|
||||
def _get_total_profiles(self):
|
||||
return self.total_profiles
|
||||
|
||||
def _do_request(self, method, action, body=None, headers=None):
|
||||
if self.broken:
|
||||
raise cisco_exceptions.VSMError(reason='VSM:Internal Server Error')
|
||||
raise c_exc.VSMError(reason='VSM:Internal Server Error')
|
||||
if self.inject_params and body:
|
||||
body['invalidKey'] = 'catchMeIfYouCan'
|
||||
if method == 'POST':
|
||||
return _validate_resource(action, body)
|
||||
elif method == 'GET':
|
||||
if 'virtual-port-profile' in action:
|
||||
profiles = _policy_profile_generator_xml(
|
||||
self._get_total_profiles())
|
||||
return self._deserialize(profiles, 200)
|
||||
else:
|
||||
raise c_exc.VSMError(reason='VSM:Internal Server Error')
|
||||
|
||||
|
||||
class TestClientInvalidRequest(TestClient):
|
||||
@ -62,10 +73,33 @@ def _validate_resource(action, body=None):
|
||||
if 'vm-network' in action and 'port' not in action:
|
||||
vmnetwork_set = set(_resource_metadata['vmnetwork'])
|
||||
if body_set - vmnetwork_set:
|
||||
raise cisco_exceptions.VSMError(reason='Invalid Request')
|
||||
raise c_exc.VSMError(reason='Invalid Request')
|
||||
elif 'port' in action:
|
||||
port_set = set(_resource_metadata['port'])
|
||||
if body_set - port_set:
|
||||
raise cisco_exceptions.VSMError(reason='Invalid Request')
|
||||
raise c_exc.VSMError(reason='Invalid Request')
|
||||
else:
|
||||
return
|
||||
|
||||
|
||||
def _policy_profile_generator_xml(total_profiles):
|
||||
"""
|
||||
Generate policy profile response in XML format.
|
||||
|
||||
:param total_profiles: integer representing total number of profiles to
|
||||
return
|
||||
"""
|
||||
xml = ["""<?xml version="1.0" encoding="utf-8"?>
|
||||
<set name="virtual_port_profile_set">"""]
|
||||
template = (
|
||||
'<instance name="%(num)d"'
|
||||
' url="/api/n1k/virtual-port-profile/%(num)s">'
|
||||
'<properties>'
|
||||
'<id>00000000-0000-0000-0000-00000000000%(num)s</id>'
|
||||
'<name>pp-%(num)s</name>'
|
||||
'</properties>'
|
||||
'</instance>'
|
||||
)
|
||||
xml.extend(template % {'num': n} for n in range(1, total_profiles + 1))
|
||||
xml.append("</set>")
|
||||
return ''.join(xml)
|
||||
|
@ -25,6 +25,7 @@ from neutron.api.v2 import attributes
|
||||
from neutron import context
|
||||
import neutron.db.api as db
|
||||
from neutron.extensions import portbindings
|
||||
from neutron import manager
|
||||
from neutron.plugins.cisco.common import cisco_exceptions as c_exc
|
||||
from neutron.plugins.cisco.db import n1kv_db_v2
|
||||
from neutron.plugins.cisco.db import network_db_v2 as cdb
|
||||
@ -69,7 +70,7 @@ class FakeResponse(object):
|
||||
def _fake_setup_vsm(self):
|
||||
"""Fake establish Communication with Cisco Nexus1000V VSM."""
|
||||
self.agent_vsm = True
|
||||
self._poll_policies(event_type="port_profile")
|
||||
self._populate_policy_profiles()
|
||||
|
||||
|
||||
class NetworkProfileTestExtensionManager(object):
|
||||
@ -506,6 +507,55 @@ class TestN1kvPorts(test_plugin.TestPortsV2,
|
||||
client_patch.stop()
|
||||
|
||||
|
||||
class TestN1kvPolicyProfiles(N1kvPluginTestCase):
|
||||
def test_populate_policy_profile(self):
|
||||
client_patch = patch(n1kv_client.__name__ + ".Client",
|
||||
new=fake_client.TestClient)
|
||||
client_patch.start()
|
||||
instance = n1kv_neutron_plugin.N1kvNeutronPluginV2()
|
||||
instance._populate_policy_profiles()
|
||||
db_session = db.get_session()
|
||||
profile = n1kv_db_v2.get_policy_profile(
|
||||
db_session, '00000000-0000-0000-0000-000000000001')
|
||||
self.assertEqual('pp-1', profile['name'])
|
||||
client_patch.stop()
|
||||
|
||||
def test_populate_policy_profile_delete(self):
|
||||
# Patch the Client class with the TestClient class
|
||||
with patch(n1kv_client.__name__ + ".Client",
|
||||
new=fake_client.TestClient):
|
||||
# Patch the _get_total_profiles() method to return a custom value
|
||||
with patch(fake_client.__name__ +
|
||||
'.TestClient._get_total_profiles') as obj_inst:
|
||||
# Return 3 policy profiles
|
||||
obj_inst.return_value = 3
|
||||
plugin = manager.NeutronManager.get_plugin()
|
||||
plugin._populate_policy_profiles()
|
||||
db_session = db.get_session()
|
||||
profile = n1kv_db_v2.get_policy_profile(
|
||||
db_session, '00000000-0000-0000-0000-000000000001')
|
||||
# Verify that DB contains only 3 policy profiles
|
||||
self.assertEqual('pp-1', profile['name'])
|
||||
profile = n1kv_db_v2.get_policy_profile(
|
||||
db_session, '00000000-0000-0000-0000-000000000002')
|
||||
self.assertEqual('pp-2', profile['name'])
|
||||
profile = n1kv_db_v2.get_policy_profile(
|
||||
db_session, '00000000-0000-0000-0000-000000000003')
|
||||
self.assertEqual('pp-3', profile['name'])
|
||||
self.assertRaises(c_exc.PolicyProfileIdNotFound,
|
||||
n1kv_db_v2.get_policy_profile,
|
||||
db_session,
|
||||
'00000000-0000-0000-0000-000000000004')
|
||||
# Return 2 policy profiles
|
||||
obj_inst.return_value = 2
|
||||
plugin._populate_policy_profiles()
|
||||
# Verify that the third policy profile is deleted
|
||||
self.assertRaises(c_exc.PolicyProfileIdNotFound,
|
||||
n1kv_db_v2.get_policy_profile,
|
||||
db_session,
|
||||
'00000000-0000-0000-0000-000000000003')
|
||||
|
||||
|
||||
class TestN1kvNetworks(test_plugin.TestNetworksV2,
|
||||
N1kvPluginTestCase):
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user