# 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.
# 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
+++ /dev/null
-# 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')
"""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
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
+++ /dev/null
-# 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)
+++ /dev/null
-# 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)
+++ /dev/null
-# 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
+++ /dev/null
-# 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'
+++ /dev/null
-# 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.")
+++ /dev/null
-# 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
+++ /dev/null
-# 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)
+++ /dev/null
-# 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))
+++ /dev/null
-# 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)
+++ /dev/null
-# 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
+++ /dev/null
-# 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']
+++ /dev/null
-# 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)
+++ /dev/null
-# 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)
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