From 86b6442cac309534003e81df80a9efb1a96363d3 Mon Sep 17 00:00:00 2001 From: mark mcclain Date: Tue, 2 Sep 2014 20:02:06 +0000 Subject: [PATCH] Revert "Cisco DFA ML2 Mechanism Driver" This reverts commit 3680fd61c9a1cceaa011b4d0d37d235abf490c50. The reverted patch incorrectly ties with Keystone and should have never been approved since the approved version only partially addressed review concerns. This revert also ensure migration timeline integrity. Change-Id: If5fbdade72c762b21a477676ded816ce5be97ca5 --- etc/neutron/plugins/ml2/ml2_conf.ini | 1 - etc/neutron/plugins/ml2/ml2_conf_cisco.ini | 14 - .../469426cd2173_cisco_dfa_mech_driver.py | 58 ---- .../58fe87a01143_cisco_csr_routing.py | 4 +- neutron/db/migration/models/head.py | 1 - .../plugins/ml2/drivers/cisco/dfa/__init__.py | 0 .../drivers/cisco/dfa/cfg_profile_db_v2.py | 109 ------- .../ml2/drivers/cisco/dfa/cisco_dfa_rest.py | 303 ------------------ .../plugins/ml2/drivers/cisco/dfa/config.py | 53 --- .../ml2/drivers/cisco/dfa/constants.py | 22 -- .../ml2/drivers/cisco/dfa/dfa_exceptions.py | 63 ---- .../ml2/drivers/cisco/dfa/dfa_instance_api.py | 140 -------- .../drivers/cisco/dfa/dfa_mech_driver_rpc.py | 49 --- .../ml2/drivers/cisco/dfa/dfa_models_v2.py | 59 ---- .../ml2/drivers/cisco/dfa/mech_cisco_dfa.py | 277 ---------------- .../ml2/drivers/cisco/dfa/project_events.py | 184 ----------- .../drivers/cisco/dfa/projects_cache_db_v2.py | 95 ------ .../unit/ml2/drivers/cisco/dfa/__init__.py | 0 .../drivers/cisco/dfa/test_cisco_dfa_rest.py | 153 --------- .../drivers/cisco/dfa/test_mech_cisco_dfa.py | 272 ---------------- setup.cfg | 1 - 21 files changed, 2 insertions(+), 1856 deletions(-) delete mode 100644 neutron/db/migration/alembic_migrations/versions/469426cd2173_cisco_dfa_mech_driver.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/cfg_profile_db_v2.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/cisco_dfa_rest.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/config.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/constants.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/dfa_exceptions.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/dfa_instance_api.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/dfa_mech_driver_rpc.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/dfa_models_v2.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/mech_cisco_dfa.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/project_events.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/dfa/projects_cache_db_v2.py delete mode 100644 neutron/tests/unit/ml2/drivers/cisco/dfa/__init__.py delete mode 100644 neutron/tests/unit/ml2/drivers/cisco/dfa/test_cisco_dfa_rest.py delete mode 100644 neutron/tests/unit/ml2/drivers/cisco/dfa/test_mech_cisco_dfa.py diff --git a/etc/neutron/plugins/ml2/ml2_conf.ini b/etc/neutron/plugins/ml2/ml2_conf.ini index f4c1d188772..6325e714eee 100644 --- a/etc/neutron/plugins/ml2/ml2_conf.ini +++ b/etc/neutron/plugins/ml2/ml2_conf.ini @@ -20,7 +20,6 @@ # Example: mechanism_drivers = cisco,logger # Example: mechanism_drivers = openvswitch,brocade # Example: mechanism_drivers = linuxbridge,brocade -# Example: mechanism_drivers = openvswitch,cisco_dfa # (ListOpt) Ordered list of extension driver entrypoints # to be loaded from the neutron.ml2.extension_drivers namespace. diff --git a/etc/neutron/plugins/ml2/ml2_conf_cisco.ini b/etc/neutron/plugins/ml2/ml2_conf_cisco.ini index c2582e08358..1b69100e775 100644 --- a/etc/neutron/plugins/ml2/ml2_conf_cisco.ini +++ b/etc/neutron/plugins/ml2/ml2_conf_cisco.ini @@ -116,17 +116,3 @@ # encap=vlan-100 # cidr_exposed=10.10.40.2/16 # gateway_ip=10.10.40.1 - -[ml2_cisco_dfa] -# (StrOpt) IP address of Cisco DCNM (Data Center Network Manager). -# dcnm_ip = 1.1.1.1 -# -# (StrOpt) User login name for DCNM. -# dcnm_user = username -# -# (StrOpt) Login password for DCNM. -# dcnm_password = password -# -# (StrOpt) Gateway MAC address when forwarding mode in created config profile -# is proxy mode. -# gateway_mac = 00:01:02:03:04:05 diff --git a/neutron/db/migration/alembic_migrations/versions/469426cd2173_cisco_dfa_mech_driver.py b/neutron/db/migration/alembic_migrations/versions/469426cd2173_cisco_dfa_mech_driver.py deleted file mode 100644 index 7d10ee73c76..00000000000 --- a/neutron/db/migration/alembic_migrations/versions/469426cd2173_cisco_dfa_mech_driver.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# -# 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. -# - -"""Cisco DFA Mechanism Driver - -Revision ID: 469426cd2173 -Revises: 32f3915891fd -Create Date: 2014-06-28 01:13:04.152945 - -""" - -# revision identifiers, used by Alembic. -revision = '469426cd2173' -down_revision = '32f3915891fd' - -from alembic import op -import sqlalchemy as sa - - -def upgrade(active_plugins=None, options=None): - op.create_table( - 'cisco_dfa_config_profiles', - sa.Column('id', sa.String(36)), - sa.Column('name', sa.String(255)), - sa.Column('forwarding_mode', sa.String(32)), - sa.PrimaryKeyConstraint('id')) - - op.create_table( - 'cisco_dfa_config_profile_bindings', - sa.Column('network_id', sa.String(36)), - sa.Column('cfg_profile_id', sa.String(36)), - sa.ForeignKeyConstraint(['network_id'], ['networks.id'], - ondelete='CASCADE'), - sa.PrimaryKeyConstraint('network_id', 'cfg_profile_id')) - - op.create_table( - 'cisco_dfa_project_cache', - sa.Column('project_id', sa.String(36)), - sa.Column('project_name', sa.String(255)), - sa.PrimaryKeyConstraint('project_id')) - - -def downgrade(active_plugins=None, options=None): - op.drop_table('cisco_dfa_project_cache') - op.drop_table('cisco_dfa_config_profile_bindings') - op.drop_table('cisco_dfa_config_profiles') diff --git a/neutron/db/migration/alembic_migrations/versions/58fe87a01143_cisco_csr_routing.py b/neutron/db/migration/alembic_migrations/versions/58fe87a01143_cisco_csr_routing.py index 0ee5d6d9922..34ee0ee9ea5 100644 --- a/neutron/db/migration/alembic_migrations/versions/58fe87a01143_cisco_csr_routing.py +++ b/neutron/db/migration/alembic_migrations/versions/58fe87a01143_cisco_csr_routing.py @@ -16,14 +16,14 @@ """cisco_csr_routing Revision ID: 58fe87a01143 -Revises: 4eba2f05c2f4 +Revises: 32f3915891fd Create Date: 2014-08-18 17:14:12.506356 """ # revision identifiers, used by Alembic. revision = '58fe87a01143' -down_revision = '469426cd2173' +down_revision = '32f3915891fd' from alembic import op import sqlalchemy as sa diff --git a/neutron/db/migration/models/head.py b/neutron/db/migration/models/head.py index 645921d9756..d15d3df7967 100644 --- a/neutron/db/migration/models/head.py +++ b/neutron/db/migration/models/head.py @@ -60,7 +60,6 @@ from neutron.plugins.ml2.drivers.arista import db # noqa from neutron.plugins.ml2.drivers.brocade.db import ( # noqa models as ml2_brocade_models) from neutron.plugins.ml2.drivers.cisco.apic import apic_model # noqa -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_models_v2 # noqa from neutron.plugins.ml2.drivers.cisco.nexus import ( # noqa nexus_models_v2 as ml2_nexus_models_v2) from neutron.plugins.ml2.drivers import type_flat # noqa diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/__init__.py b/neutron/plugins/ml2/drivers/cisco/dfa/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/cfg_profile_db_v2.py b/neutron/plugins/ml2/drivers/cisco/dfa/cfg_profile_db_v2.py deleted file mode 100644 index 430e54cbcf5..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/cfg_profile_db_v2.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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 sqlalchemy.orm import exc - -from neutron.db import models_v2 -from neutron.plugins.ml2.drivers.cisco.dfa import constants as dfac -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_exceptions as dexc -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_models_v2 - - -def get_network_profile_binding(session, net_id): - """Retrieve network and config profile binding.""" - - try: - return (session.query(dfa_models_v2.ConfigProfileBinding). - filter_by(network_id=net_id).one()) - except (exc.NoResultFound, exc.MultipleResultsFound): - pass - - -def add_dfa_cfg_profile_binding(session, netid, cpid): - """Add new entry to the config profile binding database.""" - - try: - if cpid == dfac.DEFAULT_CFG_PROFILE_ID: - # The config profile is not provided when creating network. - # Use 'defaultNetworkL2Profile' as default config profile. - cfgp_name = 'defaultNetworkL2Profile' - cfgp_entry = (session.query(dfa_models_v2.ConfigProfile). - filter_by(name=cfgp_name).one()) - cpid = cfgp_entry.id - - binding = dfa_models_v2.ConfigProfileBinding(network_id=netid, - cfg_profile_id=cpid) - session.add(binding) - except (exc.NoResultFound, exc.MultipleResultsFound): - raise dexc.ConfigProfileNotFound(network_id=netid) - - -def get_network_entry(session, netid): - """Retrieve network information.""" - - try: - return (session.query(models_v2.Network). - filter_by(id=netid).one()) - except (exc.NoResultFound, exc.MultipleResultsFound): - raise dexc.NetworkNotFound(network_id=netid) - - -def get_config_profile_name(db_session, netid): - """Retrieve configuration profile for a network.""" - - try: - cfgpobj = dfa_models_v2.ConfigProfileBinding - cfgp = db_session.query(cfgpobj).filter_by(network_id=netid).one() - cfgid = cfgp.cfg_profile_id - except (exc.NoResultFound, exc.MultipleResultsFound): - raise dexc.ConfigProfileNotFound(network_id=netid) - try: - cfgp_entry = db_session.query( - dfa_models_v2.ConfigProfile).filter_by(id=cfgid).one() - except (exc.NoResultFound, exc.MultipleResultsFound): - raise dexc.ConfigProfileIdNotFound(profile_id=cfgid) - return cfgp_entry.name - - -def get_config_profile_fwd_mode(db_session, network_id): - """Retrieve configuration profile for a network.""" - - try: - cfgp = (db_session.query(dfa_models_v2.ConfigProfileBinding). - filter_by(network_id=network_id).one()) - cfgid = cfgp.cfg_profile_id - except (exc.NoResultFound, exc.MultipleResultsFound): - raise dexc.ConfigProfileNotFound(network_id=network_id) - - try: - cfgp_entry = db_session.query( - dfa_models_v2.ConfigProfile).filter_by(id=cfgid).one() - return cfgp_entry.forwarding_mode - except (exc.NoResultFound, exc.MultipleResultsFound): - raise dexc.ConfigProfileIdNotFound(profile_id=cfgid) - - -def delete_dfa_cfg_profile_binding(db_session, network_id): - """Delete an entry from the config profile binding database.""" - - try: - with db_session.begin(subtransactions=True): - entry = (db_session.query(dfa_models_v2.ConfigProfileBinding). - filter_by(network_id=network_id).one()) - db_session.delete(entry) - except (exc.NoResultFound, exc.MultipleResultsFound): - raise dexc.ConfigProfileNotFound(network_id=network_id) diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/cisco_dfa_rest.py b/neutron/plugins/ml2/drivers/cisco/dfa/cisco_dfa_rest.py deleted file mode 100644 index 1572be754b9..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/cisco_dfa_rest.py +++ /dev/null @@ -1,303 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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 oslo.config import cfg -import requests - -from neutron.openstack.common import jsonutils -from neutron.openstack.common import log as logging -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_exceptions as dexc - -LOG = logging.getLogger(__name__) - - -class DFARESTClient(object): - """DFA client class that provides APIs to interact with DCNM.""" - - def __init__(self): - self._ip = cfg.CONF.ml2_cisco_dfa.dcnm_ip - self._user = cfg.CONF.ml2_cisco_dfa.dcnm_user - self._pwd = cfg.CONF.ml2_cisco_dfa.dcnm_password - if (not self._ip) or (not self._user) or (not self._pwd): - msg = _("[DFARESTClient] Input DCNM IP, user name or password" - "parameter is not specified") - raise ValueError(msg) - - # url timeout: 10 seconds - self._TIMEOUT_RESPONSE = 10 - - # urls - net_url = 'http://%s/' % self._ip - net_url += 'rest/auto-config/organizations/%s/partitions/%s/networks' - self._create_network_url = net_url - cfg_url = 'http://%s/rest/auto-config/profiles' % self._ip - self._cfg_profile_list_url = cfg_url - cfg_url += '/%s' - self._cfg_profile_get_url = cfg_url - self._org_url = 'http://%s/rest/auto-config/organizations' % self._ip - tmp_url = 'http://%s/rest/auto-config/organizations/' % self._ip - tmp_url += '%s/partitions' - self._create_part_url = tmp_url - self._del_org_url = self._org_url + '/%s' - self._del_part = self._org_url + '/%s/partitions/%s' - self._del_network_url = (self._org_url + - '/%s/partitions/%s/networks/segment/%s') - self._login_url = 'http://%s/rest/logon' % (self._ip) - self._logout_url = 'http://%s/rest/logout' % (self._ip) - self._exp_time = 100000 - self._resp_ok = 200 - - def _create_network(self, network_info): - """Send create network request to DCNM. - - :network_info: network parameters to be created on DCNM - """ - url = self._create_network_url % (network_info['partitionName'], - network_info['partitionName']) - payload = network_info - - LOG.info(_('url %(url)s payload %(payload)s'), - {'url': url, 'payload': payload}) - return (self._send_request('POST', url, payload, 'network')) - - def _config_profile_get(self, thisprofile): - """Get information of a config profile from DCNM. - - :thisprofile: network config profile in request - """ - url = self._cfg_profile_get_url % (thisprofile) - payload = {} - - res = self._send_request('GET', url, payload, 'config-profile') - return res.json() - - def _config_profile_list(self): - """Get list of supported config profile from DCNM.""" - url = self._cfg_profile_list_url - payload = {} - - res = self._send_request('GET', url, payload, 'config-profile') - return res.json() - - def _create_org(self, name, desc): - """Create organization on the DCNM. - - :name: Name of organization - :desc: Description of organization - """ - url = self._org_url - payload = { - "organizationName": name, - "description": name if len(desc) == 0 else desc, - "orchestrationSource": "Openstack Controller"} - - return (self._send_request('POST', url, payload, 'organization')) - - def _create_partition(self, org_name, part_name, desc): - """Send Create partition request to the DCNM. - - :org_name: name of organization - :part_name: name of partition - :desc: description of partition - """ - url = self._create_part_url % (org_name) - payload = { - "partitionName": part_name, - "description": part_name if len(desc) == 0 else desc, - "organizationName": org_name} - - return (self._send_request('POST', url, payload, 'partition')) - - def _delete_org(self, org_name): - """Send organization delete request to DCNM. - - :org_name: name of organization to be deleted - """ - url = self._del_org_url % (org_name) - self._send_request('DELETE', url, '', 'organization') - - def _delete_partition(self, org_name, partition_name): - """Send partition delete request to DCNM. - - :partition_name: name of partition to be deleted - """ - url = self._del_part % (org_name, partition_name) - self._send_request('DELETE', url, '', 'partition') - - def _delete_network(self, network_info): - """Send network delete request to DCNM. - - :partition_name: name of partition to be deleted - """ - org_name = network_info.get('organizationName', '') - part_name = network_info.get('partitionName', '') - segment_id = network_info['segmentId'] - url = self._del_network_url % (org_name, part_name, segment_id) - self._send_request('DELETE', url, '', 'network') - - def _login(self): - """Login request to DCNM.""" - url_login = self._login_url - expiration_time = self._exp_time - - payload = {'expirationTime': expiration_time} - self._req_headers = {'Accept': 'application/json', - 'Content-Type': 'application/json; charset=UTF-8'} - res = requests.post(url_login, - data=jsonutils.dumps(payload), - headers=self._req_headers, - auth=(self._user, self._pwd), - timeout=self._TIMEOUT_RESPONSE) - session_id = '' - if res and res.status_code == self._resp_ok: - session_id = res.json().get('Dcnm-Token') - self._req_headers.update({'Dcnm-Token': session_id}) - - def _logout(self): - """Logout request to DCNM.""" - url_logout = self._logout_url - requests.post(url_logout, - headers=self._req_headers, - timeout=self._TIMEOUT_RESPONSE) - - def _send_request(self, operation, url, payload, desc): - """Send request to DCNM.""" - res = None - try: - payload_json = None - if payload and payload != '': - payload_json = jsonutils.dumps(payload) - self._login() - desc_lookup = {'POST': ' creation', 'PUT': ' update', - 'DELETE': ' deletion', 'GET': ' get'} - - res = requests.request(operation, url, data=payload_json, - headers=self._req_headers, - timeout=self._TIMEOUT_RESPONSE) - desc += desc_lookup.get(operation, operation.lower()) - LOG.info(_("DCNM-send_request: %(desc)s %(url)s %(pld)s"), - {'desc': desc, 'url': url, 'pld': payload}) - - self._logout() - except (requests.HTTPError, requests.Timeout, - requests.ConnectionError) as e: - LOG.exception(_('Error during request')) - raise dexc.DFAClientRequestFailed(reason=e) - - return res - - def _check_for_supported_profile(self, thisprofile): - """Filter those profiles that are not currently supported.""" - return (thisprofile.endswith('Ipv4TfProfile') or - thisprofile.endswith('Ipv4EfProfile') or - 'defaultNetworkL2Profile' in thisprofile) - - def config_profile_list(self): - """Return config profile list from DCNM.""" - profile_list = [] - these_profiles = [] - these_profiles = self._config_profile_list() - profile_list = [q for p in these_profiles for q in - [p.get('profileName')] - if self._check_for_supported_profile(q)] - return profile_list - - def config_profile_fwding_mode_get(self, profile_name): - """Return forwarding mode of given config profile.""" - profile_params = self._config_profile_get(profile_name) - fwd_cli = 'fabric forwarding mode proxy-gateway' - if fwd_cli in profile_params['configCommands']: - return 'proxy-gateway' - else: - return 'anycast-gateway' - - def create_network(self, tenant_name, network, subnet): - """Create network on the DCNM. - - :tenant_name: name of tenant the network belongs to - :network: network parameters - :subnet: subnet parameters of the network - """ - network_info = {} - seg_id = str(network.provider__segmentation_id) - subnet_ip_mask = subnet.cidr.split('/') - gw_ip = subnet.gateway_ip - cfg_args = [ - "$segmentId=" + seg_id, - "$netMaskLength=" + subnet_ip_mask[1], - "$gatewayIpAddress=" + gw_ip, - "$networkName=" + network.name, - "$vlanId=0", - "$vrfName=" + tenant_name + ':' + tenant_name - ] - cfg_args = ';'.join(cfg_args) - - ip_range = ','.join(["%s-%s" % (p['start'], p['end']) for p in - subnet.allocation_pools]) - - dhcp_scopes = {'ipRange': ip_range, - 'subnet': subnet.cidr, - 'gateway': gw_ip} - - network_info = {"segmentId": seg_id, - "vlanId": "0", - "mobilityDomainId": "None", - "profileName": network.config_profile, - "networkName": network.name, - "configArg": cfg_args, - "organizationName": tenant_name, - "partitionName": tenant_name, - "description": network.name, - "dhcpScope": dhcp_scopes} - LOG.debug("Create %s network in DCNM." % network_info) - - self._create_network(network_info) - - def delete_network(self, tenant_name, network): - """Delete network on the DCNM. - - :tenant_name: name of tenant the network belongs to - :network: object that contains network parameters - """ - network_info = {} - seg_id = network.provider__segmentation_id - network_info = { - 'organizationName': tenant_name, - 'partitionName': tenant_name, - 'segmentId': seg_id, - } - LOG.debug("Delete %s network in DCNM." % network_info) - - self._delete_network(network_info) - - def delete_tenant(self, tenant_name): - """Delete tenant on the DCNM. - - :tenant_name: name of tenant to be deleted. - """ - self._delete_partition(tenant_name, tenant_name) - self._delete_org(tenant_name) - - def create_project(self, org_name, desc=None): - """Create project on the DCNM. - - :org_name: name of organization to be created - :desc: string that describes organization - """ - desc = desc or org_name - self._create_org(org_name, desc) - self._create_partition(org_name, org_name, desc) diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/config.py b/neutron/plugins/ml2/drivers/cisco/dfa/config.py deleted file mode 100644 index 82096ff33c7..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/config.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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 oslo.config import cfg - - -ml2_cisco_dfa_opts = [ - cfg.StrOpt('dcnm_ip', default='0.0.0.0', - help=_("IP address of DCNM.")), - cfg.StrOpt('dcnm_user', default='user', - help=_("User login name for DCNM.")), - cfg.StrOpt('dcnm_password', default='password', - secret=True, - help=_("Login password for DCNM.")), - cfg.StrOpt('gateway_mac', default='00:00:DE:AD:BE:EF', - help=_("Gateway mac address when using proxy mode.")), -] - -cfg.CONF.register_opts(ml2_cisco_dfa_opts, "ml2_cisco_dfa") - - -class CiscoDFAConfig(object): - """Cisco DFA Mechanism Driver Configuration class.""" - - dfa_cfg = {} - - def __init__(self): - multi_parser = cfg.MultiConfigParser() - read_ok = multi_parser.read(cfg.CONF.config_file) - - if len(read_ok) != len(cfg.CONF.config_file): - raise cfg.Error(_("Failed to read config files %(file)s") % - {'file': cfg.CONF.config_file}) - - for parsed_file in multi_parser.parsed: - for parsed_item in parsed_file.keys(): - for key, value in parsed_file[parsed_item].items(): - if parsed_item == 'mech_driver_agent': - self.dfa_cfg[key] = value diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/constants.py b/neutron/plugins/ml2/drivers/cisco/dfa/constants.py deleted file mode 100644 index c051b61c22a..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/constants.py +++ /dev/null @@ -1,22 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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 uuid - - -CISCO_DFA_MECH_DRVR_NAME = 'cisco_dfa' -DEFAULT_CFG_PROFILE_ID = str(uuid.UUID(int=0)) -CONFIG_PROFILE_ID = 'dfa:cfg_profile_id' diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/dfa_exceptions.py b/neutron/plugins/ml2/drivers/cisco/dfa/dfa_exceptions.py deleted file mode 100644 index bef4e16d104..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/dfa_exceptions.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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. -# - -"""Exceptions used by DFA ML2 mechanism drivers.""" - -from neutron.common import exceptions - - -class NetworkNotFound(exceptions.NotFound): - """Network cannot be found.""" - - message = _("Network %(network_id)s could not be found.") - - -class ConfigProfileNotFound(exceptions.NotFound): - """Config Profile cannot be found.""" - - message = _("Config profile for network %(network_id)s" - " could not be found.") - - -class ConfigProfileFwdModeNotFound(exceptions.NotFound): - """Config Profile forwarding mode cannot be found.""" - - message = _("Forwarding Mode for network %(network_id)s" - " could not be found.") - - -class ConfigProfileIdNotFound(exceptions.NotFound): - """Config Profile ID cannot be found.""" - - message = _("Config Profile %(profile_id)s could not be found.") - - -class ConfigProfileNameNotFound(exceptions.NotFound): - """Config Profile name cannot be found.""" - - message = _("Config Profile %(name)s could not be found.") - - -class ProjectIdNotFound(exceptions.NotFound): - """Project ID cannot be found.""" - - message = _("Project ID %(project_id)s could not be found.") - - -class DFAClientRequestFailed(exceptions.ServiceUnavailable): - """Request to DCNM failed.""" - - message = _("Request to DCNM failed: %(reason)s.") diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/dfa_instance_api.py b/neutron/plugins/ml2/drivers/cisco/dfa/dfa_instance_api.py deleted file mode 100644 index a8f320baf2b..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/dfa_instance_api.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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. -# - -""" -This file provides a wrapper to novaclient API, for getting the instacne's -information such as display_name. -""" - -from keystoneclient.v2_0 import client as keyc - -from neutron.openstack.common import log as logging -from novaclient import exceptions as nexc -from novaclient.v1_1 import client as nova_client - - -LOG = logging.getLogger(__name__) - - -class DFAInstanceAPI(object): - """This class provides API to get information for a given instance.""" - - def __init__(self, cfg): - self._tenant_name = cfg.CONF.keystone_authtoken.admin_tenant_name - self._user_name = cfg.CONF.keystone_authtoken.admin_user - self._admin_password = cfg.CONF.keystone_authtoken.admin_password - self._TIMEOUT_RESPONSE = 10 - self._token = None - self._project_id = None - self._auth_url = None - self._token_id = None - self._token = None - self._novaclnt = None - self._url = cfg.CONF.nova_admin_auth_url - self._inst_info_cache = {} - - def _create_token(self): - """Create new token for using novaclient API.""" - ks = keyc.Client(username=self._user_name, - password=self._admin_password, - tenant_name=self._tenant_name, - auth_url=self._url) - result = ks.authenticate() - if result: - access = ks.auth_ref - token = access.get('token') - self._token_id = token['id'] - self._project_id = token['tenant'].get('id') - service_catalog = access.get('serviceCatalog') - for sc in service_catalog: - if sc['type'] == "compute" and sc['name'] == 'nova': - endpoints = sc['endpoints'] - for endp in endpoints: - self._auth_url = endp['adminURL'] - LOG.info(_('_create_token: token = %s'), token) - - # Create nova client. - self._novaclnt = self._create_nova_client() - - return token - - else: - # Failed request. - LOG.error(_('Failed to send token create request.')) - - def _create_nova_client(self): - """Creates nova client object.""" - try: - clnt = nova_client.Client(self._user_name, - self._token_id, - self._project_id, - self._auth_url, - insecure=False, - cacert=None) - clnt.client.auth_token = self._token_id - clnt.client.management_url = self._auth_url - return clnt - except nexc.Unauthorized: - thismsg = (_('Failed to get novaclient:Unauthorised ' - '%(proj)s %(user)s') % {'proj': self.project_id, - 'user': self._user_name}) - raise nexc.ClientException(thismsg) - - except nexc.AuthorizationFailure as err: - raise nexc.ClientException(_("Failed to get novaclient %s") % err) - - def _get_instances_for_project(self, project_id): - """Return all instances for a given project. - - :project_id: UUID of project (tenant) - """ - search_opts = {'marker': None, - 'all_tenants': True, - 'project_id': project_id} - self._create_token() - try: - servers = self._novaclnt.servers.list(True, search_opts) - LOG.debug('_get_instances_for_project: servers=%s' % servers) - return servers - except nexc.Unauthorized: - emsg = (_('Failed to get novaclient:Unauthorised ' - 'project_id=%(proj)s user=%(user)s'), - {'proj': self.project_id, 'name': self._user_name}) - LOG.exception(emsg) - raise nexc.ClientException(emsg) - except nexc.AuthorizationFailure as err: - emsg = _("Failed to get novaclient %s") - LOG.exception(emsg % err) - raise nexc.ClientException(emsg % err) - - def get_instance_for_uuid(self, uuid, project_id): - """Return instance name for given uuid of an instance and project. - - :uuid: Instance's UUID - :project_id: UUID of project (tenant) - """ - instance_name = None - instance_name = self._inst_info_cache.get((uuid, project_id)) - if instance_name: - return instance_name - instances = self._get_instances_for_project(project_id) - for inst in instances: - if inst.id.replace('-', '') == uuid: - LOG.debug('get_instance_for_uuid: name=%s' % inst.name) - instance_name = inst.name - self._inst_info_cache[(uuid, project_id)] = instance_name - return instance_name - return instance_name diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/dfa_mech_driver_rpc.py b/neutron/plugins/ml2/drivers/cisco/dfa/dfa_mech_driver_rpc.py deleted file mode 100644 index c5a99210e77..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/dfa_mech_driver_rpc.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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 neutron.common import rpc as n_rpc -from neutron.common import topics - - -class RpcCallbacks(n_rpc.RpcCallback): - - RPC_API_VERSION = '1.1' - - def __init__(self, notifier): - self._nofifier = notifier - super(RpcCallbacks, self).__init__() - - -class MechDriversAgentNotifierApi(n_rpc.RpcProxy): - """Agent side of the cisco DFA mechanism driver rpc API. - - API version history: - 1.0 - Initial version. - """ - - BASE_RPC_API_VERSION = '1.0' - - def __init__(self, topic, agt_topic_tbl): - super(MechDriversAgentNotifierApi, self).__init__( - topic=topic, default_version=self.BASE_RPC_API_VERSION) - self.topic_dfa_update = topics.get_topic_name(topic, - agt_topic_tbl, - topics.UPDATE) - - def send_vm_info(self, context, vm_info): - self.fanout_cast(context, - self.make_msg('send_vm_info', vm_info=vm_info), - topic=self.topic_dfa_update) diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/dfa_models_v2.py b/neutron/plugins/ml2/drivers/cisco/dfa/dfa_models_v2.py deleted file mode 100644 index adecd8f138d..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/dfa_models_v2.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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 neutron.db import model_base -import sqlalchemy as sa - - -class ConfigProfile(model_base.BASEV2): - """Cisco DFA network configuration profile. - - 'id' - UUID and is localy generated, - 'name' - profile name coming form DCNM. - """ - __tablename__ = 'cisco_dfa_config_profiles' - - id = sa.Column(sa.String(36), primary_key=True) - name = sa.Column(sa.String(255)) - forwarding_mode = sa.Column(sa.String(32)) - - -class ConfigProfileBinding(model_base.BASEV2): - """Represents a binding of Network to Config Profile. - - netwrok_id - Network UUID, - cfg_profile_id - UUID of config profile. - """ - __tablename__ = 'cisco_dfa_config_profile_bindings' - - network_id = sa.Column(sa.String(36), - sa.ForeignKey('networks.id', ondelete="CASCADE"), - primary_key=True) - cfg_profile_id = sa.Column(sa.String(36), primary_key=True) - - -class ProjectNameCache(model_base.BASEV2): - """Cache project name and project ID for Cisco DFA. - - project_id - project UUID, - project_name - project name. - """ - __tablename__ = 'cisco_dfa_project_cache' - - project_id = sa.Column(sa.String(36), - primary_key=True) - project_name = sa.Column(sa.String(255)) diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/mech_cisco_dfa.py b/neutron/plugins/ml2/drivers/cisco/dfa/mech_cisco_dfa.py deleted file mode 100644 index 909ad7e7446..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/mech_cisco_dfa.py +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright (c) 2014 Cisco Systems -# All rights reserved. -# -# 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. -# - - -""" -ML2 Mechanism Driver for Cisco DFA platforms. -""" - -import eventlet -from oslo.config import cfg - -from neutron.common import exceptions as n_exc -from neutron.common import rpc as n_rpc -from neutron.common import topics -from neutron.extensions import portbindings -from neutron.openstack.common import log as logging -from neutron.plugins.ml2.common import exceptions as ml2_exc -from neutron.plugins.ml2 import driver_api as api -from neutron.plugins.ml2.drivers.cisco.dfa import cfg_profile_db_v2 -from neutron.plugins.ml2.drivers.cisco.dfa import cisco_dfa_rest -from neutron.plugins.ml2.drivers.cisco.dfa import config -from neutron.plugins.ml2.drivers.cisco.dfa import constants as dfa_const -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_exceptions as dexc -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_instance_api -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_mech_driver_rpc as drpc -from neutron.plugins.ml2.drivers.cisco.dfa import project_events -from neutron.plugins.ml2.drivers.cisco.dfa import projects_cache_db_v2 - - -LOG = logging.getLogger(__name__) - - -class SubnetObj(object): - """Represents a subnet object. - - The information in the object will be used when creating a subnet on - the DCNM. - """ - def __init__(self, subnet): - self.allocation_pools = subnet['allocation_pools'] - self.host_routes = subnet['host_routes'] - self.cidr = subnet['cidr'] - self.id = subnet['id'] - self.name = subnet['name'] - self.enable_dhcp = subnet['enable_dhcp'] - self.network_id = subnet['network_id'] - self.tenant_id = subnet['tenant_id'] - self.dns_nameservers = subnet['dns_nameservers'] - self.gateway_ip = subnet['gateway_ip'] - self.ip_version = subnet['ip_version'] - self.shared = subnet['shared'] - - -class NetworkObj(object): - """Represents a network object. - - The information in this object will be used when creating a network on - the DCNM. - """ - def __init__(self, net, segid, cfgp=None): - self.provider__segmentation_id = segid - self.tenant_id = net['tenant_id'] - self.name = net['name'] - self.config_profile = cfgp - self.id = net['id'] - - -class CiscoDfaMechanismDriver(api.MechanismDriver): - """Cisco DFA ML2 Mechanism Driver.""" - - def initialize(self): - # Initialize the config - self._dfa_cfg = config.CiscoDFAConfig().dfa_cfg - - # Initialize DCNM client. - self._dcnm_client = cisco_dfa_rest.DFARESTClient() - - # Initialize project creation/deletion events object. - # This will be used to get notification from keystone when - # a tenant (i.e. project) is created or deleted. - self._keys = project_events.EventsHandler('keystone', - self._dcnm_client) - - # Spawn a task, to process notification queue for keystone events. - eventlet.spawn(self._process_keystone_events) - - # Initialize nova client wrapper. It will be used to get more - # information for an instance. - self._inst_api = dfa_instance_api.DFAInstanceAPI(cfg) - - # Initialize mechanism driver RPC. - self._setup_mechdrv_rpc() - - # Initialize project info object. - self.projects_cache_db_v2 = projects_cache_db_v2.ProjectsInfoCache() - - self._ctask_sleep_interval = 60 - - def _get_agent_topic(self): - """Read the mech_driver_agent section from the config file.""" - mech_drvr_rpc = self._dfa_cfg.get('mech_driver_rpc') - if mech_drvr_rpc is None: - return - self._agent_topic = '' - self._mech_drv_topic = '' - for val in mech_drvr_rpc: - if len(val) > 0: - if val.split(':')[0] != dfa_const.CISCO_DFA_MECH_DRVR_NAME: - continue - try: - self._mech_drv_topic = val.split(':')[1] - self._agent_topic = val.split(':')[2] - except IndexError: - emsg = _('No topics is defined for %s mechanism driver') - LOG.error(emsg % dfa_const.CISCO_DFA_MECH_DRVR_NAME) - return - - def _setup_mechdrv_rpc(self): - """Setup RPC for this mechanism driver.""" - self._get_agent_topic() - if not self._agent_topic or not self._mech_drv_topic: - LOG.debug('Mechanism Driver notifer is not initialized') - return - self.dfa_notifier = drpc.MechDriversAgentNotifierApi(topics.AGENT, - self._agent_topic) - self.endpoints = [drpc.RpcCallbacks(self.dfa_notifier)] - self.topic = self._mech_drv_topic - self.conn = n_rpc.create_connection(new=True) - self.conn.create_consumer(self.topic, self.endpoints, fanout=False) - self.conn.consume_in_threads() - - def _process_keystone_events(self): - """Task to process notification from keystone. - - The handler processes events such as creation and deletion of projects - sent by keystone. - """ - self._keys.event_handler() - - def create_network_postcommit(self, context): - # Check if the tenant is valid. - projid = context.current.get('tenant_id') - if not self._keys.is_valid_project(projid): - return - - # Check if network id exists in the config profile DB. If not, - # exception should be raised. - net_id = context.current.get('id') - res = cfg_profile_db_v2.get_network_profile_binding( - context._plugin_context.session, net_id) - if not res: - cfgp_id = context.current.get(dfa_const.CONFIG_PROFILE_ID) - msg = (_("Failed to create network. Config Profile id %s" - " does not exist.") % cfgp_id) - raise n_exc.BadRequest(resource='network', msg=msg) - - # Get the project name. If project name does not exist, an exception - # will be raised. - self.projects_cache_db_v2.get_project_name(projid) - - def delete_network_postcommit(self, context): - projid = context.current.get('tenant_id') - if not self._keys.is_valid_project(projid): - return - - segid = context.current.get('provider:segmentation_id') - tenant_name = context._plugin_context.tenant_name - net = NetworkObj(context.current, segid) - try: - self._dcnm_client.delete_network(tenant_name, net) - except dexc.DFAClientRequestFailed as ex: - emsg = _('Failed to create network %(net)s. Error:%(err)s.') - LOG.error(emsg % {'net': net.name, 'err': ex}) - raise ml2_exc.MechanismDriverError - - def create_subnet_postcommit(self, context): - projid = context.current.get('tenant_id') - if not self._keys.is_valid_project(projid): - return - - subnet = context.current - if subnet['name'] == 'private-subnet': - emsg = _("%s is default subnet and no need to create it in DCNM.") - LOG.info(emsg % subnet['name']) - return - - session = context._plugin_context.session - netid = context.current['network_id'] - network_entry = cfg_profile_db_v2.get_network_entry(session, netid) - tenant_name = context._plugin_context.tenant_name - segid = self.projects_cache_db_v2.get_network_segid(netid) - cfgp_name = cfg_profile_db_v2.get_config_profile_name(session, netid) - snet = SubnetObj(context.current) - net = NetworkObj(network_entry, int(segid), cfgp_name) - try: - self._dcnm_client.create_network(tenant_name, net, snet) - except dexc.DFAClientRequestFailed as ex: - emsg = _('Failed to create network %(net)s. Error:%(err)s.') - LOG.error(emsg % {'net': net.name, 'err': ex}) - raise ml2_exc.MechanismDriverError - - def update_port_postcommit(self, context): - projid = context.current.get('tenant_id') - if not self._keys.is_valid_project(projid): - return - - session = context._plugin_context.session - self.device_id = context.current.get('device_id').replace('-', '') - tenant_id = context.current.get('tenant_id') - netid = context.current.get('network_id') - self.inst_name = self._inst_api.get_instance_for_uuid(self.device_id, - tenant_id) - self.fwd_mode = cfg_profile_db_v2.get_config_profile_fwd_mode(session, - netid) - self.segid = self.projects_cache_db_v2.get_network_segid(netid) - self.mac = context.current.get('mac_address') - self.ip = (context.current.get('fixed_ips')[0]['ip_address'] - if context.current.get('fixed_ips') else None) - - vm_info = { - 'status': 'up', - 'ip': self.ip, - 'mac': self.mac, - 'segid': self.segid, - 'inst_name': self.inst_name, - 'inst_uuid': self.device_id, - 'host': context.current.get(portbindings.HOST_ID), - 'port_id': context.current.get('id'), - 'network_id': context.current.get('network_id'), - 'oui_type': 'cisco', - } - if self.inst_name: - self.dfa_notifier.send_vm_info(context._plugin_context, vm_info) - LOG.debug("update_port_postcommit : %s" % vm_info) - - def delete_port_postcommit(self, context): - session = context._plugin_context.session - self.device_id = context.current.get('device_id').replace('-', '') - tenant_id = context.current.get('tenant_id') - netid = context.current.get('network_id') - self.inst_name = self._inst_api.get_instance_for_uuid(self.device_id, - tenant_id) - self.fwd_mode = cfg_profile_db_v2.get_config_profile_fwd_mode(session, - netid) - self.segid = self.projects_cache_db_v2.get_network_segid(netid) - self.mac = context.current.get('mac_address') - self.ip = (context.current.get('fixed_ips')[0]['ip_address'] - if context.current.get('fixed_ips') else None) - - vm_info = { - 'status': 'down', - 'ip': self.ip, - 'mac': self.mac, - 'segid': self.segid, - 'inst_name': self.inst_name, - 'inst_uuid': self.device_id, - 'host': context.current.get(portbindings.HOST_ID), - 'port_id': context.current.get('id'), - 'network_id': context.current.get('network_id'), - 'oui_type': 'cisco', - } - if self.inst_name: - self.dfa_notifier.send_vm_info(context._plugin_context, vm_info) - LOG.debug("delete_port_postcommit : %s" % vm_info) diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/project_events.py b/neutron/plugins/ml2/drivers/cisco/dfa/project_events.py deleted file mode 100644 index 7ea1c10dbf3..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/project_events.py +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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 keystoneclient.v3 import client -from oslo.config import cfg -from oslo import messaging - -from neutron.openstack.common import excutils -from neutron.openstack.common import log as logging -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_exceptions as dexc -from neutron.plugins.ml2.drivers.cisco.dfa import projects_cache_db_v2 - - -LOG = logging.getLogger(__name__) - - -notif_params = { - 'keystone': { - 'admin_token': 'ADMIN', - 'admin_endpoint': 'http://localhost:%(admin_port)s/', - 'admin_port': '35357', - 'default_notification_level': 'INFO', - 'notification_topics': 'notifications', - 'control_exchange': 'openstack', - } -} - -proj_exceptions_list = [ - 'admin', 'service', 'invisible_to_admin', 'demo', 'alt_demo'] - - -class NotificationEndpoint(object): - def __init__(self, evnt_hndlr): - self._event_hndlr = evnt_hndlr - - def info(self, ctxt, publisher_id, event_type, payload, metadata): - self._event_hndlr.callback(event_type, payload) - - -class EventsHandler(projects_cache_db_v2.ProjectsInfoCache): - """This class defines methods to listen and process the project events.""" - - def __init__(self, ser_name, dcnm_client): - self._keystone = None - self._service = ser_name - self._notif_params = {} - self._set_notif_params() - self._dcnm_client = dcnm_client - self.events_handler = { - 'identity.project.created': self.project_create_event, - 'identity.project.deleted': self.project_delete_event, - 'identity.user.created': self.no_op_event, - 'identity.user.deleted': self.no_op_event, - } - - def no_op_event(self, keyc, project_id, dcnmc): - pass - - def project_create_event(self, keyc, project_id, dcnmc): - """Create a project on the DCNM. - - :param keyc: keystoneclient object - :param project_id: UUID of the project - :param dcnmc: DCNM client object - """ - proj = keyc.projects.get(project_id) - proj_name = proj.name - desc = proj.description - LOG.debug("project_create_event: %(proj)s %(proj_name)s %(desc)s." % - {'proj': proj, 'proj_name': proj_name, 'desc': desc}) - if proj_name not in proj_exceptions_list: - try: - dcnmc.create_project(proj_name, desc) - except dexc.DFAClientConnectionFailed as ex: - with excutils.save_and_reraise_exception(): - LOG.exception(_('Failed to create %(proj)s. ' - 'Error:%(err)s.'), - {'proj': proj_name, 'err': ex}) - proj_info = {'project_id': project_id, - 'project_name': proj_name} - self.create_projects_cache_db(proj_info) - - def project_delete_event(self, keyc, project_id, dcnmc): - """Delete a project on the DCNM. - - :param keyc: keystoneclient object - :param project_id: UUID of the project - :param dcnmc: DCNM client object - """ - try: - proj_info = self.delete_projects_cache_db(project_id) - LOG.debug("project_delete_event: proj_info: %s." % proj_info) - dcnmc.delete_tenant(proj_info.project_name) - except dexc.ProjectIdNotFound: - with excutils.save_and_reraise_exception(): - LOG.exception(_("Failed to delete %(id)s"), {'id': project_id}) - except dexc.DFAClientConnectionFailed: - with excutils.save_and_reraise_exception(): - LOG.exception(_("Failed to delete %(proj)s in DCNM."), - {'proj': proj_info.project_name}) - - def _set_notif_params(self): - """Read notification parameters from the config file.""" - self._notif_params.update(notif_params[self._service]) - temp_db = {} - cfgfile = cfg.find_config_files(self._service) - multi_parser = cfg.MultiConfigParser() - cfgr = multi_parser.read(cfgfile) - if len(cfgr) == 0: - LOG.error(_("Failed to read %s."), cfgfile) - return - for parsed_file in multi_parser.parsed: - for parsed_item in parsed_file.keys(): - for key, value in parsed_file[parsed_item].items(): - if key in self._notif_params: - val = notif_params[self._service].get(key) - if val != value[0]: - temp_db[key] = value[0] - - self._notif_params.update(temp_db) - self._token = self.get_notif_params().get('admin_token') - _endpoint = self.get_notif_params().get('admin_endpoint') - self._endpoint_url = _endpoint % self.get_notif_params() + 'v3/' - self._keystone = client.Client(token=self._token, - endpoint=self._endpoint_url) - - def callback(self, event_type, payload): - """Callback method for processing events in notification queue. - - :param event_type: event type in the notification queue such as - identity.project.created, identity.project.deleted. - :param payload: Contains information of an event - """ - try: - event = event_type - if event in self.events_handler: - project_id = payload['resource_info'] - self.events_handler[event](self._keystone, project_id, - self._dcnm_client) - except KeyError: - LOG.error(_('event_type %s does not have payload/resource_info ' - 'key'), event) - - def event_handler(self): - """Prepare connection and channels for listenning to the events.""" - topicname = self.get_notif_params().get('notification_topics') - transport = messaging.get_transport(cfg.CONF) - targets = [messaging.Target(topic=topicname)] - endpoints = [NotificationEndpoint(self)] - server = messaging.get_notification_listener(transport, targets, - endpoints) - server.start() - server.wait() - - def get_notif_params(self): - """Return notification parameters.""" - return self._notif_params - - def is_valid_project(self, project_id): - """Check the validity of project. - - :param project_id: UUID of project - :returns: True if project is valid. - """ - proj = self._keystone.projects.get(project_id) - proj_name = proj.name - if proj_name in proj_exceptions_list: - LOG.debug("Project %s is not created by user." % proj_name) - return False - return True diff --git a/neutron/plugins/ml2/drivers/cisco/dfa/projects_cache_db_v2.py b/neutron/plugins/ml2/drivers/cisco/dfa/projects_cache_db_v2.py deleted file mode 100644 index 0ab597f4fe3..00000000000 --- a/neutron/plugins/ml2/drivers/cisco/dfa/projects_cache_db_v2.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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 sqlalchemy.orm import exc - -import neutron.db.api as db -from neutron.plugins.ml2 import db as ml2db -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_exceptions as dexc -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_models_v2 - - -class ProjectsInfoCache(object): - """Project DB API.""" - - def _get_project_entry(self, db_session, pid): - """Get a project entry from the table. - - :param db_session: database session object - :param pid: project ID - """ - try: - return db_session.query( - dfa_models_v2.ProjectNameCache).filter_by(project_id=pid).one() - except exc.NoResultFound: - raise dexc.ProjectIdNotFound(project_id=pid) - - def create_projects_cache_db(self, proj_info): - """Create an entry in the database. - - :param proj_info: dictionary that contains information of the project - """ - db_session = db.get_session() - with db_session.begin(subtransactions=True): - projid = proj_info["project_id"] - projname = proj_info["project_name"] - thisproj = dfa_models_v2.ProjectNameCache(project_id=projid, - project_name=projname) - db_session.add(thisproj) - return thisproj - - def delete_projects_cache_db(self, proj_id): - """Delete a project from the table. - - :param proj_id: UUID of the project - """ - db_session = db.get_session() - thisproj = None - with db_session.begin(subtransactions=True): - thisproj = self._get_project_entry(db_session, proj_id) - db_session.delete(thisproj) - return thisproj - - def get_project_name(self, proj_id): - """Returns project's name. - - :param proj_id: UUID of the project - """ - db_session = db.get_session() - with db_session.begin(subtransactions=True): - thisproj = self._get_project_entry(db_session, proj_id) - return thisproj.project_name - - def update_projects_cache_db(self, pid, proj_info): - """Update projects DB. - - :param pid: project ID - :param proj_info: dictionary that contains information of the project - """ - db_session = db.get_session() - with db_session.begin(subtransactions=True): - thisproj = self._get_project_entry(db_session, pid) - thisproj.update(proj_info) - - def get_network_segid(self, sid): - """Get network segmentation id. - - :param sid: requested segment id - """ - db_session = db.get_session() - seg_entry = ml2db.get_network_segments(db_session, sid) - return seg_entry[0]['segmentation_id'] diff --git a/neutron/tests/unit/ml2/drivers/cisco/dfa/__init__.py b/neutron/tests/unit/ml2/drivers/cisco/dfa/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/neutron/tests/unit/ml2/drivers/cisco/dfa/test_cisco_dfa_rest.py b/neutron/tests/unit/ml2/drivers/cisco/dfa/test_cisco_dfa_rest.py deleted file mode 100644 index 7e183cdd6b3..00000000000 --- a/neutron/tests/unit/ml2/drivers/cisco/dfa/test_cisco_dfa_rest.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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 oslo.config import cfg - -from neutron.plugins.ml2.drivers.cisco.dfa import cisco_dfa_rest as dc -from neutron.plugins.ml2.drivers.cisco.dfa import config # noqa -from neutron.tests import base - - -"""This file includes test cases for cisco_dfa_rest.py.""" - -FAKE_DCNM_IP = '1.1.1.1' -FAKE_DCNM_USERNAME = 'dcnmuser' -FAKE_DCNM_PASSWORD = 'dcnmpass' -org_url = 'http://%s/rest/auto-config/organizations' -part_url = 'http://%s/rest/auto-config/organizations/%s/partitions' -net_url = 'http://%s/rest/auto-config/organizations/%s/partitions/%s/networks' -del_net_url = ('http://%s/rest/auto-config/organizations/%s/partitions/%s/' - 'networks/segment/%s') - - -class TestNetwork(object): - provider__segmentation_id = 123456 - name = 'cisco_test_network' - config_profile = 'defaultL2ConfigProfile' - - -class TestCiscoDFAClient(base.BaseTestCase): - """Test cases for DFARESTClient.""" - - def setUp(self): - # Declare the test resource. - super(TestCiscoDFAClient, self).setUp() - - dcnm_cfg = {'dcnm_ip': FAKE_DCNM_IP, - 'dcnm_user': FAKE_DCNM_USERNAME, - 'dcnm_password': FAKE_DCNM_PASSWORD} - for k, v in dcnm_cfg.items(): - cfg.CONF.set_override(k, v, 'ml2_cisco_dfa') - - self.dcnm_client = dc.DFARESTClient() - mock.patch.object(self.dcnm_client, '_send_request').start() - self.testnetwork = TestNetwork() - - def test_create_org(self): - """Test create organization.""" - - org_name = 'Test_Project' - url = org_url % (cfg.CONF.ml2_cisco_dfa.dcnm_ip) - payload = {'organizationName': org_name, - 'description': org_name, - 'orchestrationSource': 'Openstack Controller'} - self.dcnm_client._create_org(org_name, org_name) - self.dcnm_client._send_request.assert_called_with('POST', url, - payload, - 'organization') - - def test_create_partition(self): - """Test create partition.""" - - org_name = 'Cisco' - part_name = 'Lab' - url = part_url % (cfg.CONF.ml2_cisco_dfa.dcnm_ip, org_name) - payload = {'partitionName': part_name, - 'description': org_name, - 'organizationName': org_name} - self.dcnm_client._create_partition(org_name, part_name, org_name) - self.dcnm_client._send_request.assert_called_with('POST', url, - payload, - 'partition') - - def test_create_project(self): - """Test create project.""" - - org_name = 'Cisco' - self.dcnm_client.create_project(org_name) - call_cnt = self.dcnm_client._send_request.call_count - self.assertEqual(2, call_cnt) - - def test_create_network(self): - """Test create network.""" - - network_info = {} - cfg_args = [] - seg_id = str(self.testnetwork.provider__segmentation_id) - config_profile = self.testnetwork.config_profile - network_name = self.testnetwork.name - tenant_name = 'Cisco' - url = net_url % (cfg.CONF.ml2_cisco_dfa.dcnm_ip, tenant_name, - tenant_name) - - cfg_args.append("$segmentId=" + seg_id) - cfg_args.append("$netMaskLength=16") - cfg_args.append("$gatewayIpAddress=30.31.32.1") - cfg_args.append("$networkName=" + network_name) - cfg_args.append("$vlanId=0") - cfg_args.append("$vrfName=%s:%s" % (tenant_name, tenant_name)) - cfg_args = ';'.join(cfg_args) - - dhcp_scopes = {'ipRange': '10.11.12.14-10.11.12.254', - 'subnet': '10.11.12.13', - 'gateway': '10.11.12.1'} - - network_info = {"segmentId": seg_id, - "vlanId": "0", - "mobilityDomainId": "None", - "profileName": config_profile, - "networkName": network_name, - "configArg": cfg_args, - "organizationName": tenant_name, - "partitionName": tenant_name, - "description": network_name, - "dhcpScope": dhcp_scopes} - - self.dcnm_client._create_network(network_info) - self.dcnm_client._send_request.assert_called_with('POST', url, - network_info, - 'network') - - def test_delete_network(self): - """Test delete network.""" - - seg_id = self.testnetwork.provider__segmentation_id - tenant_name = 'cisco' - url = del_net_url % (cfg.CONF.ml2_cisco_dfa.dcnm_ip, - tenant_name, tenant_name, seg_id) - self.dcnm_client.delete_network(tenant_name, self.testnetwork) - self.dcnm_client._send_request.assert_called_with('DELETE', url, - '', 'network') - - def test_delete_tenant(self): - """Test delete tenant.""" - - tenant_name = 'cisco' - self.dcnm_client.delete_tenant(tenant_name) - call_cnt = self.dcnm_client._send_request.call_count - self.assertEqual(2, call_cnt) diff --git a/neutron/tests/unit/ml2/drivers/cisco/dfa/test_mech_cisco_dfa.py b/neutron/tests/unit/ml2/drivers/cisco/dfa/test_mech_cisco_dfa.py deleted file mode 100644 index f23bc0e6f1f..00000000000 --- a/neutron/tests/unit/ml2/drivers/cisco/dfa/test_mech_cisco_dfa.py +++ /dev/null @@ -1,272 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# 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 oslo.config import cfg -import testtools - -from neutron.common import exceptions as n_exc -from neutron.plugins.ml2.drivers.cisco.dfa import cisco_dfa_rest -from neutron.plugins.ml2.drivers.cisco.dfa import config -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_exceptions as dexc -from neutron.plugins.ml2.drivers.cisco.dfa import dfa_instance_api -from neutron.plugins.ml2.drivers.cisco.dfa import mech_cisco_dfa -from neutron.plugins.ml2.drivers.cisco.dfa import project_events -from neutron.plugins.ml2.drivers.cisco.dfa import projects_cache_db_v2 -from neutron.tests import base - - -FAKE_NETWORK_NAME = 'test_dfa_network' -FAKE_NETWORK_ID = '949fdd05-a26a-4819-a829-9fc2285de6ff' -FAKE_CFG_PROF_ID = '8c30f360ffe948109c28ab56f69a82e1' -FAKE_SEG_ID = 12345 -FAKE_PROJECT_NAME = 'test_dfa_project' -FAKE_PROJECT_ID = 'aee5da7e699444889c662cf7ec1c8de7' -FAKE_CFG_PROFILE_NAME = 'defaultNetworkL2Profile' -FAKE_INSTANCE_NAME = 'test_dfa_instance' -FAKE_SUBNET_ID = '1a3c5ee1-cb92-4fd8-bff1-8312ac295d64' -FAKE_PORT_ID = 'ea0d92cf-d0cb-4ed2-bbcf-ed7c6aaea4cb' -FAKE_DEVICE_ID = '20305657-78b7-48f4-a7cd-1edf3edbfcad' -FAKE_SECURITY_GRP_ID = '4b5b387d-cf21-4594-b926-f5a5c602295f' -FAKE_MAC_ADDR = 'fa:16:3e:70:15:c4' -FAKE_IP_ADDR = '23.24.25.4' -FAKE_GW_ADDR = '23.24.25.1' -FAKE_DHCP_IP_RANGE_START = '23.24.25.2' -FAKE_DHCP_IP_RANGE_END = '23.24.25.254' -FAKE_HOST_ID = 'test_dfa_host' -FAKE_FWD_MODE = 'proxy-gateway' -FAKE_DCNM_USER = 'cisco' -FAKE_DCNM_PASS = 'password' -FAKE_DCNM_IP = '1.1.2.2' - - -class FakeNetworkContext(object): - """Network context for testing purposes only.""" - - def __init__(self, network): - self._network = network - self._session = None - - @property - def current(self): - return self._network - - @property - def original(self): - return self._network - - -class FakePortContext(object): - """Port context for testing purposes only.""" - - def __init__(self, plugin_context, port): - self._port = port - self._plugin_context = plugin_context - self._session = None - - @property - def current(self): - return self._port - - -class FakeSubnetContext(object): - """Subnet context for testing purposes only.""" - - def __init__(self, subnet): - self._subnet = subnet - - @property - def current(self): - return self._subnet - - -class TestCiscoDFAMechDriver(base.BaseTestCase): - """Test cases for cisco DFA mechanism driver.""" - - def setUp(self): - super(TestCiscoDFAMechDriver, self).setUp() - - dcnmpatcher = mock.patch(cisco_dfa_rest.__name__ + '.DFARESTClient') - self.mdcnm = dcnmpatcher.start() - - # Define retrun values for keystone project. - keys_patcher = mock.patch(project_events.__name__ + '.EventsHandler') - self.mkeys = keys_patcher.start() - - inst_api_patcher = mock.patch(dfa_instance_api.__name__ + - '.DFAInstanceAPI') - self.m_inst_api = inst_api_patcher.start() - - proj_patcher = mock.patch(projects_cache_db_v2.__name__ + - '.ProjectsInfoCache') - self.mock_proj = proj_patcher.start() - - dfa_cfg_patcher = mock.patch(config.__name__ + '.CiscoDFAConfig') - self.m_dfa_cfg = dfa_cfg_patcher.start() - ml2_cisco_dfa_opts = {'dcnm_password': FAKE_DCNM_PASS, - 'dcnm_user': FAKE_DCNM_USER, - 'dcnm_ip': FAKE_DCNM_IP} - for opt, val in ml2_cisco_dfa_opts.items(): - cfg.CONF.set_override(opt, val, 'ml2_cisco_dfa') - - self.dfa_mech_drvr = mech_cisco_dfa.CiscoDfaMechanismDriver() - self.dfa_mech_drvr.initialize() - self.dfa_mech_drvr._keys.is_valid_project.return_value = True - self.net_context = self._create_network_context() - self.proj_info = projects_cache_db_v2.ProjectsInfoCache() - - def _create_network_context(self): - net_info = {'name': FAKE_NETWORK_NAME, - 'tenant_id': FAKE_PROJECT_ID, - 'dfa:cfg_profile_id': FAKE_CFG_PROF_ID, - 'provider:segmentation_id': FAKE_SEG_ID, - 'id': FAKE_NETWORK_ID} - net_context = FakeNetworkContext(net_info) - net_context._plugin_context = mock.MagicMock() - net_context._session = net_context._plugin_context.session - return net_context - - def _create_subnet_context(self): - subnet_info = { - 'ipv6_ra_mode': None, - 'allocation_pools': [{'start': FAKE_DHCP_IP_RANGE_START, - 'end': FAKE_DHCP_IP_RANGE_END}], - 'host_routes': [], - 'ipv6_address_mode': None, - 'cidr': '23.24.25.0/24', - 'id': FAKE_SUBNET_ID, - 'name': u'', - 'enable_dhcp': True, - 'network_id': FAKE_NETWORK_ID, - 'tenant_id': FAKE_PROJECT_ID, - 'dns_nameservers': [], - 'gateway_ip': FAKE_GW_ADDR, - 'ip_version': 4, - 'shared': False} - subnet_context = FakeSubnetContext(subnet_info) - subnet_context._plugin_context = mock.MagicMock() - return subnet_context - - def _create_port_context(self): - port_info = { - 'status': 'ACTIVE', - 'binding:host_id': FAKE_HOST_ID, - 'allowed_address_pairs': [], - 'extra_dhcp_opts': [], - 'device_owner': u'compute:nova', - 'binding:profile': {}, - 'fixed_ips': [{'subnet_id': FAKE_SUBNET_ID, - 'ip_address': FAKE_IP_ADDR}], - 'id': FAKE_PORT_ID, - 'security_groups': [FAKE_SECURITY_GRP_ID], - 'device_id': FAKE_DEVICE_ID, - 'name': u'', - 'admin_state_up': True, - 'network_id': FAKE_NETWORK_ID, - 'tenant_id': FAKE_PROJECT_ID, - 'binding:vif_details': {u'port_filter': True, - u'ovs_hybrid_plug': True}, - 'binding:vnic_type': u'normal', - 'binding:vif_type': u'ovs', - 'mac_address': FAKE_MAC_ADDR} - port_context = FakePortContext(mock.MagicMock(), port_info) - port_context._plugin_context = mock.MagicMock() - port_context._session = port_context._plugin_context.session - return port_context - - def test_create_network_postcommit_no_profile(self): - query = self.net_context._session.query.return_value - query.filter_by.return_value.one.return_value = None - # Profile does not exist, catch the exception. - with testtools.ExpectedException(n_exc.BadRequest): - self.dfa_mech_drvr.create_network_postcommit(self.net_context) - - def test_create_network_postcommit_no_project(self): - self.proj_info.get_project_name.side_effect = ( - dexc.ProjectIdNotFound(project_id=FAKE_PROJECT_ID)) - # Project does not exist, catch the exception. - with testtools.ExpectedException(dexc.ProjectIdNotFound): - self.dfa_mech_drvr.create_network_postcommit(self.net_context) - - def test_delete_network_postcommit(self): - self.dfa_mech_drvr.delete_network_postcommit(self.net_context) - self.mdcnm.delete_network.return_value = None - self.assertTrue(self.dfa_mech_drvr._dcnm_client.delete_network.called) - - def test_create_subnet_postcommit(self): - subnet_ctxt = self._create_subnet_context() - proj_obj = self.dfa_mech_drvr.projects_cache_db_v2 - cfgp_mock = mock.MagicMock(return_value=FAKE_CFG_PROFILE_NAME) - self.dfa_mech_drvr.get_config_profile_name = cfgp_mock - mechdrvr_mock = mock.MagicMock(return_value=self.net_context.current) - self.dfa_mech_drvr.get_network_entry = mechdrvr_mock - proj_obj.get_network_segid.return_value = FAKE_SEG_ID - proj_obj.get_project_name.return_value = FAKE_PROJECT_NAME - self.dfa_mech_drvr.create_subnet_postcommit(subnet_ctxt) - self.assertTrue(self.dfa_mech_drvr._dcnm_client.create_network.called) - - def test_update_port_postcommit(self): - port_ctxt = self._create_port_context() - query = port_ctxt._session.query.return_value - query.filter_by.return_value.one.return_value.forwarding_mode = ( - FAKE_FWD_MODE) - vm_info = { - 'status': 'up', - 'ip': port_ctxt.current.get('fixed_ips')[0]['ip_address'], - 'mac': port_ctxt.current.get('mac_address'), - 'segid': FAKE_SEG_ID, - 'inst_name': FAKE_INSTANCE_NAME, - 'inst_uuid': port_ctxt.current.get('device_id').replace('-', ''), - 'host': FAKE_HOST_ID, - 'port_id': port_ctxt.current.get('id'), - 'network_id': port_ctxt.current.get('network_id'), - 'oui_type': 'cisco', - } - self.proj_info.get_network_segid.return_value = FAKE_SEG_ID - mechdrvr_mock = self.dfa_mech_drvr._inst_api.get_instance_for_uuid - mechdrvr_mock.return_value = FAKE_INSTANCE_NAME - self.dfa_mech_drvr.dfa_notifier = mock.MagicMock() - self.dfa_mech_drvr.update_port_postcommit(port_ctxt) - self.assertTrue(self.dfa_mech_drvr.dfa_notifier.send_vm_info.called) - self.dfa_mech_drvr.dfa_notifier.send_vm_info.assert_called_with( - port_ctxt._plugin_context, vm_info) - - def test_delete_port_postcommit(self): - port_ctxt = self._create_port_context() - query = port_ctxt._session.query.return_value - query.filter_by.return_value.one.return_value.forwarding_mode = ( - FAKE_FWD_MODE) - vm_info = { - 'status': 'down', - 'ip': port_ctxt.current.get('fixed_ips')[0]['ip_address'], - 'mac': port_ctxt.current.get('mac_address'), - 'segid': FAKE_SEG_ID, - 'inst_name': FAKE_INSTANCE_NAME, - 'inst_uuid': port_ctxt.current.get('device_id').replace('-', ''), - 'host': FAKE_HOST_ID, - 'port_id': port_ctxt.current.get('id'), - 'network_id': port_ctxt.current.get('network_id'), - 'oui_type': 'cisco', - } - self.proj_info.get_network_segid.return_value = FAKE_SEG_ID - instapi_mock = self.dfa_mech_drvr._inst_api.get_instance_for_uuid - instapi_mock.return_value = FAKE_INSTANCE_NAME - self.dfa_mech_drvr.dfa_notifier = mock.MagicMock() - self.dfa_mech_drvr.delete_port_postcommit(port_ctxt) - self.assertTrue(self.dfa_mech_drvr.dfa_notifier.send_vm_info.called) - self.dfa_mech_drvr.dfa_notifier.send_vm_info.assert_called_with( - port_ctxt._plugin_context, vm_info) diff --git a/setup.cfg b/setup.cfg index 6e4f50f73fa..019ee672036 100644 --- a/setup.cfg +++ b/setup.cfg @@ -169,7 +169,6 @@ neutron.ml2.mechanism_drivers = arista = neutron.plugins.ml2.drivers.arista.mechanism_arista:AristaDriver cisco_nexus = neutron.plugins.ml2.drivers.cisco.nexus.mech_cisco_nexus:CiscoNexusMechanismDriver cisco_apic = neutron.plugins.ml2.drivers.cisco.apic.mechanism_apic:APICMechanismDriver - cisco_dfa = neutron.plugins.ml2.drivers.cisco.dfa.mech_cisco_dfa:CiscoDfaMechanismDriver l2population = neutron.plugins.ml2.drivers.l2pop.mech_driver:L2populationMechanismDriver bigswitch = neutron.plugins.ml2.drivers.mech_bigswitch.driver:BigSwitchMechanismDriver ofagent = neutron.plugins.ml2.drivers.mech_ofagent:OfagentMechanismDriver