From d365ae3ac15dc575013ed8f7adfa0f6c8d524d09 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 8 Jul 2011 09:34:04 -0700 Subject: [PATCH 01/48] Initial checkin for the L2-Network Plugin with all the associated modules and artifacts. --- quantum/plugins.ini | 2 +- quantum/plugins/cisco/README | 78 ++++ quantum/plugins/cisco/cisco_configuration.py | 87 +++++ quantum/plugins/cisco/cisco_constants.py | 46 +++ quantum/plugins/cisco/cisco_credentials.py | 73 ++++ quantum/plugins/cisco/cisco_exceptions.py | 52 +++ quantum/plugins/cisco/cisco_nexus_plugin.py | 152 ++++++++ quantum/plugins/cisco/cisco_ucs.py | 102 +++++ .../plugins/cisco/cisco_ucs_network_driver.py | 256 +++++++++++++ quantum/plugins/cisco/cisco_ucs_plugin.py | 294 +++++++++++++++ quantum/plugins/cisco/cisco_utils.py | 59 +++ quantum/plugins/cisco/get-vif.sh | 15 + quantum/plugins/cisco/l2network_plugin.py | 348 ++++++++++++++++++ 13 files changed, 1563 insertions(+), 1 deletion(-) create mode 100644 quantum/plugins/cisco/README create mode 100644 quantum/plugins/cisco/cisco_configuration.py create mode 100644 quantum/plugins/cisco/cisco_constants.py create mode 100644 quantum/plugins/cisco/cisco_credentials.py create mode 100644 quantum/plugins/cisco/cisco_exceptions.py create mode 100644 quantum/plugins/cisco/cisco_nexus_plugin.py create mode 100644 quantum/plugins/cisco/cisco_ucs.py create mode 100644 quantum/plugins/cisco/cisco_ucs_network_driver.py create mode 100644 quantum/plugins/cisco/cisco_ucs_plugin.py create mode 100644 quantum/plugins/cisco/cisco_utils.py create mode 100755 quantum/plugins/cisco/get-vif.sh create mode 100644 quantum/plugins/cisco/l2network_plugin.py diff --git a/quantum/plugins.ini b/quantum/plugins.ini index 307d2b48d2..60db782d0c 100644 --- a/quantum/plugins.ini +++ b/quantum/plugins.ini @@ -1,3 +1,3 @@ [PLUGIN] # Quantum plugin provider module -provider = quantum.plugins.SamplePlugin.FakePlugin +provider = quantum.plugins.cisco.l2network_plugin.L2Network diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README new file mode 100644 index 0000000000..fcc50018f9 --- /dev/null +++ b/quantum/plugins/cisco/README @@ -0,0 +1,78 @@ + L2 Network Plugin +================== + +*** Current support for UCS (blade servers) with M81KR VIC (Palo) for 802.1Qbh *** + +** Pre-requisities +* UCS B200 series blades with M81KR VIC installed. +* UCSM 2.0 (Capitola) Build 230 +* RHEL 6.1 +* UCS & VIC installation (support for KVM) - please consult the accompanying installation guide available at: +http://wikicentral.cisco.com/display/GROUP/SAVBU+Palo+VM-FEX+for+Linux+KVM +* To run Quantum on RHEL, you will need to have the correct version of python-routes (version 1.12.3 or later). The RHEL 6.1 package contains an older version. Do the following and check your python-routes version: +rpm -qav | grep "python-routes" + +If it's an older version, you will need to upgrade to 1.12.3 or later. One quick way to do it as by adding the following to your /etc/yum.repos.d/openstack.repo (assuming that you had installed OpenStack on this host, and hence had this repo; else you could add to any other operational repo config), and then update the python-routes package. That should get you the python-routes-1.12.3-2.el6.noarch package. + +[openstack-deps] +name=OpenStack Nova Compute Dependencies +baseurl=http://yum.griddynamics.net/yum/cactus/deps +enabled=1 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OPENSTACK + + +** Plugin Installation Instructions: +* Make a backup copy of quantum/quantum/plugins.ini, and edit the file to remove all exisiting entries and add the following entry: +provider = quantum.plugins.cisco.l2network_plugin.L2Network +* You should have the following files in quantum/quantum/plugins/cisco directory (if you have pulled the Cisco Quantum branch, you will already have them): +l2network_plugin.py +cisco_configuration.py +cisco_constants.py +cisco_credentials.py +cisco_exceptions.py +cisco_nexus_network_driver.py +cisco_ucs_network_driver.py +cisco_ucs_plugin.py +cisco_utils.py +__init__.py +get-vif.sh +* Configure the L2 Network Pllugin: + + In cisco_configuration.py, + - change the UCSM IP in the following statement to your UCSM IP + flags.DEFINE_string('ucsm_ip_address', "172.20.231.27", 'IP address of UCSM') + - change the Nova MySQL DB IP if you are running Quantum on a different host than the OpenStack Cloud Controller (in other words you do not need to change the IP if Quantum is running on the same host on which the Nova DB is running). DB IP is changed in the following statement: + flags.DEFINE_string('db_server_ip', "127.0.0.1", 'IP address of nova DB server') + - change the hostname of the OpenStack Cloud Controller below + flags.DEFINE_string('nova_host_name', "openstack-0203", 'nova cloud controller hostname') + - change the name of the OpenStack project + flags.DEFINE_string('nova_proj_name', "demo", 'project created in nova') + - change the start range of the VLAN (if you are not sure about this number, leave this unchanged) + flags.DEFINE_string('vlan_start', "100", 'This is the start value of the allowable VLANs') + - change the end range of the VLAN (if you are not sure about this number, leave this unchanged) + flags.DEFINE_string('vlan_end', "3000", 'This is the end value of the allowable VLANs') + - unless you have VLANs created in UCSM which start with the name "q-", you do not need to change the following property. If you do need to change it, change "q-" to some other string. Do not use more than 6 characters. + flags.DEFINE_string('vlan_name_prefix', "q-", 'Prefix of the name given to the VLAN') + - unless you have Port Profiles created in UCSM which start with the name "q-", you do not need to change the following property. If you do need to change it, change "q-" to some other string. Do not use more than 6 characters. + flags.DEFINE_string('profile_name_prefix', "q-", 'Prefix of the name given to the port profile') + - Change the path to reflect the location of the get-vif.sh script, if you have followed the instructions in this README, this location should be the same as that of your other plugin modules + flags.DEFINE_string('get_next_vif', "/root/sumit/quantum/quantum/plugins/cisco/get-vif.sh", 'This is the location of the script to get the next available dynamic nic') + + In cisco_credentials.py, + - Change the following stucture to reflect the correct UCS and Nova DB details. Your UCSM_IP_ADDRESS has to match the ucsmm_ip_addresss which you provided in the cisco_configuration file earlier. Similarly, your NOVA_DATABSE_IP has to match the db_server_ip which you provided earlier. DB_USERNAME and DB_PASSWORD are those which you provided for the Nova MySQL DB when you setup OpenStack + _creds_dictionary = { + 'UCSM_IP_ADDRESS':["UCSM_USERNAME", "UCSM_PASSWORD"], + 'NOVA_DATABASE_IP':["DB_USERNAME", "DB_PASSWORD"] + } +* Start the Quantum service + +** Additional installation required on Nova Compute: +* Create DB Table in Nova DB (On the Cloud Controller) +mysql -uroot -p nova -e 'create table ports (port_id VARCHAR(255) primary key, profile_name VARCHAR(255), dynamic_vnic VARCHAR(255), host VARCHAR(255), instance_name VARCHAR(255), instance_nic_name VARCHAR(255), used tinyint(1));' + +* Replace the following files with the files from the Cisco Nova branch: +/usr/lib/python2.6/site-packages/nova/virt/libvirt_conn.py + +* Add the following files from the Cisco Nova branch: +/usr/lib/python2.6/site-packages/nova/virt/cisco_ucs.py + +* Restart nova-compute service diff --git a/quantum/plugins/cisco/cisco_configuration.py b/quantum/plugins/cisco/cisco_configuration.py new file mode 100644 index 0000000000..5ab2aaf336 --- /dev/null +++ b/quantum/plugins/cisco/cisco_configuration.py @@ -0,0 +1,87 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# +from quantum.common import flags + +# Note: All configuration values defined here are strings +FLAGS = flags.FLAGS +# +# TODO (Sumit): The following are defaults, but we also need to add to config +# file +# +flags.DEFINE_string('ucsm_ip_address', "172.20.231.27", 'IP address of \ + UCSM') +flags.DEFINE_string('db_server_ip', "127.0.0.1", 'IP address of nova DB \ + server') +flags.DEFINE_string('nova_host_name', "openstack-0203", 'nova cloud \ + controller hostname') + +flags.DEFINE_string('db_name', "nova", 'DB name') +flags.DEFINE_string('vlan_name_prefix', "q-", 'Prefix of the name given \ + to the VLAN') +flags.DEFINE_string('profile_name_prefix', "q-", 'Prefix of the name \ + given to the port profile') +flags.DEFINE_string('vlan_start', "100", 'This is the start value of the \ + allowable VLANs') +flags.DEFINE_string('vlan_end', "3000", 'This is the end value of the \ + allowable VLANs') +flags.DEFINE_string('default_vlan_name', "default", 'This is the name of \ + the VLAN which will be associated with the port profile \ + when it is created, by default the VMs will be on this \ + VLAN, until attach is called') +flags.DEFINE_string('default_vlan_id', "1", 'This is the name of the VLAN \ + which will be associated with the port profile when it \ + is created, by default the VMs will be on this VLAN, \ + until attach is called') +flags.DEFINE_string('nova_proj_name', "demo", 'project created in nova') +# +# TODO (Sumit): SAVBU to provide the accurate number below +# +flags.DEFINE_string('max_ucsm_port_profiles', "1024", 'This is the maximum \ + number port profiles that can be handled by one UCSM.') +flags.DEFINE_string('max_port_profiles', "65568", 'This is the maximum \ + number port profiles that can be handled by Cisco \ + plugin. Currently this is just an arbitrary number.') +flags.DEFINE_string('max_networks', "65568", 'This is the maximum number \ + of networks that can be handled by Cisco plugin. \ + Currently this is just an arbitrary number.') + +flags.DEFINE_string('get_next_vif', + "/root/sumit/quantum/quantum/plugins/cisco/get-vif.sh", + 'This is the location of the script to get the next \ + next available dynamic nic') + +# Inventory items +UCSM_IP_ADDRESS = FLAGS.ucsm_ip_address +DB_SERVER_IP = FLAGS.db_server_ip +NOVA_HOST_NAME = FLAGS.nova_host_name + +# General configuration items +DB_NAME = FLAGS.db_name +VLAN_NAME_PREFIX = FLAGS.vlan_name_prefix +PROFILE_NAME_PREFIX = FLAGS.profile_name_prefix +VLAN_START = FLAGS.vlan_start +VLAN_END = FLAGS.vlan_end +DEFAULT_VLAN_NAME = FLAGS.default_vlan_name +DEFAULT_VLAN_ID = FLAGS.default_vlan_id +NOVA_PROJ_NAME = FLAGS.nova_proj_name +MAX_UCSM_PORT_PROFILES = FLAGS.max_ucsm_port_profiles +MAX_PORT_PROFILES = FLAGS.max_port_profiles +MAX_NETWORKS = FLAGS.max_networks + +GET_NEXT_VIF_SCRIPT = FLAGS.get_next_vif diff --git a/quantum/plugins/cisco/cisco_constants.py b/quantum/plugins/cisco/cisco_constants.py new file mode 100644 index 0000000000..115addf423 --- /dev/null +++ b/quantum/plugins/cisco/cisco_constants.py @@ -0,0 +1,46 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +PORT_STATE = 'port-state' +PORT_UP = "UP" +PORT_DOWN = "DOWN" + +ATTACHMENT = 'attachment' +PORT_ID = 'port-id' + +NET_ID = 'net-id' +NET_NAME = 'net-name' +NET_PORTS = 'net-ports' +NET_VLAN_NAME = 'net-vlan-name' +NET_VLAN_ID = 'net-vlan-id' +NET_TENANTS = 'net-tenants' + +TENANT_ID = 'tenant-id' +TENANT_NETWORKS = 'tenant-networks' +TENANT_NAME = 'tenant-name' +TENANT_PORTPROFILES = 'tenant-portprofiles' + +PORT_PROFILE = 'port-profile' +PROFILE_ID = 'profile-id' +PROFILE_NAME = 'profile-name' +PROFILE_VLAN_NAME = 'profile-vlan-name' +PROFILE_VLAN_ID = 'profile-vlan-id' +PROFILE_QOS = 'profile-qos' + +LOGGER_COMPONENT_NAME = "cisco_plugin" diff --git a/quantum/plugins/cisco/cisco_credentials.py b/quantum/plugins/cisco/cisco_credentials.py new file mode 100644 index 0000000000..c37d00f1ab --- /dev/null +++ b/quantum/plugins/cisco/cisco_credentials.py @@ -0,0 +1,73 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import logging as LOG + +from quantum.plugins.cisco import cisco_constants as const + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + +_creds_dictionary = { + '172.20.231.27': ["admin", "c3l12345"], + '127.0.0.1': ["root", "nova"] +} + + +class Store(object): + # The format for this store is {"ip-address" :{"username", "password"}} + def __init__(self): + pass + + @staticmethod + def putId(id): + _creds_dictionary[id] = [] + + @staticmethod + def putUsername(id, username): + creds = _creds_dictionary.get(id) + creds.insert(0, username) + + @staticmethod + def putPassword(id, password): + creds = _creds_dictionary.get(id) + creds.insert(1, password) + + @staticmethod + def getUsername(id): + creds = _creds_dictionary.get(id) + return creds[0] + + @staticmethod + def getPassword(id): + creds = _creds_dictionary.get(id) + return creds[1] + + +def main(): + LOG.debug("username %s\n" % Store.getUsername("172.20.231.27")) + LOG.debug("password %s\n" % Store.getPassword("172.20.231.27")) + Store.putId("192.168.1.1") + Store.putUsername("192.168.1.1", "guest-username") + Store.putPassword("192.168.1.1", "guest-password") + LOG.debug("username %s\n" % Store.getUsername("192.168.1.1")) + LOG.debug("password %s\n" % Store.getPassword("192.168.1.1")) + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/cisco_exceptions.py b/quantum/plugins/cisco/cisco_exceptions.py new file mode 100644 index 0000000000..2829329c85 --- /dev/null +++ b/quantum/plugins/cisco/cisco_exceptions.py @@ -0,0 +1,52 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +""" +Exceptions used by the Cisco plugin +""" + +from quantum.common import exceptions + + +class NoMoreNics(exceptions.QuantumException): + message = _("Unable to complete operation on port %(port_id)s " \ + "for network %(net_id)s. No more dynamic nics are available" \ + "in the system.") + + +class PortProfileLimit(exceptions.QuantumException): + message = _("Unable to complete operation on port %(port_id)s " \ + "for network %(net_id)s. The system has reached the maximum" \ + "limit of allowed port profiles.") + + +class UCSMPortProfileLimit(exceptions.QuantumException): + message = _("Unable to complete operation on port %(port_id)s " \ + "for network %(net_id)s. The system has reached the maximum" \ + "limit of allowed UCSM port profiles.") + + +class NetworksLimit(exceptions.QuantumException): + message = _("Unable to create new network. Number of networks" \ + "for the system has exceeded the limit") + + +class PortProfileNotFound(exceptions.QuantumException): + message = _("Port profile %(port_id)s could not be found " \ + "for tenant %(tenant_id)s") diff --git a/quantum/plugins/cisco/cisco_nexus_plugin.py b/quantum/plugins/cisco/cisco_nexus_plugin.py new file mode 100644 index 0000000000..545499fe9b --- /dev/null +++ b/quantum/plugins/cisco/cisco_nexus_plugin.py @@ -0,0 +1,152 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# +import logging as LOG + +from quantum.common import exceptions as exc +from quantum.plugins.cisco import cisco_configuration as conf +from quantum.plugins.cisco import cisco_constants as const +from quantum.plugins.cisco import cisco_credentials as cred +from quantum.plugins.cisco import cisco_exceptions as cexc +from quantum.plugins.cisco import cisco_utils as cutil + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + + +class NexusPlugin(object): + _networks = {} + + def __init__(self): + """ + Initialize the Nexus driver here + """ + pass + + def get_all_networks(self, tenant_id): + """ + Returns a dictionary containing all + for + the specified tenant. + """ + LOG.debug("NexusPlugin:get_all_networks() called\n") + return self._networks.values() + + def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id): + """ + Create a VLAN in the switch, and configure the appropriate interfaces + for this VLAN + """ + LOG.debug("NexusPlugin:create_network() called\n") + # TODO (Sumit): Call the nexus driver here to create the VLAN, and + # configure the appropriate interfaces + new_net_dict = {const.NET_ID: net_id, + const.NET_NAME: net_name, + const.NET_PORTS: {}, + const.NET_VLAN_NAME: vlan_name, + const.NET_VLAN_ID: vlan_id} + self._networks[net_id] = new_net_dict + return new_net_dict + + def delete_network(self, tenant_id, net_id): + """ + Deletes a VLAN in the switch, and removes the VLAN configuration + from the relevant interfaces + """ + LOG.debug("NexusPlugin:delete_network() called\n") + net = self._networks.get(net_id) + if net: + # TODO (Sumit): Call the nexus driver here to create the VLAN, + # and configure the appropriate interfaces + self._networks.pop(net_id) + return net + # Network not found + raise exc.NetworkNotFound(net_id=net_id) + + def get_network_details(self, tenant_id, net_id): + """ + Returns the details of a particular network + """ + LOG.debug("NexusPlugin:get_network_details() called\n") + network = self._get_network(tenant_id, net_id) + return network + + def rename_network(self, tenant_id, net_id, new_name): + """ + Updates the symbolic name belonging to a particular + Virtual Network. + """ + LOG.debug("NexusPlugin:rename_network() called\n") + network = self._get_network(tenant_id, net_id) + network[const.NET_NAME] = new_name + return network + + def get_all_ports(self, tenant_id, net_id): + """ + This is probably not applicable to the Nexus plugin. + Delete if not required. + """ + LOG.debug("NexusPlugin:get_all_ports() called\n") + + def create_port(self, tenant_id, net_id, port_state, port_id): + """ + This is probably not applicable to the Nexus plugin. + Delete if not required. + """ + LOG.debug("NexusPlugin:create_port() called\n") + + def delete_port(self, tenant_id, net_id, port_id): + """ + This is probably not applicable to the Nexus plugin. + Delete if not required. + """ + LOG.debug("NexusPlugin:delete_port() called\n") + + def update_port(self, tenant_id, net_id, port_id, port_state): + """ + This is probably not applicable to the Nexus plugin. + Delete if not required. + """ + LOG.debug("NexusPlugin:update_port() called\n") + + def get_port_details(self, tenant_id, net_id, port_id): + """ + This is probably not applicable to the Nexus plugin. + Delete if not required. + """ + LOG.debug("NexusPlugin:get_port_details() called\n") + + def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id): + """ + This is probably not applicable to the Nexus plugin. + Delete if not required. + """ + LOG.debug("NexusPlugin:plug_interface() called\n") + + def unplug_interface(self, tenant_id, net_id, port_id): + """ + This is probably not applicable to the Nexus plugin. + Delete if not required. + """ + LOG.debug("NexusPlugin:unplug_interface() called\n") + + def _get_network(self, tenant_id, network_id): + network = self._networks.get(network_id) + if not network: + raise exc.NetworkNotFound(net_id=network_id) + return network diff --git a/quantum/plugins/cisco/cisco_ucs.py b/quantum/plugins/cisco/cisco_ucs.py new file mode 100644 index 0000000000..0723da9f0a --- /dev/null +++ b/quantum/plugins/cisco/cisco_ucs.py @@ -0,0 +1,102 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# +# + +import MySQLdb +import sys, traceback + +from nova import flags +from nova import log as logging + +FLAGS = flags.FLAGS +LOG = logging.getLogger('nova.virt.libvirt_conn') +# +# TODO (Sumit): The following are defaults, but we might need to make it conf file driven as well +# + +flags.DEFINE_string('db_server_ip', "127.0.0.1", 'IP address of nova DB server') +flags.DEFINE_string('db_username', "root", 'DB username') +flags.DEFINE_string('db_password', "nova", 'DB paswwprd') +flags.DEFINE_string('db_name', "nova", 'DB name') +flags.DEFINE_string('nova_proj_name', "demo", 'project created in nova') +flags.DEFINE_string('nova_host_name', "openstack-0203", 'nova cloud controller hostname') + +class CiscoUCSComputeDriver(object): + def __init__(self): + pass + + def _get_db_connection(self): + self.db = MySQLdb.connect(FLAGS.db_server_ip, FLAGS.db_username, FLAGS.db_password, FLAGS.db_name) + return self.db + + def _execute_db_query(self, sql_query): + db = self._get_db_connection() + cursor = db.cursor() + try: + cursor.execute(sql_query) + results = cursor.fetchall() + db.commit() + print "DB query execution succeeded: %s" % sql_query + except: + db.rollback() + print "DB query execution failed: %s" % sql_query + traceback.print_exc() + db.close() + return results + + def reserve_port(self, instance_name, instance_nic_name): + sql_query = "SELECT * from ports WHERE used='0'" + results = self._execute_db_query(sql_query) + if len(results) == 0: + print "No ports available/n" + return 0 + else: + for row in results: + port_id = row[0]; + sql_query = "UPDATE ports SET instance_name = '%s', instance_nic_name = '%s' WHERE port_id = '%s'" % (instance_name, instance_nic_name, port_id) + results = self._execute_db_query(sql_query) + return port_id; + return 0 + + def get_port_details(self, port_id): + port_details = {} + sql_query = "SELECT * from ports WHERE port_id='%s'" % (port_id) + results = self._execute_db_query(sql_query) + if len(results) == 0: + print "Could not fetch port from DB for port_id = %s/n" % port_id + return + else: + for row in results: + profile_name = row[1]; + dynamic_vnic = row[2]; + sql_query = "UPDATE ports SET used = %d WHERE port_id = '%s'" % (1, port_id) + results = self._execute_db_query(sql_query) + port_details = {'profile_name':profile_name, 'dynamic_vnic':dynamic_vnic} + return port_details; + + def release_port(self, instance_name, instance_nic_name): + sql_query = "SELECT * from ports WHERE instance_name='%s' and instance_nic_name='%s'" % (instance_name, instance_nic_name) + results = self._execute_db_query(sql_query) + if len(results) == 0: + print "No matching ports found for releasing/n" + return 0 + else: + for row in results: + port_id = row[0]; + sql_query = "UPDATE ports SET instance_name = NULL, instance_nic_name = NULL, used = 0 WHERE port_id = '%s'" % (port_id) + results = self._execute_db_query(sql_query) + return port_id; + return 0 + +def main(): + client = CiscoUCSComputeDriver() + port_id = client.reserve_port("instance-1", "eth1") + port_details = client.get_port_details(port_id) + print "profile_name %s dynamic_vnic %s\n" % (port_details['profile_name'], port_details['dynamic_vnic']) + port_id = client.release_port("instance-1", "eth1") + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/cisco_ucs_network_driver.py b/quantum/plugins/cisco/cisco_ucs_network_driver.py new file mode 100644 index 0000000000..ca912edf92 --- /dev/null +++ b/quantum/plugins/cisco/cisco_ucs_network_driver.py @@ -0,0 +1,256 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems Inc. +# +""" +Implements a UCSM XML API Client +""" + +import httplib +import logging as LOG +import string +import subprocess +from xml.etree import ElementTree as et +import urllib + +from quantum.plugins.cisco import cisco_configuration as conf +from quantum.plugins.cisco import cisco_constants as const +from quantum.plugins.cisco import cisco_exceptions as cexc + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + +COOKIE_VALUE = "cookie_placeholder" +PROFILE_NAME = "profilename_placeholder" +PROFILE_CLIENT = "profileclient_placeholder" +VLAN_NAME = "vlanname_placeholder" +VLAN_ID = "vlanid_placeholder" +OLD_VLAN_NAME = "old_vlanname_placeholder" +DYNAMIC_NIC_PREFIX = "eth" + +# The following are standard strings, messages used to communicate with UCSM, +#only place holder values change for each message +HEADERS = {"Content-Type": "text/xml"} +METHOD = "POST" +URL = "/nuova" + +CREATE_VLAN = " " \ +" " \ +" " + +CREATE_PROFILE = " " \ +" " \ +" " \ +" " + +ASSOCIATE_PROFILE = " " \ +" " + +CHANGE_VLAN_IN_PROFILE = " " \ +" " \ +" " \ +" " + +DELETE_VLAN = " " \ +" " \ +"" + +DELETE_PROFILE = " " \ +" " \ +" " + + +class CiscoUCSMDriver(): + + def __init__(self): + pass + + def _post_data(self, ucsm_ip, ucsm_username, ucsm_password, data): + conn = httplib.HTTPConnection(ucsm_ip) + login_data = "" + conn.request(METHOD, URL, login_data, HEADERS) + response = conn.getresponse() + response_data = response.read() + LOG.debug(response.status) + LOG.debug(response.reason) + LOG.debug(response_data) + # TODO (Sumit): If login is not successful, throw exception + xmlTree = et.XML(response_data) + cookie = xmlTree.attrib["outCookie"] + + data = data.replace(COOKIE_VALUE, cookie) + LOG.debug("POST: %s" % data) + conn.request(METHOD, URL, data, HEADERS) + response = conn.getresponse() + response_data = response.read() + LOG.debug(response.status) + LOG.debug(response.reason) + LOG.debug("UCSM Response: %s" % response_data) + + logout_data = "" + conn.request(METHOD, URL, logout_data, HEADERS) + response = conn.getresponse() + response_data = response.read() + LOG.debug(response.status) + LOG.debug(response.reason) + LOG.debug(response_data) + + def _create_vlan_post_data(self, vlan_name, vlan_id): + data = CREATE_VLAN.replace(VLAN_NAME, vlan_name) + data = data.replace(VLAN_ID, vlan_id) + return data + + def _create_profile_post_data(self, profile_name, vlan_name): + data = CREATE_PROFILE.replace(PROFILE_NAME, profile_name) + data = data.replace(VLAN_NAME, vlan_name) + return data + + def _create_profile_client_post_data(self, profile_name): + data = ASSOCIATE_PROFILE.replace(PROFILE_NAME, profile_name) + data = data.replace(PROFILE_CLIENT, profile_name) + return data + + def _change_vlan_in_profile_post_data(self, profile_name, old_vlan_name, + new_vlan_name): + data = CHANGE_VLAN_IN_PROFILE.replace(PROFILE_NAME, profile_name) + data = data.replace(OLD_VLAN_NAME, old_vlan_name) + data = data.replace(VLAN_NAME, new_vlan_name) + return data + + def _delete_vlan_post_data(self, vlan_name): + data = DELETE_VLAN.replace(VLAN_NAME, vlan_name) + return data + + def _delete_profile_post_data(self, profile_name): + data = DELETE_PROFILE.replace(PROFILE_NAME, profile_name) + return data + + def _get_next_dynamic_nic(self): + # TODO (Sumit): following should be a call to a python module + # (which will in turn eliminate the reference to the path and script) + dynamic_nic_id = string.strip(subprocess.Popen( + conf.GET_NEXT_VIF_SCRIPT, + stdout=subprocess.PIPE).communicate()[0]) + if len(dynamic_nic_id) > 0: + return dynamic_nic_id + else: + raise cisco_exceptions.NoMoreNics(net_id=net_id, port_id=port_id) + + def create_vlan(self, vlan_name, vlan_id, ucsm_ip, ucsm_username, + ucsm_password): + data = self._create_vlan_post_data(vlan_name, vlan_id) + self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) + + def create_profile(self, profile_name, vlan_name, ucsm_ip, ucsm_username, + ucsm_password): + data = self._create_profile_post_data(profile_name, vlan_name) + self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) + data = self._create_profile_client_post_data(profile_name) + self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) + + def change_vlan_in_profile(self, profile_name, old_vlan_name, + new_vlan_name, ucsm_ip, ucsm_username, + ucsm_password): + data = self._change_vlan_in_profile_post_data(profile_name, + old_vlan_name, + new_vlan_name) + self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) + + def get_dynamic_nic(self, host): + # TODO (Sumit): Check availability per host + # TODO (Sumit): If not available raise exception + # TODO (Sumit): This simple logic assumes that create-port and + # spawn-VM happens in lock-step + # But we should support multiple create-port calls, + # followed by spawn-VM calls + # That would require managing a pool of available + # dynamic vnics per host + dynamic_nic_name = self._get_next_dynamic_nic() + LOG.debug("Reserving dynamic nic %s" % dynamic_nic_name) + return dynamic_nic_name + + def delete_vlan(self, vlan_name, ucsm_ip, ucsm_username, ucsm_password): + data = self._delete_vlan_post_data(vlan_name) + self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) + + def delete_profile(self, profile_name, ucsm_ip, ucsm_username, + ucsm_password): + data = self._delete_profile_post_data(profile_name) + self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) + + def release_dynamic_nic(self, host): + # TODO (Sumit): Release on a specific host + pass + + +def main(): + client = CiscoUCSMDriver() + #client.create_vlan("quantum-vlan-3", "3","172.20.231.27","admin", + # "c3l12345") + #client.create_profile("q-prof-3", "quantum-vlan-3","172.20.231.27", + # "admin", "c3l12345") + #client.get_dynamic_nic("dummy") + #client.get_dynamic_nic("dummy") + #client.release_dynamic_nic("dummy") + #client.get_dynamic_nic("dummy") + #client.change_vlan_in_profile("br100", "default", "test-2", + # "172.20.231.27","admin", + # "c3l12345") + client.change_vlan_in_profile("br100", "test-2", "default", + "172.20.231.27", "admin", "c3l12345") + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/cisco_ucs_plugin.py b/quantum/plugins/cisco/cisco_ucs_plugin.py new file mode 100644 index 0000000000..52195a5552 --- /dev/null +++ b/quantum/plugins/cisco/cisco_ucs_plugin.py @@ -0,0 +1,294 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import logging as LOG + +from quantum.common import exceptions as exc +from quantum.plugins.cisco import cisco_configuration as conf +from quantum.plugins.cisco import cisco_constants as const +from quantum.plugins.cisco import cisco_credentials as cred +from quantum.plugins.cisco import cisco_exceptions as cexc +from quantum.plugins.cisco import cisco_ucs_network_driver +from quantum.plugins.cisco import cisco_utils as cutil + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + + +class UCSVICPlugin(object): + _networks = {} + + def __init__(self): + self._client = cisco_ucs_network_driver.CiscoUCSMDriver() + self._utils = cutil.DBUtils() + # TODO (Sumit) This is for now, when using only one chassis + self._ucsm_ip = conf.UCSM_IP_ADDRESS + self._ucsm_username = cred.Store.getUsername(conf.UCSM_IP_ADDRESS) + self._ucsm_password = cred.Store.getPassword(conf.UCSM_IP_ADDRESS) + # TODO (Sumit) Make the counter per UCSM + self._port_profile_counter = 0 + + def get_all_networks(self, tenant_id): + """ + Returns a dictionary containing all + for + the specified tenant. + """ + LOG.debug("UCSVICPlugin:get_all_networks() called\n") + return self._networks.values() + + def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id): + """ + Creates a new Virtual Network, and assigns it + a symbolic name. + """ + LOG.debug("UCSVICPlugin:create_network() called\n") + self._client.create_vlan(vlan_name, str(vlan_id), self._ucsm_ip, + self._ucsm_username, self._ucsm_password) + new_net_dict = {const.NET_ID: net_id, + const.NET_NAME: net_name, + const.NET_PORTS: {}, + const.NET_VLAN_NAME: vlan_name, + const.NET_VLAN_ID: vlan_id} + self._networks[net_id] = new_net_dict + return new_net_dict + + def delete_network(self, tenant_id, net_id): + """ + Deletes the network with the specified network identifier + belonging to the specified tenant. + """ + LOG.debug("UCSVICPlugin:delete_network() called\n") + net = self._networks.get(net_id) + # TODO (Sumit) : Verify that no attachments are plugged into the + # network + if net: + # TODO (Sumit) : Before deleting the network, make sure all the + # ports associated with this network are also deleted + self._client.delete_vlan(net[const.NET_VLAN_NAME], self._ucsm_ip, + self._ucsm_username, self._ucsm_password) + self._networks.pop(net_id) + return net + raise exc.NetworkNotFound(net_id=net_id) + + def get_network_details(self, tenant_id, net_id): + """ + Deletes the Virtual Network belonging to a the + spec + """ + LOG.debug("UCSVICPlugin:get_network_details() called\n") + network = self._get_network(tenant_id, net_id) + return network + + def rename_network(self, tenant_id, net_id, new_name): + """ + Updates the symbolic name belonging to a particular + Virtual Network. + """ + LOG.debug("UCSVICPlugin:rename_network() called\n") + network = self._get_network(tenant_id, net_id) + network[const.NET_NAME] = new_name + return network + + def get_all_ports(self, tenant_id, net_id): + """ + Retrieves all port identifiers belonging to the + specified Virtual Network. + """ + LOG.debug("UCSVICPlugin:get_all_ports() called\n") + network = self._get_network(tenant_id, net_id) + ports_on_net = network[const.NET_PORTS].values() + return ports_on_net + + def create_port(self, tenant_id, net_id, port_state, port_id): + """ + Creates a port on the specified Virtual Network. + """ + LOG.debug("UCSVICPlugin:create_port() called\n") + net = self._get_network(tenant_id, net_id) + ports = net[const.NET_PORTS] + # TODO (Sumit): This works on a single host deployment, + # in multi-host environment, dummy needs to be replaced with the + # hostname + dynamic_nic_name = self._client.get_dynamic_nic("dummy") + new_port_profile = self._create_port_profile(tenant_id, net_id, + port_id, + conf.DEFAULT_VLAN_NAME, + conf.DEFAULT_VLAN_ID) + profile_name = new_port_profile[const.PROFILE_NAME] + sql_query = "INSERT INTO ports (port_id, profile_name, dynamic_vnic," \ + "host, instance_name, instance_nic_name, used) VALUES" \ + "('%s', '%s', '%s', 'dummy', NULL, NULL, 0)" % \ + (port_id, profile_name, dynamic_nic_name) + self._utils.execute_db_query(sql_query) + new_port_dict = {const.PORT_ID: port_id, + const.PORT_STATE: const.PORT_UP, + const.ATTACHMENT: None, + const.PORT_PROFILE: new_port_profile} + ports[port_id] = new_port_dict + return new_port_dict + + def delete_port(self, tenant_id, net_id, port_id): + """ + Deletes a port on a specified Virtual Network, + if the port contains a remote interface attachment, + the remote interface should first be un-plugged and + then the port can be deleted. + """ + LOG.debug("UCSVICPlugin:delete_port() called\n") + port = self._get_port(tenant_id, net_id, port_id) + if port[const.ATTACHMENT]: + raise exc.PortInUse(net_id=net_id, port_id=port_id, + att_id=port[const.ATTACHMENT]) + try: + #TODO (Sumit): Before deleting port profile make sure that there + # is no VM using this port profile + self._client.release_dynamic_nic("dummy") + port_profile = port[const.PORT_PROFILE] + self._delete_port_profile(port_id, + port_profile[const.PROFILE_NAME]) + sql_query = "delete from ports where port_id = \"%s\"" % \ + (port[const.PORT_ID]) + self._utils.execute_db_query(sql_query) + net = self._get_network(tenant_id, net_id) + net[const.NET_PORTS].pop(port_id) + except KeyError: + raise exc.PortNotFound(net_id=net_id, port_id=port_id) + + def update_port(self, tenant_id, net_id, port_id, port_state): + """ + Updates the state of a port on the specified Virtual Network. + """ + LOG.debug("UCSVICPlugin:update_port() called\n") + port = self._get_port(tenant_id, net_id, port_id) + self._validate_port_state(port_state) + port[const.PORT_STATE] = port_state + return port + + def get_port_details(self, tenant_id, net_id, port_id): + """ + This method allows the user to retrieve a remote interface + that is attached to this particular port. + """ + LOG.debug("UCSVICPlugin:get_port_details() called\n") + return self._get_port(tenant_id, net_id, port_id) + + def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id): + """ + Attaches a remote interface to the specified port on the + specified Virtual Network. + """ + LOG.debug("UCSVICPlugin:plug_interface() called\n") + self._validate_attachment(tenant_id, net_id, port_id, + remote_interface_id) + port = self._get_port(tenant_id, net_id, port_id) + if port[const.ATTACHMENT]: + raise exc.PortInUse(net_id=net_id, port_id=port_id, + att_id=port[const.ATTACHMENT]) + port[const.ATTACHMENT] = remote_interface_id + port_profile = port[const.PORT_PROFILE] + profile_name = port_profile[const.PROFILE_NAME] + old_vlan_name = port_profile[const.PROFILE_VLAN_NAME] + new_vlan_name = self._get_vlan_name_for_network(tenant_id, net_id) + new_vlan_id = self._get_vlan_id_for_network(tenant_id, net_id) + self._client.change_vlan_in_profile(profile_name, old_vlan_name, + new_vlan_name, self._ucsm_ip, + self._ucsm_username, + self._ucsm_password) + port_profile[const.PROFILE_VLAN_NAME] = new_vlan_name + port_profile[const.PROFILE_VLAN_ID] = new_vlan_id + + def unplug_interface(self, tenant_id, net_id, port_id): + """ + Detaches a remote interface from the specified port on the + specified Virtual Network. + """ + LOG.debug("UCSVICPlugin:unplug_interface() called\n") + port = self._get_port(tenant_id, net_id, port_id) + port[const.ATTACHMENT] = None + port_profile = port[const.PORT_PROFILE] + profile_name = port_profile[const.PROFILE_NAME] + old_vlan_name = port_profile[const.PROFILE_VLAN_NAME] + new_vlan_name = conf.DEFAULT_VLAN_NAME + self._client.change_vlan_in_profile(profile_name, old_vlan_name, + new_vlan_name, self._ucsm_ip, + self._ucsm_username, + self._ucsm_password) + port_profile[const.PROFILE_VLAN_NAME] = conf.DEFAULT_VLAN_NAME + port_profile[const.PROFILE_VLAN_ID] = conf.DEFAULT_VLAN_ID + + def _get_profile_name(self, port_id): + profile_name = conf.PROFILE_NAME_PREFIX + port_id + return profile_name + + def _validate_port_state(self, port_state): + if port_state.upper() not in (const.PORT_UP, const.PORT_DOWN): + raise exc.StateInvalid(port_state=port_state) + return True + + def _validate_attachment(self, tenant_id, network_id, port_id, + remote_interface_id): + network = self._get_network(tenant_id, network_id) + for port in network[const.NET_PORTS].values(): + if port[const.ATTACHMENT] == remote_interface_id: + raise exc.AlreadyAttached(net_id=network_id, + port_id=port_id, + att_id=port[const.ATTACHMENT], + att_port_id=port[const.PORT_ID]) + + def _get_network(self, tenant_id, network_id): + network = self._networks.get(network_id) + if not network: + raise exc.NetworkNotFound(net_id=network_id) + return network + + def _get_vlan_name_for_network(self, tenant_id, network_id): + net = self._get_network(tenant_id, network_id) + vlan_name = net[const.NET_VLAN_NAME] + return vlan_name + + def _get_vlan_id_for_network(self, tenant_id, network_id): + net = self._get_network(tenant_id, network_id) + vlan_id = net[const.NET_VLAN_ID] + return vlan_id + + def _get_port(self, tenant_id, network_id, port_id): + net = self._get_network(tenant_id, network_id) + port = net[const.NET_PORTS].get(port_id) + if not port: + raise exc.PortNotFound(net_id=network_id, port_id=port_id) + return port + + def _create_port_profile(self, tenant_id, net_id, port_id, vlan_name, + vlan_id): + if self._port_profile_counter >= int(conf.MAX_UCSM_PORT_PROFILES): + raise cexc.UCSMPortProfileLimit(net_id=net_id, port_id=port_id) + profile_name = self._get_profile_name(port_id) + self._client.create_profile(profile_name, vlan_name, self._ucsm_ip, + self._ucsm_username, self._ucsm_password) + self._port_profile_counter += 1 + new_port_profile = {const.PROFILE_NAME: profile_name, + const.PROFILE_VLAN_NAME: vlan_name, + const.PROFILE_VLAN_ID: vlan_id} + return new_port_profile + + def _delete_port_profile(self, port_id, profile_name): + self._client.delete_profile(profile_name, self._ucsm_ip, + self._ucsm_username, self._ucsm_password) + self._port_profile_counter -= 1 diff --git a/quantum/plugins/cisco/cisco_utils.py b/quantum/plugins/cisco/cisco_utils.py new file mode 100644 index 0000000000..bd0b257d54 --- /dev/null +++ b/quantum/plugins/cisco/cisco_utils.py @@ -0,0 +1,59 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import MySQLdb +import logging as LOG +import sys +import traceback + +from quantum.common import exceptions as exc +from quantum.plugins.cisco import cisco_configuration as conf +from quantum.plugins.cisco import cisco_constants as const +from quantum.plugins.cisco import cisco_credentials as cred + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + + +class DBUtils(object): + + def __init__(self): + pass + + def _get_db_connection(self): + db_ip = conf.DB_SERVER_IP + db_username = cred.Store.getUsername(db_ip) + db_password = cred.Store.getPassword(db_ip) + self.db = MySQLdb.connect(db_ip, db_username, db_password, + conf.DB_NAME) + return self.db + + def execute_db_query(self, sql_query): + db = self._get_db_connection() + cursor = db.cursor() + try: + cursor.execute(sql_query) + results = cursor.fetchall() + db.commit() + LOG.debug("DB query execution succeeded: %s" % sql_query) + except: + db.rollback() + LOG.debug("DB query execution failed: %s" % sql_query) + traceback.print_exc() + db.close() diff --git a/quantum/plugins/cisco/get-vif.sh b/quantum/plugins/cisco/get-vif.sh new file mode 100755 index 0000000000..d424b5fea2 --- /dev/null +++ b/quantum/plugins/cisco/get-vif.sh @@ -0,0 +1,15 @@ +#!/bin/bash +eths=`ifconfig -a | grep eth | cut -f1 -d " "` +for eth in $eths; do + bdf=`ethtool -i $eth | grep bus-info | cut -f2 -d " "` + deviceid=`lspci -n -s $bdf | cut -f4 -d ":" | cut -f1 -d " "` + if [ $deviceid = "0044" ]; then + used=`/sbin/ip link show $eth | grep "UP"` + avail=$? + if [ $avail -eq 1 ]; then + echo $eth + exit + fi + fi +done + diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py new file mode 100644 index 0000000000..e98344e098 --- /dev/null +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -0,0 +1,348 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import logging as LOG + +from quantum.common import exceptions as exc +from quantum.plugins.cisco import cisco_configuration as conf +from quantum.plugins.cisco import cisco_constants as const +from quantum.plugins.cisco import cisco_credentials as cred +from quantum.plugins.cisco import cisco_exceptions as cexc +from quantum.plugins.cisco import cisco_nexus_plugin +from quantum.plugins.cisco import cisco_ucs_plugin +from quantum.plugins.cisco import cisco_utils as cutil + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + + +class L2Network(object): + _networks = {} + _tenants = {} + _portprofiles = {} + + def __init__(self): + self._net_counter = 0 + self._portprofile_counter = 0 + self._vlan_counter = int(conf.VLAN_START) - 1 + self._ucs_plugin = cisco_ucs_plugin.UCSVICPlugin() + self._nexus_plugin = cisco_nexus_plugin.NexusPlugin() + + """ + Core API implementation + """ + def get_all_networks(self, tenant_id): + """ + Returns a dictionary containing all + for + the specified tenant. + """ + LOG.debug("get_all_networks() called\n") + return self._networks.values() + + def create_network(self, tenant_id, net_name): + """ + Creates a new Virtual Network, and assigns it + a symbolic name. + """ + LOG.debug("create_network() called\n") + new_net_id = self._get_unique_net_id(tenant_id) + vlan_id = self._get_vlan_for_tenant(tenant_id, net_name) + vlan_name = self._get_vlan_name(new_net_id, str(vlan_id)) + self._nexus_plugin.create_network(tenant_id, net_name, new_net_id, + vlan_name, vlan_id) + self._ucs_plugin.create_network(tenant_id, net_name, new_net_id, + vlan_name, vlan_id) + new_net_dict = {const.NET_ID: new_net_id, + const.NET_NAME: net_name, + const.NET_PORTS: {}, + const.NET_VLAN_NAME: vlan_name, + const.NET_VLAN_ID: vlan_id, + const.NET_TENANTS: [tenant_id]} + self._networks[new_net_id] = new_net_dict + tenant = self._get_tenant(tenant_id) + tenant_networks = tenant[const.TENANT_NETWORKS] + tenant_networks[new_net_id] = new_net_dict + return new_net_dict + + def delete_network(self, tenant_id, net_id): + """ + Deletes the network with the specified network identifier + belonging to the specified tenant. + """ + LOG.debug("delete_network() called\n") + net = self._networks.get(net_id) + # TODO (Sumit) : Verify that no attachments are plugged into the + # network + if net: + # TODO (Sumit) : Before deleting the network, make sure all the + # ports associated with this network are also deleted + self._nexus_plugin.delete_network(tenant_id, net_id) + self._ucs_plugin.delete_network(tenant_id, net_id) + self._networks.pop(net_id) + tenant = self._get_tenant(tenant_id) + tenant_networks = tenant[const.TENANT_NETWORKS] + tenant_networks.pop(net_id) + return net + # Network not found + raise exc.NetworkNotFound(net_id=net_id) + + def get_network_details(self, tenant_id, net_id): + """ + Deletes the Virtual Network belonging to a the + spec + """ + LOG.debug("get_network_details() called\n") + network = self._get_network(tenant_id, net_id) + return network + + def rename_network(self, tenant_id, net_id, new_name): + """ + Updates the symbolic name belonging to a particular + Virtual Network. + """ + LOG.debug("rename_network() called\n") + self._nexus_plugin.rename_network(tenant_id, net_id) + self._ucs_plugin.rename_network(tenant_id, net_id) + network = self._get_network(tenant_id, net_id) + network[const.NET_NAME] = new_name + return network + + def get_all_ports(self, tenant_id, net_id): + """ + Retrieves all port identifiers belonging to the + specified Virtual Network. + """ + LOG.debug("get_all_ports() called\n") + network = self._get_network(tenant_id, net_id) + ports_on_net = network[const.NET_PORTS].values() + return ports_on_net + + def create_port(self, tenant_id, net_id, port_state=None): + """ + Creates a port on the specified Virtual Network. + """ + LOG.debug("create_port() called\n") + net = self._get_network(tenant_id, net_id) + ports = net[const.NET_PORTS] + unique_port_id_string = self._get_unique_port_id(tenant_id, net_id) + self._ucs_plugin.create_port(tenant_id, net_id, port_state, + unique_port_id_string) + new_port_dict = {const.PORT_ID: unique_port_id_string, + const.PORT_STATE: const.PORT_UP, + const.ATTACHMENT: None} + ports[unique_port_id_string] = new_port_dict + return new_port_dict + + def delete_port(self, tenant_id, net_id, port_id): + """ + Deletes a port on a specified Virtual Network, + if the port contains a remote interface attachment, + the remote interface should first be un-plugged and + then the port can be deleted. + """ + LOG.debug("delete_port() called\n") + port = self._get_port(tenant_id, net_id, port_id) + if port[const.ATTACHMENT]: + raise exc.PortInUse(net_id=net_id, port_id=port_id, + att_id=port[const.ATTACHMENT]) + try: + #TODO (Sumit): Before deleting port profile make sure that there + # is no VM using this port profile + self._ucs_plugin.delete_port(tenant_id, net_id, port_id) + net = self._get_network(tenant_id, net_id) + net[const.NET_PORTS].pop(port_id) + except KeyError: + raise exc.PortNotFound(net_id=net_id, port_id=port_id) + + def update_port(self, tenant_id, net_id, port_id, port_state): + """ + Updates the state of a port on the specified Virtual Network. + """ + LOG.debug("update_port() called\n") + port = self._get_port(tenant_id, net_id, port_id) + self._validate_port_state(port_state) + port[const.PORT_STATE] = port_state + return port + + def get_port_details(self, tenant_id, net_id, port_id): + """ + This method allows the user to retrieve a remote interface + that is attached to this particular port. + """ + LOG.debug("get_port_details() called\n") + return self._get_port(tenant_id, net_id, port_id) + + def plug_interface(self, tenant_id, net_id, port_id, + remote_interface_id): + """ + Attaches a remote interface to the specified port on the + specified Virtual Network. + """ + LOG.debug("plug_interface() called\n") + self._validate_attachment(tenant_id, net_id, port_id, + remote_interface_id) + port = self._get_port(tenant_id, net_id, port_id) + if port[const.ATTACHMENT]: + raise exc.PortInUse(net_id=net_id, port_id=port_id, + att_id=port[const.ATTACHMENT]) + self._ucs_plugin.plug_interface(tenant_id, net_id, port_id, + remote_interface_id) + port[const.ATTACHMENT] = remote_interface_id + + def unplug_interface(self, tenant_id, net_id, port_id): + """ + Detaches a remote interface from the specified port on the + specified Virtual Network. + """ + LOG.debug("unplug_interface() called\n") + port = self._get_port(tenant_id, net_id, port_id) + self._ucs_plugin.unplug_interface(tenant_id, net_id, + port_id) + port[const.ATTACHMENT] = None + + """ + Extension API implementation + """ + def get_all_portprofiles(self, tenant_id): + return self._portprofiles.values() + + def get_portprofile_details(self, tenant_id, profile_id): + return self._get_portprofile(tenant_id, profile_id) + + def create_portprofile(self, tenant_id, profile_name, vlan_id): + profile_id = self._get_unique_profile_id(tenant_id) + new_port_profile_dict = {const.PROFILE_ID: profile_id, + const.PROFILE_NAME: profile_name, + const.PROFILE_VLAN_ID: vlan_id, + const.PROFILE_QOS: None} + self._portprofiles[profile_id] = new_port_profile_dict + tenant = self._get_tenant(tenant_id) + portprofiles = tenant[const.TENANT_PORTPROFILES] + portprofiles[profile_id] = new_port_profile_dict + return new_profile_dict + + def delete_portprofile(self, tenant_id, profile_id): + portprofile = self._get_portprofile(tenant_id, profile_id) + self._portprofile.pop(profile_id) + tenant = self._get_tenant(tenant_id) + tenant[const.TENANT_PORTPROFILES].pop(profile_id) + + def rename_portprofile(self, tenant_id, profile_id, new_name): + portprofile = self._get_portprofile(tenant_id, profile_id) + portprofile[const.PROFILE_NAME] = new_name + return portprofile + + """ + Private functions + """ + def _get_vlan_for_tenant(self, tenant_id, net_name): + # TODO (Sumit): + # The VLAN ID for a tenant might need to be obtained from + # somewhere (from Donabe/Melange?) + # Also need to make sure that the VLAN ID is not being used already + # Currently, just a wrap-around counter ranging from VLAN_START to + # VLAN_END + self._vlan_counter += 1 + self._vlan_counter %= int(conf.VLAN_END) + if self._vlan_counter < int(conf.VLAN_START): + self._vlan_counter = int(conf.VLAN_START) + return self._vlan_counter + + def _get_vlan_name(self, net_id, vlan): + vlan_name = conf.VLAN_NAME_PREFIX + net_id + "-" + vlan + return vlan_name + + def _validate_port_state(self, port_state): + if port_state.upper() not in (const.PORT_UP, const.PORT_DOWN): + raise exc.StateInvalid(port_state=port_state) + return True + + def _validate_attachment(self, tenant_id, network_id, port_id, + remote_interface_id): + network = self._get_network(tenant_id, network_id) + for port in network[const.NET_PORTS].values(): + if port[const.ATTACHMENT] == remote_interface_id: + raise exc.AlreadyAttached(net_id=network_id, + port_id=port_id, + att_id=port[const.ATTACHMENT], + att_port_id=port[const.PORT_ID]) + + def _get_network(self, tenant_id, network_id): + network = self._networks.get(network_id) + if not network: + raise exc.NetworkNotFound(net_id=network_id) + return network + + def _get_tenant(self, tenant_id): + tenant = self._tenants.get(tenant_id) + if not tenant: + LOG.debug("Creating new tenant record with tenant id %s\n" % + tenant_id) + tenant = {const.TENANT_ID: tenant_id, + const.TENANT_NAME: tenant_id, + const.TENANT_NETWORKS: {}, + const.TENANT_PORTPROFILES: {}} + self._tenants[tenant_id] = tenant + return tenant + + def _get_port(self, tenant_id, network_id, port_id): + net = self._get_network(tenant_id, network_id) + port = net[const.NET_PORTS].get(port_id) + if not port: + raise exc.PortNotFound(net_id=network_id, port_id=port_id) + return port + + def _get_portprofile(self, tenant_id, portprofile_id): + portprofile = self._portprofiles.get(portprofile_id) + if not portprofile: + raise cexc.PortProfileNotFound(tenant_id=tenant_id, + profile_id=portprofile_id) + return portprofile + + def _get_unique_net_id(self, tenant_id): + self._net_counter += 1 + self._net_counter %= int(conf.MAX_NETWORKS) + id = tenant_id[:3] + \ + "-n-" + ("0" * (6 - len(str(self._net_counter)))) + \ + str(self._net_counter) + # TODO (Sumit): Need to check if the ID has already been allocated + return id + + def _get_unique_port_id(self, tenant_id, net_id): + net = self._get_network(tenant_id, net_id) + ports = net[const.NET_PORTS] + if len(ports) == 0: + new_port_id = 1 + else: + new_port_id = max(ports.keys()) + 1 + id = net_id + "-p-" + str(new_port_id) + # TODO (Sumit): Need to check if the ID has already been allocated + return id + + def _get_unique_profile_id(self, tenant_id): + self._portprofile_counter += 1 + self._portprofile_counter %= int(conf.MAX_PORT_PROFILES) + id = tenant_id[:3] + "-pp-" + \ + ("0" * (6 - len(str(self._net_counter)))) + str(self._net_counter) + # TODO (Sumit): Need to check if the ID has already been allocated + return id + +# TODO (Sumit): + # (1) Persistent storage From c644206e43a9cc198833f5ae544174c8250bffd1 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 8 Jul 2011 14:29:45 -0700 Subject: [PATCH 02/48] This file is not required. --- quantum/plugins/cisco/cisco_ucs.py | 102 ----------------------------- 1 file changed, 102 deletions(-) delete mode 100644 quantum/plugins/cisco/cisco_ucs.py diff --git a/quantum/plugins/cisco/cisco_ucs.py b/quantum/plugins/cisco/cisco_ucs.py deleted file mode 100644 index 0723da9f0a..0000000000 --- a/quantum/plugins/cisco/cisco_ucs.py +++ /dev/null @@ -1,102 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# -# @author: Sumit Naiksatam, Cisco Systems, Inc. -# -# - -import MySQLdb -import sys, traceback - -from nova import flags -from nova import log as logging - -FLAGS = flags.FLAGS -LOG = logging.getLogger('nova.virt.libvirt_conn') -# -# TODO (Sumit): The following are defaults, but we might need to make it conf file driven as well -# - -flags.DEFINE_string('db_server_ip', "127.0.0.1", 'IP address of nova DB server') -flags.DEFINE_string('db_username', "root", 'DB username') -flags.DEFINE_string('db_password', "nova", 'DB paswwprd') -flags.DEFINE_string('db_name', "nova", 'DB name') -flags.DEFINE_string('nova_proj_name', "demo", 'project created in nova') -flags.DEFINE_string('nova_host_name', "openstack-0203", 'nova cloud controller hostname') - -class CiscoUCSComputeDriver(object): - def __init__(self): - pass - - def _get_db_connection(self): - self.db = MySQLdb.connect(FLAGS.db_server_ip, FLAGS.db_username, FLAGS.db_password, FLAGS.db_name) - return self.db - - def _execute_db_query(self, sql_query): - db = self._get_db_connection() - cursor = db.cursor() - try: - cursor.execute(sql_query) - results = cursor.fetchall() - db.commit() - print "DB query execution succeeded: %s" % sql_query - except: - db.rollback() - print "DB query execution failed: %s" % sql_query - traceback.print_exc() - db.close() - return results - - def reserve_port(self, instance_name, instance_nic_name): - sql_query = "SELECT * from ports WHERE used='0'" - results = self._execute_db_query(sql_query) - if len(results) == 0: - print "No ports available/n" - return 0 - else: - for row in results: - port_id = row[0]; - sql_query = "UPDATE ports SET instance_name = '%s', instance_nic_name = '%s' WHERE port_id = '%s'" % (instance_name, instance_nic_name, port_id) - results = self._execute_db_query(sql_query) - return port_id; - return 0 - - def get_port_details(self, port_id): - port_details = {} - sql_query = "SELECT * from ports WHERE port_id='%s'" % (port_id) - results = self._execute_db_query(sql_query) - if len(results) == 0: - print "Could not fetch port from DB for port_id = %s/n" % port_id - return - else: - for row in results: - profile_name = row[1]; - dynamic_vnic = row[2]; - sql_query = "UPDATE ports SET used = %d WHERE port_id = '%s'" % (1, port_id) - results = self._execute_db_query(sql_query) - port_details = {'profile_name':profile_name, 'dynamic_vnic':dynamic_vnic} - return port_details; - - def release_port(self, instance_name, instance_nic_name): - sql_query = "SELECT * from ports WHERE instance_name='%s' and instance_nic_name='%s'" % (instance_name, instance_nic_name) - results = self._execute_db_query(sql_query) - if len(results) == 0: - print "No matching ports found for releasing/n" - return 0 - else: - for row in results: - port_id = row[0]; - sql_query = "UPDATE ports SET instance_name = NULL, instance_nic_name = NULL, used = 0 WHERE port_id = '%s'" % (port_id) - results = self._execute_db_query(sql_query) - return port_id; - return 0 - -def main(): - client = CiscoUCSComputeDriver() - port_id = client.reserve_port("instance-1", "eth1") - port_details = client.get_port_details(port_id) - print "profile_name %s dynamic_vnic %s\n" % (port_details['profile_name'], port_details['dynamic_vnic']) - port_id = client.release_port("instance-1", "eth1") - -if __name__ == '__main__': - main() From 5c1bca06ff247c712b8df587a083945a9725c183 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 8 Jul 2011 14:40:56 -0700 Subject: [PATCH 03/48] Changed some credentials (does not affect functionality). --- quantum/plugins/cisco/cisco_credentials.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/cisco_credentials.py b/quantum/plugins/cisco/cisco_credentials.py index c37d00f1ab..4c8761f6b7 100644 --- a/quantum/plugins/cisco/cisco_credentials.py +++ b/quantum/plugins/cisco/cisco_credentials.py @@ -25,7 +25,7 @@ LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) _creds_dictionary = { - '172.20.231.27': ["admin", "c3l12345"], + '10.10.10.10': ["username", "password"], '127.0.0.1': ["root", "nova"] } From 632b5bb8003ccfb2f5c9687b31738e081407647e Mon Sep 17 00:00:00 2001 From: Rick Clark Date: Fri, 8 Jul 2011 17:46:20 -0500 Subject: [PATCH 04/48] minor pep8 fix. --- quantum/plugins/cisco/cisco_credentials.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/quantum/plugins/cisco/cisco_credentials.py b/quantum/plugins/cisco/cisco_credentials.py index 4c8761f6b7..c0cd282530 100644 --- a/quantum/plugins/cisco/cisco_credentials.py +++ b/quantum/plugins/cisco/cisco_credentials.py @@ -24,10 +24,8 @@ from quantum.plugins.cisco import cisco_constants as const LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) -_creds_dictionary = { - '10.10.10.10': ["username", "password"], - '127.0.0.1': ["root", "nova"] -} +_creds_dictionary = {'10.10.10.10': ["username", "password"], + '127.0.0.1': ["root", "nova"]} class Store(object): From 617e1b5ab83c5e31cfe0d2e7c14aa3fb6dffc896 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Tue, 12 Jul 2011 14:50:49 -0700 Subject: [PATCH 05/48] Required for recognizing the "cisco" package. Missed in the initial checkin. --- quantum/plugins/cisco/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 quantum/plugins/cisco/__init__.py diff --git a/quantum/plugins/cisco/__init__.py b/quantum/plugins/cisco/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From 7fb19f22ce31c1023568cdd6ba9e5b35b15f5cf9 Mon Sep 17 00:00:00 2001 From: "rohitagarwalla roagarwa@cisco.com" <> Date: Wed, 13 Jul 2011 12:39:09 -0700 Subject: [PATCH 06/48] Porting shell script get-vif.sh to python module get-vif.py for cisco ucsm module --- quantum/plugins/cisco/get-vif.py | 37 ++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 quantum/plugins/cisco/get-vif.py diff --git a/quantum/plugins/cisco/get-vif.py b/quantum/plugins/cisco/get-vif.py new file mode 100644 index 0000000000..0512ecb0dd --- /dev/null +++ b/quantum/plugins/cisco/get-vif.py @@ -0,0 +1,37 @@ +import sys +import subprocess + + +def get_next_dynic(argv=[]): + cmd = ["ifconfig", "-a"] + f_cmd_output = subprocess.Popen(cmd, stdout=subprocess.PIPE).\ + communicate()[0] + eths = [lines.split(' ')[0] for lines in f_cmd_output.splitlines() \ + if "eth" in lines] + #print eths + for eth in eths: + cmd = ["ethtool", "-i", eth] + f_cmd_output = subprocess.Popen(cmd, stdout=subprocess.PIPE).\ + communicate()[0] + bdf = [lines.split(' ')[1] for lines in f_cmd_output.splitlines() \ + if "bus-info" in lines] + #print bdf + cmd = ["lspci", "-n", "-s", bdf[0]] + f_cmd_output = subprocess.Popen(cmd, stdout=subprocess.PIPE).\ + communicate()[0] + deviceid = [(lines.split(':')[3]).split(' ')[0] \ + for lines in f_cmd_output.splitlines()] + #print deviceid + if deviceid[0] == "0044": + cmd = ["/usr/sbin/ip", "link", "show", eth] + f_cmd_output = subprocess.Popen(cmd, stdout=subprocess.PIPE).\ + communicate()[0] + used = [lines for lines in f_cmd_output.splitlines() \ + if "UP" in lines] + if not used: + break + return eth + +if __name__ == '__main__': + nic = get_next_dynic(sys.argv) + print nic From 0d9bf52025ca3044c9ee1e02a9f6dbe30e6666bc Mon Sep 17 00:00:00 2001 From: Debo Date: Thu, 14 Jul 2011 17:11:55 -0700 Subject: [PATCH 07/48] Very initial version of the nxos driver .... lets call it ver 0.0.1! yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy added: quantum/plugins/cisco/nxosapi.py --- quantum/plugins/cisco/nxosapi.py | 172 +++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 quantum/plugins/cisco/nxosapi.py diff --git a/quantum/plugins/cisco/nxosapi.py b/quantum/plugins/cisco/nxosapi.py new file mode 100644 index 0000000000..0f0ebe04f0 --- /dev/null +++ b/quantum/plugins/cisco/nxosapi.py @@ -0,0 +1,172 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# Copyright 2011 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. +# @author: Debojyoti Dutta, Cisco Systems, Inc. + +import sys +import os +import warnings +warnings.simplefilter("ignore", DeprecationWarning) +from ncclient import manager +from ncclient import NCClientError +from ncclient.transport.errors import * + +exec_conf_prefix = """ + + + <__XML__MODE__exec_configure> +""" + + +exec_conf_postfix = """ + + + +""" + + +cmd_vlan_conf_snippet = """ + + + <__XML__PARAM_value>%s + <__XML__MODE_vlan> + + %s + + + active + + + + + + + +""" + +cmd_no_vlan_conf_snippet = """ + + + + <__XML__PARAM_value>%s + + + +""" + +cmd_vlan_int_snippet = """ + + + %s + <__XML__MODE_if-ethernet-switch> + + + + + + <__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans> + %s + + + + + + + + +""" + + +cmd_no_vlan_int_snippet = """ + + + %s + <__XML__MODE_if-ethernet-switch> + + + + + + + <__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans> + %s + + + + + + + + + +""" + + +filter_show_vlan_brief_snippet = """ + + + + + """ + + +def nxos_connect(host, port, user, password): + try: + m = manager.connect(host=host, port=port, username=user, + password=password) + return m + except SSHUnknownHostError: + sys.stderr.write('SSH unknown host error\n') + exit() + + +def enable_vlan(mgr, vlanid, vlanname): + confstr = cmd_vlan_conf_snippet % (vlanid, vlanname) + confstr = exec_conf_prefix + confstr + exec_conf_postfix + mgr.edit_config(target='running', config=confstr) + + +def disable_vlan(mgr, vlanid): + confstr = cmd_no_vlan_conf_snippet % vlanid + confstr = exec_conf_prefix + confstr + exec_conf_postfix + mgr.edit_config(target='running', config=confstr) + + +def enable_vlan_on_trunk_int(mgr, interface, vlanid): + confstr = cmd_vlan_int_snippet % (interface, vlanid) + confstr = exec_conf_prefix + confstr + exec_conf_postfix + print confstr + mgr.edit_config(target='running', config=confstr) + + +def disable_vlan_on_trunk_int(mgr, interface, vlanid): + confstr = cmd_no_vlan_int_snippet % (interface, vlanid) + confstr = exec_conf_prefix + confstr + exec_conf_postfix + print confstr + mgr.edit_config(target='running', config=confstr) + + +def test_nxos_api(host, user, password): + with nxos_connect(host, port=22, user=user, password=password) as m: + enable_vlan(m, '100', 'ccn1') + enable_vlan_on_trunk_int(m, '2/1', '100') + disable_vlan_on_trunk_int(m, '2/1', '100') + disable_vlan(m, '100') + result = m.get(("subtree", filter_show_vlan_brief_snippet)) + #print result + + +if __name__ == '__main__': + test_nxos_api(sys.argv[1], sys.argv[2], sys.argv[3]) From 62f0f53ddd48721e2bdcddaca27b0dcb59a071b1 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Thu, 14 Jul 2011 18:24:39 -0700 Subject: [PATCH 08/48] Changes to support port-profile extension. Fixed an error in the README file. --- quantum/plugins/cisco/README | 2 +- quantum/plugins/cisco/cisco_constants.py | 3 ++- quantum/plugins/cisco/cisco_exceptions.py | 7 ++++- quantum/plugins/cisco/l2network_plugin.py | 32 +++++++++++++++++++---- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index fcc50018f9..6c2bc0cdcd 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -31,7 +31,7 @@ cisco_configuration.py cisco_constants.py cisco_credentials.py cisco_exceptions.py -cisco_nexus_network_driver.py +cisco_nexus_plugin.py cisco_ucs_network_driver.py cisco_ucs_plugin.py cisco_utils.py diff --git a/quantum/plugins/cisco/cisco_constants.py b/quantum/plugins/cisco/cisco_constants.py index 115addf423..7f2367d794 100644 --- a/quantum/plugins/cisco/cisco_constants.py +++ b/quantum/plugins/cisco/cisco_constants.py @@ -40,7 +40,8 @@ PORT_PROFILE = 'port-profile' PROFILE_ID = 'profile-id' PROFILE_NAME = 'profile-name' PROFILE_VLAN_NAME = 'profile-vlan-name' -PROFILE_VLAN_ID = 'profile-vlan-id' +PROFILE_VLAN_ID = 'vlan-id' PROFILE_QOS = 'profile-qos' +PROFILE_ASSOCIATIONS = 'assignment' LOGGER_COMPONENT_NAME = "cisco_plugin" diff --git a/quantum/plugins/cisco/cisco_exceptions.py b/quantum/plugins/cisco/cisco_exceptions.py index 2829329c85..06e5e53639 100644 --- a/quantum/plugins/cisco/cisco_exceptions.py +++ b/quantum/plugins/cisco/cisco_exceptions.py @@ -48,5 +48,10 @@ class NetworksLimit(exceptions.QuantumException): class PortProfileNotFound(exceptions.QuantumException): - message = _("Port profile %(port_id)s could not be found " \ + message = _("Port profile %(portprofile_id)s could not be found " \ "for tenant %(tenant_id)s") + + +class PortProfileInvalidDelete(exceptions.QuantumException): + message = _("Port profile %(profile_id)s could not be deleted " \ + "for tenant %(tenant_id)s since port associations exist") diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index e98344e098..47f63874ee 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -230,25 +230,47 @@ class L2Network(object): profile_id = self._get_unique_profile_id(tenant_id) new_port_profile_dict = {const.PROFILE_ID: profile_id, const.PROFILE_NAME: profile_name, + const.PROFILE_ASSOCIATIONS: [], const.PROFILE_VLAN_ID: vlan_id, const.PROFILE_QOS: None} self._portprofiles[profile_id] = new_port_profile_dict tenant = self._get_tenant(tenant_id) portprofiles = tenant[const.TENANT_PORTPROFILES] portprofiles[profile_id] = new_port_profile_dict - return new_profile_dict + return new_port_profile_dict def delete_portprofile(self, tenant_id, profile_id): portprofile = self._get_portprofile(tenant_id, profile_id) - self._portprofile.pop(profile_id) - tenant = self._get_tenant(tenant_id) - tenant[const.TENANT_PORTPROFILES].pop(profile_id) + associations = portprofile[const.PROFILE_ASSOCIATIONS] + if len(associations) > 0: + raise cexc.PortProfileInvalidDelete(tenant_id=tenant_id, + profile_id=profile_id) + else: + self._portprofiles.pop(profile_id) + tenant = self._get_tenant(tenant_id) + tenant[const.TENANT_PORTPROFILES].pop(profile_id) def rename_portprofile(self, tenant_id, profile_id, new_name): portprofile = self._get_portprofile(tenant_id, profile_id) portprofile[const.PROFILE_NAME] = new_name return portprofile + def associate_portprofile(self, tenant_id, net_id, + port_id, portprofile_id): + portprofile = self._get_portprofile(tenant_id, portprofile_id) + associations = portprofile[const.PROFILE_ASSOCIATIONS] + associations.append(port_id) + + def disassociate_portprofile(self, tenant_id, net_id, + port_id, portprofile_id): + portprofile = self._get_portprofile(tenant_id, portprofile_id) + associations = portprofile[const.PROFILE_ASSOCIATIONS] + associations.remove(port_id) + + def create_defaultPProfile(self, tenant_id, network_id, profile_name, + vlan_id): + pass + """ Private functions """ @@ -313,7 +335,7 @@ class L2Network(object): portprofile = self._portprofiles.get(portprofile_id) if not portprofile: raise cexc.PortProfileNotFound(tenant_id=tenant_id, - profile_id=portprofile_id) + portprofile_id=portprofile_id) return portprofile def _get_unique_net_id(self, tenant_id): From a8915ac3bc0e593c3ba7bc9b56f96e60813a2c0c Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Fri, 15 Jul 2011 17:33:36 -0700 Subject: [PATCH 09/48] add api extensions (including portprofiles resources and associate/disassociate actions.) --- etc/quantum.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/etc/quantum.conf b/etc/quantum.conf index ba96a9a275..6bd962790c 100644 --- a/etc/quantum.conf +++ b/etc/quantum.conf @@ -15,6 +15,7 @@ bind_port = 9696 use = egg:Paste#urlmap /: quantumversions /v0.1: quantumapi +/v0.1/extensions:cisco_extensions [app:quantumversions] paste.app_factory = quantum.api.versions:Versions.factory @@ -22,4 +23,6 @@ paste.app_factory = quantum.api.versions:Versions.factory [app:quantumapi] paste.app_factory = quantum.api:APIRouterV01.factory +[app:cisco_extensions] +paste.app_factory = cisco_extensions:ExtRouterV01.factory From 6d25812ace7585c8f9187d6daf0c6db91268aabd Mon Sep 17 00:00:00 2001 From: Ying Liu Date: Fri, 15 Jul 2011 17:40:33 -0700 Subject: [PATCH 10/48] add extension code in.(last push does not include this directory.) --- cisco_extensions/__init__.py | 71 ++++++++++++ cisco_extensions/exceptions.py | 148 +++++++++++++++++++++++++ cisco_extensions/extensions.py | 42 ++++++++ cisco_extensions/faults.py | 111 +++++++++++++++++++ cisco_extensions/portprofiles.py | 180 +++++++++++++++++++++++++++++++ cisco_extensions/pprofiles.py | 45 ++++++++ 6 files changed, 597 insertions(+) create mode 100644 cisco_extensions/__init__.py create mode 100644 cisco_extensions/exceptions.py create mode 100644 cisco_extensions/extensions.py create mode 100644 cisco_extensions/faults.py create mode 100644 cisco_extensions/portprofiles.py create mode 100644 cisco_extensions/pprofiles.py diff --git a/cisco_extensions/__init__.py b/cisco_extensions/__init__.py new file mode 100644 index 0000000000..5fc5d88919 --- /dev/null +++ b/cisco_extensions/__init__.py @@ -0,0 +1,71 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Ying Liu, Cisco Systems, Inc. +# + +import logging +import routes +import webob.dec +import webob.exc + +from quantum import manager +from quantum.api import faults +from quantum.api import networks +from quantum.api import ports +from quantum.common import flags +from quantum.common import wsgi +from cisco_extensions import portprofiles +from cisco_extensions import extensions + + +LOG = logging.getLogger('quantum_extension.api') +FLAGS = flags.FLAGS + + +class ExtRouterV01(wsgi.Router): + """ + Routes requests on the Quantum API to the appropriate controller + """ + + def __init__(self, ext_mgr=None): + uri_prefix = '/tenants/{tenant_id}/' + + mapper = routes.Mapper() + plugin = manager.QuantumManager().get_plugin() + controller = portprofiles.Controller(plugin) + ext_controller = extensions.Controller(plugin) + mapper.connect("home", "/", controller=ext_controller, + action="list_extension", + conditions=dict(method=['GET'])) + #mapper.redirect("/", "www.google.com") + mapper.resource("portprofiles", "portprofiles", + controller=controller, + path_prefix=uri_prefix) + mapper.connect("associate_portprofile", + uri_prefix + + 'portprofiles/{portprofile_id}/assignment{.format}', + controller=controller, + action="associate_portprofile", + conditions=dict(method=['PUT'])) + mapper.connect("disassociate_portprofile", + uri_prefix + + 'portprofiles/{portprofile_id}/assignment{.format}', + controller=controller, + action="disassociate_portprofile", + conditions=dict(method=['DELETE'])) + + super(ExtRouterV01, self).__init__(mapper) diff --git a/cisco_extensions/exceptions.py b/cisco_extensions/exceptions.py new file mode 100644 index 0000000000..415731e385 --- /dev/null +++ b/cisco_extensions/exceptions.py @@ -0,0 +1,148 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Ying Liu, Cisco Systems, Inc. +# +import logging + + +class ExtensionException(Exception): + """Quantum Cisco api Exception + + Taken from nova.exception.NovaException + To correctly use this class, inherit from it and define + a 'message' property. That message will get printf'd + with the keyword arguments provided to the constructor. + + """ + message = _("An unknown exception occurred.") + + def __init__(self, **kwargs): + try: + self._error_string = self.message % kwargs + + except Exception: + # at least get the core message out if something happened + self._error_string = self.message + + def __str__(self): + return self._error_string + + +class ProcessExecutionError(IOError): + def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None, + description=None): + if description is None: + description = "Unexpected error while running command." + if exit_code is None: + exit_code = '-' + message = "%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r" % ( + description, cmd, exit_code, stdout, stderr) + IOError.__init__(self, message) + + +class Error(Exception): + def __init__(self, message=None): + super(Error, self).__init__(message) + + +class ApiError(Error): + def __init__(self, message='Unknown', code='Unknown'): + self.message = message + self.code = code + super(ApiError, self).__init__('%s: %s' % (code, message)) + + +class NotFound(ExtensionException): + pass + + +class ClassNotFound(NotFound): + message = _("Class %(class_name)s could not be found") + + +class PortprofileNotFound(NotFound): + message = _("Portprofile %(_id)s could not be found") + + +class PortNotFound(NotFound): + message = _("Port %(port_id)s could not be found " \ + "on Network %(net_id)s") + + +""" + + +class PortprofileInUse(ExtensionException): + message = _("Unable to complete operation on Portprofile %(net_id)s. " \ + "There is one or more attachments plugged into its ports.") + + +class PortInUse(ExtensionException): + message = _("Unable to complete operation on port %(port_id)s " \ + "for Portprofile %(net_id)s. The attachment '%(att_id)s" \ + "is plugged into the logical port.") + +class AlreadyAttached(ExtensionException): + message = _("Unable to plug the attachment %(att_id)s into port " \ + "%(port_id)s for Portprofile %(net_id)s. The attachment is " \ + "already plugged into port %(att_port_id)s") + +""" + + +class Duplicate(Error): + pass + + +class NotAuthorized(Error): + pass + + +class NotEmpty(Error): + pass + + +class Invalid(Error): + pass + + +class InvalidContentType(Invalid): + message = _("Invalid content type %(content_type)s.") + + +class BadInputError(Exception): + """Error resulting from a client sending bad input to a server""" + pass + + +class MissingArgumentError(Error): + pass + + +def wrap_exception(f): + def _wrap(*args, **kw): + try: + return f(*args, **kw) + except Exception, e: + if not isinstance(e, Error): + #exc_type, exc_value, exc_traceback = sys.exc_info() + logging.exception('Uncaught exception') + #logging.error(traceback.extract_stack(exc_traceback)) + raise Error(str(e)) + raise + _wrap.func_name = f.func_name + return _wrap diff --git a/cisco_extensions/extensions.py b/cisco_extensions/extensions.py new file mode 100644 index 0000000000..34bc37e814 --- /dev/null +++ b/cisco_extensions/extensions.py @@ -0,0 +1,42 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Ying Liu, Cisco Systems, Inc. +# +import logging +import webob.dec + +from quantum.common import wsgi +from quantum.api import api_common as common + + +LOG = logging.getLogger('quantum.api.cisco_extension.extensions') + + +class Controller(common.QuantumController): + + def __init__(self, plugin): + #self._plugin = plugin + #super(QuantumController, self).__init__() + self._resource_name = 'extensions' + super(Controller, self).__init__(plugin) + + def list_extension(self, req): + """Respond to a request for listing all extension api.""" + response = "extensions api list" + return response + + \ No newline at end of file diff --git a/cisco_extensions/faults.py b/cisco_extensions/faults.py new file mode 100644 index 0000000000..c965f731dc --- /dev/null +++ b/cisco_extensions/faults.py @@ -0,0 +1,111 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Ying Liu, Cisco Systems, Inc. +# +import webob.dec +import webob.exc + +from quantum.api import api_common as common +from quantum.common import wsgi + + +class Fault(webob.exc.HTTPException): + """Error codes for API faults""" + + _fault_names = { + 400: "malformedRequest", + 401: "unauthorized", + 420: "networkNotFound", + 421: "PortprofileInUse", + 430: "portNotFound", + 431: "requestedStateInvalid", + 432: "portInUse", + 440: "alreadyAttached", + 450: "PortprofileNotFound", + 470: "serviceUnavailable", + 471: "pluginFault"} + + def __init__(self, exception): + """Create a Fault for the given webob.exc.exception.""" + self.wrapped_exc = exception + + @webob.dec.wsgify(RequestClass=wsgi.Request) + def __call__(self, req): + """Generate a WSGI response based on the exception passed to ctor.""" + #print ("*********TEST2") + # Replace the body with fault details. + code = self.wrapped_exc.status_int + fault_name = self._fault_names.get(code, "quantumServiceFault") + fault_data = { + fault_name: { + 'code': code, + 'message': self.wrapped_exc.explanation, + 'detail': self.wrapped_exc.detail}} + # 'code' is an attribute on the fault tag itself + metadata = {'application/xml': {'attributes': {fault_name: 'code'}}} + default_xmlns = common.XML_NS_V10 + serializer = wsgi.Serializer(metadata, default_xmlns) + content_type = req.best_match_content_type() + self.wrapped_exc.body = serializer.serialize(fault_data, content_type) + self.wrapped_exc.content_type = content_type + return self.wrapped_exc + + +class PortprofileNotFound(webob.exc.HTTPClientError): + """ + subclass of :class:`~HTTPClientError` + + This indicates that the server did not find the Portprofile specified + in the HTTP request + + code: 450, title: Portprofile not Found + """ + #print ("*********TEST1") + code = 450 + title = 'Portprofile Not Found' + explanation = ('Unable to find a Portprofile with' + + ' the specified identifier.') + + +class PortNotFound(webob.exc.HTTPClientError): + """ + subclass of :class:`~HTTPClientError` + + This indicates that the server did not find the port specified + in the HTTP request for a given network + + code: 430, title: Port not Found + """ + code = 430 + title = 'Port not Found' + explanation = ('Unable to find a port with the specified identifier.') + + +class RequestedStateInvalid(webob.exc.HTTPClientError): + """ + subclass of :class:`~HTTPClientError` + + This indicates that the server could not update the port state to + to the request value + + code: 431, title: Requested State Invalid + """ + code = 431 + title = 'Requested State Invalid' + explanation = ('Unable to update port state with specified value.') + + diff --git a/cisco_extensions/portprofiles.py b/cisco_extensions/portprofiles.py new file mode 100644 index 0000000000..5d195528f8 --- /dev/null +++ b/cisco_extensions/portprofiles.py @@ -0,0 +1,180 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Ying Liu, Cisco Systems, Inc. +# + +import logging +import webob.dec +from quantum.common import wsgi +from webob import exc + +from quantum.api import api_common as common + +from cisco_extensions import pprofiles as pprofiles_view +from cisco_extensions import exceptions as exception +from cisco_extensions import faults as faults + +LOG = logging.getLogger('quantum.api.portprofiles') + + +class Controller(common.QuantumController): + """ portprofile API controller + based on QuantumController """ + + _portprofile_ops_param_list = [{ + 'param-name': 'portprofile-name', + 'required': True}, { + 'param-name': 'vlan-id', + 'required': True}, { + 'param-name': 'assignment', + 'required': False}] + + _assignprofile_ops_param_list = [{ + 'param-name': 'network-id', + 'required': True}, { + 'param-name': 'port-id', + 'required': True}] + + _serialization_metadata = { + "application/xml": { + "attributes": { + "portprofile": ["id", "name"], + }, + }, + } + + def __init__(self, plugin): + self._resource_name = 'portprofile' + super(Controller, self).__init__(plugin) + + def index(self, request, tenant_id): + """ Returns a list of portprofile ids """ + #TODO: this should be for a given tenant!!! + return self._items(request, tenant_id, is_detail=False) + + def _items(self, request, tenant_id, is_detail): + """ Returns a list of portprofiles. """ + portprofiles = self._plugin.get_all_portprofiles(tenant_id) + builder = pprofiles_view.get_view_builder(request) + result = [builder.build(portprofile, is_detail)['portprofile'] + for portprofile in portprofiles] + return dict(portprofiles=result) + + def show(self, request, tenant_id, id): + """ Returns portprofile details for the given portprofile id """ + try: + portprofile = self._plugin.get_portprofile_details( + tenant_id, id) + builder = pprofiles_view.get_view_builder(request) + #build response with details + result = builder.build(portprofile, True) + return dict(portprofiles=result) + except exception.PortprofileNotFound as e: + return faults.Fault(faults.PortprofileNotFound(e)) + #return faults.Fault(e) + + def create(self, request, tenant_id): + """ Creates a new portprofile for a given tenant """ + #look for portprofile name in request + try: + req_params = \ + self._parse_request_params(request, + self._portprofile_ops_param_list) + except exc.HTTPError as e: + return faults.Fault(e) + portprofile = self._plugin.\ + create_portprofile(tenant_id, + req_params['portprofile-name'], + req_params['vlan-id']) + builder = pprofiles_view.get_view_builder(request) + result = builder.build(portprofile) + return dict(portprofiles=result) + + def update(self, request, tenant_id, id): + """ Updates the name for the portprofile with the given id """ + try: + req_params = \ + self._parse_request_params(request, + self._portprofile_ops_param_list) + except exc.HTTPError as e: + return faults.Fault(e) + try: + portprofile = self._plugin.\ + rename_portprofile(tenant_id, + id, req_params['portprofile-name']) + + builder = pprofiles_view.get_view_builder(request) + result = builder.build(portprofile, True) + return dict(portprofiles=result) + except exception.PortprofileNotFound as e: + return faults.Fault(faults.PortprofileNotFound(e)) + + def delete(self, request, tenant_id, id): + """ Destroys the portprofile with the given id """ + try: + self._plugin.delete_portprofile(tenant_id, id) + return exc.HTTPAccepted() + except exception.PortprofileNotFound as e: + return faults.Fault(faults.PortprofileNotFound(e)) + + #added for cisco's extension + def associate_portprofile(self, request, tenant_id, portprofile_id): + content_type = request.best_match_content_type() + print "Content type:%s" % content_type + + try: + req_params = \ + self._parse_request_params(request, + self._assignprofile_ops_param_list) + except exc.HTTPError as e: + return faults.Fault(e) + net_id = req_params['network-id'].strip() + #print "*****net id "+net_id + port_id = req_params['port-id'].strip() + try: + self._plugin.associate_portprofile(tenant_id, + net_id, port_id, + portprofile_id) + return exc.HTTPAccepted() + except exception.PortprofileNotFound as e: + return faults.Fault(faults.PortprofileNotFound(e)) + except exception.PortNotFound as e: + return faults.Fault(faults.PortNotFound(e)) + + #added for Cisco extension + def disassociate_portprofile(self, request, tenant_id, portprofile_id): + content_type = request.best_match_content_type() + print "Content type:%s" % content_type + + try: + req_params = \ + self._parse_request_params(request, + self._assignprofile_ops_param_list) + except exc.HTTPError as e: + return faults.Fault(e) + net_id = req_params['network-id'].strip() + #print "*****net id "+net_id + port_id = req_params['port-id'].strip() + try: + self._plugin. \ + disassociate_portprofile(tenant_id, + net_id, port_id, portprofile_id) + return exc.HTTPAccepted() + except exception.PortprofileNotFound as e: + return faults.Fault(faults.PortprofileNotFound(e)) + except exception.PortNotFound as e: + return faults.Fault(faults.PortNotFound(e)) diff --git a/cisco_extensions/pprofiles.py b/cisco_extensions/pprofiles.py new file mode 100644 index 0000000000..ba7f8a328b --- /dev/null +++ b/cisco_extensions/pprofiles.py @@ -0,0 +1,45 @@ + + +import os + + +def get_view_builder(req): + base_url = req.application_url + return ViewBuilder(base_url) + + +class ViewBuilder(object): + """ + ViewBuilder for Portprofile, + derived from quantum.views.networks + """ + def __init__(self, base_url): + """ + :param base_url: url of the root wsgi application + """ + self.base_url = base_url + + def build(self, portprofile_data, is_detail=False): + """Generic method used to generate a portprofile entity.""" + print "portprofile-DATA:%s" %portprofile_data + if is_detail: + portprofile = self._build_detail(portprofile_data) + else: + portprofile = self._build_simple(portprofile_data) + return portprofile + + def _build_simple(self, portprofile_data): + """Return a simple model of a server.""" + return dict(portprofile=dict(id=portprofile_data['profile-id'])) + + def _build_detail(self, portprofile_data): + """Return a simple model of a server.""" + if (portprofile_data['assignment']==None): + return dict(portprofile=dict(id=portprofile_data['profile-id'], + name=portprofile_data['profile-name'], + vlan_id=portprofile_data['vlan-id'])) + else: + return dict(portprofile=dict(id=portprofile_data['profile-id'], + name=portprofile_data['profile-name'], + vlan_id=portprofile_data['vlan-id'], + assignment=portprofile_data['assignment'])) From 6244bccdbada53f90f8a5557d28ef6bff1ac9bb1 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Thu, 28 Jul 2011 18:28:07 -0700 Subject: [PATCH 11/48] Changed the param name "network-name" to "net-name" since the Quantum service expects the later. --- quantum/cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quantum/cli.py b/quantum/cli.py index 02bafbd09d..0f6a0c27e0 100644 --- a/quantum/cli.py +++ b/quantum/cli.py @@ -114,7 +114,7 @@ def create_net(manager, *args): def api_create_net(client, *args): tid, name = args - data = {'network': {'network-name': '%s' % name}} + data = {'network': {'net-name': '%s' % name}} body = Serializer().serialize(data, CONTENT_TYPE) res = client.do_request(tid, 'POST', "/networks." + FORMAT, body=body) rd = json.loads(res.read()) @@ -185,7 +185,7 @@ def rename_net(manager, *args): def api_rename_net(client, *args): tid, nid, name = args - data = {'network': {'network-name': '%s' % name}} + data = {'network': {'net-name': '%s' % name}} body = Serializer().serialize(data, CONTENT_TYPE) res = client.do_request(tid, 'PUT', "/networks/%s.%s" % (nid, FORMAT), body=body) From 5796e43bd9c4021996112c14aaa3be6537d52187 Mon Sep 17 00:00:00 2001 From: rohitagarwalla Date: Fri, 29 Jul 2011 20:48:41 -0700 Subject: [PATCH 12/48] persistence of l2network & ucs plugins using mysql - db_conn.ini - configuration details of making a connection to the database - db_test_plugin.py - contains abstraction methods for storing database values in a dict and unit test cases for DB testing - l2network_db.py - db methods for l2network models - l2network_models.py - class definitions for the l2 network tables - ucs_db.py - db methods for ucs models - ucs_models.py - class definition for the ucs tables dynamic loading of the 2nd layer plugin db's based on passed arguments Create, Delete, Get, Getall, Update database methods at - Quantum, L2Network and Ucs Unit test cases for create, delete, getall and update operations for L2Network and Ucs plugins pep8 checks done branch based off revision 34 plugin-framework --- quantum/plugins/cisco/db_conn.ini | 5 + quantum/plugins/cisco/db_test_plugin.py | 1046 +++++++++++++++++++++ quantum/plugins/cisco/l2network_db.py | 239 +++++ quantum/plugins/cisco/l2network_models.py | 86 ++ quantum/plugins/cisco/ucs_db.py | 314 +++++++ quantum/plugins/cisco/ucs_models.py | 113 +++ 6 files changed, 1803 insertions(+) create mode 100644 quantum/plugins/cisco/db_conn.ini create mode 100644 quantum/plugins/cisco/db_test_plugin.py create mode 100644 quantum/plugins/cisco/l2network_db.py create mode 100644 quantum/plugins/cisco/l2network_models.py create mode 100644 quantum/plugins/cisco/ucs_db.py create mode 100644 quantum/plugins/cisco/ucs_models.py diff --git a/quantum/plugins/cisco/db_conn.ini b/quantum/plugins/cisco/db_conn.ini new file mode 100644 index 0000000000..29c5c95369 --- /dev/null +++ b/quantum/plugins/cisco/db_conn.ini @@ -0,0 +1,5 @@ +[DATABASE] +name = cisco_naas +user = root +pass = nova +host = 127.0.0.1 diff --git a/quantum/plugins/cisco/db_test_plugin.py b/quantum/plugins/cisco/db_test_plugin.py new file mode 100644 index 0000000000..3e39399774 --- /dev/null +++ b/quantum/plugins/cisco/db_test_plugin.py @@ -0,0 +1,1046 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011, Cisco Systems, Inc. +# +# 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. +# @author: Rohit Agarwalla, Cisco Systems, Inc. + +import ConfigParser +import os +import logging as LOG +import unittest +from optparse import OptionParser + +import quantum.db.api as db +import quantum.plugins.cisco.l2network_db as l2network_db +import quantum.db.models +import quantum.plugins.cisco.l2network_models + +CONF_FILE = "db_conn.ini" + + +def find_config(basepath): + for root, dirs, files in os.walk(basepath): + if CONF_FILE in files: + return os.path.join(root, CONF_FILE) + return None + + +def db_conf(configfile=None): + config = ConfigParser.ConfigParser() + if configfile == None: + if os.path.exists(CONF_FILE): + configfile = CONF_FILE + else: + configfile = \ + find_config(os.path.abspath(os.path.dirname(__file__))) + if configfile == None: + raise Exception("Configuration file \"%s\" doesn't exist" % + (configfile)) + LOG.debug("Using configuration file: %s" % configfile) + config.read(configfile) + + DB_NAME = config.get("DATABASE", "name") + DB_USER = config.get("DATABASE", "user") + DB_PASS = config.get("DATABASE", "pass") + DB_HOST = config.get("DATABASE", "host") + options = {"sql_connection": "mysql://%s:%s@%s/%s" % (DB_USER, + DB_PASS, DB_HOST, DB_NAME)} + db.configure_db(options) + + +class UcsDB(object): + def get_all_ucsmbindings(self): + bindings = [] + try: + for x in ucs_db.get_all_ucsmbinding(): + LOG.debug("Getting ucsm binding : %s" % x.ucsm_ip) + bind_dict = {} + bind_dict["ucsm-ip"] = str(x.ucsm_ip) + bind_dict["network-id"] = str(x.network_id) + bindings.append(bind_dict) + except Exception, e: + LOG.error("Failed to get all bindings: %s" % str(e)) + return bindings + + def get_ucsmbinding(self, ucsm_ip): + binding = [] + try: + for x in ucs_db.get_ucsmbinding(ucsm_ip): + LOG.debug("Getting ucsm binding : %s" % x.ucsm_ip) + bind_dict = {} + bind_dict["ucsm-ip"] = str(res.ucsm_ip) + bind_dict["network-id"] = str(res.network_id) + binding.append(bind_dict) + except Exception, e: + LOG.error("Failed to get binding: %s" % str(e)) + return binding + + def create_ucsmbinding(self, ucsm_ip, networ_id): + bind_dict = {} + try: + res = ucs_db.add_ucsmbinding(ucsm_ip, networ_id) + LOG.debug("Created ucsm binding: %s" % res.ucsm_ip) + bind_dict["ucsm-ip"] = str(res.ucsm_ip) + bind_dict["network-id"] = str(res.network_id) + return bind_dict + except Exception, e: + LOG.error("Failed to create ucsm binding: %s" % str(e)) + + def delete_ucsmbinding(self, ucsm_ip): + try: + res = ucs_db.remove_ucsmbinding(ucsm_ip) + LOG.debug("Deleted ucsm binding : %s" % res.ucsm_ip) + bind_dict = {} + bind_dict["ucsm-ip"] = str(res.ucsm_ip) + return bind_dict + except Exception, e: + raise Exception("Failed to delete dynamic vnic: %s" % str(e)) + + def update_ucsmbinding(self, ucsm_ip, network_id): + try: + res = ucs_db.update_ucsmbinding(ucsm_ip, network_id) + LOG.debug("Updating ucsm binding : %s" % res.ucsm_ip) + bind_dict = {} + bind_dict["ucsm-ip"] = str(res.ucsm_ip) + bind_dict["network-id"] = str(res.network_id) + return bind_dict + except Exception, e: + raise Exception("Failed to update dynamic vnic: %s" % str(e)) + + def get_all_dynamicvnics(self): + vnics = [] + try: + for x in ucs_db.get_all_dynamicvnics(): + LOG.debug("Getting dynamic vnic : %s" % x.uuid) + vnic_dict = {} + vnic_dict["vnic-id"] = str(x.uuid) + vnic_dict["device-name"] = x.device_name + vnic_dict["blade-id"] = str(x.blade_id) + vnics.append(vnic_dict) + except Exception, e: + LOG.error("Failed to get all dynamic vnics: %s" % str(e)) + return vnics + + def get_dynamicvnic(self, vnic_id): + vnic = [] + try: + for x in ucs_db.get_dynamicvnic(vnic_id): + LOG.debug("Getting dynamic vnic : %s" % x.uuid) + vnic_dict = {} + vnic_dict["vnic-id"] = str(x.uuid) + vnic_dict["device-name"] = x.device_name + vnic_dict["blade-id"] = str(x.blade_id) + vnic.append(vnic_dict) + except Exception, e: + LOG.error("Failed to get dynamic vnic: %s" % str(e)) + return vnic + + def create_dynamicvnic(self, device_name, blade_id): + vnic_dict = {} + try: + res = ucs_db.add_dynamicvnic(device_name, blade_id) + LOG.debug("Created dynamic vnic: %s" % res.uuid) + vnic_dict["vnic-id"] = str(res.uuid) + vnic_dict["device-name"] = res.device_name + vnic_dict["blade-id"] = str(res.blade_id) + return vnic_dict + except Exception, e: + LOG.error("Failed to create dynamic vnic: %s" % str(e)) + + def delete_dynamicvnic(self, vnic_id): + try: + res = ucs_db.remove_dynamicvnic(vnic_id) + LOG.debug("Deleted dynamic vnic : %s" % res.uuid) + vnic_dict = {} + vnic_dict["vnic-id"] = str(res.uuid) + return vnic_dict + except Exception, e: + raise Exception("Failed to delete dynamic vnic: %s" % str(e)) + + def update_dynamicvnic(self, vnic_id, device_name=None, blade_id=None): + try: + res = ucs_db.update_dynamicvnic(vnic_id, device_name, blade_id) + LOG.debug("Updating dynamic vnic : %s" % res.uuid) + vnic_dict = {} + vnic_dict["vnic-id"] = str(res.uuid) + vnic_dict["device-name"] = res.device_name + vnic_dict["blade-id"] = str(res.blade_id) + return vnic_dict + except Exception, e: + raise Exception("Failed to update dynamic vnic: %s" % str(e)) + + def get_all_blades(self): + blades = [] + try: + for x in ucs_db.get_all_blades(): + LOG.debug("Getting blade : %s" % x.uuid) + blade_dict = {} + blade_dict["blade-id"] = str(x.uuid) + blade_dict["mgmt-ip"] = str(x.mgmt_ip) + blade_dict["mac-addr"] = str(x.mac_addr) + blade_dict["chassis-id"] = str(x.chassis_id) + blade_dict["ucsm-ip"] = str(x.ucsm_ip) + blades.append(blade_dict) + except Exception, e: + LOG.error("Failed to get all blades: %s" % str(e)) + return blades + + def get_blade(self, blade_id): + blade = [] + try: + for x in ucs_db.get_blade(blade_id): + LOG.debug("Getting blade : %s" % x.uuid) + blade_dict = {} + blade_dict["blade-id"] = str(x.uuid) + blade_dict["mgmt-ip"] = str(x.mgmt_ip) + blade_dict["mac-addr"] = str(x.mac_addr) + blade_dict["chassis-id"] = str(x.chassis_id) + blade_dict["ucsm-ip"] = str(x.ucsm_ip) + blade.append(blade_dict) + except Exception, e: + LOG.error("Failed to get all blades: %s" % str(e)) + return blade + + def create_blade(self, mgmt_ip, mac_addr, chassis_id, ucsm_ip): + blade_dict = {} + try: + res = ucs_db.add_blade(mgmt_ip, mac_addr, chassis_id, ucsm_ip) + LOG.debug("Created blade: %s" % res.uuid) + blade_dict["blade-id"] = str(res.uuid) + blade_dict["mgmt-ip"] = str(res.mgmt_ip) + blade_dict["mac-addr"] = str(res.mac_addr) + blade_dict["chassis-id"] = str(res.chassis_id) + blade_dict["ucsm-ip"] = str(res.ucsm_ip) + return blade_dict + except Exception, e: + LOG.error("Failed to create blade: %s" % str(e)) + + def delete_blade(self, blade_id): + try: + res = ucs_db.remove_blade(blade_id) + LOG.debug("Deleted blade : %s" % res.uuid) + blade_dict = {} + blade_dict["blade-id"] = str(res.uuid) + return blade_dict + except Exception, e: + raise Exception("Failed to delete blade: %s" % str(e)) + + def update_blade(self, blade_id, mgmt_ip=None, mac_addr=None,\ + chassis_id=None, ucsm_ip=None): + try: + res = ucs_db.update_blade(blade_id, mgmt_ip, mac_addr, \ + chassis_id, ucsm_ip) + LOG.debug("Updating blade : %s" % res.uuid) + blade_dict = {} + blade_dict["blade-id"] = str(res.uuid) + blade_dict["mgmt-ip"] = str(res.mgmt_ip) + blade_dict["mac-addr"] = str(res.mac_addr) + blade_dict["chassis-id"] = str(res.chassis_id) + blade_dict["ucsm-ip"] = str(res.ucsm_ip) + return blade_dict + except Exception, e: + raise Exception("Failed to update blade: %s" % str(e)) + + def get_all_port_bindings(self): + port_bindings = [] + try: + for x in ucs_db.get_all_portbindings(): + LOG.debug("Getting port binding for port: %s" % x.port_id) + port_bind_dict = {} + port_bind_dict["port-id"] = x.port_id + port_bind_dict["dynamic-vnic-id"] = str(x.dynamic_vnic_id) + port_bind_dict["portprofile-name"] = x.portprofile_name + port_bind_dict["vlan-name"] = x.vlan_name + port_bind_dict["vlan-id"] = str(x.vlan_id) + port_bind_dict["qos"] = x.qos + port_bindings.append(port_bind_dict) + except Exception, e: + LOG.error("Failed to get all port bindings: %s" % str(e)) + return port_bindings + + def get_port_binding(self): + port_binding = [] + try: + for x in ucs_db.get_portbinding(port_id): + LOG.debug("Getting port binding for port: %s" % x.port_id) + port_bind_dict = {} + port_bind_dict["port-id"] = x.port_id + port_bind_dict["dynamic-vnic-id"] = str(x.dynamic_vnic_id) + port_bind_dict["portprofile-name"] = x.portprofile_name + port_bind_dict["vlan-name"] = x.vlan_name + port_bind_dict["vlan-id"] = str(x.vlan_id) + port_bind_dict["qos"] = x.qos + port_bindings.append(port_bind_dict) + except Exception, e: + LOG.error("Failed to get port binding: %s" % str(e)) + return port_binding + + def create_port_binding(self, port_id, dynamic_vnic_id, portprofile_name, \ + vlan_name, vlan_id, qos): + port_bind_dict = {} + try: + res = ucs_db.add_portbinding(port_id, dynamic_vnic_id, \ + portprofile_name, vlan_name, vlan_id, qos) + LOG.debug("Created port binding: %s" % res.port_id) + port_bind_dict["port-id"] = res.port_id + port_bind_dict["dynamic-vnic-id"] = str(res.dynamic_vnic_id) + port_bind_dict["portprofile-name"] = res.portprofile_name + port_bind_dict["vlan-name"] = res.vlan_name + port_bind_dict["vlan-id"] = str(res.vlan_id) + port_bind_dict["qos"] = res.qos + return port_bind_dict + except Exception, e: + LOG.error("Failed to create port binding: %s" % str(e)) + + def delete_port_binding(self, port_id): + try: + res = ucs_db.remove_portbinding(port_id) + LOG.debug("Deleted port binding : %s" % res.port_id) + port_bind_dict = {} + port_bind_dict["port-id"] = res.port_id + return port_bind_dict + except Exception, e: + raise Exception("Failed to delete port profile: %s" % str(e)) + + def update_port_binding(self, port_id, dynamic_vnic_id, \ + portprofile_name, vlan_name, vlan_id, qos): + try: + res = ucs_db.update_portbinding(port_id, dynamic_vnic_id, \ + portprofile_name, vlan_name, vlan_id, qos) + LOG.debug("Updating port binding: %s" % res.port_id) + port_bind_dict = {} + port_bind_dict["port-id"] = res.port_id + port_bind_dict["dynamic-vnic-id"] = str(res.dynamic_vnic_id) + port_bind_dict["portprofile-name"] = res.portprofile_name + port_bind_dict["vlan-name"] = res.vlan_name + port_bind_dict["vlan-id"] = str(res.vlan_id) + port_bind_dict["qos"] = res.qos + return port_bind_dict + except Exception, e: + raise Exception("Failed to update portprofile binding:%s" % str(e)) + + +class QuantumDB(object): + def get_all_networks(self, tenant_id): + nets = [] + try: + for x in db.network_list(tenant_id): + LOG.debug("Getting network: %s" % x.uuid) + net_dict = {} + net_dict["tenant-id"] = x.tenant_id + net_dict["net-id"] = str(x.uuid) + net_dict["net-name"] = x.name + nets.append(net_dict) + except Exception, e: + LOG.error("Failed to get all networks: %s" % str(e)) + return nets + + def get_network(self, network_id): + net = [] + try: + for x in db.network_get(network_id): + LOG.debug("Getting network: %s" % x.uuid) + net_dict = {} + net_dict["tenant-id"] = x.tenant_id + net_dict["net-id"] = str(x.uuid) + net_dict["net-name"] = x.name + nets.append(net_dict) + except Exception, e: + LOG.error("Failed to get network: %s" % str(e)) + return net + + def create_network(self, tenant_id, net_name): + net_dict = {} + try: + res = db.network_create(tenant_id, net_name) + LOG.debug("Created network: %s" % res.uuid) + net_dict["tenant-id"] = res.tenant_id + net_dict["net-id"] = str(res.uuid) + net_dict["net-name"] = res.name + return net_dict + except Exception, e: + LOG.error("Failed to create network: %s" % str(e)) + + def delete_network(self, net_id): + try: + net = db.network_destroy(net_id) + LOG.debug("Deleted network: %s" % net.uuid) + net_dict = {} + net_dict["net-id"] = str(net.uuid) + return net_dict + except Exception, e: + raise Exception("Failed to delete port: %s" % str(e)) + + def rename_network(self, tenant_id, net_id, new_name): + try: + net = db.network_rename(net_id, tenant_id, new_name) + LOG.debug("Renamed network: %s" % net.uuid) + net_dict = {} + net_dict["net-id"] = str(net.uuid) + net_dict["net-name"] = net.name + return net_dict + except Exception, e: + raise Exception("Failed to rename network: %s" % str(e)) + + def get_all_ports(self, net_id): + ports = [] + try: + for x in db.port_list(net_id): + LOG.debug("Getting port: %s" % x.uuid) + port_dict = {} + port_dict["port-id"] = str(x.uuid) + port_dict["net-id"] = str(x.network_id) + port_dict["int-id"] = x.interface_id + port_dict["state"] = x.state + ports.append(port_dict) + return ports + except Exception, e: + LOG.error("Failed to get all ports: %s" % str(e)) + + def get_port(self, port_id): + port = [] + try: + for x in db.port_get(port_id): + LOG.debug("Getting port: %s" % x.uuid) + port_dict = {} + port_dict["port-id"] = str(x.uuid) + port_dict["net-id"] = str(x.network_id) + port_dict["int-id"] = x.interface_id + port_dict["state"] = x.state + port.append(port_dict) + return port + except Exception, e: + LOG.error("Failed to get port: %s" % str(e)) + + def create_port(self, net_id): + port_dict = {} + try: + port = db.port_create(net_id) + LOG.debug("Creating port %s" % port.uuid) + port_dict["port-id"] = str(port.uuid) + port_dict["net-id"] = str(port.network_id) + port_dict["int-id"] = port.interface_id + port_dict["state"] = port.state + return port_dict + except Exception, e: + LOG.error("Failed to create port: %s" % str(e)) + + def delete_port(self, port_id): + try: + port = db.port_destroy(port_id) + LOG.debug("Deleted port %s" % port.uuid) + port_dict = {} + port_dict["port-id"] = str(port.uuid) + return port_dict + except Exception, e: + raise Exception("Failed to delete port: %s" % str(e)) + + def update_port(self, port_id, port_state): + try: + port = db.port_set_state(port_id, port_state) + LOG.debug("Updated port %s" % port.uuid) + port_dict = {} + port_dict["port-id"] = str(port.uuid) + port_dict["net-id"] = str(port.network_id) + port_dict["int-id"] = port.interface_id + port_dict["state"] = port.state + return port_dict + except Exception, e: + raise Exception("Failed to update port state: %s" % str(e)) + + +class L2networkDB(object): + def get_all_vlan_bindings(self): + vlans = [] + try: + for x in l2network_db.get_all_vlan_bindings(): + LOG.debug("Getting vlan bindings for vlan: %s" % x.vlan_id) + vlan_dict = {} + vlan_dict["vlan-id"] = str(x.vlan_id) + vlan_dict["vlan-name"] = x.vlan_name + vlan_dict["net-id"] = str(x.network_id) + vlans.append(vlan_dict) + except Exception, e: + LOG.error("Failed to get all vlan bindings: %s" % str(e)) + return vlans + + def get_vlan_binding(self, network_id): + vlan = [] + try: + for x in l2network_db.get_vlan_binding(network_id): + LOG.debug("Getting vlan binding for vlan: %s" % x.vlan_id) + vlan_dict = {} + vlan_dict["vlan-id"] = str(x.vlan_id) + vlan_dict["vlan-name"] = x.vlan_name + vlan_dict["net-id"] = str(x.network_id) + vlan.append(vlan_dict) + except Exception, e: + LOG.error("Failed to get vlan binding: %s" % str(e)) + return vlan + + def create_vlan_binding(self, vlan_id, vlan_name, network_id): + vlan_dict = {} + try: + res = l2network_db.add_vlan_binding(vlan_id, vlan_name, network_id) + LOG.debug("Created vlan binding for vlan: %s" % res.vlan_id) + vlan_dict["vlan-id"] = str(res.vlan_id) + vlan_dict["vlan-name"] = res.vlan_name + vlan_dict["net-id"] = str(res.network_id) + return vlan_dict + except Exception, e: + LOG.error("Failed to create vlan binding: %s" % str(e)) + + def delete_vlan_binding(self, network_id): + try: + res = l2network_db.remove_vlan_binding(network_id) + LOG.debug("Deleted vlan binding for vlan: %s" % res.vlan_id) + vlan_dict = {} + vlan_dict["vlan-id"] = str(res.vlan_id) + return vlan_dict + except Exception, e: + raise Exception("Failed to delete vlan binding: %s" % str(e)) + + def update_vlan_binding(self, network_id, vlan_id, vlan_name): + try: + res = l2network_db.update_vlan_binding(network_id, vlan_id, \ + vlan_name) + LOG.debug("Updating vlan binding for vlan: %s" % res.vlan_id) + vlan_dict = {} + vlan_dict["vlan-id"] = str(res.vlan_id) + vlan_dict["vlan-name"] = res.vlan_name + vlan_dict["net-id"] = str(res.network_id) + return vlan_dict + except Exception, e: + raise Exception("Failed to update vlan binding: %s" % str(e)) + + def get_all_portprofiles(self): + pps = [] + try: + for x in l2network_db.get_all_portprofiles(): + LOG.debug("Getting port profile : %s" % x.uuid) + pp_dict = {} + pp_dict["portprofile-id"] = str(x.uuid) + pp_dict["portprofile-name"] = x.name + pp_dict["vlan-id"] = str(x.vlan_id) + pp_dict["qos"] = x.qos + pps.append(pp_dict) + except Exception, e: + LOG.error("Failed to get all port profiles: %s" % str(e)) + return pps + + def get_portprofile(self, port_id): + pp = [] + try: + for x in l2network_db.get_portprofile(port_id): + LOG.debug("Getting port profile : %s" % x.uuid) + pp_dict = {} + pp_dict["portprofile-id"] = str(x.uuid) + pp_dict["portprofile-name"] = x.name + pp_dict["vlan-id"] = str(x.vlan_id) + pp_dict["qos"] = x.qos + pp.append(pp_dict) + except Exception, e: + LOG.error("Failed to get port profile: %s" % str(e)) + return pp + + def create_portprofile(self, name, vlan_id, qos): + pp_dict = {} + try: + res = l2network_db.add_portprofile(name, vlan_id, qos) + LOG.debug("Created port profile: %s" % res.uuid) + pp_dict["portprofile-id"] = str(res.uuid) + pp_dict["portprofile-name"] = res.name + pp_dict["vlan-id"] = str(res.vlan_id) + pp_dict["qos"] = res.qos + return pp_dict + except Exception, e: + LOG.error("Failed to create port profile: %s" % str(e)) + + def delete_portprofile(self, pp_id): + try: + res = l2network_db.remove_portprofile(pp_id) + LOG.debug("Deleted port profile : %s" % res.uuid) + pp_dict = {} + pp_dict["pp-id"] = str(res.uuid) + return pp_dict + except Exception, e: + raise Exception("Failed to delete port profile: %s" % str(e)) + + def update_portprofile(self, pp_id, name, vlan_id, qos): + try: + res = l2network_db.update_portprofile(pp_id, name, vlan_id, qos) + LOG.debug("Updating port profile : %s" % res.uuid) + pp_dict = {} + pp_dict["portprofile-id"] = str(res.uuid) + pp_dict["portprofile-name"] = res.name + pp_dict["vlan-id"] = str(res.vlan_id) + pp_dict["qos"] = res.qos + return pp_dict + except Exception, e: + raise Exception("Failed to update port profile: %s" % str(e)) + + def get_all_pp_bindings(self): + pp_bindings = [] + try: + for x in l2network_db.get_all_pp_bindings(): + LOG.debug("Getting port profile binding: %s" % \ + x.portprofile_id) + ppbinding_dict = {} + ppbinding_dict["portprofile-id"] = str(x.portprofile_id) + ppbinding_dict["net-id"] = str(x.network_id) + ppbinding_dict["tenant-id"] = x.tenant_id + ppbinding_dict["default"] = x.default + pp_bindings.append(ppbinding_dict) + except Exception, e: + LOG.error("Failed to get all port profiles: %s" % str(e)) + return pp_bindings + + def get_pp_binding(self, pp_id): + pp_binding = [] + try: + for x in l2network_db.get_pp_binding(pp_id): + LOG.debug("Getting port profile binding: %s" % \ + x.portprofile_id) + ppbinding_dict = {} + ppbinding_dict["portprofile-id"] = str(x.portprofile_id) + ppbinding_dict["net-id"] = str(x.network_id) + ppbinding_dict["tenant-id"] = x.tenant_id + ppbinding_dict["default"] = x.default + pp_bindings.append(ppbinding_dict) + except Exception, e: + LOG.error("Failed to get port profile binding: %s" % str(e)) + return pp_binding + + def create_pp_binding(self, tenant_id, net_id, pp_id, default): + ppbinding_dict = {} + try: + res = l2network_db.add_pp_binding(tenant_id, net_id, pp_id, \ + default) + LOG.debug("Created port profile binding: %s" % res.portprofile_id) + ppbinding_dict["portprofile-id"] = str(res.portprofile_id) + ppbinding_dict["net-id"] = str(res.network_id) + ppbinding_dict["tenant-id"] = res.tenant_id + ppbinding_dict["default"] = res.default + return ppbinding_dict + except Exception, e: + LOG.error("Failed to create port profile binding: %s" % str(e)) + + def delete_pp_binding(self, pp_id): + try: + res = l2network_db.remove_pp_binding(pp_id) + LOG.debug("Deleted port profile binding : %s" % res.portprofile_id) + ppbinding_dict = {} + ppbinding_dict["portprofile-id"] = str(res.portprofile_id) + return ppbinding_dict + except Exception, e: + raise Exception("Failed to delete port profile: %s" % str(e)) + + def update_pp_binding(self, pp_id, tenant_id, net_id, default): + try: + res = l2network_db.update_pp_binding(pp_id, tenant_id, net_id,\ + default) + LOG.debug("Updating port profile binding: %s" % res.portprofile_id) + ppbinding_dict = {} + ppbinding_dict["portprofile-id"] = str(res.portprofile_id) + ppbinding_dict["net-id"] = str(res.network_id) + ppbinding_dict["tenant-id"] = res.tenant_id + ppbinding_dict["default"] = res.default + return ppbinding_dict + except Exception, e: + raise Exception("Failed to update portprofile binding:%s" % str(e)) + + +class UcsDBTest(unittest.TestCase): + def setUp(self): + self.dbtest = UcsDB() + LOG.debug("Setup") + + def testACreateUcsmBinding(self): + binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", "net1") + self.assertTrue(binding1["ucsm-ip"] == "1.2.3.4") + self.tearDownUcsmBinding() + + def testBGetAllUcsmBindings(self): + binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", "net1") + binding2 = self.dbtest.create_ucsmbinding("2.3.4.5", "net1") + bindings = self.dbtest.get_all_ucsmbindings() + count = 0 + for x in bindings: + if "net" in x["network-id"]: + count += 1 + self.assertTrue(count == 2) + self.tearDownUcsmBinding() + + def testCDeleteUcsmBinding(self): + binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", "net1") + self.dbtest.delete_ucsmbinding(binding1["ucsm-ip"]) + bindings = self.dbtest.get_all_ucsmbindings() + count = 0 + for x in bindings: + if "net " in x["network-id"]: + count += 1 + self.assertTrue(count == 0) + self.tearDownUcsmBinding() + + def testDUpdateUcsmBinding(self): + binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", "net1") + binding1 = self.dbtest.update_ucsmbinding(binding1["ucsm-ip"], \ + "newnet1") + bindings = self.dbtest.get_all_ucsmbindings() + count = 0 + for x in bindings: + if "new" in x["network-id"]: + count += 1 + self.assertTrue(count == 1) + self.tearDownUcsmBinding() + + def testECreateDynamicVnic(self): + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ + "9.8.7.6") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"]) + self.assertTrue(vnic1["device-name"] == "eth1") + self.tearDownDyanmicVnic() + + def testFGetAllDyanmicVnics(self): + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ + "9.8.7.6") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"]) + vnic2 = self.dbtest.create_dynamicvnic("eth2", blade1["blade-id"]) + vnics = self.dbtest.get_all_dynamicvnics() + count = 0 + for x in vnics: + if "eth" in x["device-name"]: + count += 1 + self.assertTrue(count == 2) + self.tearDownDyanmicVnic() + + def testGDeleteDyanmicVnic(self): + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ + "9.8.7.6") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"]) + self.dbtest.delete_dynamicvnic(vnic1["vnic-id"]) + vnics = self.dbtest.get_all_dynamicvnics() + count = 0 + for x in vnics: + if "eth " in x["device-name"]: + count += 1 + self.assertTrue(count == 0) + self.tearDownDyanmicVnic() + + def testHUpdateDynamicVnic(self): + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ + "9.8.7.6") + vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"]) + vnic1 = self.dbtest.update_dynamicvnic(vnic1["vnic-id"], "neweth1", \ + "newblade2") + vnics = self.dbtest.get_all_dynamicvnics() + count = 0 + for x in vnics: + if "new" in x["device-name"]: + count += 1 + self.assertTrue(count == 1) + self.tearDownDyanmicVnic() + + def testICreateUcsBlade(self): + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ + "9.8.7.6") + self.assertTrue(blade1["mgmt-ip"] == "1.2.3.4") + self.tearDownUcsBlade() + + def testJGetAllUcsBlade(self): + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ + "9.8.7.6") + blade2 = self.dbtest.create_blade("2.3.4.5", "efgh", "chassis1", \ + "9.8.7.6") + blades = self.dbtest.get_all_blades() + count = 0 + for x in blades: + if "chassis" in x["chassis-id"]: + count += 1 + self.assertTrue(count == 2) + self.tearDownUcsBlade() + + def testKDeleteUcsBlade(self): + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ + "9.8.7.6") + self.dbtest.delete_blade(blade1["blade-id"]) + blades = self.dbtest.get_all_blades() + count = 0 + for x in blades: + if "chassis " in x["chassis-id"]: + count += 1 + self.assertTrue(count == 0) + self.tearDownUcsBlade() + + def testLUpdateUcsBlade(self): + blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ + "9.8.7.6") + blade2 = self.dbtest.update_blade(blade1["blade-id"], "2.3.4.5", \ + "newabcd", "chassis1", "9.8.7.6") + blades = self.dbtest.get_all_blades() + count = 0 + for x in blades: + if "new" in x["mac-addr"]: + count += 1 + self.assertTrue(count == 1) + self.tearDownUcsBlade() + + def testMCreatePortBinding(self): + port_bind1 = self.dbtest.create_port_binding("port1", "dv1", "pp1", \ + "vlan1", 10, "qos1") + self.assertTrue(port_bind1["port-id"] == "port1") + self.tearDownPortBinding() + + def testNGetAllPortBinding(self): + port_bind1 = self.dbtest.create_port_binding("port1", "dv1", "pp1", \ + "vlan1", 10, "qos1") + port_bind2 = self.dbtest.create_port_binding("port2", "dv2", "pp2", \ + "vlan2", 20, "qos2") + port_bindings = self.dbtest.get_all_port_bindings() + count = 0 + for x in port_bindings: + if "port" in x["port-id"]: + count += 1 + self.assertTrue(count == 2) + self.tearDownPortBinding() + + def testODeletePortBinding(self): + port_bind1 = self.dbtest.create_port_binding("port1", "dv1", "pp1", \ + "vlan1", 10, "qos1") + self.dbtest.delete_port_binding("port1") + port_bindings = self.dbtest.get_all_port_bindings() + count = 0 + for x in port_bindings: + if "port " in x["port-id"]: + count += 1 + self.assertTrue(count == 0) + self.tearDownPortBinding() + + def testPUpdatePortBinding(self): + port_bind1 = self.dbtest.create_port_binding("port1", "dv1", "pp1", \ + "vlan1", 10, "qos1") + port_bind1 = self.dbtest.update_port_binding("port1", "newdv1", \ + "newpp1", "newvlan1", 11, "newqos1") + port_bindings = self.dbtest.get_all_port_bindings() + count = 0 + for x in port_bindings: + if "new" in x["dynamic-vnic-id"]: + count += 1 + self.assertTrue(count == 1) + self.tearDownPortBinding() + + def tearDownUcsmBinding(self): + print "Tearing Down Ucsm Bindings" + binds = self.dbtest.get_all_ucsmbindings() + for bind in binds: + ip = bind["ucsm-ip"] + self.dbtest.delete_ucsmbinding(ip) + + def tearDownDyanmicVnic(self): + print "Tearing Down Dynamic Vnics" + vnics = self.dbtest.get_all_dynamicvnics() + for vnic in vnics: + id = vnic["vnic-id"] + self.dbtest.delete_dynamicvnic(id) + self.tearDownUcsBlade() + + def tearDownUcsBlade(self): + print "Tearing Down Blades" + blades = self.dbtest.get_all_blades() + for blade in blades: + id = blade["blade-id"] + self.dbtest.delete_blade(id) + + def tearDownPortBinding(self): + print "Tearing Down Port Binding" + port_bindings = self.dbtest.get_all_port_bindings() + for port_binding in port_bindings: + id = port_binding["port-id"] + self.dbtest.delete_port_binding(id) + + +class L2networkDBTest(unittest.TestCase): + def setUp(self): + self.dbtest = L2networkDB() + LOG.debug("Setup") + + def testACreateVlanBinding(self): + vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", "netid1") + self.assertTrue(vlan1["vlan-id"] == "10") + self.tearDownVlanBinding() + + def testBGetAllVlanBindings(self): + vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", "netid1") + vlan2 = self.dbtest.create_vlan_binding(20, "vlan2", "netid2") + vlans = self.dbtest.get_all_vlan_bindings() + count = 0 + for x in vlans: + if "netid" in x["net-id"]: + count += 1 + self.assertTrue(count == 2) + self.tearDownVlanBinding() + + def testCDeleteVlanBinding(self): + vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", "netid1") + self.dbtest.delete_vlan_binding("netid1") + vlans = self.dbtest.get_all_vlan_bindings() + count = 0 + for x in vlans: + if "netid " in x["net-id"]: + count += 1 + self.assertTrue(count == 0) + self.tearDownVlanBinding() + + def testDUpdateVlanBinding(self): + vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", "netid1") + vlan1 = self.dbtest.update_vlan_binding("netid1", 11, "newvlan1") + vlans = self.dbtest.get_all_vlan_bindings() + count = 0 + for x in vlans: + if "new" in x["vlan-name"]: + count += 1 + self.assertTrue(count == 1) + self.tearDownVlanBinding() + + def testICreatePortProfile(self): + pp1 = self.dbtest.create_portprofile("portprofile1", 10, "qos1") + self.assertTrue(pp1["portprofile-name"] == "portprofile1") + self.tearDownPortProfile() + + def testJGetAllPortProfile(self): + pp1 = self.dbtest.create_portprofile("portprofile1", 10, "qos1") + pp2 = self.dbtest.create_portprofile("portprofile2", 20, "qos2") + pps = self.dbtest.get_all_portprofiles() + count = 0 + for x in pps: + if "portprofile" in x["portprofile-name"]: + count += 1 + self.assertTrue(count == 2) + self.tearDownPortProfile() + + def testKDeletePortProfile(self): + pp1 = self.dbtest.create_portprofile("portprofile1", 10, "qos1") + self.dbtest.delete_portprofile(pp1["portprofile-id"]) + pps = self.dbtest.get_all_portprofiles() + count = 0 + for x in pps: + if "portprofile " in x["portprofile-name"]: + count += 1 + self.assertTrue(count == 0) + self.tearDownPortProfile() + + def testLUpdatePortProfile(self): + pp1 = self.dbtest.create_portprofile("portprofile1", 10, "qos1") + pp1 = self.dbtest.update_portprofile(pp1["portprofile-id"], \ + "newportprofile1", 20, "qos2") + pps = self.dbtest.get_all_portprofiles() + count = 0 + for x in pps: + if "new" in x["portprofile-name"]: + count += 1 + self.assertTrue(count == 1) + self.tearDownPortProfile() + + def testMCreatePortProfileBinding(self): + pp_binding1 = self.dbtest.create_pp_binding("t1", "net1", \ + "portprofile1", "0") + self.assertTrue(pp_binding1["portprofile-id"] == "portprofile1") + self.tearDownPortProfileBinding() + + def testNGetAllPortProfileBinding(self): + pp_binding1 = self.dbtest.create_pp_binding("t1", "net1", \ + "portprofile1", "0") + pp_binding2 = self.dbtest.create_pp_binding("t2", "net2", \ + "portprofile2", "0") + pp_bindings = self.dbtest.get_all_pp_bindings() + count = 0 + for x in pp_bindings: + if "portprofile" in x["portprofile-id"]: + count += 1 + self.assertTrue(count == 2) + self.tearDownPortProfileBinding() + + def testODeletePortProfileBinding(self): + pp_binding1 = self.dbtest.create_pp_binding("t1", "net1", \ + "portprofile1", "0") + self.dbtest.delete_pp_binding(pp_binding1["portprofile-id"]) + pp_bindings = self.dbtest.get_all_pp_bindings() + count = 0 + for x in pp_bindings: + if "portprofile " in x["portprofile-id"]: + count += 1 + self.assertTrue(count == 0) + self.tearDownPortProfileBinding() + + def testPUpdatePortProfileBinding(self): + pp_binding1 = self.dbtest.create_pp_binding("t1", "net1", \ + "portprofile1", "0") + pp_binding1 = self.dbtest.update_pp_binding("portprofile1", \ + "newt1", "newnet1", "1") + pp_bindings = self.dbtest.get_all_pp_bindings() + count = 0 + for x in pp_bindings: + if "new" in x["net-id"]: + count += 1 + self.assertTrue(count == 1) + self.tearDownPortProfileBinding() + + def tearDownVlanBinding(self): + print "Tearing Down Vlan Binding" + vlans = self.dbtest.get_all_vlan_bindings() + for vlan in vlans: + id = vlan["net-id"] + self.dbtest.delete_vlan_binding(id) + + def tearDownPortProfile(self): + print "Tearing Down Port Profile" + pps = self.dbtest.get_all_portprofiles() + for pp in pps: + id = pp["portprofile-id"] + self.dbtest.delete_portprofile(id) + + def tearDownPortProfileBinding(self): + print "Tearing Down Port Profile Binding" + pp_bindings = self.dbtest.get_all_pp_bindings() + for pp_binding in pp_bindings: + id = pp_binding["portprofile-id"] + self.dbtest.delete_pp_binding(id) + +if __name__ == "__main__": + usagestr = "Usage: %prog [OPTIONS] [args]" + parser = OptionParser(usage=usagestr) + parser.add_option("-v", "--verbose", dest="verbose", + action="store_true", default=False, help="turn on verbose logging") + + options, args = parser.parse_args() + + if options.verbose: + LOG.basicConfig(level=LOG.DEBUG) + else: + LOG.basicConfig(level=LOG.WARN) + + #load the models and db based on the 2nd level plugin argument + if args[0] == "ucs": + ucs_db = __import__("quantum.plugins.cisco.ucs_db", \ + fromlist=["ucs_db"]) + ucs_model = __import__("quantum.plugins.cisco.ucs_models", \ + fromlist=["ucs_models"]) + + db_conf() + + # Run the tests + suite = unittest.TestLoader().loadTestsFromTestCase(L2networkDBTest) + unittest.TextTestRunner(verbosity=2).run(suite) + suite = unittest.TestLoader().loadTestsFromTestCase(UcsDBTest) + unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/quantum/plugins/cisco/l2network_db.py b/quantum/plugins/cisco/l2network_db.py new file mode 100644 index 0000000000..ca773b6567 --- /dev/null +++ b/quantum/plugins/cisco/l2network_db.py @@ -0,0 +1,239 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011, Cisco Systems, Inc. +# +# 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. +# @author: Rohit Agarwalla, Cisco Systems, Inc. + +from sqlalchemy.orm import exc + +import quantum.db.api as db +import quantum.db.models as models +import l2network_models + + +def get_all_vlan_bindings(): + """Lists all the vlan to network associations""" + session = db.get_session() + try: + bindings = session.query(l2network_models.VlanBinding).\ + all() + return bindings + except exc.NoResultFound: + return [] + + +def get_vlan_binding(netid): + """Lists the vlan given a network_id""" + session = db.get_session() + try: + binding = session.query(l2network_models.VlanBinding).\ + filter_by(network_id=netid).\ + one() + return binding + except exc.NoResultFound: + raise Exception("No network found with net-id = %s" % network_id) + + +def add_vlan_binding(vlanid, vlanname, netid): + """Adds a vlan to network association""" + session = db.get_session() + try: + binding = session.query(l2network_models.VlanBinding).\ + filter_by(vlan_id=vlanid).\ + one() + raise Exception("Vlan with id \"%s\" already exists" % vlanid) + except exc.NoResultFound: + binding = l2network_models.VlanBinding(vlanid, vlanname, netid) + session.add(binding) + session.flush() + return binding + + +def remove_vlan_binding(netid): + """Removes a vlan to network association""" + session = db.get_session() + try: + binding = session.query(l2network_models.VlanBinding).\ + filter_by(network_id=netid).\ + one() + session.delete(binding) + session.flush() + return binding + except exc.NoResultFound: + pass + + +def update_vlan_binding(netid, newvlanid=None, newvlanname=None): + """Updates a vlan to network association""" + session = db.get_session() + try: + binding = session.query(l2network_models.VlanBinding).\ + filter_by(network_id=netid).\ + one() + if newvlanid: + binding.vlan_id = newvlanid + if newvlanname: + binding.vlan_name = newvlanname + session.merge(binding) + session.flush() + return binding + except exc.NoResultFound: + raise Exception("No vlan binding found with network_id = %s" % netid) + + +def get_all_portprofiles(): + """Lists all the port profiles""" + session = db.get_session() + try: + pps = session.query(l2network_models.PortProfile).\ + all() + return pps + except exc.NoResultFound: + return [] + + +def get_portprofile(ppid): + """Lists a port profile""" + session = db.get_session() + try: + pp = session.query(l2network_models.PortProfile).\ + filter_by(uuid=ppid).\ + one() + return pp + except exc.NoResultFound: + raise Exception("No portprofile found with id = %s" % ppid) + + +def add_portprofile(ppname, vlanid, qos): + """Adds a port profile""" + session = db.get_session() + try: + pp = session.query(l2network_models.PortProfile).\ + filter_by(name=ppname).\ + one() + raise Exception("Port profile with name %s already exists" % ppname) + except exc.NoResultFound: + pp = l2network_models.PortProfile(ppname, vlanid, qos) + session.add(pp) + session.flush() + return pp + + +def remove_portprofile(ppid): + """Removes a port profile""" + session = db.get_session() + try: + pp = session.query(l2network_models.PortProfile).\ + filter_by(uuid=ppid).\ + one() + session.delete(pp) + session.flush() + return pp + except exc.NoResultFound: + pass + + +def update_portprofile(ppid, newppname=None, newvlanid=None, newqos=None): + """Updates port profile""" + session = db.get_session() + try: + pp = session.query(l2network_models.PortProfile).\ + filter_by(uuid=ppid).\ + one() + if newppname: + pp.name = newppname + if newvlanid: + pp.vlan_id = newvlanid + if newqos: + pp.qos = newqos + session.merge(pp) + session.flush() + return pp + except exc.NoResultFound: + raise Exception("No port profile with id = %s" % ppid) + + +def get_all_pp_bindings(): + """Lists all the port profiles""" + session = db.get_session() + try: + bindings = session.query(l2network_models.PortProfileBinding).\ + all() + return bindings + except exc.NoResultFound: + return [] + + +def get_pp_binding(ppid): + """Lists a port profile binding""" + session = db.get_session() + try: + binding = session.query(l2network_models.PortProfileBinding).\ + filter_by(portprofile_id=ppid).\ + one() + return binding + except exc.NoResultFound: + raise Exception("No portprofile binding found with id = %s" % ppid) + + +def add_pp_binding(tenantid, networkid, ppid, default): + """Adds a port profile binding""" + session = db.get_session() + try: + binding = session.query(l2network_models.PortProfileBinding).\ + filter_by(portprofile_id=ppid).\ + one() + raise Exception("Port profile binding with id \"%s\" already \ + exists" % ppid) + except exc.NoResultFound: + binding = l2network_models.PortProfileBinding(tenantid, networkid, \ + ppid, default) + session.add(binding) + session.flush() + return binding + + +def remove_pp_binding(ppid): + """Removes a port profile binding""" + session = db.get_session() + try: + binding = session.query(l2network_models.PortProfileBinding).\ + filter_by(portprofile_id=ppid).\ + one() + session.delete(binding) + session.flush() + return binding + except exc.NoResultFound: + pass + + +def update_pp_binding(ppid, newtenantid=None, newnetworkid=None, \ + newdefault=None): + """Updates port profile binding""" + session = db.get_session() + try: + binding = session.query(l2network_models.PortProfileBinding).\ + filter_by(portprofile_id=ppid).\ + one() + if newtenantid: + binding.tenant_id = newtenantid + if newnetworkid: + binding.network_id = newnetworkid + if newdefault: + binding.default = newdefault + session.merge(binding) + session.flush() + return binding + except exc.NoResultFound: + raise Exception("No port profile binding with id = %s" % ppid) diff --git a/quantum/plugins/cisco/l2network_models.py b/quantum/plugins/cisco/l2network_models.py new file mode 100644 index 0000000000..12d75bb303 --- /dev/null +++ b/quantum/plugins/cisco/l2network_models.py @@ -0,0 +1,86 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011, Cisco Systems, Inc. +# +# 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. +# @author: Rohit Agarwalla, Cisco Systems, Inc. + +import uuid + +from sqlalchemy import Column, Integer, String, ForeignKey, Boolean +from sqlalchemy.orm import relation + +from quantum.db.models import BASE + + +class VlanBinding(BASE): + """Represents a binding of vlan_id to network_id""" + __tablename__ = 'vlan_bindings' + + vlan_id = Column(Integer, primary_key=True) + vlan_name = Column(String(255)) + network_id = Column(String(255), nullable=False) + #foreign key to networks.uuid + + def __init__(self, vlan_id, vlan_name, network_id): + self.vlan_id = vlan_id + self.vlan_name = vlan_name + self.network_id = network_id + + def __repr__(self): + return "" % \ + (self.vlan_id, self.vlan_name, self.network_id) + + +class PortProfile(BASE): + """Represents Cisco plugin level PortProfile for a network""" + __tablename__ = 'portprofiles' + + uuid = Column(String(255), primary_key=True) + name = Column(String(255)) + vlan_id = Column(Integer) + qos = Column(String(255)) + + def __init__(self, name, vlan_id, qos=None): + self.uuid = uuid.uuid4() + self.name = name + self.vlan_id = vlan_id + self.qos = qos + + def __repr__(self): + return "" % \ + (self.uuid, self.name, self.vlan_id, self.qos) + + +class PortProfileBinding(BASE): + """Represents PortProfile binding to tenant and network""" + __tablename__ = 'portprofile_bindings' + + id = Column(Integer, primary_key=True, autoincrement=True) + tenant_id = Column(String(255)) + + network_id = Column(String(255), nullable=False) + #foreign key to networks.uuid + portprofile_id = Column(String(255), nullable=False) + #foreign key to portprofiles.uuid + default = Column(Boolean) + + def __init__(self, tenant_id, network_id, portprofile_id, default): + self.tenant_id = tenant_id + self.network_id = network_id + self.portprofile_id = portprofile_id + self.default = default + + def __repr__(self): + return "" % \ + (self.tenant_id, self.network_id, self.portprofile_id, self.default) diff --git a/quantum/plugins/cisco/ucs_db.py b/quantum/plugins/cisco/ucs_db.py new file mode 100644 index 0000000000..92198e89bb --- /dev/null +++ b/quantum/plugins/cisco/ucs_db.py @@ -0,0 +1,314 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011, Cisco Systems, Inc. +# +# 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. +# @author: Rohit Agarwalla, Cisco Systems, Inc. + +from sqlalchemy.orm import exc + +import quantum.db.api as db +import ucs_models + + +def get_all_ucsmbinding(): + """Lists all the ucsm bindings""" + session = db.get_session() + try: + bindings = session.query(ucs_models.UcsmBinding).\ + all() + return bindings + except exc.NoResultFound: + return [] + + +def get_ucsmbinding(ucsm_ip): + """Lists a ucsm binding""" + session = db.get_session() + try: + binding = session.query(ucs_models.UcsmBinding).\ + filter_by(ucsm_ip=ucsm_ip).\ + one() + return binding + except exc.NoResultFound: + raise Exception("No binding found with ip = %s" % ucsm_ip) + + +def add_ucsmbinding(ucsm_ip, network_id): + """Adds a ucsm binding""" + session = db.get_session() + try: + ip = session.query(ucs_models.UcsmBinding).\ + filter_by(ucsm_ip=ucsm_ip).\ + one() + raise Exception("Binding with ucsm ip \"%s\" already exists" % ucsm_ip) + except exc.NoResultFound: + binding = ucs_models.UcsmBinding(ucsm_ip, network_id) + session.add(binding) + session.flush() + return binding + + +def remove_ucsmbinding(ucsm_ip): + """Removes a ucsm binding""" + session = db.get_session() + try: + binding = session.query(ucs_models.UcsmBinding).\ + filter_by(ucsm_ip=ucsm_ip).\ + one() + session.delete(binding) + session.flush() + return binding + except exc.NoResultFound: + pass + + +def update_ucsmbinding(ucsm_ip, new_network_id): + """Updates ucsm binding""" + session = db.get_session() + try: + binding = session.query(ucs_models.UcsmBinding).\ + filter_by(ucsm_ip=ucsm_ip).\ + one() + if new_network_id: + binding.network_id = new_network_id + session.merge(binding) + session.flush() + return binding + except exc.NoResultFound: + raise Exception("No binding with ip = %s" % ucsm_ip) + + +def get_all_dynamicvnics(): + """Lists all the dynamic vnics""" + session = db.get_session() + try: + vnics = session.query(ucs_models.DynamicVnic).\ + all() + return vnics + except exc.NoResultFound: + return [] + + +def get_dynamicvnic(vnic_id): + """Lists a dynamic vnic""" + session = db.get_session() + try: + vnic = session.query(ucs_models.DynamicVnic).\ + filter_by(uuid=vnic_id).\ + one() + return vnic + except exc.NoResultFound: + raise Exception("No dynamic vnic found with id = %s" % vnic_id) + + +def add_dynamicvnic(device_name, blade_id): + """Adds a dynamic vnic""" + session = db.get_session() + try: + name = session.query(ucs_models.DynamicVnic).\ + filter_by(device_name=device_name).\ + one() + raise Exception("Dynamic vnic with device name %s already exists" % \ + device_name) + except exc.NoResultFound: + vnic = ucs_models.DynamicVnic(device_name, blade_id) + session.add(vnic) + session.flush() + return vnic + + +def remove_dynamicvnic(vnic_id): + """Removes a dynamic vnic""" + session = db.get_session() + try: + vnic = session.query(ucs_models.DynamicVnic).\ + filter_by(uuid=vnic_id).\ + one() + session.delete(vnic) + session.flush() + return vnic + except exc.NoResultFound: + pass + + +def update_dynamicvnic(vnic_id, new_device_name=None, new_blade_id=None): + """Updates dynamic vnic""" + session = db.get_session() + try: + vnic = session.query(ucs_models.DynamicVnic).\ + filter_by(uuid=vnic_id).\ + one() + if new_device_name: + vnic.device_name = new_device_name + if new_blade_id: + vnic.blade_id = new_blade_id + session.merge(vnic) + session.flush() + return vnic + except exc.NoResultFound: + raise Exception("No dynamic vnic with id = %s" % vnic_id) + + +def get_all_blades(): + """Lists all the blades details""" + session = db.get_session() + try: + blades = session.query(ucs_models.UcsBlade).\ + all() + return blades + except exc.NoResultFound: + return [] + + +def get_blade(blade_id): + """Lists a blade details""" + session = db.get_session() + try: + blade = session.query(ucs_models.UcsBlade).\ + filter_by(uuid=blade_id).\ + one() + return blade + except exc.NoResultFound: + raise Exception("No blade found with id = %s" % blade_id) + + +def add_blade(mgmt_ip, mac_addr, chassis_id, ucsm_ip): + """Adds a blade""" + session = db.get_session() + try: + ip = session.query(ucs_models.UcsBlade).\ + filter_by(mgmt_ip=mgmt_ip).\ + one() + raise Exception("Blade with ip \"%s\" already exists" % mgmt_ip) + except exc.NoResultFound: + blade = ucs_models.UcsBlade(mgmt_ip, mac_addr, chassis_id, ucsm_ip) + session.add(blade) + session.flush() + return blade + + +def remove_blade(blade_id): + """Removes a blade""" + session = db.get_session() + try: + blade = session.query(ucs_models.UcsBlade).\ + filter_by(uuid=blade_id).\ + one() + session.delete(blade) + session.flush() + return blade + except exc.NoResultFound: + pass + + +def update_blade(blade_id, new_mgmt_ip=None, new_mac_addr=None, \ + new_chassis_id=None, new_ucsm_ip=None): + """Updates details of a blade""" + session = db.get_session() + try: + blade = session.query(ucs_models.UcsBlade).\ + filter_by(uuid=blade_id).\ + one() + if new_mgmt_ip: + blade.mgmt_ip = new_mgmt_ip + if new_mac_addr: + blade.mac_addr = new_mac_addr + if new_chassis_id: + blade.chassis_id = new_chassis_id + if new_ucsm_ip: + blade.ucsm_ip = new_ucsm_ip + session.merge(blade) + session.flush() + return blade + except exc.NoResultFound: + raise Exception("No blade with id = %s" % blade_id) + + +def get_all_portbindings(): + """Lists all the port bindings""" + session = db.get_session() + try: + port_bindings = session.query(ucs_models.PortBinding).\ + all() + return port_bindings + except exc.NoResultFound: + return [] + + +def get_portbinding(port_id): + """Lists a port binding""" + session = db.get_session() + try: + port_binding = session.query(ucs_models.PortBinding).\ + filter_by(port_id=port_id).\ + one() + return port_binding + except exc.NoResultFound: + raise Exception("No port binding found with port id = %s" % port_id) + + +def add_portbinding(port_id, dynamic_vnic_id, portprofile_name, \ + vlan_name, vlan_id, qos): + """Adds a port binding""" + session = db.get_session() + try: + port_binding = session.query(ucs_models.PortBinding).\ + filter_by(port_id=port_id).\ + one() + raise Exception("Port Binding with portid %s already exists" % port_id) + except exc.NoResultFound: + port_binding = ucs_models.PortBinding(port_id, dynamic_vnic_id, \ + portprofile_name, vlan_name, vlan_id, qos) + session.add(port_binding) + session.flush() + return port_binding + + +def remove_portbinding(port_id): + """Removes a port binding""" + session = db.get_session() + try: + port_binding = session.query(ucs_models.PortBinding).\ + filter_by(port_id=port_id).\ + one() + session.delete(port_binding) + session.flush() + return port_binding + except exc.NoResultFound: + pass + + +def update_portbinding(port_id, dynamic_vnic_id=None, portprofile_name=None, \ + vlan_name=None, vlan_id=None, qos=None): + """Updates port binding""" + session = db.get_session() + try: + port_binding = session.query(ucs_models.PortBinding).\ + filter_by(port_id=port_id).\ + one() + if dynamic_vnic_id: + port_binding.dynamic_vnic_id = dynamic_vnic_id + if portprofile_name: + port_binding.portprofile_name = portprofile_name + if vlan_name: + port_binding.vlan_name = vlan_name + if vlan_name: + port_binding.vlan_id = vlan_id + if qos: + port_binding.qos = qos + session.merge(port_binding) + session.flush() + return port_binding + except exc.NoResultFound: + raise Exception("No port binding with port id = %s" % port_id) diff --git a/quantum/plugins/cisco/ucs_models.py b/quantum/plugins/cisco/ucs_models.py new file mode 100644 index 0000000000..68cd3dddea --- /dev/null +++ b/quantum/plugins/cisco/ucs_models.py @@ -0,0 +1,113 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011, Cisco Systems, Inc. +# +# 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. +# @author: Rohit Agarwalla, Cisco Systems, Inc. + +import uuid + +from sqlalchemy import Column, Integer, String, ForeignKey, Boolean +from sqlalchemy.orm import relation + +from quantum.db.models import BASE + + +class UcsmBinding(BASE): + """Represents a binding of ucsm to network_id""" + __tablename__ = 'ucsm_bindings' + + id = Column(Integer, primary_key=True, autoincrement=True) + ucsm_ip = Column(String(255)) + network_id = Column(String(255), nullable=False) + #foreign key to networks.uuid + + def __init__(self, ucsm_ip, network_id): + self.ucsm_ip = ucsm_ip + self.network_id = network_id + + def __repr__(self): + return "" % \ + (self.ucsm_ip, self.network_id) + + +class DynamicVnic(BASE): + """Represents Cisco UCS Dynamic Vnics""" + __tablename__ = 'dynamic_vnics' + + uuid = Column(String(255), primary_key=True) + device_name = Column(String(255)) + blade_id = Column(String(255), ForeignKey("ucs_blades.uuid"), \ + nullable=False) + + def __init__(self, device_name, blade_id): + self.uuid = uuid.uuid4() + self.device_name = device_name + self.blade_id = blade_id + + def __repr__(self): + return "" % \ + (self.uuid, self.device_name, self.blade_id) + + +class UcsBlade(BASE): + """Represents details of ucs blades""" + __tablename__ = 'ucs_blades' + + uuid = Column(String(255), primary_key=True) + mgmt_ip = Column(String(255)) + mac_addr = Column(String(255)) + chassis_id = Column(String(255)) + ucsm_ip = Column(String(255)) + dynamic_vnics = relation(DynamicVnic, order_by=DynamicVnic.uuid, \ + backref="blade") + + def __init__(self, mgmt_ip, mac_addr, chassis_id, ucsm_ip): + self.uuid = uuid.uuid4() + self.mgmt_ip = mgmt_ip + self.mac_addr = mac_addr + self.chassis_id = chassis_id + self.ucsm_ip = ucsm_ip + + def __repr__(self): + return "" % \ + (self.uuid, self.mgmt_ip, self.mac_addr, self.chassis_id, self.ucsm_ip) + + +class PortBinding(BASE): + """Represents Port binding to device interface""" + __tablename__ = 'port_bindings' + + id = Column(Integer, primary_key=True, autoincrement=True) + port_id = Column(String(255), nullable=False) + #foreign key to ports.uuid + dynamic_vnic_id = Column(String(255), nullable=False) + #foreign key to dynamic_vnics.uuid + portprofile_name = Column(String(255)) + vlan_name = Column(String(255)) + vlan_id = Column(Integer) + qos = Column(String(255)) + + def __init__(self, port_id, dynamic_vnic_id, portprofile_name, vlan_name, \ + vlan_id, qos): + self.port_id = port_id + self.dynamic_vnic_id = dynamic_vnic_id + self.portprofile_name = portprofile_name + self.vlan_name = vlan_name + self.vlan_id = vlan_id + self.qos = qos + + def __repr__(self): + return "" % \ + (self.port_id, self.dynamic_vnic_id, self.portprofile_name, \ + self.vlan_name, self.vlan_id, self.qos) From 6fa2f538e7a825e3e582f44615c2599cb73fce41 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sun, 31 Jul 2011 11:38:26 -0700 Subject: [PATCH 13/48] Changed the directory structure to a more organized one. Fixed the imports to reflect the new structure. --- quantum/plugins/cisco/README | 18 +++++++++--------- .../cisco/{ => common}/cisco_configuration.py | 0 .../cisco/{ => common}/cisco_constants.py | 0 .../cisco/{ => common}/cisco_credentials.py | 2 +- .../cisco/{ => common}/cisco_exceptions.py | 0 .../plugins/cisco/{ => common}/cisco_utils.py | 6 +++--- quantum/plugins/cisco/l2network_plugin.py | 14 +++++++------- .../cisco/{ => nexus}/cisco_nexus_plugin.py | 10 +++++----- quantum/plugins/cisco/{ => nexus}/nxosapi.py | 0 .../{ => ucs}/cisco_ucs_network_driver.py | 6 +++--- .../cisco/{ => ucs}/cisco_ucs_plugin.py | 12 ++++++------ quantum/plugins/cisco/{ => ucs}/get-vif.py | 0 quantum/plugins/cisco/{ => ucs}/get-vif.sh | 0 13 files changed, 34 insertions(+), 34 deletions(-) rename quantum/plugins/cisco/{ => common}/cisco_configuration.py (100%) rename quantum/plugins/cisco/{ => common}/cisco_constants.py (100%) rename quantum/plugins/cisco/{ => common}/cisco_credentials.py (96%) rename quantum/plugins/cisco/{ => common}/cisco_exceptions.py (100%) rename quantum/plugins/cisco/{ => common}/cisco_utils.py (89%) rename quantum/plugins/cisco/{ => nexus}/cisco_nexus_plugin.py (93%) rename quantum/plugins/cisco/{ => nexus}/nxosapi.py (100%) rename quantum/plugins/cisco/{ => ucs}/cisco_ucs_network_driver.py (98%) rename quantum/plugins/cisco/{ => ucs}/cisco_ucs_plugin.py (96%) rename quantum/plugins/cisco/{ => ucs}/get-vif.py (100%) rename quantum/plugins/cisco/{ => ucs}/get-vif.sh (100%) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 6c2bc0cdcd..cb6057c724 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -27,16 +27,16 @@ gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OPENSTACK provider = quantum.plugins.cisco.l2network_plugin.L2Network * You should have the following files in quantum/quantum/plugins/cisco directory (if you have pulled the Cisco Quantum branch, you will already have them): l2network_plugin.py -cisco_configuration.py -cisco_constants.py -cisco_credentials.py -cisco_exceptions.py -cisco_nexus_plugin.py -cisco_ucs_network_driver.py -cisco_ucs_plugin.py -cisco_utils.py +common/cisco_configuration.py +common/cisco_constants.py +common/cisco_credentials.py +common/cisco_exceptions.py +nexus/cisco_nexus_plugin.py +ucs/cisco_ucs_network_driver.py +ucs/cisco_ucs_plugin.py +common/cisco_utils.py __init__.py -get-vif.sh +ucs/get-vif.sh * Configure the L2 Network Pllugin: + In cisco_configuration.py, - change the UCSM IP in the following statement to your UCSM IP diff --git a/quantum/plugins/cisco/cisco_configuration.py b/quantum/plugins/cisco/common/cisco_configuration.py similarity index 100% rename from quantum/plugins/cisco/cisco_configuration.py rename to quantum/plugins/cisco/common/cisco_configuration.py diff --git a/quantum/plugins/cisco/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py similarity index 100% rename from quantum/plugins/cisco/cisco_constants.py rename to quantum/plugins/cisco/common/cisco_constants.py diff --git a/quantum/plugins/cisco/cisco_credentials.py b/quantum/plugins/cisco/common/cisco_credentials.py similarity index 96% rename from quantum/plugins/cisco/cisco_credentials.py rename to quantum/plugins/cisco/common/cisco_credentials.py index c0cd282530..cdbb6c379a 100644 --- a/quantum/plugins/cisco/cisco_credentials.py +++ b/quantum/plugins/cisco/common/cisco_credentials.py @@ -19,7 +19,7 @@ import logging as LOG -from quantum.plugins.cisco import cisco_constants as const +from quantum.plugins.cisco.common import cisco_constants as const LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) diff --git a/quantum/plugins/cisco/cisco_exceptions.py b/quantum/plugins/cisco/common/cisco_exceptions.py similarity index 100% rename from quantum/plugins/cisco/cisco_exceptions.py rename to quantum/plugins/cisco/common/cisco_exceptions.py diff --git a/quantum/plugins/cisco/cisco_utils.py b/quantum/plugins/cisco/common/cisco_utils.py similarity index 89% rename from quantum/plugins/cisco/cisco_utils.py rename to quantum/plugins/cisco/common/cisco_utils.py index bd0b257d54..8d0d803b3f 100644 --- a/quantum/plugins/cisco/cisco_utils.py +++ b/quantum/plugins/cisco/common/cisco_utils.py @@ -23,9 +23,9 @@ import sys import traceback from quantum.common import exceptions as exc -from quantum.plugins.cisco import cisco_configuration as conf -from quantum.plugins.cisco import cisco_constants as const -from quantum.plugins.cisco import cisco_credentials as cred +from quantum.plugins.cisco.common import cisco_configuration as conf +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.common import cisco_credentials as cred LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 47f63874ee..8be63bb067 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -20,13 +20,13 @@ import logging as LOG from quantum.common import exceptions as exc -from quantum.plugins.cisco import cisco_configuration as conf -from quantum.plugins.cisco import cisco_constants as const -from quantum.plugins.cisco import cisco_credentials as cred -from quantum.plugins.cisco import cisco_exceptions as cexc -from quantum.plugins.cisco import cisco_nexus_plugin -from quantum.plugins.cisco import cisco_ucs_plugin -from quantum.plugins.cisco import cisco_utils as cutil +from quantum.plugins.cisco.common import cisco_configuration as conf +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.common import cisco_credentials as cred +from quantum.plugins.cisco.common import cisco_exceptions as cexc +from quantum.plugins.cisco.nexus import cisco_nexus_plugin +from quantum.plugins.cisco.ucs import cisco_ucs_plugin +from quantum.plugins.cisco.common import cisco_utils as cutil LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) diff --git a/quantum/plugins/cisco/cisco_nexus_plugin.py b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py similarity index 93% rename from quantum/plugins/cisco/cisco_nexus_plugin.py rename to quantum/plugins/cisco/nexus/cisco_nexus_plugin.py index 545499fe9b..9d55115ab6 100644 --- a/quantum/plugins/cisco/cisco_nexus_plugin.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py @@ -19,11 +19,11 @@ import logging as LOG from quantum.common import exceptions as exc -from quantum.plugins.cisco import cisco_configuration as conf -from quantum.plugins.cisco import cisco_constants as const -from quantum.plugins.cisco import cisco_credentials as cred -from quantum.plugins.cisco import cisco_exceptions as cexc -from quantum.plugins.cisco import cisco_utils as cutil +from quantum.plugins.cisco.common import cisco_configuration as conf +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.common import cisco_credentials as cred +from quantum.plugins.cisco.common import cisco_exceptions as cexc +from quantum.plugins.cisco.common import cisco_utils as cutil LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) diff --git a/quantum/plugins/cisco/nxosapi.py b/quantum/plugins/cisco/nexus/nxosapi.py similarity index 100% rename from quantum/plugins/cisco/nxosapi.py rename to quantum/plugins/cisco/nexus/nxosapi.py diff --git a/quantum/plugins/cisco/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py similarity index 98% rename from quantum/plugins/cisco/cisco_ucs_network_driver.py rename to quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index ca912edf92..593706e3db 100644 --- a/quantum/plugins/cisco/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -27,9 +27,9 @@ import subprocess from xml.etree import ElementTree as et import urllib -from quantum.plugins.cisco import cisco_configuration as conf -from quantum.plugins.cisco import cisco_constants as const -from quantum.plugins.cisco import cisco_exceptions as cexc +from quantum.plugins.cisco.common import cisco_configuration as conf +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.common import cisco_exceptions as cexc LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) diff --git a/quantum/plugins/cisco/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py similarity index 96% rename from quantum/plugins/cisco/cisco_ucs_plugin.py rename to quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index 52195a5552..264d14f783 100644 --- a/quantum/plugins/cisco/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -20,12 +20,12 @@ import logging as LOG from quantum.common import exceptions as exc -from quantum.plugins.cisco import cisco_configuration as conf -from quantum.plugins.cisco import cisco_constants as const -from quantum.plugins.cisco import cisco_credentials as cred -from quantum.plugins.cisco import cisco_exceptions as cexc -from quantum.plugins.cisco import cisco_ucs_network_driver -from quantum.plugins.cisco import cisco_utils as cutil +from quantum.plugins.cisco.common import cisco_configuration as conf +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.common import cisco_credentials as cred +from quantum.plugins.cisco.common import cisco_exceptions as cexc +from quantum.plugins.cisco.ucs import cisco_ucs_network_driver +from quantum.plugins.cisco.common import cisco_utils as cutil LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) diff --git a/quantum/plugins/cisco/get-vif.py b/quantum/plugins/cisco/ucs/get-vif.py similarity index 100% rename from quantum/plugins/cisco/get-vif.py rename to quantum/plugins/cisco/ucs/get-vif.py diff --git a/quantum/plugins/cisco/get-vif.sh b/quantum/plugins/cisco/ucs/get-vif.sh similarity index 100% rename from quantum/plugins/cisco/get-vif.sh rename to quantum/plugins/cisco/ucs/get-vif.sh From 1ab10658b3439a4c80f597c2e5bcbee1f4c08b5c Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sun, 31 Jul 2011 11:54:29 -0700 Subject: [PATCH 14/48] For the modules to get added, missed in the earlier checkin. --- quantum/plugins/cisco/common/__init__.py | 0 quantum/plugins/cisco/db/__init__.py | 0 quantum/plugins/cisco/nexus/__init__.py | 0 quantum/plugins/cisco/ucs/__init__.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 quantum/plugins/cisco/common/__init__.py create mode 100644 quantum/plugins/cisco/db/__init__.py create mode 100644 quantum/plugins/cisco/nexus/__init__.py create mode 100644 quantum/plugins/cisco/ucs/__init__.py diff --git a/quantum/plugins/cisco/common/__init__.py b/quantum/plugins/cisco/common/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/quantum/plugins/cisco/db/__init__.py b/quantum/plugins/cisco/db/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/quantum/plugins/cisco/nexus/__init__.py b/quantum/plugins/cisco/nexus/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/quantum/plugins/cisco/ucs/__init__.py b/quantum/plugins/cisco/ucs/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From a084284c20bca5dc05df732b9e5323d3950955a0 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sun, 31 Jul 2011 12:04:01 -0700 Subject: [PATCH 15/48] Including copyright info. --- quantum/plugins/cisco/__init__.py | 18 ++++++++++++++++++ quantum/plugins/cisco/common/__init__.py | 18 ++++++++++++++++++ quantum/plugins/cisco/db/__init__.py | 18 ++++++++++++++++++ quantum/plugins/cisco/nexus/__init__.py | 18 ++++++++++++++++++ quantum/plugins/cisco/ucs/__init__.py | 18 ++++++++++++++++++ 5 files changed, 90 insertions(+) diff --git a/quantum/plugins/cisco/__init__.py b/quantum/plugins/cisco/__init__.py index e69de29bb2..db695fb0af 100644 --- a/quantum/plugins/cisco/__init__.py +++ b/quantum/plugins/cisco/__init__.py @@ -0,0 +1,18 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# diff --git a/quantum/plugins/cisco/common/__init__.py b/quantum/plugins/cisco/common/__init__.py index e69de29bb2..db695fb0af 100644 --- a/quantum/plugins/cisco/common/__init__.py +++ b/quantum/plugins/cisco/common/__init__.py @@ -0,0 +1,18 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# diff --git a/quantum/plugins/cisco/db/__init__.py b/quantum/plugins/cisco/db/__init__.py index e69de29bb2..db695fb0af 100644 --- a/quantum/plugins/cisco/db/__init__.py +++ b/quantum/plugins/cisco/db/__init__.py @@ -0,0 +1,18 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# diff --git a/quantum/plugins/cisco/nexus/__init__.py b/quantum/plugins/cisco/nexus/__init__.py index e69de29bb2..db695fb0af 100644 --- a/quantum/plugins/cisco/nexus/__init__.py +++ b/quantum/plugins/cisco/nexus/__init__.py @@ -0,0 +1,18 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# diff --git a/quantum/plugins/cisco/ucs/__init__.py b/quantum/plugins/cisco/ucs/__init__.py index e69de29bb2..db695fb0af 100644 --- a/quantum/plugins/cisco/ucs/__init__.py +++ b/quantum/plugins/cisco/ucs/__init__.py @@ -0,0 +1,18 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# From 3eb5bcc009961a2d6b11f7428e7c603ede489888 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sun, 31 Jul 2011 18:00:56 -0700 Subject: [PATCH 16/48] Adding a tests directory, this can be used for plugin-specific test cases. --- quantum/plugins/cisco/tests/__init__.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 quantum/plugins/cisco/tests/__init__.py diff --git a/quantum/plugins/cisco/tests/__init__.py b/quantum/plugins/cisco/tests/__init__.py new file mode 100644 index 0000000000..db695fb0af --- /dev/null +++ b/quantum/plugins/cisco/tests/__init__.py @@ -0,0 +1,18 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# From 07281aa581dccfde3a98b5c7aa338dad28397b5a Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Mon, 1 Aug 2011 12:40:07 -0700 Subject: [PATCH 17/48] Adding the Nexus OS driver based on the new PlugIn structure --- quantum/plugins/cisco/README | 9 +- .../cisco/common/cisco_configuration.py | 7 + .../cisco/nexus/cisco_nexus_network_driver.py | 236 ++++++++++++++++++ .../plugins/cisco/nexus/cisco_nexus_plugin.py | 28 ++- 4 files changed, 271 insertions(+), 9 deletions(-) create mode 100644 quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 3bf20a7512..2672675cd8 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -7,6 +7,7 @@ * UCS B200 series blades with M81KR VIC installed. * UCSM 2.0 (Capitola) Build 230 * RHEL 6.1 +* ncclcient v0.3.1 - Python library for NETCONF clients (http://schmizz.net/ncclient/) * UCS & VIC installation (support for KVM) - please consult the accompanying installation guide available at: http://wikicentral.cisco.com/display/GROUP/SAVBU+Palo+VM-FEX+for+Linux+KVM * To run Quantum on RHEL, you will need to have the correct version of python-routes (version 1.12.3 or later). The RHEL 6.1 package contains an older version. Do the following and check your python-routes version: @@ -41,6 +42,10 @@ ucs/get-vif.sh + In cisco_configuration.py, - change the UCSM IP in the following statement to your UCSM IP flags.DEFINE_string('ucsm_ip_address', "172.20.231.27", 'IP address of UCSM') + - change the NEXUS 7K IP in the following statement to your N7K Switch IP + flags.DEFINE_string('nexus_ip_address', "172.20.231.61", 'IP address of N7K') + - change the NEXUS Interface in the following statement to the interface number in your N7K which is connected to your UCSM UpLink port + flags.DEFINE_string('nexus_port', "3/23", 'Port number of the Interface connected from the Nexus 7K Switch to UCSM 6120') - change the Nova MySQL DB IP if you are running Quantum on a different host than the OpenStack Cloud Controller (in other words you do not need to change the IP if Quantum is running on the same host on which the Nova DB is running). DB IP is changed in the following statement: flags.DEFINE_string('db_server_ip', "127.0.0.1", 'IP address of nova DB server') - change the hostname of the OpenStack Cloud Controller below @@ -58,9 +63,11 @@ ucs/get-vif.sh - Change the path to reflect the location of the get-vif.sh script, if you have followed the instructions in this README, this location should be the same as that of your other plugin modules flags.DEFINE_string('get_next_vif', "/root/sumit/quantum/quantum/plugins/cisco/get-vif.sh", 'This is the location of the script to get the next available dynamic nic') + In cisco_credentials.py, - - Change the following stucture to reflect the correct UCS and Nova DB details. Your UCSM_IP_ADDRESS has to match the ucsmm_ip_addresss which you provided in the cisco_configuration file earlier. Similarly, your NOVA_DATABSE_IP has to match the db_server_ip which you provided earlier. DB_USERNAME and DB_PASSWORD are those which you provided for the Nova MySQL DB when you setup OpenStack + - Change the following structure to reflect the correct UCS, N7K and Nova DB details. Your UCSM_IP_ADDRESS has to match the ucsmm_ip_addresss which you provided in the cisco_configuration file earlier. Similarly, your NOVA_DATABSE_IP has to match the db_server_ip which you provided earlier. DB_USERNAME and DB_PASSWORD are those which you provided for the Nova MySQL DB when you setup OpenStack + N7K_IP_ADDRESS has to match with your Nexus 7k switch IP Address, N7K_USERNAME is the administrator user-name and N7K_PASSWORD is the password. _creds_dictionary = { 'UCSM_IP_ADDRESS':["UCSM_USERNAME", "UCSM_PASSWORD"], + 'N7K_IP_ADDRESS':["N7K_USERNAME", "N7K_PASSWORD"], 'NOVA_DATABASE_IP':["DB_USERNAME", "DB_PASSWORD"] } * Start the Quantum service diff --git a/quantum/plugins/cisco/common/cisco_configuration.py b/quantum/plugins/cisco/common/cisco_configuration.py index 5ab2aaf336..12ca0d4280 100644 --- a/quantum/plugins/cisco/common/cisco_configuration.py +++ b/quantum/plugins/cisco/common/cisco_configuration.py @@ -15,6 +15,7 @@ # under the License. # # @author: Sumit Naiksatam, Cisco Systems, Inc. +# @author: Edgar Magana, Cisco Systems, Inc. # from quantum.common import flags @@ -26,6 +27,10 @@ FLAGS = flags.FLAGS # flags.DEFINE_string('ucsm_ip_address', "172.20.231.27", 'IP address of \ UCSM') +flags.DEFINE_string('nexus_ip_address', "172.20.231.61", 'IP address of \ + Nexus Switch') +flags.DEFINE_string('nexus_port', "3/23", 'Port number of the Interface \ + connected from the Nexus Switch to UCSM 6120') flags.DEFINE_string('db_server_ip', "127.0.0.1", 'IP address of nova DB \ server') flags.DEFINE_string('nova_host_name', "openstack-0203", 'nova cloud \ @@ -68,6 +73,8 @@ flags.DEFINE_string('get_next_vif', # Inventory items UCSM_IP_ADDRESS = FLAGS.ucsm_ip_address +NEXUS_IP_ADDRESS = FLAGS.nexus_ip_address +NEXUS_PORT = FLAGS.nexus_port DB_SERVER_IP = FLAGS.db_server_ip NOVA_HOST_NAME = FLAGS.nova_host_name diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py new file mode 100644 index 0000000000..2e95409d35 --- /dev/null +++ b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py @@ -0,0 +1,236 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Debojyoti Dutta, Cisco Systems, Inc. +# @author: Edgar Magana, Cisco Systems Inc. +# +""" +Implements a Nexus-OS NETCONF over SSHv2 API Client +""" + +import logging as LOG +import string +import subprocess + +from quantum.plugins.cisco.common import cisco_configuration as conf +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.common import cisco_exceptions as cexc + +from ncclient import manager + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + + +# The following are standard strings, messages used to communicate with Nexus, +#only place holder values change for each message +exec_conf_prefix = """ + + + <__XML__MODE__exec_configure> +""" + + +exec_conf_postfix = """ + + + +""" + + +cmd_vlan_conf_snippet = """ + + + <__XML__PARAM_value>%s + <__XML__MODE_vlan> + + %s + + + active + + + + + + + +""" + +cmd_no_vlan_conf_snippet = """ + + + + <__XML__PARAM_value>%s + + + +""" + +cmd_vlan_int_snippet = """ + + + %s + <__XML__MODE_if-ethernet-switch> + + + + + + <__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans> + %s + + + + + + + + +""" + +cmd_port_trunk = """ + + + %s + <__XML__MODE_if-ethernet-switch> + + + + + + + + + + +""" + +cmd_no_switchport = """ + + + %s + <__XML__MODE_if-ethernet-switch> + + + + + + + +""" + + +cmd_no_vlan_int_snippet = """ + + + %s + <__XML__MODE_if-ethernet-switch> + + + + + + + <__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans> + %s + + + + + + + + + +""" + + +filter_show_vlan_brief_snippet = """ + + + + + """ + + +class CiscoNEXUSDriver(): + + def __init__(self): + pass + + def nxos_connect(self, nexus_host, port, nexus_user, nexus_password): + m = manager.connect(host=nexus_host, port=22, username=nexus_user, + password=nexus_password) + return m + + def enable_vlan(self, mgr, vlanid, vlanname): + confstr = cmd_vlan_conf_snippet % (vlanid, vlanname) + confstr = exec_conf_prefix + confstr + exec_conf_postfix + mgr.edit_config(target='running', config=confstr) + + def disable_vlan(self, mgr, vlanid): + confstr = cmd_no_vlan_conf_snippet % vlanid + confstr = exec_conf_prefix + confstr + exec_conf_postfix + mgr.edit_config(target='running', config=confstr) + + def enable_port_trunk(self, mgr, interface): + confstr = cmd_port_trunk % (interface) + confstr = exec_conf_prefix + confstr + exec_conf_postfix + print confstr + mgr.edit_config(target='running', config=confstr) + + def enable_vlan_on_trunk_int(self, mgr, interface, vlanid): + confstr = cmd_vlan_int_snippet % (interface, vlanid) + confstr = exec_conf_prefix + confstr + exec_conf_postfix + print confstr + mgr.edit_config(target='running', config=confstr) + + def disable_vlan_on_trunk_int(self, mgr, interface, vlanid): + confstr = cmd_no_vlan_int_snippet % (interface, vlanid) + confstr = exec_conf_prefix + confstr + exec_conf_postfix + print confstr + mgr.edit_config(target='running', config=confstr) + + def test_nxos_api(self, host, user, password): + with self.nxos_connect(host, port=22, user=user, + password=password) as m: + #enable_vlan(m, '100', 'ccn1') + #enable_vlan_on_trunk_int(m, '2/1', '100') + #disable_vlan_on_trunk_int(m, '2/1', '100') + #disable_vlan(m, '100') + result = m.get(("subtree", filter_show_vlan_brief_snippet)) + print result + + def create_vlan(self, vlan_name, vlan_id, nexus_host, nexus_user, + nexus_password, nexus_interface): + #TODO (Edgar) Move the SSH port to the configuration file + with self.nxos_connect(nexus_host, 22, nexus_user, + nexus_password) as m: + self.enable_vlan(m, vlan_id, vlan_name) + self.enable_port_trunk(m, nexus_interface) + + def delete_vlan(self, vlan_id, nexus_host, nexus_user, nexus_password): + with self.nxos_connect(nexus_host, 22, nexus_user, + nexus_password) as m: + self.disable_vlan(m, vlan_id) + + +def main(): + client = CiscoNEXUSDriver() + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py index 9d55115ab6..4d8cfa654f 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py @@ -15,6 +15,7 @@ # under the License. # # @author: Sumit Naiksatam, Cisco Systems, Inc. +# @author: Edgar Magana, Cisco Systems, Inc. # import logging as LOG @@ -25,6 +26,8 @@ from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc from quantum.plugins.cisco.common import cisco_utils as cutil +from quantum.plugins.cisco.nexus import cisco_nexus_network_driver + LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) @@ -33,10 +36,12 @@ class NexusPlugin(object): _networks = {} def __init__(self): - """ - Initialize the Nexus driver here - """ - pass + self._client = cisco_nexus_network_driver.CiscoNEXUSDriver() + #TODO (Edgar) Using just one Nexus 7K Switch and Port + self._nexus_ip = conf.NEXUS_IP_ADDRESS + self._nexus_username = cred.Store.getUsername(conf.NEXUS_IP_ADDRESS) + self._nexus_password = cred.Store.getPassword(conf.NEXUS_IP_ADDRESS) + self._nexus_port = conf.NEXUS_PORT def get_all_networks(self, tenant_id): """ @@ -53,8 +58,9 @@ class NexusPlugin(object): for this VLAN """ LOG.debug("NexusPlugin:create_network() called\n") - # TODO (Sumit): Call the nexus driver here to create the VLAN, and - # configure the appropriate interfaces + self._client.create_vlan(vlan_name, str(vlan_id), self._nexus_ip, + self._nexus_username, self._nexus_password, self._nexus_port) + new_net_dict = {const.NET_ID: net_id, const.NET_NAME: net_name, const.NET_PORTS: {}, @@ -70,9 +76,10 @@ class NexusPlugin(object): """ LOG.debug("NexusPlugin:delete_network() called\n") net = self._networks.get(net_id) + vlan_id = self._get_vlan_id_for_network(tenant_id, net_id) if net: - # TODO (Sumit): Call the nexus driver here to create the VLAN, - # and configure the appropriate interfaces + self._client.delete_vlan(str(vlan_id), self._nexus_ip, + self._nexus_username, self._nexus_password) self._networks.pop(net_id) return net # Network not found @@ -145,6 +152,11 @@ class NexusPlugin(object): """ LOG.debug("NexusPlugin:unplug_interface() called\n") + def _get_vlan_id_for_network(self, tenant_id, network_id): + net = self._get_network(tenant_id, network_id) + vlan_id = net[const.NET_VLAN_ID] + return vlan_id + def _get_network(self, tenant_id, network_id): network = self._networks.get(network_id) if not network: From 5c0dbe9aee15c403910bf7c0deb7eb92f18d0967 Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Mon, 1 Aug 2011 18:32:25 -0700 Subject: [PATCH 18/48] Including a flag to activate the NX-OS driver Updating the README documentation --- quantum/plugins/cisco/README | 25 +++++++++++++++---- .../cisco/common/cisco_configuration.py | 3 +++ quantum/plugins/cisco/l2network_plugin.py | 22 +++++++++++++--- .../plugins/cisco/nexus/cisco_nexus_plugin.py | 1 + 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 2672675cd8..b77ce22ca8 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -38,14 +38,10 @@ ucs/cisco_ucs_plugin.py common/cisco_utils.py __init__.py ucs/get-vif.sh -* Configure the L2 Network Pllugin: +* Configure the L2 Network Plugin: + In cisco_configuration.py, - change the UCSM IP in the following statement to your UCSM IP flags.DEFINE_string('ucsm_ip_address', "172.20.231.27", 'IP address of UCSM') - - change the NEXUS 7K IP in the following statement to your N7K Switch IP - flags.DEFINE_string('nexus_ip_address', "172.20.231.61", 'IP address of N7K') - - change the NEXUS Interface in the following statement to the interface number in your N7K which is connected to your UCSM UpLink port - flags.DEFINE_string('nexus_port', "3/23", 'Port number of the Interface connected from the Nexus 7K Switch to UCSM 6120') - change the Nova MySQL DB IP if you are running Quantum on a different host than the OpenStack Cloud Controller (in other words you do not need to change the IP if Quantum is running on the same host on which the Nova DB is running). DB IP is changed in the following statement: flags.DEFINE_string('db_server_ip', "127.0.0.1", 'IP address of nova DB server') - change the hostname of the OpenStack Cloud Controller below @@ -62,6 +58,24 @@ ucs/get-vif.sh flags.DEFINE_string('profile_name_prefix', "q-", 'Prefix of the name given to the port profile') - Change the path to reflect the location of the get-vif.sh script, if you have followed the instructions in this README, this location should be the same as that of your other plugin modules flags.DEFINE_string('get_next_vif', "/root/sumit/quantum/quantum/plugins/cisco/get-vif.sh", 'This is the location of the script to get the next available dynamic nic') + + + In cisco_credentials.py, + - Change the following structure to reflect the correct UCS, N7K and Nova DB details. Your UCSM_IP_ADDRESS has to match the ucsmm_ip_addresss which you provided in the cisco_configuration file earlier. Similarly, your NOVA_DATABSE_IP has to match the db_server_ip which you provided earlier. DB_USERNAME and DB_PASSWORD are those which you provided for the Nova MySQL DB when you setup OpenStack + N7K_IP_ADDRESS has to match with your Nexus 7k switch IP Address, N7K_USERNAME is the administrator user-name and N7K_PASSWORD is the password. + _creds_dictionary = { + 'UCSM_IP_ADDRESS':["UCSM_USERNAME", "UCSM_PASSWORD"], + 'NOVA_DATABASE_IP':["DB_USERNAME", "DB_PASSWORD"] + } + +* Configure the L2 Network Plugin with Nexus OS Driver for testing VLANs CRUD on Nexus 7k Switch. Making these changes requires one Nexus 7K Switch connected to the UCSM and the ncclient patch not just the regular library, otherwise the system will fail. + + In cisco_configuration.py, + - change the NEXUS 7K IP in the following statement to your N7K Switch IP + flags.DEFINE_string('nexus_ip_address', "172.20.231.61", 'IP address of N7K') + - change the NEXUS Interface in the following statement to the interface number in your N7K which is connected to your UCSM UpLink port + flags.DEFINE_string('nexus_port', "3/23", 'Port number of the Interface connected from the Nexus 7K Switch to UCSM 6120') + - change NEXUS Driver Flag to "on" in the following statement + flags.DEFINE_string('nexus_driver_active', "off", 'Flag to activate Nexus OS Driver') + + In cisco_credentials.py, - Change the following structure to reflect the correct UCS, N7K and Nova DB details. Your UCSM_IP_ADDRESS has to match the ucsmm_ip_addresss which you provided in the cisco_configuration file earlier. Similarly, your NOVA_DATABSE_IP has to match the db_server_ip which you provided earlier. DB_USERNAME and DB_PASSWORD are those which you provided for the Nova MySQL DB when you setup OpenStack N7K_IP_ADDRESS has to match with your Nexus 7k switch IP Address, N7K_USERNAME is the administrator user-name and N7K_PASSWORD is the password. @@ -70,6 +84,7 @@ ucs/get-vif.sh 'N7K_IP_ADDRESS':["N7K_USERNAME", "N7K_PASSWORD"], 'NOVA_DATABASE_IP':["DB_USERNAME", "DB_PASSWORD"] } + * Start the Quantum service ** Additional installation required on Nova Compute: diff --git a/quantum/plugins/cisco/common/cisco_configuration.py b/quantum/plugins/cisco/common/cisco_configuration.py index 12ca0d4280..01762e5fa8 100644 --- a/quantum/plugins/cisco/common/cisco_configuration.py +++ b/quantum/plugins/cisco/common/cisco_configuration.py @@ -31,6 +31,8 @@ flags.DEFINE_string('nexus_ip_address', "172.20.231.61", 'IP address of \ Nexus Switch') flags.DEFINE_string('nexus_port', "3/23", 'Port number of the Interface \ connected from the Nexus Switch to UCSM 6120') +flags.DEFINE_string('nexus_driver_active', "off", 'Flag to activate Nexus OS\ + Driver') flags.DEFINE_string('db_server_ip', "127.0.0.1", 'IP address of nova DB \ server') flags.DEFINE_string('nova_host_name', "openstack-0203", 'nova cloud \ @@ -74,6 +76,7 @@ flags.DEFINE_string('get_next_vif', # Inventory items UCSM_IP_ADDRESS = FLAGS.ucsm_ip_address NEXUS_IP_ADDRESS = FLAGS.nexus_ip_address +NEXUS_DRIVER_ACTIVE = FLAGS.nexus_driver_active NEXUS_PORT = FLAGS.nexus_port DB_SERVER_IP = FLAGS.db_server_ip NOVA_HOST_NAME = FLAGS.nova_host_name diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 8be63bb067..9a8c4a4f0e 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -15,6 +15,7 @@ # under the License. # # @author: Sumit Naiksatam, Cisco Systems, Inc. +# @author: Edgar Magana, Cisco Systems, Inc. # import logging as LOG @@ -65,8 +66,13 @@ class L2Network(object): new_net_id = self._get_unique_net_id(tenant_id) vlan_id = self._get_vlan_for_tenant(tenant_id, net_name) vlan_name = self._get_vlan_name(new_net_id, str(vlan_id)) - self._nexus_plugin.create_network(tenant_id, net_name, new_net_id, + nexus_driver_flag = conf.NEXUS_DRIVER_ACTIVE + if nexus_driver_flag == 'on': + LOG.debug("Nexus OS Driver called\n") + self._nexus_plugin.create_network(tenant_id, net_name, new_net_id, vlan_name, vlan_id) + else: + LOG.debug("No Nexus OS Driver available\n") self._ucs_plugin.create_network(tenant_id, net_name, new_net_id, vlan_name, vlan_id) new_net_dict = {const.NET_ID: new_net_id, @@ -88,12 +94,17 @@ class L2Network(object): """ LOG.debug("delete_network() called\n") net = self._networks.get(net_id) + nexus_driver_flag = conf.NEXUS_DRIVER_ACTIVE # TODO (Sumit) : Verify that no attachments are plugged into the # network if net: # TODO (Sumit) : Before deleting the network, make sure all the # ports associated with this network are also deleted - self._nexus_plugin.delete_network(tenant_id, net_id) + if nexus_driver_flag == 'on': + LOG.debug("Nexus OS Driver called\n") + self._nexus_plugin.delete_network(tenant_id, net_id) + else: + LOG.debug("No Nexus OS Driver available\n") self._ucs_plugin.delete_network(tenant_id, net_id) self._networks.pop(net_id) tenant = self._get_tenant(tenant_id) @@ -118,7 +129,12 @@ class L2Network(object): Virtual Network. """ LOG.debug("rename_network() called\n") - self._nexus_plugin.rename_network(tenant_id, net_id) + nexus_driver_flag = conf.NEXUS_DRIVER_ACTIVE + if nexus_driver_flag == 'on': + LOG.debug("Nexus OS Driver called\n") + self._nexus_plugin.rename_network(tenant_id, net_id) + else: + LOG.debug("No Nexus OS Driver available\n") self._ucs_plugin.rename_network(tenant_id, net_id) network = self._get_network(tenant_id, net_id) network[const.NET_NAME] = new_name diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py index 4d8cfa654f..349a69ca55 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py @@ -98,6 +98,7 @@ class NexusPlugin(object): Updates the symbolic name belonging to a particular Virtual Network. """ + #TODO (Edgar) We need to add an update method in the Nexus Driver LOG.debug("NexusPlugin:rename_network() called\n") network = self._get_network(tenant_id, net_id) network[const.NET_NAME] = new_name From 9f8b25e53c9957f09bab49a14f198356e00bce6c Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Tue, 2 Aug 2011 17:08:58 -0700 Subject: [PATCH 19/48] Truncated the port profile client name length to 16 characters (ucsm excepts max 17 chars). --- quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index 593706e3db..9383f9b965 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -198,7 +198,7 @@ class CiscoUCSMDriver(): ucsm_password): data = self._create_profile_post_data(profile_name, vlan_name) self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) - data = self._create_profile_client_post_data(profile_name) + data = self._create_profile_client_post_data(profile_name[-16:]) self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) def change_vlan_in_profile(self, profile_name, old_vlan_name, From 33ee4cabd061ba696c227289bea932e57a865554 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Tue, 2 Aug 2011 18:39:51 -0700 Subject: [PATCH 20/48] Earlier fix resulted in a different issue (profile client name, was also being used as profile name, hence breaking). --- quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index 9383f9b965..be1c89e223 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -158,9 +158,9 @@ class CiscoUCSMDriver(): data = data.replace(VLAN_NAME, vlan_name) return data - def _create_profile_client_post_data(self, profile_name): + def _create_profile_client_post_data(self, profile_name, profile_client_name): data = ASSOCIATE_PROFILE.replace(PROFILE_NAME, profile_name) - data = data.replace(PROFILE_CLIENT, profile_name) + data = data.replace(PROFILE_CLIENT, profile_client_name) return data def _change_vlan_in_profile_post_data(self, profile_name, old_vlan_name, @@ -198,7 +198,7 @@ class CiscoUCSMDriver(): ucsm_password): data = self._create_profile_post_data(profile_name, vlan_name) self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) - data = self._create_profile_client_post_data(profile_name[-16:]) + data = self._create_profile_client_post_data(profile_name, profile_name[-16:]) self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) def change_vlan_in_profile(self, profile_name, old_vlan_name, From b113a0a2550781e3e76cc9d6f716ed57f8f06a11 Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Wed, 3 Aug 2011 13:29:43 -0700 Subject: [PATCH 21/48] Fixed an issue selecting the right port interface and also properly switching off the Nexus Interface --- .../cisco/nexus/cisco_nexus_network_driver.py | 12 ++++++++++-- quantum/plugins/cisco/nexus/cisco_nexus_plugin.py | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py index 2e95409d35..27e63ce4cb 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py @@ -193,6 +193,12 @@ class CiscoNEXUSDriver(): print confstr mgr.edit_config(target='running', config=confstr) + def disable_switch_port(self, mgr, interface): + confstr = cmd_no_switchport % (interface) + confstr = exec_conf_prefix + confstr + exec_conf_postfix + print confstr + mgr.edit_config(target='running', config=confstr) + def enable_vlan_on_trunk_int(self, mgr, interface, vlanid): confstr = cmd_vlan_int_snippet % (interface, vlanid) confstr = exec_conf_prefix + confstr + exec_conf_postfix @@ -221,12 +227,14 @@ class CiscoNEXUSDriver(): with self.nxos_connect(nexus_host, 22, nexus_user, nexus_password) as m: self.enable_vlan(m, vlan_id, vlan_name) - self.enable_port_trunk(m, nexus_interface) + self.enable_vlan_on_trunk_int(m, nexus_interface, vlan_id) - def delete_vlan(self, vlan_id, nexus_host, nexus_user, nexus_password): + def delete_vlan(self, vlan_id, nexus_host, nexus_user, + nexus_password, nexus_interface): with self.nxos_connect(nexus_host, 22, nexus_user, nexus_password) as m: self.disable_vlan(m, vlan_id) + self.disable_switch_port(m, nexus_interface) def main(): diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py index 349a69ca55..31baac4729 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py @@ -79,7 +79,7 @@ class NexusPlugin(object): vlan_id = self._get_vlan_id_for_network(tenant_id, net_id) if net: self._client.delete_vlan(str(vlan_id), self._nexus_ip, - self._nexus_username, self._nexus_password) + self._nexus_username, self._nexus_password, self._nexus_port) self._networks.pop(net_id) return net # Network not found From e4e1891cc13c8318a1351b3df44db1cb30f2eeef Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Wed, 3 Aug 2011 15:41:06 -0700 Subject: [PATCH 22/48] Fixed pep8 error. --- quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index be1c89e223..2d994ddec1 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -158,7 +158,8 @@ class CiscoUCSMDriver(): data = data.replace(VLAN_NAME, vlan_name) return data - def _create_profile_client_post_data(self, profile_name, profile_client_name): + def _create_profile_client_post_data(self, profile_name, + profile_client_name): data = ASSOCIATE_PROFILE.replace(PROFILE_NAME, profile_name) data = data.replace(PROFILE_CLIENT, profile_client_name) return data @@ -198,7 +199,8 @@ class CiscoUCSMDriver(): ucsm_password): data = self._create_profile_post_data(profile_name, vlan_name) self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) - data = self._create_profile_client_post_data(profile_name, profile_name[-16:]) + data = self._create_profile_client_post_data(profile_name, + profile_name[-16:]) self._post_data(ucsm_ip, ucsm_username, ucsm_password, data) def change_vlan_in_profile(self, profile_name, old_vlan_name, From b653ea1c5ccd5626043d7ec75d4aec47f19eedb0 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Wed, 3 Aug 2011 16:17:06 -0700 Subject: [PATCH 24/48] Removed quantum/plugins/cisco/db/ and quantum/cisco_extensions since these will be merged separately. --- cisco_extensions/__init__.py | 71 -- cisco_extensions/exceptions.py | 148 --- cisco_extensions/extensions.py | 42 - cisco_extensions/faults.py | 111 -- cisco_extensions/portprofiles.py | 180 --- cisco_extensions/pprofiles.py | 45 - quantum/plugins/cisco/db/db_conn.ini | 5 - quantum/plugins/cisco/db/db_test_plugin.py | 1049 ------------------ quantum/plugins/cisco/db/l2network_db.py | 239 ---- quantum/plugins/cisco/db/l2network_models.py | 86 -- quantum/plugins/cisco/db/ucs_db.py | 314 ------ quantum/plugins/cisco/db/ucs_models.py | 113 -- 12 files changed, 2403 deletions(-) delete mode 100644 cisco_extensions/__init__.py delete mode 100644 cisco_extensions/exceptions.py delete mode 100644 cisco_extensions/extensions.py delete mode 100644 cisco_extensions/faults.py delete mode 100644 cisco_extensions/portprofiles.py delete mode 100644 cisco_extensions/pprofiles.py delete mode 100644 quantum/plugins/cisco/db/db_conn.ini delete mode 100644 quantum/plugins/cisco/db/db_test_plugin.py delete mode 100644 quantum/plugins/cisco/db/l2network_db.py delete mode 100644 quantum/plugins/cisco/db/l2network_models.py delete mode 100644 quantum/plugins/cisco/db/ucs_db.py delete mode 100644 quantum/plugins/cisco/db/ucs_models.py diff --git a/cisco_extensions/__init__.py b/cisco_extensions/__init__.py deleted file mode 100644 index 5fc5d88919..0000000000 --- a/cisco_extensions/__init__.py +++ /dev/null @@ -1,71 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 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. -# -# @author: Ying Liu, Cisco Systems, Inc. -# - -import logging -import routes -import webob.dec -import webob.exc - -from quantum import manager -from quantum.api import faults -from quantum.api import networks -from quantum.api import ports -from quantum.common import flags -from quantum.common import wsgi -from cisco_extensions import portprofiles -from cisco_extensions import extensions - - -LOG = logging.getLogger('quantum_extension.api') -FLAGS = flags.FLAGS - - -class ExtRouterV01(wsgi.Router): - """ - Routes requests on the Quantum API to the appropriate controller - """ - - def __init__(self, ext_mgr=None): - uri_prefix = '/tenants/{tenant_id}/' - - mapper = routes.Mapper() - plugin = manager.QuantumManager().get_plugin() - controller = portprofiles.Controller(plugin) - ext_controller = extensions.Controller(plugin) - mapper.connect("home", "/", controller=ext_controller, - action="list_extension", - conditions=dict(method=['GET'])) - #mapper.redirect("/", "www.google.com") - mapper.resource("portprofiles", "portprofiles", - controller=controller, - path_prefix=uri_prefix) - mapper.connect("associate_portprofile", - uri_prefix - + 'portprofiles/{portprofile_id}/assignment{.format}', - controller=controller, - action="associate_portprofile", - conditions=dict(method=['PUT'])) - mapper.connect("disassociate_portprofile", - uri_prefix - + 'portprofiles/{portprofile_id}/assignment{.format}', - controller=controller, - action="disassociate_portprofile", - conditions=dict(method=['DELETE'])) - - super(ExtRouterV01, self).__init__(mapper) diff --git a/cisco_extensions/exceptions.py b/cisco_extensions/exceptions.py deleted file mode 100644 index 415731e385..0000000000 --- a/cisco_extensions/exceptions.py +++ /dev/null @@ -1,148 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 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. -# -# @author: Ying Liu, Cisco Systems, Inc. -# -import logging - - -class ExtensionException(Exception): - """Quantum Cisco api Exception - - Taken from nova.exception.NovaException - To correctly use this class, inherit from it and define - a 'message' property. That message will get printf'd - with the keyword arguments provided to the constructor. - - """ - message = _("An unknown exception occurred.") - - def __init__(self, **kwargs): - try: - self._error_string = self.message % kwargs - - except Exception: - # at least get the core message out if something happened - self._error_string = self.message - - def __str__(self): - return self._error_string - - -class ProcessExecutionError(IOError): - def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None, - description=None): - if description is None: - description = "Unexpected error while running command." - if exit_code is None: - exit_code = '-' - message = "%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r" % ( - description, cmd, exit_code, stdout, stderr) - IOError.__init__(self, message) - - -class Error(Exception): - def __init__(self, message=None): - super(Error, self).__init__(message) - - -class ApiError(Error): - def __init__(self, message='Unknown', code='Unknown'): - self.message = message - self.code = code - super(ApiError, self).__init__('%s: %s' % (code, message)) - - -class NotFound(ExtensionException): - pass - - -class ClassNotFound(NotFound): - message = _("Class %(class_name)s could not be found") - - -class PortprofileNotFound(NotFound): - message = _("Portprofile %(_id)s could not be found") - - -class PortNotFound(NotFound): - message = _("Port %(port_id)s could not be found " \ - "on Network %(net_id)s") - - -""" - - -class PortprofileInUse(ExtensionException): - message = _("Unable to complete operation on Portprofile %(net_id)s. " \ - "There is one or more attachments plugged into its ports.") - - -class PortInUse(ExtensionException): - message = _("Unable to complete operation on port %(port_id)s " \ - "for Portprofile %(net_id)s. The attachment '%(att_id)s" \ - "is plugged into the logical port.") - -class AlreadyAttached(ExtensionException): - message = _("Unable to plug the attachment %(att_id)s into port " \ - "%(port_id)s for Portprofile %(net_id)s. The attachment is " \ - "already plugged into port %(att_port_id)s") - -""" - - -class Duplicate(Error): - pass - - -class NotAuthorized(Error): - pass - - -class NotEmpty(Error): - pass - - -class Invalid(Error): - pass - - -class InvalidContentType(Invalid): - message = _("Invalid content type %(content_type)s.") - - -class BadInputError(Exception): - """Error resulting from a client sending bad input to a server""" - pass - - -class MissingArgumentError(Error): - pass - - -def wrap_exception(f): - def _wrap(*args, **kw): - try: - return f(*args, **kw) - except Exception, e: - if not isinstance(e, Error): - #exc_type, exc_value, exc_traceback = sys.exc_info() - logging.exception('Uncaught exception') - #logging.error(traceback.extract_stack(exc_traceback)) - raise Error(str(e)) - raise - _wrap.func_name = f.func_name - return _wrap diff --git a/cisco_extensions/extensions.py b/cisco_extensions/extensions.py deleted file mode 100644 index 34bc37e814..0000000000 --- a/cisco_extensions/extensions.py +++ /dev/null @@ -1,42 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 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. -# -# @author: Ying Liu, Cisco Systems, Inc. -# -import logging -import webob.dec - -from quantum.common import wsgi -from quantum.api import api_common as common - - -LOG = logging.getLogger('quantum.api.cisco_extension.extensions') - - -class Controller(common.QuantumController): - - def __init__(self, plugin): - #self._plugin = plugin - #super(QuantumController, self).__init__() - self._resource_name = 'extensions' - super(Controller, self).__init__(plugin) - - def list_extension(self, req): - """Respond to a request for listing all extension api.""" - response = "extensions api list" - return response - - \ No newline at end of file diff --git a/cisco_extensions/faults.py b/cisco_extensions/faults.py deleted file mode 100644 index c965f731dc..0000000000 --- a/cisco_extensions/faults.py +++ /dev/null @@ -1,111 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 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. -# -# @author: Ying Liu, Cisco Systems, Inc. -# -import webob.dec -import webob.exc - -from quantum.api import api_common as common -from quantum.common import wsgi - - -class Fault(webob.exc.HTTPException): - """Error codes for API faults""" - - _fault_names = { - 400: "malformedRequest", - 401: "unauthorized", - 420: "networkNotFound", - 421: "PortprofileInUse", - 430: "portNotFound", - 431: "requestedStateInvalid", - 432: "portInUse", - 440: "alreadyAttached", - 450: "PortprofileNotFound", - 470: "serviceUnavailable", - 471: "pluginFault"} - - def __init__(self, exception): - """Create a Fault for the given webob.exc.exception.""" - self.wrapped_exc = exception - - @webob.dec.wsgify(RequestClass=wsgi.Request) - def __call__(self, req): - """Generate a WSGI response based on the exception passed to ctor.""" - #print ("*********TEST2") - # Replace the body with fault details. - code = self.wrapped_exc.status_int - fault_name = self._fault_names.get(code, "quantumServiceFault") - fault_data = { - fault_name: { - 'code': code, - 'message': self.wrapped_exc.explanation, - 'detail': self.wrapped_exc.detail}} - # 'code' is an attribute on the fault tag itself - metadata = {'application/xml': {'attributes': {fault_name: 'code'}}} - default_xmlns = common.XML_NS_V10 - serializer = wsgi.Serializer(metadata, default_xmlns) - content_type = req.best_match_content_type() - self.wrapped_exc.body = serializer.serialize(fault_data, content_type) - self.wrapped_exc.content_type = content_type - return self.wrapped_exc - - -class PortprofileNotFound(webob.exc.HTTPClientError): - """ - subclass of :class:`~HTTPClientError` - - This indicates that the server did not find the Portprofile specified - in the HTTP request - - code: 450, title: Portprofile not Found - """ - #print ("*********TEST1") - code = 450 - title = 'Portprofile Not Found' - explanation = ('Unable to find a Portprofile with' - + ' the specified identifier.') - - -class PortNotFound(webob.exc.HTTPClientError): - """ - subclass of :class:`~HTTPClientError` - - This indicates that the server did not find the port specified - in the HTTP request for a given network - - code: 430, title: Port not Found - """ - code = 430 - title = 'Port not Found' - explanation = ('Unable to find a port with the specified identifier.') - - -class RequestedStateInvalid(webob.exc.HTTPClientError): - """ - subclass of :class:`~HTTPClientError` - - This indicates that the server could not update the port state to - to the request value - - code: 431, title: Requested State Invalid - """ - code = 431 - title = 'Requested State Invalid' - explanation = ('Unable to update port state with specified value.') - - diff --git a/cisco_extensions/portprofiles.py b/cisco_extensions/portprofiles.py deleted file mode 100644 index 5d195528f8..0000000000 --- a/cisco_extensions/portprofiles.py +++ /dev/null @@ -1,180 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 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. -# -# @author: Ying Liu, Cisco Systems, Inc. -# - -import logging -import webob.dec -from quantum.common import wsgi -from webob import exc - -from quantum.api import api_common as common - -from cisco_extensions import pprofiles as pprofiles_view -from cisco_extensions import exceptions as exception -from cisco_extensions import faults as faults - -LOG = logging.getLogger('quantum.api.portprofiles') - - -class Controller(common.QuantumController): - """ portprofile API controller - based on QuantumController """ - - _portprofile_ops_param_list = [{ - 'param-name': 'portprofile-name', - 'required': True}, { - 'param-name': 'vlan-id', - 'required': True}, { - 'param-name': 'assignment', - 'required': False}] - - _assignprofile_ops_param_list = [{ - 'param-name': 'network-id', - 'required': True}, { - 'param-name': 'port-id', - 'required': True}] - - _serialization_metadata = { - "application/xml": { - "attributes": { - "portprofile": ["id", "name"], - }, - }, - } - - def __init__(self, plugin): - self._resource_name = 'portprofile' - super(Controller, self).__init__(plugin) - - def index(self, request, tenant_id): - """ Returns a list of portprofile ids """ - #TODO: this should be for a given tenant!!! - return self._items(request, tenant_id, is_detail=False) - - def _items(self, request, tenant_id, is_detail): - """ Returns a list of portprofiles. """ - portprofiles = self._plugin.get_all_portprofiles(tenant_id) - builder = pprofiles_view.get_view_builder(request) - result = [builder.build(portprofile, is_detail)['portprofile'] - for portprofile in portprofiles] - return dict(portprofiles=result) - - def show(self, request, tenant_id, id): - """ Returns portprofile details for the given portprofile id """ - try: - portprofile = self._plugin.get_portprofile_details( - tenant_id, id) - builder = pprofiles_view.get_view_builder(request) - #build response with details - result = builder.build(portprofile, True) - return dict(portprofiles=result) - except exception.PortprofileNotFound as e: - return faults.Fault(faults.PortprofileNotFound(e)) - #return faults.Fault(e) - - def create(self, request, tenant_id): - """ Creates a new portprofile for a given tenant """ - #look for portprofile name in request - try: - req_params = \ - self._parse_request_params(request, - self._portprofile_ops_param_list) - except exc.HTTPError as e: - return faults.Fault(e) - portprofile = self._plugin.\ - create_portprofile(tenant_id, - req_params['portprofile-name'], - req_params['vlan-id']) - builder = pprofiles_view.get_view_builder(request) - result = builder.build(portprofile) - return dict(portprofiles=result) - - def update(self, request, tenant_id, id): - """ Updates the name for the portprofile with the given id """ - try: - req_params = \ - self._parse_request_params(request, - self._portprofile_ops_param_list) - except exc.HTTPError as e: - return faults.Fault(e) - try: - portprofile = self._plugin.\ - rename_portprofile(tenant_id, - id, req_params['portprofile-name']) - - builder = pprofiles_view.get_view_builder(request) - result = builder.build(portprofile, True) - return dict(portprofiles=result) - except exception.PortprofileNotFound as e: - return faults.Fault(faults.PortprofileNotFound(e)) - - def delete(self, request, tenant_id, id): - """ Destroys the portprofile with the given id """ - try: - self._plugin.delete_portprofile(tenant_id, id) - return exc.HTTPAccepted() - except exception.PortprofileNotFound as e: - return faults.Fault(faults.PortprofileNotFound(e)) - - #added for cisco's extension - def associate_portprofile(self, request, tenant_id, portprofile_id): - content_type = request.best_match_content_type() - print "Content type:%s" % content_type - - try: - req_params = \ - self._parse_request_params(request, - self._assignprofile_ops_param_list) - except exc.HTTPError as e: - return faults.Fault(e) - net_id = req_params['network-id'].strip() - #print "*****net id "+net_id - port_id = req_params['port-id'].strip() - try: - self._plugin.associate_portprofile(tenant_id, - net_id, port_id, - portprofile_id) - return exc.HTTPAccepted() - except exception.PortprofileNotFound as e: - return faults.Fault(faults.PortprofileNotFound(e)) - except exception.PortNotFound as e: - return faults.Fault(faults.PortNotFound(e)) - - #added for Cisco extension - def disassociate_portprofile(self, request, tenant_id, portprofile_id): - content_type = request.best_match_content_type() - print "Content type:%s" % content_type - - try: - req_params = \ - self._parse_request_params(request, - self._assignprofile_ops_param_list) - except exc.HTTPError as e: - return faults.Fault(e) - net_id = req_params['network-id'].strip() - #print "*****net id "+net_id - port_id = req_params['port-id'].strip() - try: - self._plugin. \ - disassociate_portprofile(tenant_id, - net_id, port_id, portprofile_id) - return exc.HTTPAccepted() - except exception.PortprofileNotFound as e: - return faults.Fault(faults.PortprofileNotFound(e)) - except exception.PortNotFound as e: - return faults.Fault(faults.PortNotFound(e)) diff --git a/cisco_extensions/pprofiles.py b/cisco_extensions/pprofiles.py deleted file mode 100644 index ba7f8a328b..0000000000 --- a/cisco_extensions/pprofiles.py +++ /dev/null @@ -1,45 +0,0 @@ - - -import os - - -def get_view_builder(req): - base_url = req.application_url - return ViewBuilder(base_url) - - -class ViewBuilder(object): - """ - ViewBuilder for Portprofile, - derived from quantum.views.networks - """ - def __init__(self, base_url): - """ - :param base_url: url of the root wsgi application - """ - self.base_url = base_url - - def build(self, portprofile_data, is_detail=False): - """Generic method used to generate a portprofile entity.""" - print "portprofile-DATA:%s" %portprofile_data - if is_detail: - portprofile = self._build_detail(portprofile_data) - else: - portprofile = self._build_simple(portprofile_data) - return portprofile - - def _build_simple(self, portprofile_data): - """Return a simple model of a server.""" - return dict(portprofile=dict(id=portprofile_data['profile-id'])) - - def _build_detail(self, portprofile_data): - """Return a simple model of a server.""" - if (portprofile_data['assignment']==None): - return dict(portprofile=dict(id=portprofile_data['profile-id'], - name=portprofile_data['profile-name'], - vlan_id=portprofile_data['vlan-id'])) - else: - return dict(portprofile=dict(id=portprofile_data['profile-id'], - name=portprofile_data['profile-name'], - vlan_id=portprofile_data['vlan-id'], - assignment=portprofile_data['assignment'])) diff --git a/quantum/plugins/cisco/db/db_conn.ini b/quantum/plugins/cisco/db/db_conn.ini deleted file mode 100644 index 55066aaeb1..0000000000 --- a/quantum/plugins/cisco/db/db_conn.ini +++ /dev/null @@ -1,5 +0,0 @@ -[DATABASE] -name = quantum_l2network -user = root -pass = nova -host = 127.0.0.1 diff --git a/quantum/plugins/cisco/db/db_test_plugin.py b/quantum/plugins/cisco/db/db_test_plugin.py deleted file mode 100644 index e0ec6fa9f4..0000000000 --- a/quantum/plugins/cisco/db/db_test_plugin.py +++ /dev/null @@ -1,1049 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011, Cisco Systems, Inc. -# -# 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. -# @author: Rohit Agarwalla, Cisco Systems, Inc. - -import ConfigParser -import os -import logging as LOG -import unittest - -from optparse import OptionParser -from quantum.plugins.cisco.common import cisco_constants as const - -import quantum.db.api as db -import quantum.db.models -import quantum.plugins.cisco.db.l2network_db as l2network_db -import quantum.plugins.cisco.db.l2network_models - -CONF_FILE = "db_conn.ini" -LOG.getLogger(const.LOGGER_COMPONENT_NAME) - - -def find_config(basepath): - for root, dirs, files in os.walk(basepath): - if CONF_FILE in files: - return os.path.join(root, CONF_FILE) - return None - - -def db_conf(configfile=None): - config = ConfigParser.ConfigParser() - if configfile == None: - if os.path.exists(CONF_FILE): - configfile = CONF_FILE - else: - configfile = \ - find_config(os.path.abspath(os.path.dirname(__file__))) - if configfile == None: - raise Exception("Configuration file \"%s\" doesn't exist" % - (configfile)) - LOG.debug("Using configuration file: %s" % configfile) - config.read(configfile) - - DB_NAME = config.get("DATABASE", "name") - DB_USER = config.get("DATABASE", "user") - DB_PASS = config.get("DATABASE", "pass") - DB_HOST = config.get("DATABASE", "host") - options = {"sql_connection": "mysql://%s:%s@%s/%s" % (DB_USER, - DB_PASS, DB_HOST, DB_NAME)} - db.configure_db(options) - - -class UcsDB(object): - def get_all_ucsmbindings(self): - bindings = [] - try: - for x in ucs_db.get_all_ucsmbinding(): - LOG.debug("Getting ucsm binding : %s" % x.ucsm_ip) - bind_dict = {} - bind_dict["ucsm-ip"] = str(x.ucsm_ip) - bind_dict["network-id"] = str(x.network_id) - bindings.append(bind_dict) - except Exception, e: - LOG.error("Failed to get all bindings: %s" % str(e)) - return bindings - - def get_ucsmbinding(self, ucsm_ip): - binding = [] - try: - for x in ucs_db.get_ucsmbinding(ucsm_ip): - LOG.debug("Getting ucsm binding : %s" % x.ucsm_ip) - bind_dict = {} - bind_dict["ucsm-ip"] = str(res.ucsm_ip) - bind_dict["network-id"] = str(res.network_id) - binding.append(bind_dict) - except Exception, e: - LOG.error("Failed to get binding: %s" % str(e)) - return binding - - def create_ucsmbinding(self, ucsm_ip, networ_id): - bind_dict = {} - try: - res = ucs_db.add_ucsmbinding(ucsm_ip, networ_id) - LOG.debug("Created ucsm binding: %s" % res.ucsm_ip) - bind_dict["ucsm-ip"] = str(res.ucsm_ip) - bind_dict["network-id"] = str(res.network_id) - return bind_dict - except Exception, e: - LOG.error("Failed to create ucsm binding: %s" % str(e)) - - def delete_ucsmbinding(self, ucsm_ip): - try: - res = ucs_db.remove_ucsmbinding(ucsm_ip) - LOG.debug("Deleted ucsm binding : %s" % res.ucsm_ip) - bind_dict = {} - bind_dict["ucsm-ip"] = str(res.ucsm_ip) - return bind_dict - except Exception, e: - raise Exception("Failed to delete dynamic vnic: %s" % str(e)) - - def update_ucsmbinding(self, ucsm_ip, network_id): - try: - res = ucs_db.update_ucsmbinding(ucsm_ip, network_id) - LOG.debug("Updating ucsm binding : %s" % res.ucsm_ip) - bind_dict = {} - bind_dict["ucsm-ip"] = str(res.ucsm_ip) - bind_dict["network-id"] = str(res.network_id) - return bind_dict - except Exception, e: - raise Exception("Failed to update dynamic vnic: %s" % str(e)) - - def get_all_dynamicvnics(self): - vnics = [] - try: - for x in ucs_db.get_all_dynamicvnics(): - LOG.debug("Getting dynamic vnic : %s" % x.uuid) - vnic_dict = {} - vnic_dict["vnic-id"] = str(x.uuid) - vnic_dict["device-name"] = x.device_name - vnic_dict["blade-id"] = str(x.blade_id) - vnics.append(vnic_dict) - except Exception, e: - LOG.error("Failed to get all dynamic vnics: %s" % str(e)) - return vnics - - def get_dynamicvnic(self, vnic_id): - vnic = [] - try: - for x in ucs_db.get_dynamicvnic(vnic_id): - LOG.debug("Getting dynamic vnic : %s" % x.uuid) - vnic_dict = {} - vnic_dict["vnic-id"] = str(x.uuid) - vnic_dict["device-name"] = x.device_name - vnic_dict["blade-id"] = str(x.blade_id) - vnic.append(vnic_dict) - except Exception, e: - LOG.error("Failed to get dynamic vnic: %s" % str(e)) - return vnic - - def create_dynamicvnic(self, device_name, blade_id): - vnic_dict = {} - try: - res = ucs_db.add_dynamicvnic(device_name, blade_id) - LOG.debug("Created dynamic vnic: %s" % res.uuid) - vnic_dict["vnic-id"] = str(res.uuid) - vnic_dict["device-name"] = res.device_name - vnic_dict["blade-id"] = str(res.blade_id) - return vnic_dict - except Exception, e: - LOG.error("Failed to create dynamic vnic: %s" % str(e)) - - def delete_dynamicvnic(self, vnic_id): - try: - res = ucs_db.remove_dynamicvnic(vnic_id) - LOG.debug("Deleted dynamic vnic : %s" % res.uuid) - vnic_dict = {} - vnic_dict["vnic-id"] = str(res.uuid) - return vnic_dict - except Exception, e: - raise Exception("Failed to delete dynamic vnic: %s" % str(e)) - - def update_dynamicvnic(self, vnic_id, device_name=None, blade_id=None): - try: - res = ucs_db.update_dynamicvnic(vnic_id, device_name, blade_id) - LOG.debug("Updating dynamic vnic : %s" % res.uuid) - vnic_dict = {} - vnic_dict["vnic-id"] = str(res.uuid) - vnic_dict["device-name"] = res.device_name - vnic_dict["blade-id"] = str(res.blade_id) - return vnic_dict - except Exception, e: - raise Exception("Failed to update dynamic vnic: %s" % str(e)) - - def get_all_blades(self): - blades = [] - try: - for x in ucs_db.get_all_blades(): - LOG.debug("Getting blade : %s" % x.uuid) - blade_dict = {} - blade_dict["blade-id"] = str(x.uuid) - blade_dict["mgmt-ip"] = str(x.mgmt_ip) - blade_dict["mac-addr"] = str(x.mac_addr) - blade_dict["chassis-id"] = str(x.chassis_id) - blade_dict["ucsm-ip"] = str(x.ucsm_ip) - blades.append(blade_dict) - except Exception, e: - LOG.error("Failed to get all blades: %s" % str(e)) - return blades - - def get_blade(self, blade_id): - blade = [] - try: - for x in ucs_db.get_blade(blade_id): - LOG.debug("Getting blade : %s" % x.uuid) - blade_dict = {} - blade_dict["blade-id"] = str(x.uuid) - blade_dict["mgmt-ip"] = str(x.mgmt_ip) - blade_dict["mac-addr"] = str(x.mac_addr) - blade_dict["chassis-id"] = str(x.chassis_id) - blade_dict["ucsm-ip"] = str(x.ucsm_ip) - blade.append(blade_dict) - except Exception, e: - LOG.error("Failed to get all blades: %s" % str(e)) - return blade - - def create_blade(self, mgmt_ip, mac_addr, chassis_id, ucsm_ip): - blade_dict = {} - try: - res = ucs_db.add_blade(mgmt_ip, mac_addr, chassis_id, ucsm_ip) - LOG.debug("Created blade: %s" % res.uuid) - blade_dict["blade-id"] = str(res.uuid) - blade_dict["mgmt-ip"] = str(res.mgmt_ip) - blade_dict["mac-addr"] = str(res.mac_addr) - blade_dict["chassis-id"] = str(res.chassis_id) - blade_dict["ucsm-ip"] = str(res.ucsm_ip) - return blade_dict - except Exception, e: - LOG.error("Failed to create blade: %s" % str(e)) - - def delete_blade(self, blade_id): - try: - res = ucs_db.remove_blade(blade_id) - LOG.debug("Deleted blade : %s" % res.uuid) - blade_dict = {} - blade_dict["blade-id"] = str(res.uuid) - return blade_dict - except Exception, e: - raise Exception("Failed to delete blade: %s" % str(e)) - - def update_blade(self, blade_id, mgmt_ip=None, mac_addr=None,\ - chassis_id=None, ucsm_ip=None): - try: - res = ucs_db.update_blade(blade_id, mgmt_ip, mac_addr, \ - chassis_id, ucsm_ip) - LOG.debug("Updating blade : %s" % res.uuid) - blade_dict = {} - blade_dict["blade-id"] = str(res.uuid) - blade_dict["mgmt-ip"] = str(res.mgmt_ip) - blade_dict["mac-addr"] = str(res.mac_addr) - blade_dict["chassis-id"] = str(res.chassis_id) - blade_dict["ucsm-ip"] = str(res.ucsm_ip) - return blade_dict - except Exception, e: - raise Exception("Failed to update blade: %s" % str(e)) - - def get_all_port_bindings(self): - port_bindings = [] - try: - for x in ucs_db.get_all_portbindings(): - LOG.debug("Getting port binding for port: %s" % x.port_id) - port_bind_dict = {} - port_bind_dict["port-id"] = x.port_id - port_bind_dict["dynamic-vnic-id"] = str(x.dynamic_vnic_id) - port_bind_dict["portprofile-name"] = x.portprofile_name - port_bind_dict["vlan-name"] = x.vlan_name - port_bind_dict["vlan-id"] = str(x.vlan_id) - port_bind_dict["qos"] = x.qos - port_bindings.append(port_bind_dict) - except Exception, e: - LOG.error("Failed to get all port bindings: %s" % str(e)) - return port_bindings - - def get_port_binding(self): - port_binding = [] - try: - for x in ucs_db.get_portbinding(port_id): - LOG.debug("Getting port binding for port: %s" % x.port_id) - port_bind_dict = {} - port_bind_dict["port-id"] = x.port_id - port_bind_dict["dynamic-vnic-id"] = str(x.dynamic_vnic_id) - port_bind_dict["portprofile-name"] = x.portprofile_name - port_bind_dict["vlan-name"] = x.vlan_name - port_bind_dict["vlan-id"] = str(x.vlan_id) - port_bind_dict["qos"] = x.qos - port_bindings.append(port_bind_dict) - except Exception, e: - LOG.error("Failed to get port binding: %s" % str(e)) - return port_binding - - def create_port_binding(self, port_id, dynamic_vnic_id, portprofile_name, \ - vlan_name, vlan_id, qos): - port_bind_dict = {} - try: - res = ucs_db.add_portbinding(port_id, dynamic_vnic_id, \ - portprofile_name, vlan_name, vlan_id, qos) - LOG.debug("Created port binding: %s" % res.port_id) - port_bind_dict["port-id"] = res.port_id - port_bind_dict["dynamic-vnic-id"] = str(res.dynamic_vnic_id) - port_bind_dict["portprofile-name"] = res.portprofile_name - port_bind_dict["vlan-name"] = res.vlan_name - port_bind_dict["vlan-id"] = str(res.vlan_id) - port_bind_dict["qos"] = res.qos - return port_bind_dict - except Exception, e: - LOG.error("Failed to create port binding: %s" % str(e)) - - def delete_port_binding(self, port_id): - try: - res = ucs_db.remove_portbinding(port_id) - LOG.debug("Deleted port binding : %s" % res.port_id) - port_bind_dict = {} - port_bind_dict["port-id"] = res.port_id - return port_bind_dict - except Exception, e: - raise Exception("Failed to delete port profile: %s" % str(e)) - - def update_port_binding(self, port_id, dynamic_vnic_id, \ - portprofile_name, vlan_name, vlan_id, qos): - try: - res = ucs_db.update_portbinding(port_id, dynamic_vnic_id, \ - portprofile_name, vlan_name, vlan_id, qos) - LOG.debug("Updating port binding: %s" % res.port_id) - port_bind_dict = {} - port_bind_dict["port-id"] = res.port_id - port_bind_dict["dynamic-vnic-id"] = str(res.dynamic_vnic_id) - port_bind_dict["portprofile-name"] = res.portprofile_name - port_bind_dict["vlan-name"] = res.vlan_name - port_bind_dict["vlan-id"] = str(res.vlan_id) - port_bind_dict["qos"] = res.qos - return port_bind_dict - except Exception, e: - raise Exception("Failed to update portprofile binding:%s" % str(e)) - - -class QuantumDB(object): - def get_all_networks(self, tenant_id): - nets = [] - try: - for x in db.network_list(tenant_id): - LOG.debug("Getting network: %s" % x.uuid) - net_dict = {} - net_dict["tenant-id"] = x.tenant_id - net_dict["net-id"] = str(x.uuid) - net_dict["net-name"] = x.name - nets.append(net_dict) - except Exception, e: - LOG.error("Failed to get all networks: %s" % str(e)) - return nets - - def get_network(self, network_id): - net = [] - try: - for x in db.network_get(network_id): - LOG.debug("Getting network: %s" % x.uuid) - net_dict = {} - net_dict["tenant-id"] = x.tenant_id - net_dict["net-id"] = str(x.uuid) - net_dict["net-name"] = x.name - nets.append(net_dict) - except Exception, e: - LOG.error("Failed to get network: %s" % str(e)) - return net - - def create_network(self, tenant_id, net_name): - net_dict = {} - try: - res = db.network_create(tenant_id, net_name) - LOG.debug("Created network: %s" % res.uuid) - net_dict["tenant-id"] = res.tenant_id - net_dict["net-id"] = str(res.uuid) - net_dict["net-name"] = res.name - return net_dict - except Exception, e: - LOG.error("Failed to create network: %s" % str(e)) - - def delete_network(self, net_id): - try: - net = db.network_destroy(net_id) - LOG.debug("Deleted network: %s" % net.uuid) - net_dict = {} - net_dict["net-id"] = str(net.uuid) - return net_dict - except Exception, e: - raise Exception("Failed to delete port: %s" % str(e)) - - def rename_network(self, tenant_id, net_id, new_name): - try: - net = db.network_rename(net_id, tenant_id, new_name) - LOG.debug("Renamed network: %s" % net.uuid) - net_dict = {} - net_dict["net-id"] = str(net.uuid) - net_dict["net-name"] = net.name - return net_dict - except Exception, e: - raise Exception("Failed to rename network: %s" % str(e)) - - def get_all_ports(self, net_id): - ports = [] - try: - for x in db.port_list(net_id): - LOG.debug("Getting port: %s" % x.uuid) - port_dict = {} - port_dict["port-id"] = str(x.uuid) - port_dict["net-id"] = str(x.network_id) - port_dict["int-id"] = x.interface_id - port_dict["state"] = x.state - ports.append(port_dict) - return ports - except Exception, e: - LOG.error("Failed to get all ports: %s" % str(e)) - - def get_port(self, port_id): - port = [] - try: - for x in db.port_get(port_id): - LOG.debug("Getting port: %s" % x.uuid) - port_dict = {} - port_dict["port-id"] = str(x.uuid) - port_dict["net-id"] = str(x.network_id) - port_dict["int-id"] = x.interface_id - port_dict["state"] = x.state - port.append(port_dict) - return port - except Exception, e: - LOG.error("Failed to get port: %s" % str(e)) - - def create_port(self, net_id): - port_dict = {} - try: - port = db.port_create(net_id) - LOG.debug("Creating port %s" % port.uuid) - port_dict["port-id"] = str(port.uuid) - port_dict["net-id"] = str(port.network_id) - port_dict["int-id"] = port.interface_id - port_dict["state"] = port.state - return port_dict - except Exception, e: - LOG.error("Failed to create port: %s" % str(e)) - - def delete_port(self, port_id): - try: - port = db.port_destroy(port_id) - LOG.debug("Deleted port %s" % port.uuid) - port_dict = {} - port_dict["port-id"] = str(port.uuid) - return port_dict - except Exception, e: - raise Exception("Failed to delete port: %s" % str(e)) - - def update_port(self, port_id, port_state): - try: - port = db.port_set_state(port_id, port_state) - LOG.debug("Updated port %s" % port.uuid) - port_dict = {} - port_dict["port-id"] = str(port.uuid) - port_dict["net-id"] = str(port.network_id) - port_dict["int-id"] = port.interface_id - port_dict["state"] = port.state - return port_dict - except Exception, e: - raise Exception("Failed to update port state: %s" % str(e)) - - -class L2networkDB(object): - def get_all_vlan_bindings(self): - vlans = [] - try: - for x in l2network_db.get_all_vlan_bindings(): - LOG.debug("Getting vlan bindings for vlan: %s" % x.vlan_id) - vlan_dict = {} - vlan_dict["vlan-id"] = str(x.vlan_id) - vlan_dict["vlan-name"] = x.vlan_name - vlan_dict["net-id"] = str(x.network_id) - vlans.append(vlan_dict) - except Exception, e: - LOG.error("Failed to get all vlan bindings: %s" % str(e)) - return vlans - - def get_vlan_binding(self, network_id): - vlan = [] - try: - for x in l2network_db.get_vlan_binding(network_id): - LOG.debug("Getting vlan binding for vlan: %s" % x.vlan_id) - vlan_dict = {} - vlan_dict["vlan-id"] = str(x.vlan_id) - vlan_dict["vlan-name"] = x.vlan_name - vlan_dict["net-id"] = str(x.network_id) - vlan.append(vlan_dict) - except Exception, e: - LOG.error("Failed to get vlan binding: %s" % str(e)) - return vlan - - def create_vlan_binding(self, vlan_id, vlan_name, network_id): - vlan_dict = {} - try: - res = l2network_db.add_vlan_binding(vlan_id, vlan_name, network_id) - LOG.debug("Created vlan binding for vlan: %s" % res.vlan_id) - vlan_dict["vlan-id"] = str(res.vlan_id) - vlan_dict["vlan-name"] = res.vlan_name - vlan_dict["net-id"] = str(res.network_id) - return vlan_dict - except Exception, e: - LOG.error("Failed to create vlan binding: %s" % str(e)) - - def delete_vlan_binding(self, network_id): - try: - res = l2network_db.remove_vlan_binding(network_id) - LOG.debug("Deleted vlan binding for vlan: %s" % res.vlan_id) - vlan_dict = {} - vlan_dict["vlan-id"] = str(res.vlan_id) - return vlan_dict - except Exception, e: - raise Exception("Failed to delete vlan binding: %s" % str(e)) - - def update_vlan_binding(self, network_id, vlan_id, vlan_name): - try: - res = l2network_db.update_vlan_binding(network_id, vlan_id, \ - vlan_name) - LOG.debug("Updating vlan binding for vlan: %s" % res.vlan_id) - vlan_dict = {} - vlan_dict["vlan-id"] = str(res.vlan_id) - vlan_dict["vlan-name"] = res.vlan_name - vlan_dict["net-id"] = str(res.network_id) - return vlan_dict - except Exception, e: - raise Exception("Failed to update vlan binding: %s" % str(e)) - - def get_all_portprofiles(self): - pps = [] - try: - for x in l2network_db.get_all_portprofiles(): - LOG.debug("Getting port profile : %s" % x.uuid) - pp_dict = {} - pp_dict["portprofile-id"] = str(x.uuid) - pp_dict["portprofile-name"] = x.name - pp_dict["vlan-id"] = str(x.vlan_id) - pp_dict["qos"] = x.qos - pps.append(pp_dict) - except Exception, e: - LOG.error("Failed to get all port profiles: %s" % str(e)) - return pps - - def get_portprofile(self, port_id): - pp = [] - try: - for x in l2network_db.get_portprofile(port_id): - LOG.debug("Getting port profile : %s" % x.uuid) - pp_dict = {} - pp_dict["portprofile-id"] = str(x.uuid) - pp_dict["portprofile-name"] = x.name - pp_dict["vlan-id"] = str(x.vlan_id) - pp_dict["qos"] = x.qos - pp.append(pp_dict) - except Exception, e: - LOG.error("Failed to get port profile: %s" % str(e)) - return pp - - def create_portprofile(self, name, vlan_id, qos): - pp_dict = {} - try: - res = l2network_db.add_portprofile(name, vlan_id, qos) - LOG.debug("Created port profile: %s" % res.uuid) - pp_dict["portprofile-id"] = str(res.uuid) - pp_dict["portprofile-name"] = res.name - pp_dict["vlan-id"] = str(res.vlan_id) - pp_dict["qos"] = res.qos - return pp_dict - except Exception, e: - LOG.error("Failed to create port profile: %s" % str(e)) - - def delete_portprofile(self, pp_id): - try: - res = l2network_db.remove_portprofile(pp_id) - LOG.debug("Deleted port profile : %s" % res.uuid) - pp_dict = {} - pp_dict["pp-id"] = str(res.uuid) - return pp_dict - except Exception, e: - raise Exception("Failed to delete port profile: %s" % str(e)) - - def update_portprofile(self, pp_id, name, vlan_id, qos): - try: - res = l2network_db.update_portprofile(pp_id, name, vlan_id, qos) - LOG.debug("Updating port profile : %s" % res.uuid) - pp_dict = {} - pp_dict["portprofile-id"] = str(res.uuid) - pp_dict["portprofile-name"] = res.name - pp_dict["vlan-id"] = str(res.vlan_id) - pp_dict["qos"] = res.qos - return pp_dict - except Exception, e: - raise Exception("Failed to update port profile: %s" % str(e)) - - def get_all_pp_bindings(self): - pp_bindings = [] - try: - for x in l2network_db.get_all_pp_bindings(): - LOG.debug("Getting port profile binding: %s" % \ - x.portprofile_id) - ppbinding_dict = {} - ppbinding_dict["portprofile-id"] = str(x.portprofile_id) - ppbinding_dict["net-id"] = str(x.network_id) - ppbinding_dict["tenant-id"] = x.tenant_id - ppbinding_dict["default"] = x.default - pp_bindings.append(ppbinding_dict) - except Exception, e: - LOG.error("Failed to get all port profiles: %s" % str(e)) - return pp_bindings - - def get_pp_binding(self, pp_id): - pp_binding = [] - try: - for x in l2network_db.get_pp_binding(pp_id): - LOG.debug("Getting port profile binding: %s" % \ - x.portprofile_id) - ppbinding_dict = {} - ppbinding_dict["portprofile-id"] = str(x.portprofile_id) - ppbinding_dict["net-id"] = str(x.network_id) - ppbinding_dict["tenant-id"] = x.tenant_id - ppbinding_dict["default"] = x.default - pp_bindings.append(ppbinding_dict) - except Exception, e: - LOG.error("Failed to get port profile binding: %s" % str(e)) - return pp_binding - - def create_pp_binding(self, tenant_id, net_id, pp_id, default): - ppbinding_dict = {} - try: - res = l2network_db.add_pp_binding(tenant_id, net_id, pp_id, \ - default) - LOG.debug("Created port profile binding: %s" % res.portprofile_id) - ppbinding_dict["portprofile-id"] = str(res.portprofile_id) - ppbinding_dict["net-id"] = str(res.network_id) - ppbinding_dict["tenant-id"] = res.tenant_id - ppbinding_dict["default"] = res.default - return ppbinding_dict - except Exception, e: - LOG.error("Failed to create port profile binding: %s" % str(e)) - - def delete_pp_binding(self, pp_id): - try: - res = l2network_db.remove_pp_binding(pp_id) - LOG.debug("Deleted port profile binding : %s" % res.portprofile_id) - ppbinding_dict = {} - ppbinding_dict["portprofile-id"] = str(res.portprofile_id) - return ppbinding_dict - except Exception, e: - raise Exception("Failed to delete port profile: %s" % str(e)) - - def update_pp_binding(self, pp_id, tenant_id, net_id, default): - try: - res = l2network_db.update_pp_binding(pp_id, tenant_id, net_id,\ - default) - LOG.debug("Updating port profile binding: %s" % res.portprofile_id) - ppbinding_dict = {} - ppbinding_dict["portprofile-id"] = str(res.portprofile_id) - ppbinding_dict["net-id"] = str(res.network_id) - ppbinding_dict["tenant-id"] = res.tenant_id - ppbinding_dict["default"] = res.default - return ppbinding_dict - except Exception, e: - raise Exception("Failed to update portprofile binding:%s" % str(e)) - - -class UcsDBTest(unittest.TestCase): - def setUp(self): - self.dbtest = UcsDB() - LOG.debug("Setup") - - def testACreateUcsmBinding(self): - binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", "net1") - self.assertTrue(binding1["ucsm-ip"] == "1.2.3.4") - self.tearDownUcsmBinding() - - def testBGetAllUcsmBindings(self): - binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", "net1") - binding2 = self.dbtest.create_ucsmbinding("2.3.4.5", "net1") - bindings = self.dbtest.get_all_ucsmbindings() - count = 0 - for x in bindings: - if "net" in x["network-id"]: - count += 1 - self.assertTrue(count == 2) - self.tearDownUcsmBinding() - - def testCDeleteUcsmBinding(self): - binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", "net1") - self.dbtest.delete_ucsmbinding(binding1["ucsm-ip"]) - bindings = self.dbtest.get_all_ucsmbindings() - count = 0 - for x in bindings: - if "net " in x["network-id"]: - count += 1 - self.assertTrue(count == 0) - self.tearDownUcsmBinding() - - def testDUpdateUcsmBinding(self): - binding1 = self.dbtest.create_ucsmbinding("1.2.3.4", "net1") - binding1 = self.dbtest.update_ucsmbinding(binding1["ucsm-ip"], \ - "newnet1") - bindings = self.dbtest.get_all_ucsmbindings() - count = 0 - for x in bindings: - if "new" in x["network-id"]: - count += 1 - self.assertTrue(count == 1) - self.tearDownUcsmBinding() - - def testECreateDynamicVnic(self): - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ - "9.8.7.6") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"]) - self.assertTrue(vnic1["device-name"] == "eth1") - self.tearDownDyanmicVnic() - - def testFGetAllDyanmicVnics(self): - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ - "9.8.7.6") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"]) - vnic2 = self.dbtest.create_dynamicvnic("eth2", blade1["blade-id"]) - vnics = self.dbtest.get_all_dynamicvnics() - count = 0 - for x in vnics: - if "eth" in x["device-name"]: - count += 1 - self.assertTrue(count == 2) - self.tearDownDyanmicVnic() - - def testGDeleteDyanmicVnic(self): - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ - "9.8.7.6") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"]) - self.dbtest.delete_dynamicvnic(vnic1["vnic-id"]) - vnics = self.dbtest.get_all_dynamicvnics() - count = 0 - for x in vnics: - if "eth " in x["device-name"]: - count += 1 - self.assertTrue(count == 0) - self.tearDownDyanmicVnic() - - def testHUpdateDynamicVnic(self): - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ - "9.8.7.6") - vnic1 = self.dbtest.create_dynamicvnic("eth1", blade1["blade-id"]) - vnic1 = self.dbtest.update_dynamicvnic(vnic1["vnic-id"], "neweth1", \ - "newblade2") - vnics = self.dbtest.get_all_dynamicvnics() - count = 0 - for x in vnics: - if "new" in x["device-name"]: - count += 1 - self.assertTrue(count == 1) - self.tearDownDyanmicVnic() - - def testICreateUcsBlade(self): - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ - "9.8.7.6") - self.assertTrue(blade1["mgmt-ip"] == "1.2.3.4") - self.tearDownUcsBlade() - - def testJGetAllUcsBlade(self): - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ - "9.8.7.6") - blade2 = self.dbtest.create_blade("2.3.4.5", "efgh", "chassis1", \ - "9.8.7.6") - blades = self.dbtest.get_all_blades() - count = 0 - for x in blades: - if "chassis" in x["chassis-id"]: - count += 1 - self.assertTrue(count == 2) - self.tearDownUcsBlade() - - def testKDeleteUcsBlade(self): - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ - "9.8.7.6") - self.dbtest.delete_blade(blade1["blade-id"]) - blades = self.dbtest.get_all_blades() - count = 0 - for x in blades: - if "chassis " in x["chassis-id"]: - count += 1 - self.assertTrue(count == 0) - self.tearDownUcsBlade() - - def testLUpdateUcsBlade(self): - blade1 = self.dbtest.create_blade("1.2.3.4", "abcd", "chassis1", \ - "9.8.7.6") - blade2 = self.dbtest.update_blade(blade1["blade-id"], "2.3.4.5", \ - "newabcd", "chassis1", "9.8.7.6") - blades = self.dbtest.get_all_blades() - count = 0 - for x in blades: - if "new" in x["mac-addr"]: - count += 1 - self.assertTrue(count == 1) - self.tearDownUcsBlade() - - def testMCreatePortBinding(self): - port_bind1 = self.dbtest.create_port_binding("port1", "dv1", "pp1", \ - "vlan1", 10, "qos1") - self.assertTrue(port_bind1["port-id"] == "port1") - self.tearDownPortBinding() - - def testNGetAllPortBinding(self): - port_bind1 = self.dbtest.create_port_binding("port1", "dv1", "pp1", \ - "vlan1", 10, "qos1") - port_bind2 = self.dbtest.create_port_binding("port2", "dv2", "pp2", \ - "vlan2", 20, "qos2") - port_bindings = self.dbtest.get_all_port_bindings() - count = 0 - for x in port_bindings: - if "port" in x["port-id"]: - count += 1 - self.assertTrue(count == 2) - self.tearDownPortBinding() - - def testODeletePortBinding(self): - port_bind1 = self.dbtest.create_port_binding("port1", "dv1", "pp1", \ - "vlan1", 10, "qos1") - self.dbtest.delete_port_binding("port1") - port_bindings = self.dbtest.get_all_port_bindings() - count = 0 - for x in port_bindings: - if "port " in x["port-id"]: - count += 1 - self.assertTrue(count == 0) - self.tearDownPortBinding() - - def testPUpdatePortBinding(self): - port_bind1 = self.dbtest.create_port_binding("port1", "dv1", "pp1", \ - "vlan1", 10, "qos1") - port_bind1 = self.dbtest.update_port_binding("port1", "newdv1", \ - "newpp1", "newvlan1", 11, "newqos1") - port_bindings = self.dbtest.get_all_port_bindings() - count = 0 - for x in port_bindings: - if "new" in x["dynamic-vnic-id"]: - count += 1 - self.assertTrue(count == 1) - self.tearDownPortBinding() - - def tearDownUcsmBinding(self): - print "Tearing Down Ucsm Bindings" - binds = self.dbtest.get_all_ucsmbindings() - for bind in binds: - ip = bind["ucsm-ip"] - self.dbtest.delete_ucsmbinding(ip) - - def tearDownDyanmicVnic(self): - print "Tearing Down Dynamic Vnics" - vnics = self.dbtest.get_all_dynamicvnics() - for vnic in vnics: - id = vnic["vnic-id"] - self.dbtest.delete_dynamicvnic(id) - self.tearDownUcsBlade() - - def tearDownUcsBlade(self): - print "Tearing Down Blades" - blades = self.dbtest.get_all_blades() - for blade in blades: - id = blade["blade-id"] - self.dbtest.delete_blade(id) - - def tearDownPortBinding(self): - print "Tearing Down Port Binding" - port_bindings = self.dbtest.get_all_port_bindings() - for port_binding in port_bindings: - id = port_binding["port-id"] - self.dbtest.delete_port_binding(id) - - -class L2networkDBTest(unittest.TestCase): - def setUp(self): - self.dbtest = L2networkDB() - LOG.debug("Setup") - - def testACreateVlanBinding(self): - vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", "netid1") - self.assertTrue(vlan1["vlan-id"] == "10") - self.tearDownVlanBinding() - - def testBGetAllVlanBindings(self): - vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", "netid1") - vlan2 = self.dbtest.create_vlan_binding(20, "vlan2", "netid2") - vlans = self.dbtest.get_all_vlan_bindings() - count = 0 - for x in vlans: - if "netid" in x["net-id"]: - count += 1 - self.assertTrue(count == 2) - self.tearDownVlanBinding() - - def testCDeleteVlanBinding(self): - vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", "netid1") - self.dbtest.delete_vlan_binding("netid1") - vlans = self.dbtest.get_all_vlan_bindings() - count = 0 - for x in vlans: - if "netid " in x["net-id"]: - count += 1 - self.assertTrue(count == 0) - self.tearDownVlanBinding() - - def testDUpdateVlanBinding(self): - vlan1 = self.dbtest.create_vlan_binding(10, "vlan1", "netid1") - vlan1 = self.dbtest.update_vlan_binding("netid1", 11, "newvlan1") - vlans = self.dbtest.get_all_vlan_bindings() - count = 0 - for x in vlans: - if "new" in x["vlan-name"]: - count += 1 - self.assertTrue(count == 1) - self.tearDownVlanBinding() - - def testICreatePortProfile(self): - pp1 = self.dbtest.create_portprofile("portprofile1", 10, "qos1") - self.assertTrue(pp1["portprofile-name"] == "portprofile1") - self.tearDownPortProfile() - - def testJGetAllPortProfile(self): - pp1 = self.dbtest.create_portprofile("portprofile1", 10, "qos1") - pp2 = self.dbtest.create_portprofile("portprofile2", 20, "qos2") - pps = self.dbtest.get_all_portprofiles() - count = 0 - for x in pps: - if "portprofile" in x["portprofile-name"]: - count += 1 - self.assertTrue(count == 2) - self.tearDownPortProfile() - - def testKDeletePortProfile(self): - pp1 = self.dbtest.create_portprofile("portprofile1", 10, "qos1") - self.dbtest.delete_portprofile(pp1["portprofile-id"]) - pps = self.dbtest.get_all_portprofiles() - count = 0 - for x in pps: - if "portprofile " in x["portprofile-name"]: - count += 1 - self.assertTrue(count == 0) - self.tearDownPortProfile() - - def testLUpdatePortProfile(self): - pp1 = self.dbtest.create_portprofile("portprofile1", 10, "qos1") - pp1 = self.dbtest.update_portprofile(pp1["portprofile-id"], \ - "newportprofile1", 20, "qos2") - pps = self.dbtest.get_all_portprofiles() - count = 0 - for x in pps: - if "new" in x["portprofile-name"]: - count += 1 - self.assertTrue(count == 1) - self.tearDownPortProfile() - - def testMCreatePortProfileBinding(self): - pp_binding1 = self.dbtest.create_pp_binding("t1", "net1", \ - "portprofile1", "0") - self.assertTrue(pp_binding1["portprofile-id"] == "portprofile1") - self.tearDownPortProfileBinding() - - def testNGetAllPortProfileBinding(self): - pp_binding1 = self.dbtest.create_pp_binding("t1", "net1", \ - "portprofile1", "0") - pp_binding2 = self.dbtest.create_pp_binding("t2", "net2", \ - "portprofile2", "0") - pp_bindings = self.dbtest.get_all_pp_bindings() - count = 0 - for x in pp_bindings: - if "portprofile" in x["portprofile-id"]: - count += 1 - self.assertTrue(count == 2) - self.tearDownPortProfileBinding() - - def testODeletePortProfileBinding(self): - pp_binding1 = self.dbtest.create_pp_binding("t1", "net1", \ - "portprofile1", "0") - self.dbtest.delete_pp_binding(pp_binding1["portprofile-id"]) - pp_bindings = self.dbtest.get_all_pp_bindings() - count = 0 - for x in pp_bindings: - if "portprofile " in x["portprofile-id"]: - count += 1 - self.assertTrue(count == 0) - self.tearDownPortProfileBinding() - - def testPUpdatePortProfileBinding(self): - pp_binding1 = self.dbtest.create_pp_binding("t1", "net1", \ - "portprofile1", "0") - pp_binding1 = self.dbtest.update_pp_binding("portprofile1", \ - "newt1", "newnet1", "1") - pp_bindings = self.dbtest.get_all_pp_bindings() - count = 0 - for x in pp_bindings: - if "new" in x["net-id"]: - count += 1 - self.assertTrue(count == 1) - self.tearDownPortProfileBinding() - - def tearDownVlanBinding(self): - print "Tearing Down Vlan Binding" - vlans = self.dbtest.get_all_vlan_bindings() - for vlan in vlans: - id = vlan["net-id"] - self.dbtest.delete_vlan_binding(id) - - def tearDownPortProfile(self): - print "Tearing Down Port Profile" - pps = self.dbtest.get_all_portprofiles() - for pp in pps: - id = pp["portprofile-id"] - self.dbtest.delete_portprofile(id) - - def tearDownPortProfileBinding(self): - print "Tearing Down Port Profile Binding" - pp_bindings = self.dbtest.get_all_pp_bindings() - for pp_binding in pp_bindings: - id = pp_binding["portprofile-id"] - self.dbtest.delete_pp_binding(id) - -if __name__ == "__main__": - usagestr = "Usage: %prog [OPTIONS] [args]" - parser = OptionParser(usage=usagestr) - parser.add_option("-v", "--verbose", dest="verbose", - action="store_true", default=False, help="turn on verbose logging") - - options, args = parser.parse_args() - - if options.verbose: - LOG.basicConfig(level=LOG.DEBUG) - else: - LOG.basicConfig(level=LOG.WARN) - - #load the models and db based on the 2nd level plugin argument - if args[0] == "ucs": - ucs_db = __import__("quantum.plugins.cisco.db.ucs_db", \ - fromlist=["ucs_db"]) - ucs_model = __import__("quantum.plugins.cisco.db.ucs_models", \ - fromlist=["ucs_models"]) - - db_conf() - - # Run the tests - suite = unittest.TestLoader().loadTestsFromTestCase(L2networkDBTest) - unittest.TextTestRunner(verbosity=2).run(suite) - suite = unittest.TestLoader().loadTestsFromTestCase(UcsDBTest) - unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/quantum/plugins/cisco/db/l2network_db.py b/quantum/plugins/cisco/db/l2network_db.py deleted file mode 100644 index 15861eee30..0000000000 --- a/quantum/plugins/cisco/db/l2network_db.py +++ /dev/null @@ -1,239 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011, Cisco Systems, Inc. -# -# 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. -# @author: Rohit Agarwalla, Cisco Systems, Inc. - -from sqlalchemy.orm import exc - -import l2network_models -import quantum.db.api as db -import quantum.db.models as models - - -def get_all_vlan_bindings(): - """Lists all the vlan to network associations""" - session = db.get_session() - try: - bindings = session.query(l2network_models.VlanBinding).\ - all() - return bindings - except exc.NoResultFound: - return [] - - -def get_vlan_binding(netid): - """Lists the vlan given a network_id""" - session = db.get_session() - try: - binding = session.query(l2network_models.VlanBinding).\ - filter_by(network_id=netid).\ - one() - return binding - except exc.NoResultFound: - raise Exception("No network found with net-id = %s" % network_id) - - -def add_vlan_binding(vlanid, vlanname, netid): - """Adds a vlan to network association""" - session = db.get_session() - try: - binding = session.query(l2network_models.VlanBinding).\ - filter_by(vlan_id=vlanid).\ - one() - raise Exception("Vlan with id \"%s\" already exists" % vlanid) - except exc.NoResultFound: - binding = l2network_models.VlanBinding(vlanid, vlanname, netid) - session.add(binding) - session.flush() - return binding - - -def remove_vlan_binding(netid): - """Removes a vlan to network association""" - session = db.get_session() - try: - binding = session.query(l2network_models.VlanBinding).\ - filter_by(network_id=netid).\ - one() - session.delete(binding) - session.flush() - return binding - except exc.NoResultFound: - pass - - -def update_vlan_binding(netid, newvlanid=None, newvlanname=None): - """Updates a vlan to network association""" - session = db.get_session() - try: - binding = session.query(l2network_models.VlanBinding).\ - filter_by(network_id=netid).\ - one() - if newvlanid: - binding.vlan_id = newvlanid - if newvlanname: - binding.vlan_name = newvlanname - session.merge(binding) - session.flush() - return binding - except exc.NoResultFound: - raise Exception("No vlan binding found with network_id = %s" % netid) - - -def get_all_portprofiles(): - """Lists all the port profiles""" - session = db.get_session() - try: - pps = session.query(l2network_models.PortProfile).\ - all() - return pps - except exc.NoResultFound: - return [] - - -def get_portprofile(ppid): - """Lists a port profile""" - session = db.get_session() - try: - pp = session.query(l2network_models.PortProfile).\ - filter_by(uuid=ppid).\ - one() - return pp - except exc.NoResultFound: - raise Exception("No portprofile found with id = %s" % ppid) - - -def add_portprofile(ppname, vlanid, qos): - """Adds a port profile""" - session = db.get_session() - try: - pp = session.query(l2network_models.PortProfile).\ - filter_by(name=ppname).\ - one() - raise Exception("Port profile with name %s already exists" % ppname) - except exc.NoResultFound: - pp = l2network_models.PortProfile(ppname, vlanid, qos) - session.add(pp) - session.flush() - return pp - - -def remove_portprofile(ppid): - """Removes a port profile""" - session = db.get_session() - try: - pp = session.query(l2network_models.PortProfile).\ - filter_by(uuid=ppid).\ - one() - session.delete(pp) - session.flush() - return pp - except exc.NoResultFound: - pass - - -def update_portprofile(ppid, newppname=None, newvlanid=None, newqos=None): - """Updates port profile""" - session = db.get_session() - try: - pp = session.query(l2network_models.PortProfile).\ - filter_by(uuid=ppid).\ - one() - if newppname: - pp.name = newppname - if newvlanid: - pp.vlan_id = newvlanid - if newqos: - pp.qos = newqos - session.merge(pp) - session.flush() - return pp - except exc.NoResultFound: - raise Exception("No port profile with id = %s" % ppid) - - -def get_all_pp_bindings(): - """Lists all the port profiles""" - session = db.get_session() - try: - bindings = session.query(l2network_models.PortProfileBinding).\ - all() - return bindings - except exc.NoResultFound: - return [] - - -def get_pp_binding(ppid): - """Lists a port profile binding""" - session = db.get_session() - try: - binding = session.query(l2network_models.PortProfileBinding).\ - filter_by(portprofile_id=ppid).\ - one() - return binding - except exc.NoResultFound: - raise Exception("No portprofile binding found with id = %s" % ppid) - - -def add_pp_binding(tenantid, networkid, ppid, default): - """Adds a port profile binding""" - session = db.get_session() - try: - binding = session.query(l2network_models.PortProfileBinding).\ - filter_by(portprofile_id=ppid).\ - one() - raise Exception("Port profile binding with id \"%s\" already \ - exists" % ppid) - except exc.NoResultFound: - binding = l2network_models.PortProfileBinding(tenantid, networkid, \ - ppid, default) - session.add(binding) - session.flush() - return binding - - -def remove_pp_binding(ppid): - """Removes a port profile binding""" - session = db.get_session() - try: - binding = session.query(l2network_models.PortProfileBinding).\ - filter_by(portprofile_id=ppid).\ - one() - session.delete(binding) - session.flush() - return binding - except exc.NoResultFound: - pass - - -def update_pp_binding(ppid, newtenantid=None, newnetworkid=None, \ - newdefault=None): - """Updates port profile binding""" - session = db.get_session() - try: - binding = session.query(l2network_models.PortProfileBinding).\ - filter_by(portprofile_id=ppid).\ - one() - if newtenantid: - binding.tenant_id = newtenantid - if newnetworkid: - binding.network_id = newnetworkid - if newdefault: - binding.default = newdefault - session.merge(binding) - session.flush() - return binding - except exc.NoResultFound: - raise Exception("No port profile binding with id = %s" % ppid) diff --git a/quantum/plugins/cisco/db/l2network_models.py b/quantum/plugins/cisco/db/l2network_models.py deleted file mode 100644 index 12d75bb303..0000000000 --- a/quantum/plugins/cisco/db/l2network_models.py +++ /dev/null @@ -1,86 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011, Cisco Systems, Inc. -# -# 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. -# @author: Rohit Agarwalla, Cisco Systems, Inc. - -import uuid - -from sqlalchemy import Column, Integer, String, ForeignKey, Boolean -from sqlalchemy.orm import relation - -from quantum.db.models import BASE - - -class VlanBinding(BASE): - """Represents a binding of vlan_id to network_id""" - __tablename__ = 'vlan_bindings' - - vlan_id = Column(Integer, primary_key=True) - vlan_name = Column(String(255)) - network_id = Column(String(255), nullable=False) - #foreign key to networks.uuid - - def __init__(self, vlan_id, vlan_name, network_id): - self.vlan_id = vlan_id - self.vlan_name = vlan_name - self.network_id = network_id - - def __repr__(self): - return "" % \ - (self.vlan_id, self.vlan_name, self.network_id) - - -class PortProfile(BASE): - """Represents Cisco plugin level PortProfile for a network""" - __tablename__ = 'portprofiles' - - uuid = Column(String(255), primary_key=True) - name = Column(String(255)) - vlan_id = Column(Integer) - qos = Column(String(255)) - - def __init__(self, name, vlan_id, qos=None): - self.uuid = uuid.uuid4() - self.name = name - self.vlan_id = vlan_id - self.qos = qos - - def __repr__(self): - return "" % \ - (self.uuid, self.name, self.vlan_id, self.qos) - - -class PortProfileBinding(BASE): - """Represents PortProfile binding to tenant and network""" - __tablename__ = 'portprofile_bindings' - - id = Column(Integer, primary_key=True, autoincrement=True) - tenant_id = Column(String(255)) - - network_id = Column(String(255), nullable=False) - #foreign key to networks.uuid - portprofile_id = Column(String(255), nullable=False) - #foreign key to portprofiles.uuid - default = Column(Boolean) - - def __init__(self, tenant_id, network_id, portprofile_id, default): - self.tenant_id = tenant_id - self.network_id = network_id - self.portprofile_id = portprofile_id - self.default = default - - def __repr__(self): - return "" % \ - (self.tenant_id, self.network_id, self.portprofile_id, self.default) diff --git a/quantum/plugins/cisco/db/ucs_db.py b/quantum/plugins/cisco/db/ucs_db.py deleted file mode 100644 index 92198e89bb..0000000000 --- a/quantum/plugins/cisco/db/ucs_db.py +++ /dev/null @@ -1,314 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011, Cisco Systems, Inc. -# -# 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. -# @author: Rohit Agarwalla, Cisco Systems, Inc. - -from sqlalchemy.orm import exc - -import quantum.db.api as db -import ucs_models - - -def get_all_ucsmbinding(): - """Lists all the ucsm bindings""" - session = db.get_session() - try: - bindings = session.query(ucs_models.UcsmBinding).\ - all() - return bindings - except exc.NoResultFound: - return [] - - -def get_ucsmbinding(ucsm_ip): - """Lists a ucsm binding""" - session = db.get_session() - try: - binding = session.query(ucs_models.UcsmBinding).\ - filter_by(ucsm_ip=ucsm_ip).\ - one() - return binding - except exc.NoResultFound: - raise Exception("No binding found with ip = %s" % ucsm_ip) - - -def add_ucsmbinding(ucsm_ip, network_id): - """Adds a ucsm binding""" - session = db.get_session() - try: - ip = session.query(ucs_models.UcsmBinding).\ - filter_by(ucsm_ip=ucsm_ip).\ - one() - raise Exception("Binding with ucsm ip \"%s\" already exists" % ucsm_ip) - except exc.NoResultFound: - binding = ucs_models.UcsmBinding(ucsm_ip, network_id) - session.add(binding) - session.flush() - return binding - - -def remove_ucsmbinding(ucsm_ip): - """Removes a ucsm binding""" - session = db.get_session() - try: - binding = session.query(ucs_models.UcsmBinding).\ - filter_by(ucsm_ip=ucsm_ip).\ - one() - session.delete(binding) - session.flush() - return binding - except exc.NoResultFound: - pass - - -def update_ucsmbinding(ucsm_ip, new_network_id): - """Updates ucsm binding""" - session = db.get_session() - try: - binding = session.query(ucs_models.UcsmBinding).\ - filter_by(ucsm_ip=ucsm_ip).\ - one() - if new_network_id: - binding.network_id = new_network_id - session.merge(binding) - session.flush() - return binding - except exc.NoResultFound: - raise Exception("No binding with ip = %s" % ucsm_ip) - - -def get_all_dynamicvnics(): - """Lists all the dynamic vnics""" - session = db.get_session() - try: - vnics = session.query(ucs_models.DynamicVnic).\ - all() - return vnics - except exc.NoResultFound: - return [] - - -def get_dynamicvnic(vnic_id): - """Lists a dynamic vnic""" - session = db.get_session() - try: - vnic = session.query(ucs_models.DynamicVnic).\ - filter_by(uuid=vnic_id).\ - one() - return vnic - except exc.NoResultFound: - raise Exception("No dynamic vnic found with id = %s" % vnic_id) - - -def add_dynamicvnic(device_name, blade_id): - """Adds a dynamic vnic""" - session = db.get_session() - try: - name = session.query(ucs_models.DynamicVnic).\ - filter_by(device_name=device_name).\ - one() - raise Exception("Dynamic vnic with device name %s already exists" % \ - device_name) - except exc.NoResultFound: - vnic = ucs_models.DynamicVnic(device_name, blade_id) - session.add(vnic) - session.flush() - return vnic - - -def remove_dynamicvnic(vnic_id): - """Removes a dynamic vnic""" - session = db.get_session() - try: - vnic = session.query(ucs_models.DynamicVnic).\ - filter_by(uuid=vnic_id).\ - one() - session.delete(vnic) - session.flush() - return vnic - except exc.NoResultFound: - pass - - -def update_dynamicvnic(vnic_id, new_device_name=None, new_blade_id=None): - """Updates dynamic vnic""" - session = db.get_session() - try: - vnic = session.query(ucs_models.DynamicVnic).\ - filter_by(uuid=vnic_id).\ - one() - if new_device_name: - vnic.device_name = new_device_name - if new_blade_id: - vnic.blade_id = new_blade_id - session.merge(vnic) - session.flush() - return vnic - except exc.NoResultFound: - raise Exception("No dynamic vnic with id = %s" % vnic_id) - - -def get_all_blades(): - """Lists all the blades details""" - session = db.get_session() - try: - blades = session.query(ucs_models.UcsBlade).\ - all() - return blades - except exc.NoResultFound: - return [] - - -def get_blade(blade_id): - """Lists a blade details""" - session = db.get_session() - try: - blade = session.query(ucs_models.UcsBlade).\ - filter_by(uuid=blade_id).\ - one() - return blade - except exc.NoResultFound: - raise Exception("No blade found with id = %s" % blade_id) - - -def add_blade(mgmt_ip, mac_addr, chassis_id, ucsm_ip): - """Adds a blade""" - session = db.get_session() - try: - ip = session.query(ucs_models.UcsBlade).\ - filter_by(mgmt_ip=mgmt_ip).\ - one() - raise Exception("Blade with ip \"%s\" already exists" % mgmt_ip) - except exc.NoResultFound: - blade = ucs_models.UcsBlade(mgmt_ip, mac_addr, chassis_id, ucsm_ip) - session.add(blade) - session.flush() - return blade - - -def remove_blade(blade_id): - """Removes a blade""" - session = db.get_session() - try: - blade = session.query(ucs_models.UcsBlade).\ - filter_by(uuid=blade_id).\ - one() - session.delete(blade) - session.flush() - return blade - except exc.NoResultFound: - pass - - -def update_blade(blade_id, new_mgmt_ip=None, new_mac_addr=None, \ - new_chassis_id=None, new_ucsm_ip=None): - """Updates details of a blade""" - session = db.get_session() - try: - blade = session.query(ucs_models.UcsBlade).\ - filter_by(uuid=blade_id).\ - one() - if new_mgmt_ip: - blade.mgmt_ip = new_mgmt_ip - if new_mac_addr: - blade.mac_addr = new_mac_addr - if new_chassis_id: - blade.chassis_id = new_chassis_id - if new_ucsm_ip: - blade.ucsm_ip = new_ucsm_ip - session.merge(blade) - session.flush() - return blade - except exc.NoResultFound: - raise Exception("No blade with id = %s" % blade_id) - - -def get_all_portbindings(): - """Lists all the port bindings""" - session = db.get_session() - try: - port_bindings = session.query(ucs_models.PortBinding).\ - all() - return port_bindings - except exc.NoResultFound: - return [] - - -def get_portbinding(port_id): - """Lists a port binding""" - session = db.get_session() - try: - port_binding = session.query(ucs_models.PortBinding).\ - filter_by(port_id=port_id).\ - one() - return port_binding - except exc.NoResultFound: - raise Exception("No port binding found with port id = %s" % port_id) - - -def add_portbinding(port_id, dynamic_vnic_id, portprofile_name, \ - vlan_name, vlan_id, qos): - """Adds a port binding""" - session = db.get_session() - try: - port_binding = session.query(ucs_models.PortBinding).\ - filter_by(port_id=port_id).\ - one() - raise Exception("Port Binding with portid %s already exists" % port_id) - except exc.NoResultFound: - port_binding = ucs_models.PortBinding(port_id, dynamic_vnic_id, \ - portprofile_name, vlan_name, vlan_id, qos) - session.add(port_binding) - session.flush() - return port_binding - - -def remove_portbinding(port_id): - """Removes a port binding""" - session = db.get_session() - try: - port_binding = session.query(ucs_models.PortBinding).\ - filter_by(port_id=port_id).\ - one() - session.delete(port_binding) - session.flush() - return port_binding - except exc.NoResultFound: - pass - - -def update_portbinding(port_id, dynamic_vnic_id=None, portprofile_name=None, \ - vlan_name=None, vlan_id=None, qos=None): - """Updates port binding""" - session = db.get_session() - try: - port_binding = session.query(ucs_models.PortBinding).\ - filter_by(port_id=port_id).\ - one() - if dynamic_vnic_id: - port_binding.dynamic_vnic_id = dynamic_vnic_id - if portprofile_name: - port_binding.portprofile_name = portprofile_name - if vlan_name: - port_binding.vlan_name = vlan_name - if vlan_name: - port_binding.vlan_id = vlan_id - if qos: - port_binding.qos = qos - session.merge(port_binding) - session.flush() - return port_binding - except exc.NoResultFound: - raise Exception("No port binding with port id = %s" % port_id) diff --git a/quantum/plugins/cisco/db/ucs_models.py b/quantum/plugins/cisco/db/ucs_models.py deleted file mode 100644 index 68cd3dddea..0000000000 --- a/quantum/plugins/cisco/db/ucs_models.py +++ /dev/null @@ -1,113 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011, Cisco Systems, Inc. -# -# 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. -# @author: Rohit Agarwalla, Cisco Systems, Inc. - -import uuid - -from sqlalchemy import Column, Integer, String, ForeignKey, Boolean -from sqlalchemy.orm import relation - -from quantum.db.models import BASE - - -class UcsmBinding(BASE): - """Represents a binding of ucsm to network_id""" - __tablename__ = 'ucsm_bindings' - - id = Column(Integer, primary_key=True, autoincrement=True) - ucsm_ip = Column(String(255)) - network_id = Column(String(255), nullable=False) - #foreign key to networks.uuid - - def __init__(self, ucsm_ip, network_id): - self.ucsm_ip = ucsm_ip - self.network_id = network_id - - def __repr__(self): - return "" % \ - (self.ucsm_ip, self.network_id) - - -class DynamicVnic(BASE): - """Represents Cisco UCS Dynamic Vnics""" - __tablename__ = 'dynamic_vnics' - - uuid = Column(String(255), primary_key=True) - device_name = Column(String(255)) - blade_id = Column(String(255), ForeignKey("ucs_blades.uuid"), \ - nullable=False) - - def __init__(self, device_name, blade_id): - self.uuid = uuid.uuid4() - self.device_name = device_name - self.blade_id = blade_id - - def __repr__(self): - return "" % \ - (self.uuid, self.device_name, self.blade_id) - - -class UcsBlade(BASE): - """Represents details of ucs blades""" - __tablename__ = 'ucs_blades' - - uuid = Column(String(255), primary_key=True) - mgmt_ip = Column(String(255)) - mac_addr = Column(String(255)) - chassis_id = Column(String(255)) - ucsm_ip = Column(String(255)) - dynamic_vnics = relation(DynamicVnic, order_by=DynamicVnic.uuid, \ - backref="blade") - - def __init__(self, mgmt_ip, mac_addr, chassis_id, ucsm_ip): - self.uuid = uuid.uuid4() - self.mgmt_ip = mgmt_ip - self.mac_addr = mac_addr - self.chassis_id = chassis_id - self.ucsm_ip = ucsm_ip - - def __repr__(self): - return "" % \ - (self.uuid, self.mgmt_ip, self.mac_addr, self.chassis_id, self.ucsm_ip) - - -class PortBinding(BASE): - """Represents Port binding to device interface""" - __tablename__ = 'port_bindings' - - id = Column(Integer, primary_key=True, autoincrement=True) - port_id = Column(String(255), nullable=False) - #foreign key to ports.uuid - dynamic_vnic_id = Column(String(255), nullable=False) - #foreign key to dynamic_vnics.uuid - portprofile_name = Column(String(255)) - vlan_name = Column(String(255)) - vlan_id = Column(Integer) - qos = Column(String(255)) - - def __init__(self, port_id, dynamic_vnic_id, portprofile_name, vlan_name, \ - vlan_id, qos): - self.port_id = port_id - self.dynamic_vnic_id = dynamic_vnic_id - self.portprofile_name = portprofile_name - self.vlan_name = vlan_name - self.vlan_id = vlan_id - self.qos = qos - - def __repr__(self): - return "" % \ - (self.port_id, self.dynamic_vnic_id, self.portprofile_name, \ - self.vlan_name, self.vlan_id, self.qos) From fdf92daaa4d96ec12c4bc87b19dbf57f626b501f Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Thu, 4 Aug 2011 12:02:43 -0700 Subject: [PATCH 25/48] Removing extra file in Nexus Driver --- quantum/plugins/cisco/nexus/nxosapi.py | 172 ------------------------- 1 file changed, 172 deletions(-) delete mode 100644 quantum/plugins/cisco/nexus/nxosapi.py diff --git a/quantum/plugins/cisco/nexus/nxosapi.py b/quantum/plugins/cisco/nexus/nxosapi.py deleted file mode 100644 index 0f0ebe04f0..0000000000 --- a/quantum/plugins/cisco/nexus/nxosapi.py +++ /dev/null @@ -1,172 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2011 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. -# @author: Debojyoti Dutta, Cisco Systems, Inc. - -import sys -import os -import warnings -warnings.simplefilter("ignore", DeprecationWarning) -from ncclient import manager -from ncclient import NCClientError -from ncclient.transport.errors import * - -exec_conf_prefix = """ - - - <__XML__MODE__exec_configure> -""" - - -exec_conf_postfix = """ - - - -""" - - -cmd_vlan_conf_snippet = """ - - - <__XML__PARAM_value>%s - <__XML__MODE_vlan> - - %s - - - active - - - - - - - -""" - -cmd_no_vlan_conf_snippet = """ - - - - <__XML__PARAM_value>%s - - - -""" - -cmd_vlan_int_snippet = """ - - - %s - <__XML__MODE_if-ethernet-switch> - - - - - - <__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans> - %s - - - - - - - - -""" - - -cmd_no_vlan_int_snippet = """ - - - %s - <__XML__MODE_if-ethernet-switch> - - - - - - - <__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans> - %s - - - - - - - - - -""" - - -filter_show_vlan_brief_snippet = """ - - - - - """ - - -def nxos_connect(host, port, user, password): - try: - m = manager.connect(host=host, port=port, username=user, - password=password) - return m - except SSHUnknownHostError: - sys.stderr.write('SSH unknown host error\n') - exit() - - -def enable_vlan(mgr, vlanid, vlanname): - confstr = cmd_vlan_conf_snippet % (vlanid, vlanname) - confstr = exec_conf_prefix + confstr + exec_conf_postfix - mgr.edit_config(target='running', config=confstr) - - -def disable_vlan(mgr, vlanid): - confstr = cmd_no_vlan_conf_snippet % vlanid - confstr = exec_conf_prefix + confstr + exec_conf_postfix - mgr.edit_config(target='running', config=confstr) - - -def enable_vlan_on_trunk_int(mgr, interface, vlanid): - confstr = cmd_vlan_int_snippet % (interface, vlanid) - confstr = exec_conf_prefix + confstr + exec_conf_postfix - print confstr - mgr.edit_config(target='running', config=confstr) - - -def disable_vlan_on_trunk_int(mgr, interface, vlanid): - confstr = cmd_no_vlan_int_snippet % (interface, vlanid) - confstr = exec_conf_prefix + confstr + exec_conf_postfix - print confstr - mgr.edit_config(target='running', config=confstr) - - -def test_nxos_api(host, user, password): - with nxos_connect(host, port=22, user=user, password=password) as m: - enable_vlan(m, '100', 'ccn1') - enable_vlan_on_trunk_int(m, '2/1', '100') - disable_vlan_on_trunk_int(m, '2/1', '100') - disable_vlan(m, '100') - result = m.get(("subtree", filter_show_vlan_brief_snippet)) - #print result - - -if __name__ == '__main__': - test_nxos_api(sys.argv[1], sys.argv[2], sys.argv[3]) From 3c461229f83fc03064c074939b91f38b012fc528 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 5 Aug 2011 02:59:54 -0700 Subject: [PATCH 26/48] Loading of device-specific plugins and drivers is done dynamically by setting configuration. All configuration is driven through configuration files place in the conf directory. Each .ini conf file contains info on the configuration. README file updated to reflect all the changes. Fixed issue with delete_network deleting the network even when attachments were present. Fixed issue with port id generation. --- etc/quantum.conf | 5 - quantum/plugins/cisco/README | 78 +++------------ .../cisco/common/cisco_configparser.py | 49 ++++++++++ .../cisco/common/cisco_configuration.py | 97 ------------------- .../plugins/cisco/common/cisco_constants.py | 51 ++++++++++ .../plugins/cisco/common/cisco_credentials.py | 55 +++++------ .../cisco/common/cisco_nova_configuration.py | 42 ++++++++ quantum/plugins/cisco/common/cisco_utils.py | 6 +- quantum/plugins/cisco/conf/credentials.ini | 15 +++ .../plugins/cisco/conf/l2network_plugin.ini | 11 +++ quantum/plugins/cisco/conf/nexus.ini | 8 ++ quantum/plugins/cisco/conf/nova.ini | 8 ++ quantum/plugins/cisco/conf/plugins.ini | 4 + quantum/plugins/cisco/conf/ucs.ini | 10 ++ quantum/plugins/cisco/l2network_plugin.py | 82 ++++++++-------- .../cisco/l2network_plugin_configuration.py | 51 ++++++++++ .../cisco/nexus/cisco_nexus_configuration.py | 42 ++++++++ .../cisco/nexus/cisco_nexus_network_driver.py | 1 - .../plugins/cisco/nexus/cisco_nexus_plugin.py | 8 +- .../cisco/ucs/{get-vif.py => cisco_getvif.py} | 23 ++++- .../cisco/ucs/cisco_ucs_configuration.py | 44 +++++++++ .../cisco/ucs/cisco_ucs_network_driver.py | 19 ++-- quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 7 +- quantum/plugins/cisco/ucs/get-vif.sh | 15 --- 24 files changed, 452 insertions(+), 279 deletions(-) create mode 100644 quantum/plugins/cisco/common/cisco_configparser.py delete mode 100644 quantum/plugins/cisco/common/cisco_configuration.py create mode 100644 quantum/plugins/cisco/common/cisco_nova_configuration.py create mode 100644 quantum/plugins/cisco/conf/credentials.ini create mode 100644 quantum/plugins/cisco/conf/l2network_plugin.ini create mode 100644 quantum/plugins/cisco/conf/nexus.ini create mode 100644 quantum/plugins/cisco/conf/nova.ini create mode 100644 quantum/plugins/cisco/conf/plugins.ini create mode 100644 quantum/plugins/cisco/conf/ucs.ini create mode 100644 quantum/plugins/cisco/l2network_plugin_configuration.py create mode 100644 quantum/plugins/cisco/nexus/cisco_nexus_configuration.py rename quantum/plugins/cisco/ucs/{get-vif.py => cisco_getvif.py} (60%) create mode 100644 quantum/plugins/cisco/ucs/cisco_ucs_configuration.py delete mode 100755 quantum/plugins/cisco/ucs/get-vif.sh diff --git a/etc/quantum.conf b/etc/quantum.conf index 6bd962790c..2580913c32 100644 --- a/etc/quantum.conf +++ b/etc/quantum.conf @@ -15,14 +15,9 @@ bind_port = 9696 use = egg:Paste#urlmap /: quantumversions /v0.1: quantumapi -/v0.1/extensions:cisco_extensions [app:quantumversions] paste.app_factory = quantum.api.versions:Versions.factory [app:quantumapi] paste.app_factory = quantum.api:APIRouterV01.factory - -[app:cisco_extensions] -paste.app_factory = cisco_extensions:ExtRouterV01.factory - diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index b77ce22ca8..f8711193ab 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -7,9 +7,13 @@ * UCS B200 series blades with M81KR VIC installed. * UCSM 2.0 (Capitola) Build 230 * RHEL 6.1 -* ncclcient v0.3.1 - Python library for NETCONF clients (http://schmizz.net/ncclient/) * UCS & VIC installation (support for KVM) - please consult the accompanying installation guide available at: http://wikicentral.cisco.com/display/GROUP/SAVBU+Palo+VM-FEX+for+Linux+KVM + +* If you have a Nexus switch in your topology and decide to turn on Nexus support, you will need: + - ncclcient v0.3.1 - Python library for NETCONF clients (http://schmizz.net/ncclient/). + - paramiko library (do: yum install python-paramiko.noarch) + * To run Quantum on RHEL, you will need to have the correct version of python-routes (version 1.12.3 or later). The RHEL 6.1 package contains an older version. Do the following and check your python-routes version: rpm -qav | grep "python-routes" @@ -26,64 +30,12 @@ gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OPENSTACK ** Plugin Installation Instructions: * Make a backup copy of quantum/quantum/plugins.ini, and edit the file to remove all exisiting entries and add the following entry: provider = quantum.plugins.cisco.l2network_plugin.L2Network -* You should have the following files in quantum/quantum/plugins/cisco directory (if you have pulled the Cisco Quantum branch, you will already have them): -l2network_plugin.py -common/cisco_configuration.py -common/cisco_constants.py -common/cisco_credentials.py -common/cisco_exceptions.py -nexus/cisco_nexus_plugin.py -ucs/cisco_ucs_network_driver.py -ucs/cisco_ucs_plugin.py -common/cisco_utils.py -__init__.py -ucs/get-vif.sh -* Configure the L2 Network Plugin: - + In cisco_configuration.py, - - change the UCSM IP in the following statement to your UCSM IP - flags.DEFINE_string('ucsm_ip_address', "172.20.231.27", 'IP address of UCSM') - - change the Nova MySQL DB IP if you are running Quantum on a different host than the OpenStack Cloud Controller (in other words you do not need to change the IP if Quantum is running on the same host on which the Nova DB is running). DB IP is changed in the following statement: - flags.DEFINE_string('db_server_ip', "127.0.0.1", 'IP address of nova DB server') - - change the hostname of the OpenStack Cloud Controller below - flags.DEFINE_string('nova_host_name', "openstack-0203", 'nova cloud controller hostname') - - change the name of the OpenStack project - flags.DEFINE_string('nova_proj_name', "demo", 'project created in nova') - - change the start range of the VLAN (if you are not sure about this number, leave this unchanged) - flags.DEFINE_string('vlan_start', "100", 'This is the start value of the allowable VLANs') - - change the end range of the VLAN (if you are not sure about this number, leave this unchanged) - flags.DEFINE_string('vlan_end', "3000", 'This is the end value of the allowable VLANs') - - unless you have VLANs created in UCSM which start with the name "q-", you do not need to change the following property. If you do need to change it, change "q-" to some other string. Do not use more than 6 characters. - flags.DEFINE_string('vlan_name_prefix', "q-", 'Prefix of the name given to the VLAN') - - unless you have Port Profiles created in UCSM which start with the name "q-", you do not need to change the following property. If you do need to change it, change "q-" to some other string. Do not use more than 6 characters. - flags.DEFINE_string('profile_name_prefix', "q-", 'Prefix of the name given to the port profile') - - Change the path to reflect the location of the get-vif.sh script, if you have followed the instructions in this README, this location should be the same as that of your other plugin modules - flags.DEFINE_string('get_next_vif', "/root/sumit/quantum/quantum/plugins/cisco/get-vif.sh", 'This is the location of the script to get the next available dynamic nic') - - + In cisco_credentials.py, - - Change the following structure to reflect the correct UCS, N7K and Nova DB details. Your UCSM_IP_ADDRESS has to match the ucsmm_ip_addresss which you provided in the cisco_configuration file earlier. Similarly, your NOVA_DATABSE_IP has to match the db_server_ip which you provided earlier. DB_USERNAME and DB_PASSWORD are those which you provided for the Nova MySQL DB when you setup OpenStack - N7K_IP_ADDRESS has to match with your Nexus 7k switch IP Address, N7K_USERNAME is the administrator user-name and N7K_PASSWORD is the password. - _creds_dictionary = { - 'UCSM_IP_ADDRESS':["UCSM_USERNAME", "UCSM_PASSWORD"], - 'NOVA_DATABASE_IP':["DB_USERNAME", "DB_PASSWORD"] - } - -* Configure the L2 Network Plugin with Nexus OS Driver for testing VLANs CRUD on Nexus 7k Switch. Making these changes requires one Nexus 7K Switch connected to the UCSM and the ncclient patch not just the regular library, otherwise the system will fail. - + In cisco_configuration.py, - - change the NEXUS 7K IP in the following statement to your N7K Switch IP - flags.DEFINE_string('nexus_ip_address', "172.20.231.61", 'IP address of N7K') - - change the NEXUS Interface in the following statement to the interface number in your N7K which is connected to your UCSM UpLink port - flags.DEFINE_string('nexus_port', "3/23", 'Port number of the Interface connected from the Nexus 7K Switch to UCSM 6120') - - change NEXUS Driver Flag to "on" in the following statement - flags.DEFINE_string('nexus_driver_active', "off", 'Flag to activate Nexus OS Driver') - - + In cisco_credentials.py, - - Change the following structure to reflect the correct UCS, N7K and Nova DB details. Your UCSM_IP_ADDRESS has to match the ucsmm_ip_addresss which you provided in the cisco_configuration file earlier. Similarly, your NOVA_DATABSE_IP has to match the db_server_ip which you provided earlier. DB_USERNAME and DB_PASSWORD are those which you provided for the Nova MySQL DB when you setup OpenStack - N7K_IP_ADDRESS has to match with your Nexus 7k switch IP Address, N7K_USERNAME is the administrator user-name and N7K_PASSWORD is the password. - _creds_dictionary = { - 'UCSM_IP_ADDRESS':["UCSM_USERNAME", "UCSM_PASSWORD"], - 'N7K_IP_ADDRESS':["N7K_USERNAME", "N7K_PASSWORD"], - 'NOVA_DATABASE_IP':["DB_USERNAME", "DB_PASSWORD"] - } + +* All configuration files are located under quantum/plugins/cisco/conf. Where you find kind of placeholder, please replace it entirely with the relevant values (don't forget to remove the angle brackets as well) + +* If you are not running Quantum on the same host as the OpenStack Cloud Controller, you will need to change the db_ip_address configuration in nova.ini + +* If you want to turn on Nexus support, please uncomment the nexus_plugin property in the nexus.ini file. You will also require a patch to the ncclient in addition to the library mentioned in the prerequisities. * Start the Quantum service @@ -98,11 +50,3 @@ mysql -uroot -p nova -e 'create table ports (port_id VARCHA /usr/lib/python2.6/site-packages/nova/virt/cisco_ucs.py * Restart nova-compute service - -**L2network database usage requirements - -* mysql database "quantum_l2network" is required for persistence of the l2network plugin data. - + The database can be created as follows - - - # mysql -uroot -pnova; (username/password here is root/nova) - - mysql> create database quantum_l2network; - - mysql> use quantum_l2network; - + The database and login details must be specified in quantum/plugins/cisco/db/db_conn.ini. diff --git a/quantum/plugins/cisco/common/cisco_configparser.py b/quantum/plugins/cisco/common/cisco_configparser.py new file mode 100644 index 0000000000..312c230acb --- /dev/null +++ b/quantum/plugins/cisco/common/cisco_configparser.py @@ -0,0 +1,49 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import logging as LOG +import os + +from configobj import ConfigObj +from validate import Validator + +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.common import cisco_exceptions as cexc + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + + +class CiscoConfigParser(ConfigObj): + + def __init__(self, filename): + super(CiscoConfigParser, self).__init__(filename, raise_errors=True, + file_error=True) + + def dummy(self, section, key): + return section[key] + + +def main(): + cp = CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ + + "/" + "test.ini") + print ("%s\n") % cp['PLUGIN']['provider'] + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/common/cisco_configuration.py b/quantum/plugins/cisco/common/cisco_configuration.py deleted file mode 100644 index 01762e5fa8..0000000000 --- a/quantum/plugins/cisco/common/cisco_configuration.py +++ /dev/null @@ -1,97 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 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. -# -# @author: Sumit Naiksatam, Cisco Systems, Inc. -# @author: Edgar Magana, Cisco Systems, Inc. -# -from quantum.common import flags - -# Note: All configuration values defined here are strings -FLAGS = flags.FLAGS -# -# TODO (Sumit): The following are defaults, but we also need to add to config -# file -# -flags.DEFINE_string('ucsm_ip_address', "172.20.231.27", 'IP address of \ - UCSM') -flags.DEFINE_string('nexus_ip_address', "172.20.231.61", 'IP address of \ - Nexus Switch') -flags.DEFINE_string('nexus_port', "3/23", 'Port number of the Interface \ - connected from the Nexus Switch to UCSM 6120') -flags.DEFINE_string('nexus_driver_active', "off", 'Flag to activate Nexus OS\ - Driver') -flags.DEFINE_string('db_server_ip', "127.0.0.1", 'IP address of nova DB \ - server') -flags.DEFINE_string('nova_host_name', "openstack-0203", 'nova cloud \ - controller hostname') - -flags.DEFINE_string('db_name', "nova", 'DB name') -flags.DEFINE_string('vlan_name_prefix', "q-", 'Prefix of the name given \ - to the VLAN') -flags.DEFINE_string('profile_name_prefix', "q-", 'Prefix of the name \ - given to the port profile') -flags.DEFINE_string('vlan_start', "100", 'This is the start value of the \ - allowable VLANs') -flags.DEFINE_string('vlan_end', "3000", 'This is the end value of the \ - allowable VLANs') -flags.DEFINE_string('default_vlan_name', "default", 'This is the name of \ - the VLAN which will be associated with the port profile \ - when it is created, by default the VMs will be on this \ - VLAN, until attach is called') -flags.DEFINE_string('default_vlan_id', "1", 'This is the name of the VLAN \ - which will be associated with the port profile when it \ - is created, by default the VMs will be on this VLAN, \ - until attach is called') -flags.DEFINE_string('nova_proj_name', "demo", 'project created in nova') -# -# TODO (Sumit): SAVBU to provide the accurate number below -# -flags.DEFINE_string('max_ucsm_port_profiles', "1024", 'This is the maximum \ - number port profiles that can be handled by one UCSM.') -flags.DEFINE_string('max_port_profiles', "65568", 'This is the maximum \ - number port profiles that can be handled by Cisco \ - plugin. Currently this is just an arbitrary number.') -flags.DEFINE_string('max_networks', "65568", 'This is the maximum number \ - of networks that can be handled by Cisco plugin. \ - Currently this is just an arbitrary number.') - -flags.DEFINE_string('get_next_vif', - "/root/sumit/quantum/quantum/plugins/cisco/get-vif.sh", - 'This is the location of the script to get the next \ - next available dynamic nic') - -# Inventory items -UCSM_IP_ADDRESS = FLAGS.ucsm_ip_address -NEXUS_IP_ADDRESS = FLAGS.nexus_ip_address -NEXUS_DRIVER_ACTIVE = FLAGS.nexus_driver_active -NEXUS_PORT = FLAGS.nexus_port -DB_SERVER_IP = FLAGS.db_server_ip -NOVA_HOST_NAME = FLAGS.nova_host_name - -# General configuration items -DB_NAME = FLAGS.db_name -VLAN_NAME_PREFIX = FLAGS.vlan_name_prefix -PROFILE_NAME_PREFIX = FLAGS.profile_name_prefix -VLAN_START = FLAGS.vlan_start -VLAN_END = FLAGS.vlan_end -DEFAULT_VLAN_NAME = FLAGS.default_vlan_name -DEFAULT_VLAN_ID = FLAGS.default_vlan_id -NOVA_PROJ_NAME = FLAGS.nova_proj_name -MAX_UCSM_PORT_PROFILES = FLAGS.max_ucsm_port_profiles -MAX_PORT_PROFILES = FLAGS.max_port_profiles -MAX_NETWORKS = FLAGS.max_networks - -GET_NEXT_VIF_SCRIPT = FLAGS.get_next_vif diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index 7f2367d794..b14ce09347 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -17,6 +17,8 @@ # @author: Sumit Naiksatam, Cisco Systems, Inc. # +PLUGINS = 'PLUGINS' + PORT_STATE = 'port-state' PORT_UP = "UP" PORT_DOWN = "DOWN" @@ -35,6 +37,8 @@ TENANT_ID = 'tenant-id' TENANT_NETWORKS = 'tenant-networks' TENANT_NAME = 'tenant-name' TENANT_PORTPROFILES = 'tenant-portprofiles' +TENANT_QOS_LEVELS = 'tenant-qos-levels' +TENANT_CREDENTIALS = 'tenant-credentials' PORT_PROFILE = 'port-profile' PROFILE_ID = 'profile-id' @@ -44,4 +48,51 @@ PROFILE_VLAN_ID = 'vlan-id' PROFILE_QOS = 'profile-qos' PROFILE_ASSOCIATIONS = 'assignment' +QOS_LEVEL_ID = 'qos-id' +QOS_LEVEL_NAME = 'qos-name' +QOS_LEVEL_ASSOCIATIONS = 'qos-level-associations' +QOS_LEVEL_DESCRIPTION = 'qos-desc' + +CREDENTIAL_ID = 'credential-id' +CREDENTIAL_NAME = 'credential-name' +CREDENTIAL_USERNAME = 'credential-username' +CREDENTIAL_PASSWORD = 'credential-password' +MASKED_PASSWORD = '********' + +USERNAME = 'username' +PASSWORD = 'password' + LOGGER_COMPONENT_NAME = "cisco_plugin" + +BLADE_INTF_DN = "blade-intf-distinguished-name" +BLADE_INTF_ORDER = "blade-intf-order" +BLADE_INTF_LINK_STATE = "blade-intf-link-state" +BLADE_INTF_OPER_STATE = "blade-intf-operational-state" +BLADE_INTF_INST_TYPE = "blade-intf-inst-type" +BLADE_INTF_RHEL_DEVICE_NAME = "blade-intf-rhel-device-name" +BLADE_INTF_DYNAMIC = "dynamic" +BLADE_INTF_STATE_UNKNOWN = "unknown" +BLADE_INTF_STATE_UNALLOCATED = "unallocated" +BLADE_INTF_RESERVED = "blade-intf-reserved" +BLADE_INTF_UNRESERVED = "blade-intf-unreserved" +BLADE_INTF_RESERVATION = "blade-intf-reservation-status" +BLADE_UNRESERVED_INTF_COUNT = "blade-unreserved-interfaces-count" +BLADE_INTF_DATA = "blade-intf-data" + +LEAST_RSVD_BLADE_UCSM = "least-reserved-blade-ucsm" +LEAST_RSVD_BLADE_CHASSIS = "least-reserved-blade-chassis" +LEAST_RSVD_BLADE_ID = "least-reserved-blade-id" +LEAST_RSVD_BLADE_DATA = "least-reserved-blade-data" + +RESERVED_NIC_HOSTNAME = "reserved-dynamic-nic-hostname" +RESERVED_NIC_NAME = "reserved-dynamic-nic-device-name" + +RESERVED_INTERFACE_UCSM = "reserved-interface-ucsm-ip" +RESERVED_INTERFACE_CHASSIS = "reserved-interface-chassis" +RESERVED_INTERFACE_BLADE = "reserved-interface-blade" +RESERVED_INTERFACE_DN = "reserved-interface-dn" + +RHEL_DEVICE_NAME_REPFIX = "eth" + +UCS_PLUGIN = 'ucs_plugin' +NEXUS_PLUGIN = 'nexus_plugin' diff --git a/quantum/plugins/cisco/common/cisco_credentials.py b/quantum/plugins/cisco/common/cisco_credentials.py index cdbb6c379a..edc2288cde 100644 --- a/quantum/plugins/cisco/common/cisco_credentials.py +++ b/quantum/plugins/cisco/common/cisco_credentials.py @@ -18,54 +18,51 @@ # import logging as LOG +import os from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.common import cisco_configparser as confp LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) -_creds_dictionary = {'10.10.10.10': ["username", "password"], - '127.0.0.1': ["root", "nova"]} +CREDENTIALS_FILE = "../conf/credentials.ini" + +cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ + + "/" + CREDENTIALS_FILE) +_creds_dictionary = cp.walk(cp.dummy) class Store(object): - # The format for this store is {"ip-address" :{"username", "password"}} - def __init__(self): - pass - @staticmethod - def putId(id): - _creds_dictionary[id] = [] - - @staticmethod - def putUsername(id, username): - creds = _creds_dictionary.get(id) - creds.insert(0, username) - - @staticmethod - def putPassword(id, password): - creds = _creds_dictionary.get(id) - creds.insert(1, password) + def putCredential(id, username, password): + _creds_dictionary[id] = {const.USERNAME: username, + const.PASSWORD: password} @staticmethod def getUsername(id): - creds = _creds_dictionary.get(id) - return creds[0] + return _creds_dictionary[id][const.USERNAME] @staticmethod def getPassword(id): - creds = _creds_dictionary.get(id) - return creds[1] + return _creds_dictionary[id][const.PASSWORD] + + @staticmethod + def getCredential(id): + return _creds_dictionary[id] + + @staticmethod + def getCredentials(): + return _creds_dictionary + + @staticmethod + def deleteCredential(id): + return _creds_dictionary.pop(id) def main(): - LOG.debug("username %s\n" % Store.getUsername("172.20.231.27")) - LOG.debug("password %s\n" % Store.getPassword("172.20.231.27")) - Store.putId("192.168.1.1") - Store.putUsername("192.168.1.1", "guest-username") - Store.putPassword("192.168.1.1", "guest-password") - LOG.debug("username %s\n" % Store.getUsername("192.168.1.1")) - LOG.debug("password %s\n" % Store.getPassword("192.168.1.1")) + Store.putCredential("10.10.10.10", "foo", "bar") + print ("%s\n") % Store.getCredentials() if __name__ == '__main__': main() diff --git a/quantum/plugins/cisco/common/cisco_nova_configuration.py b/quantum/plugins/cisco/common/cisco_nova_configuration.py new file mode 100644 index 0000000000..f1cbf2a1ec --- /dev/null +++ b/quantum/plugins/cisco/common/cisco_nova_configuration.py @@ -0,0 +1,42 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import os + +from quantum.plugins.cisco.common import cisco_configparser as confp + +CONF_FILE = "../conf/nova.ini" + +cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ + + "/" + CONF_FILE) + +section = cp['NOVA'] +DB_SERVER_IP = section['db_server_ip'] +DB_NAME = section['db_name'] +DB_USERNAME = section['db_username'] +DB_PASSWORD = section['db_password'] +NOVA_HOST_NAME = section['nova_host_name'] +NOVA_PROJ_NAME = section['nova_proj_name'] + + +def main(): + print NOVA_PROJ_NAME + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/common/cisco_utils.py b/quantum/plugins/cisco/common/cisco_utils.py index 8d0d803b3f..695136db8d 100644 --- a/quantum/plugins/cisco/common/cisco_utils.py +++ b/quantum/plugins/cisco/common/cisco_utils.py @@ -23,9 +23,9 @@ import sys import traceback from quantum.common import exceptions as exc -from quantum.plugins.cisco.common import cisco_configuration as conf from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred +from quantum.plugins.cisco.common import cisco_nova_configuration as conf LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) @@ -38,8 +38,8 @@ class DBUtils(object): def _get_db_connection(self): db_ip = conf.DB_SERVER_IP - db_username = cred.Store.getUsername(db_ip) - db_password = cred.Store.getPassword(db_ip) + db_username = conf.DB_USERNAME + db_password = conf.DB_PASSWORD self.db = MySQLdb.connect(db_ip, db_username, db_password, conf.DB_NAME) return self.db diff --git a/quantum/plugins/cisco/conf/credentials.ini b/quantum/plugins/cisco/conf/credentials.ini new file mode 100644 index 0000000000..96e912cc70 --- /dev/null +++ b/quantum/plugins/cisco/conf/credentials.ini @@ -0,0 +1,15 @@ +#Provide the UCSM credentials +[] +username= +password= + +#Provide the Nova DB credentials, the IP address should be the same as in nova.ini +[] +username= +password= + +#Provide the Nexus credentials, if you are using Nexus +[] +username= +password= + diff --git a/quantum/plugins/cisco/conf/l2network_plugin.ini b/quantum/plugins/cisco/conf/l2network_plugin.ini new file mode 100644 index 0000000000..f6ac8613bf --- /dev/null +++ b/quantum/plugins/cisco/conf/l2network_plugin.ini @@ -0,0 +1,11 @@ +[VLANS] +#Change the following to reflect the VLAN range in your system +vlan_start=100 +vlan_end=3000 +vlan_name_prefix=q- + +[PORTS] +max_ports=100 + +[NETWORKS] +max_networks=65568 diff --git a/quantum/plugins/cisco/conf/nexus.ini b/quantum/plugins/cisco/conf/nexus.ini new file mode 100644 index 0000000000..fede46eb83 --- /dev/null +++ b/quantum/plugins/cisco/conf/nexus.ini @@ -0,0 +1,8 @@ +[SWITCH] +# Change the following to reflect the Nexus switch details +nexus_ip_address= +#Port number of the Interface connected from the Nexus 7K Switch to UCSM 6120, e.g.: 3/23 +nexus_port= + +[DRIVER] +name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver diff --git a/quantum/plugins/cisco/conf/nova.ini b/quantum/plugins/cisco/conf/nova.ini new file mode 100644 index 0000000000..357a586430 --- /dev/null +++ b/quantum/plugins/cisco/conf/nova.ini @@ -0,0 +1,8 @@ +[NOVA] +#Change the following details to reflect your OpenStack Nova configuration. If you are running this service on the same machine as the Nova DB, you do not have to change the IP address. +db_server_ip=127.0.0.1 +db_name=nova +db_username=root +db_password=nova +nova_host_name=openstack0203 +nova_proj_name=demo diff --git a/quantum/plugins/cisco/conf/plugins.ini b/quantum/plugins/cisco/conf/plugins.ini new file mode 100644 index 0000000000..15f6e5412f --- /dev/null +++ b/quantum/plugins/cisco/conf/plugins.ini @@ -0,0 +1,4 @@ +[PLUGINS] +ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin +#Uncomment the following line if you want to enable Nexus support +#nexus_plugin=quantum.plugins.cisco.ucs.cisco_nexus_plugin.NexusPlugin diff --git a/quantum/plugins/cisco/conf/ucs.ini b/quantum/plugins/cisco/conf/ucs.ini new file mode 100644 index 0000000000..4310253131 --- /dev/null +++ b/quantum/plugins/cisco/conf/ucs.ini @@ -0,0 +1,10 @@ +[UCSM] +#change the following to the appropriate UCSM IP address +ip_address= +default_vlan_name=default +default_vlan_id=1 +max_ucsm_port_profiles=1024 +profile_name_prefix=q- + +[DRIVER] +name=quantum.plugins.cisco.ucs.cisco_ucs_network_driver.CiscoUCSMDriver diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 9a8c4a4f0e..e34a1c491e 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -15,18 +15,16 @@ # under the License. # # @author: Sumit Naiksatam, Cisco Systems, Inc. -# @author: Edgar Magana, Cisco Systems, Inc. # import logging as LOG from quantum.common import exceptions as exc -from quantum.plugins.cisco.common import cisco_configuration as conf +from quantum.common import utils +from quantum.plugins.cisco import l2network_plugin_configuration as conf from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc -from quantum.plugins.cisco.nexus import cisco_nexus_plugin -from quantum.plugins.cisco.ucs import cisco_ucs_plugin from quantum.plugins.cisco.common import cisco_utils as cutil LOG.basicConfig(level=LOG.WARN) @@ -37,13 +35,18 @@ class L2Network(object): _networks = {} _tenants = {} _portprofiles = {} + _plugins = {} def __init__(self): self._net_counter = 0 self._portprofile_counter = 0 + self._port_counter = 0 self._vlan_counter = int(conf.VLAN_START) - 1 - self._ucs_plugin = cisco_ucs_plugin.UCSVICPlugin() - self._nexus_plugin = cisco_nexus_plugin.NexusPlugin() + for key in conf.plugins[const.PLUGINS].keys(): + self._plugins[key] = utils.import_object( + conf.plugins[const.PLUGINS][key]) + LOG.debug("Loaded device plugin %s\n" % \ + conf.plugins[const.PLUGINS][key]) """ Core API implementation @@ -66,15 +69,9 @@ class L2Network(object): new_net_id = self._get_unique_net_id(tenant_id) vlan_id = self._get_vlan_for_tenant(tenant_id, net_name) vlan_name = self._get_vlan_name(new_net_id, str(vlan_id)) - nexus_driver_flag = conf.NEXUS_DRIVER_ACTIVE - if nexus_driver_flag == 'on': - LOG.debug("Nexus OS Driver called\n") - self._nexus_plugin.create_network(tenant_id, net_name, new_net_id, - vlan_name, vlan_id) - else: - LOG.debug("No Nexus OS Driver available\n") - self._ucs_plugin.create_network(tenant_id, net_name, new_net_id, - vlan_name, vlan_id) + for pluginClass in self._plugins.values(): + pluginClass.create_network(tenant_id, net_name, + new_net_id, vlan_name, vlan_id) new_net_dict = {const.NET_ID: new_net_id, const.NET_NAME: net_name, const.NET_PORTS: {}, @@ -94,18 +91,20 @@ class L2Network(object): """ LOG.debug("delete_network() called\n") net = self._networks.get(net_id) - nexus_driver_flag = conf.NEXUS_DRIVER_ACTIVE # TODO (Sumit) : Verify that no attachments are plugged into the # network if net: + if len(net[const.NET_PORTS].values()) > 0: + ports_on_net = net[const.NET_PORTS].values() + for port in ports_on_net: + if port[const.ATTACHMENT]: + raise exc.NetworkInUse(net_id=net_id) + for port in ports_on_net: + self.delete_port(tenant_id, net_id, port[const.PORT_ID]) # TODO (Sumit) : Before deleting the network, make sure all the # ports associated with this network are also deleted - if nexus_driver_flag == 'on': - LOG.debug("Nexus OS Driver called\n") - self._nexus_plugin.delete_network(tenant_id, net_id) - else: - LOG.debug("No Nexus OS Driver available\n") - self._ucs_plugin.delete_network(tenant_id, net_id) + for pluginClass in self._plugins.values(): + pluginClass.delete_network(tenant_id, net_id) self._networks.pop(net_id) tenant = self._get_tenant(tenant_id) tenant_networks = tenant[const.TENANT_NETWORKS] @@ -129,13 +128,8 @@ class L2Network(object): Virtual Network. """ LOG.debug("rename_network() called\n") - nexus_driver_flag = conf.NEXUS_DRIVER_ACTIVE - if nexus_driver_flag == 'on': - LOG.debug("Nexus OS Driver called\n") - self._nexus_plugin.rename_network(tenant_id, net_id) - else: - LOG.debug("No Nexus OS Driver available\n") - self._ucs_plugin.rename_network(tenant_id, net_id) + for pluginClass in self._plugins.values(): + pluginClas.rename_network(tenant_id, net_id) network = self._get_network(tenant_id, net_id) network[const.NET_NAME] = new_name return network @@ -158,8 +152,9 @@ class L2Network(object): net = self._get_network(tenant_id, net_id) ports = net[const.NET_PORTS] unique_port_id_string = self._get_unique_port_id(tenant_id, net_id) - self._ucs_plugin.create_port(tenant_id, net_id, port_state, - unique_port_id_string) + self._plugins[const.UCS_PLUGIN].create_port(tenant_id, net_id, + port_state, + unique_port_id_string) new_port_dict = {const.PORT_ID: unique_port_id_string, const.PORT_STATE: const.PORT_UP, const.ATTACHMENT: None} @@ -181,7 +176,8 @@ class L2Network(object): try: #TODO (Sumit): Before deleting port profile make sure that there # is no VM using this port profile - self._ucs_plugin.delete_port(tenant_id, net_id, port_id) + self._plugins[const.UCS_PLUGIN].delete_port(tenant_id, net_id, + port_id) net = self._get_network(tenant_id, net_id) net[const.NET_PORTS].pop(port_id) except KeyError: @@ -218,8 +214,9 @@ class L2Network(object): if port[const.ATTACHMENT]: raise exc.PortInUse(net_id=net_id, port_id=port_id, att_id=port[const.ATTACHMENT]) - self._ucs_plugin.plug_interface(tenant_id, net_id, port_id, - remote_interface_id) + self._plugins[const.UCS_PLUGIN].plug_interface(tenant_id, + net_id, port_id, + remote_interface_id) port[const.ATTACHMENT] = remote_interface_id def unplug_interface(self, tenant_id, net_id, port_id): @@ -229,8 +226,8 @@ class L2Network(object): """ LOG.debug("unplug_interface() called\n") port = self._get_port(tenant_id, net_id, port_id) - self._ucs_plugin.unplug_interface(tenant_id, net_id, - port_id) + self._plugins[const.UCS_PLUGIN].unplug_interface(tenant_id, net_id, + port_id) port[const.ATTACHMENT] = None """ @@ -361,17 +358,15 @@ class L2Network(object): "-n-" + ("0" * (6 - len(str(self._net_counter)))) + \ str(self._net_counter) # TODO (Sumit): Need to check if the ID has already been allocated + # ID will be generated by DB return id def _get_unique_port_id(self, tenant_id, net_id): - net = self._get_network(tenant_id, net_id) - ports = net[const.NET_PORTS] - if len(ports) == 0: - new_port_id = 1 - else: - new_port_id = max(ports.keys()) + 1 - id = net_id + "-p-" + str(new_port_id) + self._port_counter += 1 + self._port_counter %= int(conf.MAX_PORTS) + id = net_id + "-p-" + str(self._port_counter) # TODO (Sumit): Need to check if the ID has already been allocated + # ID will be generated by DB return id def _get_unique_profile_id(self, tenant_id): @@ -380,6 +375,7 @@ class L2Network(object): id = tenant_id[:3] + "-pp-" + \ ("0" * (6 - len(str(self._net_counter)))) + str(self._net_counter) # TODO (Sumit): Need to check if the ID has already been allocated + # ID will be generated by DB return id # TODO (Sumit): diff --git a/quantum/plugins/cisco/l2network_plugin_configuration.py b/quantum/plugins/cisco/l2network_plugin_configuration.py new file mode 100644 index 0000000000..e0fe786a51 --- /dev/null +++ b/quantum/plugins/cisco/l2network_plugin_configuration.py @@ -0,0 +1,51 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import os + +from quantum.plugins.cisco.common import cisco_configparser as confp + +CONF_FILE = "conf/l2network_plugin.ini" + +cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ + + "/" + CONF_FILE) + +section = cp['VLANS'] +VLAN_NAME_PREFIX = section['vlan_name_prefix'] +VLAN_START = section['vlan_start'] +VLAN_END = section['vlan_end'] + +section = cp['PORTS'] +MAX_PORTS = section['max_ports'] + +section = cp['NETWORKS'] +MAX_NETWORKS = section['max_networks'] + +CONF_FILE = "conf/plugins.ini" + +cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ + + "/" + CONF_FILE) +plugins = cp.walk(cp.dummy) + + +def main(): + print plugins['PLUGINS'] + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py b/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py new file mode 100644 index 0000000000..f1ad149028 --- /dev/null +++ b/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py @@ -0,0 +1,42 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# @author: Edgar Magana, Cisco Systems, Inc. +# + +import os + +from quantum.plugins.cisco.common import cisco_configparser as confp + +CONF_FILE = "../conf/nexus.ini" + +cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ + + "/" + CONF_FILE) + +section = cp['SWITCH'] +NEXUS_IP_ADDRESS = section['nexus_ip_address'] +NEXUS_PORT = section['nexus_port'] + +section = cp['DRIVER'] +NEXUS_DRIVER = section['name'] + + +def main(): + print NEXUS_PORT + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py index 27e63ce4cb..78090d5f9c 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py @@ -25,7 +25,6 @@ import logging as LOG import string import subprocess -from quantum.plugins.cisco.common import cisco_configuration as conf from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_exceptions as cexc diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py index 31baac4729..8fa6424f93 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py @@ -20,13 +20,12 @@ import logging as LOG from quantum.common import exceptions as exc -from quantum.plugins.cisco.common import cisco_configuration as conf +from quantum.common import utils from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc from quantum.plugins.cisco.common import cisco_utils as cutil - -from quantum.plugins.cisco.nexus import cisco_nexus_network_driver +from quantum.plugins.cisco.nexus import cisco_nexus_configuration as conf LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) @@ -36,7 +35,8 @@ class NexusPlugin(object): _networks = {} def __init__(self): - self._client = cisco_nexus_network_driver.CiscoNEXUSDriver() + self._client = utils.import_object(conf.NEXUS_DRIVER) + LOG.debug("Loaded driver %s\n" % conf.NEXUS_DRIVER) #TODO (Edgar) Using just one Nexus 7K Switch and Port self._nexus_ip = conf.NEXUS_IP_ADDRESS self._nexus_username = cred.Store.getUsername(conf.NEXUS_IP_ADDRESS) diff --git a/quantum/plugins/cisco/ucs/get-vif.py b/quantum/plugins/cisco/ucs/cisco_getvif.py similarity index 60% rename from quantum/plugins/cisco/ucs/get-vif.py rename to quantum/plugins/cisco/ucs/cisco_getvif.py index 0512ecb0dd..f00116ee1f 100644 --- a/quantum/plugins/cisco/ucs/get-vif.py +++ b/quantum/plugins/cisco/ucs/cisco_getvif.py @@ -1,3 +1,21 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Rohit Agarwalla, Cisco Systems Inc. +# import sys import subprocess @@ -23,7 +41,7 @@ def get_next_dynic(argv=[]): for lines in f_cmd_output.splitlines()] #print deviceid if deviceid[0] == "0044": - cmd = ["/usr/sbin/ip", "link", "show", eth] + cmd = ["/sbin/ip", "link", "show", eth] f_cmd_output = subprocess.Popen(cmd, stdout=subprocess.PIPE).\ communicate()[0] used = [lines for lines in f_cmd_output.splitlines() \ @@ -33,5 +51,6 @@ def get_next_dynic(argv=[]): return eth if __name__ == '__main__': - nic = get_next_dynic(sys.argv) + #nic = get_next_dynic(sys.argv) + nic = get_next_dynic() print nic diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py b/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py new file mode 100644 index 0000000000..3053741712 --- /dev/null +++ b/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py @@ -0,0 +1,44 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import os + +from quantum.plugins.cisco.common import cisco_configparser as confp + +CONF_FILE = "../conf/ucs.ini" + +cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ + + "/" + CONF_FILE) + +section = cp['UCSM'] +UCSM_IP_ADDRESS = section['ip_address'] +DEFAULT_VLAN_NAME = section['default_vlan_name'] +DEFAULT_VLAN_ID = section['default_vlan_id'] +MAX_UCSM_PORT_PROFILES = section['max_ucsm_port_profiles'] +PROFILE_NAME_PREFIX = section['profile_name_prefix'] + +section = cp['DRIVER'] +UCSM_DRIVER = section['name'] + + +def main(): + print MAX_UCSM_PORT_PROFILES + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index 2d994ddec1..acf0df100d 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -27,9 +27,10 @@ import subprocess from xml.etree import ElementTree as et import urllib -from quantum.plugins.cisco.common import cisco_configuration as conf from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_exceptions as cexc +from quantum.plugins.cisco.ucs import cisco_getvif as gvif + LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) @@ -180,11 +181,7 @@ class CiscoUCSMDriver(): return data def _get_next_dynamic_nic(self): - # TODO (Sumit): following should be a call to a python module - # (which will in turn eliminate the reference to the path and script) - dynamic_nic_id = string.strip(subprocess.Popen( - conf.GET_NEXT_VIF_SCRIPT, - stdout=subprocess.PIPE).communicate()[0]) + dynamic_nic_id = gvif.get_next_dynic() if len(dynamic_nic_id) > 0: return dynamic_nic_id else: @@ -247,12 +244,14 @@ def main(): #client.get_dynamic_nic("dummy") #client.get_dynamic_nic("dummy") #client.release_dynamic_nic("dummy") - #client.get_dynamic_nic("dummy") - #client.change_vlan_in_profile("br100", "default", "test-2", - # "172.20.231.27","admin", - # "c3l12345") + print client.get_dynamic_nic("dummy") + """ + client.change_vlan_in_profile("br100", "default", "test-2", + "172.20.231.27","admin", + "c3l12345") client.change_vlan_in_profile("br100", "test-2", "default", "172.20.231.27", "admin", "c3l12345") + """ if __name__ == '__main__': main() diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index 264d14f783..f7969cab13 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -20,11 +20,11 @@ import logging as LOG from quantum.common import exceptions as exc -from quantum.plugins.cisco.common import cisco_configuration as conf +from quantum.common import utils from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc -from quantum.plugins.cisco.ucs import cisco_ucs_network_driver +from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf from quantum.plugins.cisco.common import cisco_utils as cutil LOG.basicConfig(level=LOG.WARN) @@ -35,7 +35,8 @@ class UCSVICPlugin(object): _networks = {} def __init__(self): - self._client = cisco_ucs_network_driver.CiscoUCSMDriver() + self._client = utils.import_object(conf.UCSM_DRIVER) + LOG.debug("Loaded driver %s\n" % conf.UCSM_DRIVER) self._utils = cutil.DBUtils() # TODO (Sumit) This is for now, when using only one chassis self._ucsm_ip = conf.UCSM_IP_ADDRESS diff --git a/quantum/plugins/cisco/ucs/get-vif.sh b/quantum/plugins/cisco/ucs/get-vif.sh deleted file mode 100755 index d424b5fea2..0000000000 --- a/quantum/plugins/cisco/ucs/get-vif.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -eths=`ifconfig -a | grep eth | cut -f1 -d " "` -for eth in $eths; do - bdf=`ethtool -i $eth | grep bus-info | cut -f2 -d " "` - deviceid=`lspci -n -s $bdf | cut -f4 -d ":" | cut -f1 -d " "` - if [ $deviceid = "0044" ]; then - used=`/sbin/ip link show $eth | grep "UP"` - avail=$? - if [ $avail -eq 1 ]; then - echo $eth - exit - fi - fi -done - From d523ce7c18420c998f5f0e8bf16ffad64e005c42 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 5 Aug 2011 12:05:14 -0700 Subject: [PATCH 27/48] Fixes the broken call to second level of plugins. Renaming will work now. --- quantum/plugins/cisco/l2network_plugin.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index e34a1c491e..b9ada4d5fd 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -115,12 +115,14 @@ class L2Network(object): def get_network_details(self, tenant_id, net_id): """ - Deletes the Virtual Network belonging to a the - spec + Gets the details of a particular network """ LOG.debug("get_network_details() called\n") network = self._get_network(tenant_id, net_id) - return network + ports_on_net = network[const.NET_PORTS].values() + return {const.NET_ID: network[const.NET_ID], + const.NET_NAME: network[const.NET_NAME], + const.NET_PORTS: ports_on_net} def rename_network(self, tenant_id, net_id, new_name): """ @@ -129,7 +131,7 @@ class L2Network(object): """ LOG.debug("rename_network() called\n") for pluginClass in self._plugins.values(): - pluginClas.rename_network(tenant_id, net_id) + pluginClass.rename_network(tenant_id, net_id, new_name) network = self._get_network(tenant_id, net_id) network[const.NET_NAME] = new_name return network From c5bc02a04b99c093fcd7a76bc19dabd19a356ffb Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 5 Aug 2011 12:45:28 -0700 Subject: [PATCH 28/48] Fixed issue with creating new port profiles (one configuration parameter got left out during the migration to the new configuration scheme). Also fixed a bug in the calculation of the profile id. --- .../plugins/cisco/conf/l2network_plugin.ini | 4 +++- quantum/plugins/cisco/l2network_plugin.py | 19 ++++++++++++++++--- .../cisco/l2network_plugin_configuration.py | 3 +++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/quantum/plugins/cisco/conf/l2network_plugin.ini b/quantum/plugins/cisco/conf/l2network_plugin.ini index f6ac8613bf..5a0d7d7a93 100644 --- a/quantum/plugins/cisco/conf/l2network_plugin.ini +++ b/quantum/plugins/cisco/conf/l2network_plugin.ini @@ -1,5 +1,4 @@ [VLANS] -#Change the following to reflect the VLAN range in your system vlan_start=100 vlan_end=3000 vlan_name_prefix=q- @@ -7,5 +6,8 @@ vlan_name_prefix=q- [PORTS] max_ports=100 +[PORTPROFILES] +max_port_profiles=65568 + [NETWORKS] max_networks=65568 diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index b9ada4d5fd..e3642515ce 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -375,10 +375,23 @@ class L2Network(object): self._portprofile_counter += 1 self._portprofile_counter %= int(conf.MAX_PORT_PROFILES) id = tenant_id[:3] + "-pp-" + \ - ("0" * (6 - len(str(self._net_counter)))) + str(self._net_counter) + ("0" * (6 - len(str(self._net_counter)))) \ + + str(self._portprofile_counter) # TODO (Sumit): Need to check if the ID has already been allocated # ID will be generated by DB return id -# TODO (Sumit): - # (1) Persistent storage + +def main(): + client = L2Network() + client.create_portprofile("12345", "tpp1", "2") + client.create_portprofile("12345", "tpp2", "3") + print ("%s\n") % client.get_all_portprofiles("12345") + +if __name__ == '__main__': + main() + +""" +TODO (Sumit): +(1) Persistent storage +""" diff --git a/quantum/plugins/cisco/l2network_plugin_configuration.py b/quantum/plugins/cisco/l2network_plugin_configuration.py index e0fe786a51..fe619ddfcd 100644 --- a/quantum/plugins/cisco/l2network_plugin_configuration.py +++ b/quantum/plugins/cisco/l2network_plugin_configuration.py @@ -34,6 +34,9 @@ VLAN_END = section['vlan_end'] section = cp['PORTS'] MAX_PORTS = section['max_ports'] +section = cp['PORTPROFILES'] +MAX_PORT_PROFILES = section['max_port_profiles'] + section = cp['NETWORKS'] MAX_NETWORKS = section['max_networks'] From 9093c6f81c741ac716967665a3ad46b043f92590 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 5 Aug 2011 19:15:27 -0700 Subject: [PATCH 29/48] Edits to reflect conf changes, made it easier to follow. --- quantum/plugins/cisco/README | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index f8711193ab..74e9e53480 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -2,6 +2,7 @@ ================== *** Current support for UCS (blade servers) with M81KR VIC (Palo) for 802.1Qbh *** +*** Also supports Nexus 7k *** ** Pre-requisities * UCS B200 series blades with M81KR VIC installed. @@ -28,14 +29,16 @@ gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OPENSTACK ** Plugin Installation Instructions: -* Make a backup copy of quantum/quantum/plugins.ini, and edit the file to remove all exisiting entries and add the following entry: +* Make a backup copy of quantum/quantum/plugins.ini, and edit the "provider" entry to point to the L2Network-plugin: provider = quantum.plugins.cisco.l2network_plugin.L2Network -* All configuration files are located under quantum/plugins/cisco/conf. Where you find kind of placeholder, please replace it entirely with the relevant values (don't forget to remove the angle brackets as well) +* All configuration files are located under quantum/plugins/cisco/conf. Wherever you find kind of placeholder, please replace it entirely with the relevant values (don't forget to remove the angle brackets as well) * If you are not running Quantum on the same host as the OpenStack Cloud Controller, you will need to change the db_ip_address configuration in nova.ini -* If you want to turn on Nexus support, please uncomment the nexus_plugin property in the nexus.ini file. You will also require a patch to the ncclient in addition to the library mentioned in the prerequisities. +* If you want to turn on Nexus support, please uncomment the nexus_plugin property in the plugins.ini file, and enter the relevant configuration in the nexus.ini file. You will also require a patch to the ncclient in addition to the library mentioned in the prerequisities. If you are not turning the Nexus support on, your Nexus configuration will be ignored. + +* Check again if you have gone through every conf file and made the required changes (check if all IP addresses are correct, and check if you have entered the credentials correponding to each of those IP addresses in the credentials.ini file). * Start the Quantum service From 742e77389f5e1b5b20933203f88a16a27a12c075 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 5 Aug 2011 22:16:25 -0700 Subject: [PATCH 30/48] Nexus plugin classpath was incorrect, fixed it. --- quantum/plugins/cisco/conf/plugins.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/quantum/plugins/cisco/conf/plugins.ini b/quantum/plugins/cisco/conf/plugins.ini index 15f6e5412f..8b4b476a0a 100644 --- a/quantum/plugins/cisco/conf/plugins.ini +++ b/quantum/plugins/cisco/conf/plugins.ini @@ -1,4 +1,3 @@ [PLUGINS] ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin -#Uncomment the following line if you want to enable Nexus support -#nexus_plugin=quantum.plugins.cisco.ucs.cisco_nexus_plugin.NexusPlugin +#nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin From d725cb3a8807e4c6df48455c759ace43005d3147 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Fri, 5 Aug 2011 23:01:55 -0700 Subject: [PATCH 31/48] Added info about ssh conf required for nexus switch. --- quantum/plugins/cisco/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 74e9e53480..36ea4ea274 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -36,7 +36,7 @@ provider = quantum.plugins.cisco.l2network_plugin.L2Network * If you are not running Quantum on the same host as the OpenStack Cloud Controller, you will need to change the db_ip_address configuration in nova.ini -* If you want to turn on Nexus support, please uncomment the nexus_plugin property in the plugins.ini file, and enter the relevant configuration in the nexus.ini file. You will also require a patch to the ncclient in addition to the library mentioned in the prerequisities. If you are not turning the Nexus support on, your Nexus configuration will be ignored. +* If you want to turn on Nexus support, please uncomment the nexus_plugin property in the plugins.ini file, and enter the relevant configuration in the nexus.ini file. In addition, you will require a patch to the ncclient library. Also make sure that the switch's host key is known to the host on which you are running the Quantum service (since the connection to the switch is over ssh). If you are not turning the Nexus support on, your Nexus configuration will be ignored. * Check again if you have gone through every conf file and made the required changes (check if all IP addresses are correct, and check if you have entered the credentials correponding to each of those IP addresses in the credentials.ini file). From 6f5eced38fa6b930b5a75905d2ac8610af509ead Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 6 Aug 2011 18:41:27 -0700 Subject: [PATCH 32/48] Generalized and put placeholders. --- quantum/plugins/cisco/conf/nova.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/quantum/plugins/cisco/conf/nova.ini b/quantum/plugins/cisco/conf/nova.ini index 357a586430..7ef5d43968 100644 --- a/quantum/plugins/cisco/conf/nova.ini +++ b/quantum/plugins/cisco/conf/nova.ini @@ -2,7 +2,7 @@ #Change the following details to reflect your OpenStack Nova configuration. If you are running this service on the same machine as the Nova DB, you do not have to change the IP address. db_server_ip=127.0.0.1 db_name=nova -db_username=root -db_password=nova -nova_host_name=openstack0203 -nova_proj_name=demo +db_username= +db_password= +nova_host_name= +nova_proj_name= From bc522e178853337da10939444605e248f5462ecd Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 6 Aug 2011 20:43:08 -0700 Subject: [PATCH 33/48] Added QuantunPluginBase as the base class for the l2network_plugin. --- quantum/plugins/cisco/l2network_plugin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index e3642515ce..7149bc5f10 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -21,6 +21,7 @@ import logging as LOG from quantum.common import exceptions as exc from quantum.common import utils +from quantum.quantum_plugin_base import QuantumPluginBase from quantum.plugins.cisco import l2network_plugin_configuration as conf from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred @@ -31,7 +32,7 @@ LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) -class L2Network(object): +class L2Network(QuantumPluginBase): _networks = {} _tenants = {} _portprofiles = {} From e3b8bafbb9f3b70e7086ef69adf4f78dc2faa4d3 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sun, 7 Aug 2011 04:58:50 -0700 Subject: [PATCH 34/48] Changes to enhance L2 network plugin framework. --- quantum/plugins/cisco/README | 3 + .../plugins/cisco/common/cisco_constants.py | 5 + .../plugins/cisco/conf/l2network_plugin.ini | 7 +- quantum/plugins/cisco/l2device_plugin_base.py | 152 ++++++++++++++++++ quantum/plugins/cisco/l2network_model.py | 105 ++++++++++++ quantum/plugins/cisco/l2network_model_base.py | 150 +++++++++++++++++ quantum/plugins/cisco/l2network_plugin.py | 67 ++++---- .../cisco/l2network_plugin_configuration.py | 3 + .../plugins/cisco/nexus/cisco_nexus_plugin.py | 27 ++-- quantum/plugins/cisco/ucs/cisco_ucs_plugin.py | 31 ++-- 10 files changed, 493 insertions(+), 57 deletions(-) create mode 100644 quantum/plugins/cisco/l2device_plugin_base.py create mode 100644 quantum/plugins/cisco/l2network_model.py create mode 100644 quantum/plugins/cisco/l2network_model_base.py diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 36ea4ea274..ee03219593 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -1,6 +1,8 @@ L2 Network Plugin ================== +*** Reference implementation of plugin framework for L2 network *** +*** Multi-switch (devices and types) capability *** *** Current support for UCS (blade servers) with M81KR VIC (Palo) for 802.1Qbh *** *** Also supports Nexus 7k *** @@ -10,6 +12,7 @@ * RHEL 6.1 * UCS & VIC installation (support for KVM) - please consult the accompanying installation guide available at: http://wikicentral.cisco.com/display/GROUP/SAVBU+Palo+VM-FEX+for+Linux+KVM +* Package python-configobj-4.6.0-3.el6.noarch * If you have a Nexus switch in your topology and decide to turn on Nexus support, you will need: - ncclcient v0.3.1 - Python library for NETCONF clients (http://schmizz.net/ncclient/). diff --git a/quantum/plugins/cisco/common/cisco_constants.py b/quantum/plugins/cisco/common/cisco_constants.py index b14ce09347..71ae304d18 100644 --- a/quantum/plugins/cisco/common/cisco_constants.py +++ b/quantum/plugins/cisco/common/cisco_constants.py @@ -96,3 +96,8 @@ RHEL_DEVICE_NAME_REPFIX = "eth" UCS_PLUGIN = 'ucs_plugin' NEXUS_PLUGIN = 'nexus_plugin' + +PLUGIN_OBJ_REF = 'plugin-obj-ref' +PARAM_LIST = 'param-list' + +DEVICE_IP = 'device-ip' diff --git a/quantum/plugins/cisco/conf/l2network_plugin.ini b/quantum/plugins/cisco/conf/l2network_plugin.ini index 5a0d7d7a93..3a740a9713 100644 --- a/quantum/plugins/cisco/conf/l2network_plugin.ini +++ b/quantum/plugins/cisco/conf/l2network_plugin.ini @@ -1,6 +1,6 @@ [VLANS] -vlan_start=100 -vlan_end=3000 +vlan_start= +vlan_end= vlan_name_prefix=q- [PORTS] @@ -11,3 +11,6 @@ max_port_profiles=65568 [NETWORKS] max_networks=65568 + +[MODEL] +model_class=quantum.plugins.cisco.l2network_model.L2NetworkModel diff --git a/quantum/plugins/cisco/l2device_plugin_base.py b/quantum/plugins/cisco/l2device_plugin_base.py new file mode 100644 index 0000000000..b108d02423 --- /dev/null +++ b/quantum/plugins/cisco/l2device_plugin_base.py @@ -0,0 +1,152 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import inspect +from abc import ABCMeta, abstractmethod + + +class L2DevicePluginBase(object): + + __metaclass__ = ABCMeta + + @abstractmethod + def get_all_networks(self, tenant_id, **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id, + **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def delete_network(self, tenant_id, net_id, **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def get_network_details(self, tenant_id, net_id, **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def rename_network(self, tenant_id, net_id, new_name, **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def get_all_ports(self, tenant_id, net_id, **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def delete_port(self, tenant_id, net_id, port_id, **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def update_port(self, tenant_id, net_id, port_id, port_state, **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def get_port_details(self, tenant_id, net_id, port_id, **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id, + **kwargs): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def unplug_interface(self, tenant_id, net_id, port_id, **kwargs): + """ + :returns: + :raises: + """ + pass + + @classmethod + def __subclasshook__(cls, klass): + """ + The __subclasshook__ method is a class method + that will be called everytime a class is tested + using issubclass(klass, Plugin). + In that case, it will check that every method + marked with the abstractmethod decorator is + provided by the plugin class. + """ + if cls is QuantumPluginBase: + for method in cls.__abstractmethods__: + method_ok = False + for base in klass.__mro__: + if method in base.__dict__: + fn_obj = base.__dict__[method] + if inspect.isfunction(fn_obj): + abstract_fn_obj = cls.__dict__[method] + arg_count = fn_obj.func_code.co_argcount + expected_arg_count = \ + abstract_fn_obj.func_code.co_argcount + method_ok = arg_count == expected_arg_count + if method_ok: + continue + return NotImplemented + return True + return NotImplemented diff --git a/quantum/plugins/cisco/l2network_model.py b/quantum/plugins/cisco/l2network_model.py new file mode 100644 index 0000000000..3fa986b2a3 --- /dev/null +++ b/quantum/plugins/cisco/l2network_model.py @@ -0,0 +1,105 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import inspect +import logging as LOG + +from quantum.common import utils +from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase +from quantum.plugins.cisco import l2network_plugin_configuration as conf +from quantum.plugins.cisco.common import cisco_constants as const + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger(const.LOGGER_COMPONENT_NAME) + + +class L2NetworkModel(L2NetworkModelBase): + _plugins = {} + + def __init__(self): + for key in conf.plugins[const.PLUGINS].keys(): + self._plugins[key] = utils.import_object( + conf.plugins[const.PLUGINS][key]) + LOG.debug("Loaded device plugin %s\n" % \ + conf.plugins[const.PLUGINS][key]) + + def _funcName(self, offset=0): + return inspect.stack()[1 + offset][3] + + def _invokeAllDevicePlugins(self, function_name, args, kwargs): + for pluginObjRef in self._plugins.values(): + getattr(pluginObjRef, function_name)(*args, **kwargs) + + def _invokeUCSPlugin(self, function_name, args, kwargs): + getattr(self._plugins[const.UCS_PLUGIN], + function_name)(*args, **kwargs) + + def _invokeNexusPlugin(self, function_name, args, kwargs): + getattr(self._plugins[const.NEXUS_PLUGIN], + function_name)(*args, **kwargs) + + def get_all_networks(self, args): + pass + + def create_network(self, args): + deviceParams = {const.DEVICE_IP: ""} + self._invokeAllDevicePlugins(self._funcName(), args, deviceParams) + + def delete_network(self, args): + deviceParams = {const.DEVICE_IP: ""} + self._invokeAllDevicePlugins(self._funcName(), args, deviceParams) + + def get_network_details(self, args): + pass + + def rename_network(self, args): + deviceParams = {const.DEVICE_IP: ""} + self._invokeAllDevicePlugins(self._funcName(), args, deviceParams) + + def get_all_ports(self, args): + pass + + def create_port(self, args): + deviceParams = {const.DEVICE_IP: ""} + self._invokeUCSPlugin(self._funcName(), args, deviceParams) + + def delete_port(self, args): + deviceParams = {const.DEVICE_IP: ""} + self._invokeUCSPlugin(self._funcName(), args, deviceParams) + + def update_port(self, args): + pass + + def get_port_details(self, args): + pass + + def plug_interface(self, args): + deviceParams = {const.DEVICE_IP: ""} + self._invokeUCSPlugin(self._funcName(), args, deviceParams) + + def unplug_interface(self, args): + deviceParams = {const.DEVICE_IP: ""} + self._invokeUCSPlugin(self._funcName(), args, deviceParams) + + +def main(): + client = L2NetworkModel() + +if __name__ == '__main__': + main() diff --git a/quantum/plugins/cisco/l2network_model_base.py b/quantum/plugins/cisco/l2network_model_base.py new file mode 100644 index 0000000000..f23fce4cfc --- /dev/null +++ b/quantum/plugins/cisco/l2network_model_base.py @@ -0,0 +1,150 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Sumit Naiksatam, Cisco Systems, Inc. +# + +import inspect +from abc import ABCMeta, abstractmethod + + +class L2NetworkModelBase(object): + + __metaclass__ = ABCMeta + + @abstractmethod + def get_all_networks(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def create_network(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def delete_network(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def get_network_details(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def rename_network(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def get_all_ports(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def create_port(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def delete_port(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def update_port(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def get_port_details(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def plug_interface(self, args): + """ + :returns: + :raises: + """ + pass + + @abstractmethod + def unplug_interface(self, args): + """ + :returns: + :raises: + """ + pass + + @classmethod + def __subclasshook__(cls, klass): + """ + The __subclasshook__ method is a class method + that will be called everytime a class is tested + using issubclass(klass, Plugin). + In that case, it will check that every method + marked with the abstractmethod decorator is + provided by the plugin class. + """ + if cls is QuantumPluginBase: + for method in cls.__abstractmethods__: + method_ok = False + for base in klass.__mro__: + if method in base.__dict__: + fn_obj = base.__dict__[method] + if inspect.isfunction(fn_obj): + abstract_fn_obj = cls.__dict__[method] + arg_count = fn_obj.func_code.co_argcount + expected_arg_count = \ + abstract_fn_obj.func_code.co_argcount + method_ok = arg_count == expected_arg_count + if method_ok: + continue + return NotImplemented + return True + return NotImplemented diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index 7149bc5f10..f627de2541 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -17,6 +17,7 @@ # @author: Sumit Naiksatam, Cisco Systems, Inc. # +import inspect import logging as LOG from quantum.common import exceptions as exc @@ -24,9 +25,7 @@ from quantum.common import utils from quantum.quantum_plugin_base import QuantumPluginBase from quantum.plugins.cisco import l2network_plugin_configuration as conf from quantum.plugins.cisco.common import cisco_constants as const -from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc -from quantum.plugins.cisco.common import cisco_utils as cutil LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) @@ -36,18 +35,13 @@ class L2Network(QuantumPluginBase): _networks = {} _tenants = {} _portprofiles = {} - _plugins = {} def __init__(self): self._net_counter = 0 self._portprofile_counter = 0 self._port_counter = 0 self._vlan_counter = int(conf.VLAN_START) - 1 - for key in conf.plugins[const.PLUGINS].keys(): - self._plugins[key] = utils.import_object( - conf.plugins[const.PLUGINS][key]) - LOG.debug("Loaded device plugin %s\n" % \ - conf.plugins[const.PLUGINS][key]) + self._model = utils.import_object(conf.MODEL_CLASS) """ Core API implementation @@ -59,6 +53,7 @@ class L2Network(QuantumPluginBase): the specified tenant. """ LOG.debug("get_all_networks() called\n") + self._invokeDevicePlugins(self._funcName(), [tenant_id]) return self._networks.values() def create_network(self, tenant_id, net_name): @@ -70,9 +65,9 @@ class L2Network(QuantumPluginBase): new_net_id = self._get_unique_net_id(tenant_id) vlan_id = self._get_vlan_for_tenant(tenant_id, net_name) vlan_name = self._get_vlan_name(new_net_id, str(vlan_id)) - for pluginClass in self._plugins.values(): - pluginClass.create_network(tenant_id, net_name, - new_net_id, vlan_name, vlan_id) + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_name, + new_net_id, vlan_name, + vlan_id]) new_net_dict = {const.NET_ID: new_net_id, const.NET_NAME: net_name, const.NET_PORTS: {}, @@ -92,8 +87,6 @@ class L2Network(QuantumPluginBase): """ LOG.debug("delete_network() called\n") net = self._networks.get(net_id) - # TODO (Sumit) : Verify that no attachments are plugged into the - # network if net: if len(net[const.NET_PORTS].values()) > 0: ports_on_net = net[const.NET_PORTS].values() @@ -102,10 +95,8 @@ class L2Network(QuantumPluginBase): raise exc.NetworkInUse(net_id=net_id) for port in ports_on_net: self.delete_port(tenant_id, net_id, port[const.PORT_ID]) - # TODO (Sumit) : Before deleting the network, make sure all the - # ports associated with this network are also deleted - for pluginClass in self._plugins.values(): - pluginClass.delete_network(tenant_id, net_id) + + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id]) self._networks.pop(net_id) tenant = self._get_tenant(tenant_id) tenant_networks = tenant[const.TENANT_NETWORKS] @@ -119,6 +110,7 @@ class L2Network(QuantumPluginBase): Gets the details of a particular network """ LOG.debug("get_network_details() called\n") + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id]) network = self._get_network(tenant_id, net_id) ports_on_net = network[const.NET_PORTS].values() return {const.NET_ID: network[const.NET_ID], @@ -131,8 +123,8 @@ class L2Network(QuantumPluginBase): Virtual Network. """ LOG.debug("rename_network() called\n") - for pluginClass in self._plugins.values(): - pluginClass.rename_network(tenant_id, net_id, new_name) + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id, + new_name]) network = self._get_network(tenant_id, net_id) network[const.NET_NAME] = new_name return network @@ -143,6 +135,7 @@ class L2Network(QuantumPluginBase): specified Virtual Network. """ LOG.debug("get_all_ports() called\n") + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id]) network = self._get_network(tenant_id, net_id) ports_on_net = network[const.NET_PORTS].values() return ports_on_net @@ -155,9 +148,9 @@ class L2Network(QuantumPluginBase): net = self._get_network(tenant_id, net_id) ports = net[const.NET_PORTS] unique_port_id_string = self._get_unique_port_id(tenant_id, net_id) - self._plugins[const.UCS_PLUGIN].create_port(tenant_id, net_id, - port_state, - unique_port_id_string) + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id, + port_state, + unique_port_id_string]) new_port_dict = {const.PORT_ID: unique_port_id_string, const.PORT_STATE: const.PORT_UP, const.ATTACHMENT: None} @@ -179,8 +172,8 @@ class L2Network(QuantumPluginBase): try: #TODO (Sumit): Before deleting port profile make sure that there # is no VM using this port profile - self._plugins[const.UCS_PLUGIN].delete_port(tenant_id, net_id, - port_id) + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id, + port_id]) net = self._get_network(tenant_id, net_id) net[const.NET_PORTS].pop(port_id) except KeyError: @@ -191,6 +184,8 @@ class L2Network(QuantumPluginBase): Updates the state of a port on the specified Virtual Network. """ LOG.debug("update_port() called\n") + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id, + port_id, port_state]) port = self._get_port(tenant_id, net_id, port_id) self._validate_port_state(port_state) port[const.PORT_STATE] = port_state @@ -202,6 +197,8 @@ class L2Network(QuantumPluginBase): that is attached to this particular port. """ LOG.debug("get_port_details() called\n") + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id, + port_id]) return self._get_port(tenant_id, net_id, port_id) def plug_interface(self, tenant_id, net_id, port_id, @@ -217,9 +214,9 @@ class L2Network(QuantumPluginBase): if port[const.ATTACHMENT]: raise exc.PortInUse(net_id=net_id, port_id=port_id, att_id=port[const.ATTACHMENT]) - self._plugins[const.UCS_PLUGIN].plug_interface(tenant_id, - net_id, port_id, - remote_interface_id) + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id, + port_id, + remote_interface_id]) port[const.ATTACHMENT] = remote_interface_id def unplug_interface(self, tenant_id, net_id, port_id): @@ -229,8 +226,8 @@ class L2Network(QuantumPluginBase): """ LOG.debug("unplug_interface() called\n") port = self._get_port(tenant_id, net_id, port_id) - self._plugins[const.UCS_PLUGIN].unplug_interface(tenant_id, net_id, - port_id) + self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id, + port_id]) port[const.ATTACHMENT] = None """ @@ -290,6 +287,12 @@ class L2Network(QuantumPluginBase): """ Private functions """ + def _invokeDevicePlugins(self, function_name, args): + """ + All device-specific calls are delegate to the model + """ + getattr(self._model, function_name)(args) + def _get_vlan_for_tenant(self, tenant_id, net_name): # TODO (Sumit): # The VLAN ID for a tenant might need to be obtained from @@ -382,12 +385,18 @@ class L2Network(QuantumPluginBase): # ID will be generated by DB return id + def _funcName(self, offset=0): + return inspect.stack()[1 + offset][3] + def main(): client = L2Network() + """ client.create_portprofile("12345", "tpp1", "2") client.create_portprofile("12345", "tpp2", "3") print ("%s\n") % client.get_all_portprofiles("12345") + """ + if __name__ == '__main__': main() diff --git a/quantum/plugins/cisco/l2network_plugin_configuration.py b/quantum/plugins/cisco/l2network_plugin_configuration.py index fe619ddfcd..81f221f039 100644 --- a/quantum/plugins/cisco/l2network_plugin_configuration.py +++ b/quantum/plugins/cisco/l2network_plugin_configuration.py @@ -40,6 +40,9 @@ MAX_PORT_PROFILES = section['max_port_profiles'] section = cp['NETWORKS'] MAX_NETWORKS = section['max_networks'] +section = cp['MODEL'] +MODEL_CLASS = section['model_class'] + CONF_FILE = "conf/plugins.ini" cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py index 8fa6424f93..fdb4ef4466 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py @@ -25,13 +25,14 @@ from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc from quantum.plugins.cisco.common import cisco_utils as cutil +from quantum.plugins.cisco.l2device_plugin_base import L2DevicePluginBase from quantum.plugins.cisco.nexus import cisco_nexus_configuration as conf LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) -class NexusPlugin(object): +class NexusPlugin(L2DevicePluginBase): _networks = {} def __init__(self): @@ -52,7 +53,8 @@ class NexusPlugin(object): LOG.debug("NexusPlugin:get_all_networks() called\n") return self._networks.values() - def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id): + def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id, + **kwargs): """ Create a VLAN in the switch, and configure the appropriate interfaces for this VLAN @@ -69,7 +71,7 @@ class NexusPlugin(object): self._networks[net_id] = new_net_dict return new_net_dict - def delete_network(self, tenant_id, net_id): + def delete_network(self, tenant_id, net_id, **kwargs): """ Deletes a VLAN in the switch, and removes the VLAN configuration from the relevant interfaces @@ -85,7 +87,7 @@ class NexusPlugin(object): # Network not found raise exc.NetworkNotFound(net_id=net_id) - def get_network_details(self, tenant_id, net_id): + def get_network_details(self, tenant_id, net_id, **kwargs): """ Returns the details of a particular network """ @@ -93,7 +95,7 @@ class NexusPlugin(object): network = self._get_network(tenant_id, net_id) return network - def rename_network(self, tenant_id, net_id, new_name): + def rename_network(self, tenant_id, net_id, new_name, **kwargs): """ Updates the symbolic name belonging to a particular Virtual Network. @@ -104,49 +106,50 @@ class NexusPlugin(object): network[const.NET_NAME] = new_name return network - def get_all_ports(self, tenant_id, net_id): + def get_all_ports(self, tenant_id, net_id, **kwargs): """ This is probably not applicable to the Nexus plugin. Delete if not required. """ LOG.debug("NexusPlugin:get_all_ports() called\n") - def create_port(self, tenant_id, net_id, port_state, port_id): + def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs): """ This is probably not applicable to the Nexus plugin. Delete if not required. """ LOG.debug("NexusPlugin:create_port() called\n") - def delete_port(self, tenant_id, net_id, port_id): + def delete_port(self, tenant_id, net_id, port_id, **kwargs): """ This is probably not applicable to the Nexus plugin. Delete if not required. """ LOG.debug("NexusPlugin:delete_port() called\n") - def update_port(self, tenant_id, net_id, port_id, port_state): + def update_port(self, tenant_id, net_id, port_id, port_state, **kwargs): """ This is probably not applicable to the Nexus plugin. Delete if not required. """ LOG.debug("NexusPlugin:update_port() called\n") - def get_port_details(self, tenant_id, net_id, port_id): + def get_port_details(self, tenant_id, net_id, port_id, **kwargs): """ This is probably not applicable to the Nexus plugin. Delete if not required. """ LOG.debug("NexusPlugin:get_port_details() called\n") - def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id): + def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id, + **kwargs): """ This is probably not applicable to the Nexus plugin. Delete if not required. """ LOG.debug("NexusPlugin:plug_interface() called\n") - def unplug_interface(self, tenant_id, net_id, port_id): + def unplug_interface(self, tenant_id, net_id, port_id, **kwargs): """ This is probably not applicable to the Nexus plugin. Delete if not required. diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py index f7969cab13..ad70c74b57 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py @@ -24,14 +24,15 @@ from quantum.common import utils from quantum.plugins.cisco.common import cisco_constants as const from quantum.plugins.cisco.common import cisco_credentials as cred from quantum.plugins.cisco.common import cisco_exceptions as cexc -from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf from quantum.plugins.cisco.common import cisco_utils as cutil +from quantum.plugins.cisco.l2device_plugin_base import L2DevicePluginBase +from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf LOG.basicConfig(level=LOG.WARN) LOG.getLogger(const.LOGGER_COMPONENT_NAME) -class UCSVICPlugin(object): +class UCSVICPlugin(L2DevicePluginBase): _networks = {} def __init__(self): @@ -45,7 +46,7 @@ class UCSVICPlugin(object): # TODO (Sumit) Make the counter per UCSM self._port_profile_counter = 0 - def get_all_networks(self, tenant_id): + def get_all_networks(self, tenant_id, **kwargs): """ Returns a dictionary containing all for @@ -54,7 +55,8 @@ class UCSVICPlugin(object): LOG.debug("UCSVICPlugin:get_all_networks() called\n") return self._networks.values() - def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id): + def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id, + **kwargs): """ Creates a new Virtual Network, and assigns it a symbolic name. @@ -70,7 +72,7 @@ class UCSVICPlugin(object): self._networks[net_id] = new_net_dict return new_net_dict - def delete_network(self, tenant_id, net_id): + def delete_network(self, tenant_id, net_id, **kwargs): """ Deletes the network with the specified network identifier belonging to the specified tenant. @@ -88,7 +90,7 @@ class UCSVICPlugin(object): return net raise exc.NetworkNotFound(net_id=net_id) - def get_network_details(self, tenant_id, net_id): + def get_network_details(self, tenant_id, net_id, **kwargs): """ Deletes the Virtual Network belonging to a the spec @@ -97,7 +99,7 @@ class UCSVICPlugin(object): network = self._get_network(tenant_id, net_id) return network - def rename_network(self, tenant_id, net_id, new_name): + def rename_network(self, tenant_id, net_id, new_name, **kwargs): """ Updates the symbolic name belonging to a particular Virtual Network. @@ -107,7 +109,7 @@ class UCSVICPlugin(object): network[const.NET_NAME] = new_name return network - def get_all_ports(self, tenant_id, net_id): + def get_all_ports(self, tenant_id, net_id, **kwargs): """ Retrieves all port identifiers belonging to the specified Virtual Network. @@ -117,7 +119,7 @@ class UCSVICPlugin(object): ports_on_net = network[const.NET_PORTS].values() return ports_on_net - def create_port(self, tenant_id, net_id, port_state, port_id): + def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs): """ Creates a port on the specified Virtual Network. """ @@ -145,7 +147,7 @@ class UCSVICPlugin(object): ports[port_id] = new_port_dict return new_port_dict - def delete_port(self, tenant_id, net_id, port_id): + def delete_port(self, tenant_id, net_id, port_id, **kwargs): """ Deletes a port on a specified Virtual Network, if the port contains a remote interface attachment, @@ -172,7 +174,7 @@ class UCSVICPlugin(object): except KeyError: raise exc.PortNotFound(net_id=net_id, port_id=port_id) - def update_port(self, tenant_id, net_id, port_id, port_state): + def update_port(self, tenant_id, net_id, port_id, port_state, **kwargs): """ Updates the state of a port on the specified Virtual Network. """ @@ -182,7 +184,7 @@ class UCSVICPlugin(object): port[const.PORT_STATE] = port_state return port - def get_port_details(self, tenant_id, net_id, port_id): + def get_port_details(self, tenant_id, net_id, port_id, **kwargs): """ This method allows the user to retrieve a remote interface that is attached to this particular port. @@ -190,7 +192,8 @@ class UCSVICPlugin(object): LOG.debug("UCSVICPlugin:get_port_details() called\n") return self._get_port(tenant_id, net_id, port_id) - def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id): + def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id, + **kwargs): """ Attaches a remote interface to the specified port on the specified Virtual Network. @@ -215,7 +218,7 @@ class UCSVICPlugin(object): port_profile[const.PROFILE_VLAN_NAME] = new_vlan_name port_profile[const.PROFILE_VLAN_ID] = new_vlan_id - def unplug_interface(self, tenant_id, net_id, port_id): + def unplug_interface(self, tenant_id, net_id, port_id, **kwargs): """ Detaches a remote interface from the specified port on the specified Virtual Network. From 7b39a29dedc7c201906f31cb3de5eec8ec887b15 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sun, 7 Aug 2011 17:13:33 -0700 Subject: [PATCH 35/48] RHEL limitation updated. --- quantum/plugins/cisco/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index ee03219593..3f02dc5a1b 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -9,7 +9,7 @@ ** Pre-requisities * UCS B200 series blades with M81KR VIC installed. * UCSM 2.0 (Capitola) Build 230 -* RHEL 6.1 +* RHEL 6.1 (Currently UCS support is only on RHEL, Ubuntu will be supporting in upcoming releases) * UCS & VIC installation (support for KVM) - please consult the accompanying installation guide available at: http://wikicentral.cisco.com/display/GROUP/SAVBU+Palo+VM-FEX+for+Linux+KVM * Package python-configobj-4.6.0-3.el6.noarch From fb9e81b380b1be0e59e324b43a2fd594683b3b0a Mon Sep 17 00:00:00 2001 From: Shweta P Date: Mon, 8 Aug 2011 00:01:03 -0700 Subject: [PATCH 36/48] Adding Cisco Unit Tests --- quantum/plugins/cisco/README | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index b77ce22ca8..f3152e75eb 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -106,3 +106,13 @@ mysql -uroot -p nova -e 'create table ports (port_id VARCHA - mysql> create database quantum_l2network; - mysql> use quantum_l2network; + The database and login details must be specified in quantum/plugins/cisco/db/db_conn.ini. + +** Execute the Test cases +* The unit tests are located at quantum/plugins/cisco/tests/unit. They are executed from quantum/plugins/cisco/ using the runtests.py script. + +* Execution of the runtests.py script. + All unit tests + python runtests.py unit + Specific Plugin unit test + python runtests.py unit. + From cc660e0cff0fdaa72f90a8e829dd18cc2643603b Mon Sep 17 00:00:00 2001 From: Shweta P Date: Mon, 8 Aug 2011 00:23:44 -0700 Subject: [PATCH 37/48] Adding Unit Test Cases Now --- quantum/plugins/cisco/run_tests.py | 301 ++++++ quantum/plugins/cisco/tests/unit/__init__.py | 32 + .../cisco/tests/unit/test_l2networkApi.py | 892 ++++++++++++++++++ .../cisco/tests/unit/test_nexus_plugin.py | 282 ++++++ .../cisco/tests/unit/test_ucs_driver.py | 165 ++++ .../cisco/tests/unit/test_ucs_plugin.py | 480 ++++++++++ 6 files changed, 2152 insertions(+) create mode 100644 quantum/plugins/cisco/run_tests.py create mode 100644 quantum/plugins/cisco/tests/unit/__init__.py create mode 100644 quantum/plugins/cisco/tests/unit/test_l2networkApi.py create mode 100644 quantum/plugins/cisco/tests/unit/test_nexus_plugin.py create mode 100644 quantum/plugins/cisco/tests/unit/test_ucs_driver.py create mode 100644 quantum/plugins/cisco/tests/unit/test_ucs_plugin.py diff --git a/quantum/plugins/cisco/run_tests.py b/quantum/plugins/cisco/run_tests.py new file mode 100644 index 0000000000..d63cc34a42 --- /dev/null +++ b/quantum/plugins/cisco/run_tests.py @@ -0,0 +1,301 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 OpenStack, LLC +# 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. + +# Colorizer Code is borrowed from Twisted: +# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Unittest runner for quantum + +To run all test:: + python run_tests.py + +To run all unit tests:: + python run_tests.py unit + +To run all functional tests:: + python run_tests.py functional + +To run a single unit test:: + python run_tests.py unit.test_stores:TestSwiftBackend.test_get + +To run a single functional test:: + python run_tests.py functional.test_service:TestController.test_create + +To run a single unit test module:: + python run_tests.py unit.test_stores + +To run a single functional test module:: + python run_tests.py functional.test_stores +""" + +import gettext +import logging +import os +import unittest +import sys + +from nose import config +from nose import result +from nose import core + + +class _AnsiColorizer(object): + """ + A colorizer is an object that loosely wraps around a stream, allowing + callers to write text to the stream in a particular color. + + Colorizer classes must implement C{supported()} and C{write(text, color)}. + """ + _colors = dict(black=30, red=31, green=32, yellow=33, + blue=34, magenta=35, cyan=36, white=37) + + def __init__(self, stream): + self.stream = stream + + def supported(cls, stream=sys.stdout): + """ + A class method that returns True if the current platform supports + coloring terminal output using this method. Returns False otherwise. + """ + if not stream.isatty(): + return False # auto color only on TTYs + try: + import curses + except ImportError: + return False + else: + try: + try: + return curses.tigetnum("colors") > 2 + except curses.error: + curses.setupterm() + return curses.tigetnum("colors") > 2 + except: + raise + # guess false in case of error + return False + supported = classmethod(supported) + + def write(self, text, color): + """ + Write the given text to the stream in the given color. + + @param text: Text to be written to the stream. + + @param color: A string label for a color. e.g. 'red', 'white'. + """ + color = self._colors[color] + self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text)) + + +class _Win32Colorizer(object): + """ + See _AnsiColorizer docstring. + """ + def __init__(self, stream): + from win32console import GetStdHandle, STD_OUT_HANDLE, \ + FOREGROUND_RED, FOREGROUND_BLUE, FOREGROUND_GREEN, \ + FOREGROUND_INTENSITY + red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN, + FOREGROUND_BLUE, FOREGROUND_INTENSITY) + self.stream = stream + self.screenBuffer = GetStdHandle(STD_OUT_HANDLE) + self._colors = { + 'normal': red | green | blue, + 'red': red | bold, + 'green': green | bold, + 'blue': blue | bold, + 'yellow': red | green | bold, + 'magenta': red | blue | bold, + 'cyan': green | blue | bold, + 'white': red | green | blue | bold} + + def supported(cls, stream=sys.stdout): + try: + import win32console + screenBuffer = win32console.GetStdHandle( + win32console.STD_OUT_HANDLE) + except ImportError: + return False + import pywintypes + try: + screenBuffer.SetConsoleTextAttribute( + win32console.FOREGROUND_RED | + win32console.FOREGROUND_GREEN | + win32console.FOREGROUND_BLUE) + except pywintypes.error: + return False + else: + return True + supported = classmethod(supported) + + def write(self, text, color): + color = self._colors[color] + self.screenBuffer.SetConsoleTextAttribute(color) + self.stream.write(text) + self.screenBuffer.SetConsoleTextAttribute(self._colors['normal']) + + +class _NullColorizer(object): + """ + See _AnsiColorizer docstring. + """ + def __init__(self, stream): + self.stream = stream + + def supported(cls, stream=sys.stdout): + return True + supported = classmethod(supported) + + def write(self, text, color): + self.stream.write(text) + + +class QuantumTestResult(result.TextTestResult): + def __init__(self, *args, **kw): + result.TextTestResult.__init__(self, *args, **kw) + self._last_case = None + self.colorizer = None + # NOTE(vish, tfukushima): reset stdout for the terminal check + stdout = sys.__stdout__ + for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]: + if colorizer.supported(): + self.colorizer = colorizer(self.stream) + break + sys.stdout = stdout + + def getDescription(self, test): + return str(test) + + # NOTE(vish, tfukushima): copied from unittest with edit to add color + def addSuccess(self, test): + unittest.TestResult.addSuccess(self, test) + if self.showAll: + self.colorizer.write("OK", 'green') + self.stream.writeln() + elif self.dots: + self.stream.write('.') + self.stream.flush() + + # NOTE(vish, tfukushima): copied from unittest with edit to add color + def addFailure(self, test, err): + unittest.TestResult.addFailure(self, test, err) + if self.showAll: + self.colorizer.write("FAIL", 'red') + self.stream.writeln() + elif self.dots: + self.stream.write('F') + self.stream.flush() + + # NOTE(vish, tfukushima): copied from unittest with edit to add color + def addError(self, test, err): + """Overrides normal addError to add support for errorClasses. + If the exception is a registered class, the error will be added + to the list for that class, not errors. + """ + stream = getattr(self, 'stream', None) + ec, ev, tb = err + try: + exc_info = self._exc_info_to_string(err, test) + except TypeError: + # This is for compatibility with Python 2.3. + exc_info = self._exc_info_to_string(err) + for cls, (storage, label, isfail) in self.errorClasses.items(): + if result.isclass(ec) and issubclass(ec, cls): + if isfail: + test.passwd = False + storage.append((test, exc_info)) + # Might get patched into a streamless result + if stream is not None: + if self.showAll: + message = [label] + detail = result._exception_details(err[1]) + if detail: + message.append(detail) + stream.writeln(": ".join(message)) + elif self.dots: + stream.write(label[:1]) + return + self.errors.append((test, exc_info)) + test.passed = False + if stream is not None: + if self.showAll: + self.colorizer.write("ERROR", 'red') + self.stream.writeln() + elif self.dots: + stream.write('E') + + def startTest(self, test): + unittest.TestResult.startTest(self, test) + current_case = test.test.__class__.__name__ + + if self.showAll: + if current_case != self._last_case: + self.stream.writeln(current_case) + self._last_case = current_case + + self.stream.write( + ' %s' % str(test.test._testMethodName).ljust(60)) + self.stream.flush() + + +class QuantumTestRunner(core.TextTestRunner): + def _makeResult(self): + return QuantumTestResult(self.stream, + self.descriptions, + self.verbosity, + self.config) + + +if __name__ == '__main__': + # Set up test logger. + logger = logging.getLogger() + hdlr = logging.StreamHandler() + formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') + hdlr.setFormatter(formatter) + logger.addHandler(hdlr) + logger.setLevel(logging.DEBUG) + + working_dir = os.path.abspath("tests") + c = config.Config(stream=sys.stdout, + env=os.environ, + verbosity=3, + workingDir=working_dir) + runner = QuantumTestRunner(stream=c.stream, + verbosity=c.verbosity, + config=c) + sys.exit(not core.run(config=c, testRunner=runner)) diff --git a/quantum/plugins/cisco/tests/unit/__init__.py b/quantum/plugins/cisco/tests/unit/__init__.py new file mode 100644 index 0000000000..5910e35494 --- /dev/null +++ b/quantum/plugins/cisco/tests/unit/__init__.py @@ -0,0 +1,32 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# 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. + +# See http://code.google.com/p/python-nose/issues/detail?id=373 +# The code below enables nosetests to work with i18n _() blocks +import __builtin__ +import unittest +setattr(__builtin__, '_', lambda x: x) + + +class BaseTest(unittest.TestCase): + + def setUp(self): + pass + + +def setUp(): + pass diff --git a/quantum/plugins/cisco/tests/unit/test_l2networkApi.py b/quantum/plugins/cisco/tests/unit/test_l2networkApi.py new file mode 100644 index 0000000000..9cd619ef64 --- /dev/null +++ b/quantum/plugins/cisco/tests/unit/test_l2networkApi.py @@ -0,0 +1,892 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Shweta Padubidri, Cisco Systems, Inc. +# + +import logging +import unittest +from quantum.common import exceptions as exc +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.common import cisco_exceptions as cexc +from quantum.plugins.cisco import l2network_plugin +from quantum.plugins.cisco import l2network_plugin_configuration as conf + +LOG = logging.getLogger('quantum.tests.test_core_api_func') + + +class CoreAPITestFunc(unittest.TestCase): + + def test_create_network(self, net_tenant_id=None, net_name=None): + + """ + Tests creation of new Virtual Network. + """ + + LOG.debug("test_create_network - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + if net_name: + network_name = net_name + else: + network_name = self.network_name + new_net_dict = self._l2network_plugin.create_network( + tenant_id, network_name) + self.assertEqual(new_net_dict[const.NET_NAME], network_name) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_create_network - END") + + def test_delete_network(self, net_tenant_id=None): + """ + Tests deletion of a Virtual Network. + """ + LOG.debug("test_delete_network - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + delete_net_dict = self._l2network_plugin.delete_network( + tenant_id, new_net_dict[const.NET_ID]) + self.assertEqual( + new_net_dict[const.NET_ID], delete_net_dict[const.NET_ID]) + LOG.debug("test_delete_network - END") + + def test_delete_networkDNE(self, net_tenant_id=None, net_id='0005'): + """ + Tests deletion of a Virtual Network when Network does not exist. + """ + LOG.debug("test_delete_network_not_found - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + self.assertRaises( + exc.NetworkNotFound, self._l2network_plugin.delete_network, + tenant_id, net_id) + LOG.debug("test_delete_network_not_found - END") + + def test_delete_networkInUse(self, tenant_id='test_network'): + """ + Tests deletion of a Virtual Network when Network is in Use. + """ + LOG.debug("test_delete_networkInUse - START") + + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + port_dict = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], self.port_state) + self._l2network_plugin.plug_interface( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID], self.remote_interface) + self.assertRaises(exc.NetworkInUse, + self._l2network_plugin.delete_network, tenant_id, + new_net_dict[const.NET_ID]) + self.tearDownNetworkPortInterface( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + LOG.debug("test_delete_networkInUse - END") + + def test_show_network(self, net_tenant_id=None): + """ + Tests display of details of a Virtual Network . + """ + + LOG.debug("test_show_network - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + result_net_dict = self._l2network_plugin.get_network_details( + tenant_id, new_net_dict[const.NET_ID]) + self.assertEqual( + new_net_dict[const.NET_ID], result_net_dict[const.NET_ID]) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_show_network - END") + + def test_show_networkDNE(self, net_tenant_id=None, net_id='0005'): + """ + Tests display of a Virtual Network when Network does not exist. + """ + + LOG.debug("test_show_network_not_found - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + self.assertRaises(exc.NetworkNotFound, + self._l2network_plugin.get_network_details, + tenant_id, net_id) + LOG.debug("test_show_network_not_found - END") + + def test_rename_network(self, net_tenant_id=None, + new_name='new_test_network'): + """ + Tests rename of a Virtual Network . + """ + + LOG.debug("test_rename_network - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + rename_net_dict = self._l2network_plugin.rename_network( + tenant_id, new_net_dict[const.NET_ID], new_name) + self.assertEqual(new_name, rename_net_dict[const.NET_NAME]) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_rename_network - END") + + def test_rename_networkDNE(self, net_tenant_id=None, + net_id='0005', new_name='new_test_network'): + """ + Tests rename of a Virtual Network when Network does not exist. + """ + + LOG.debug("test_rename_network_not_found - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + self.assertRaises(exc.NetworkNotFound, + self._l2network_plugin.rename_network, + tenant_id, net_id, new_name) + LOG.debug("test_rename_network_not_found - END") + + def test_list_networks(self, tenant_id='test_network'): + """ + Tests listing of all the Virtual Networks . + """ + + LOG.debug("test_list_networks - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + new_net_dict2 = self._l2network_plugin.create_network( + tenant_id, 'test_net2') + net_list = self._l2network_plugin.get_all_networks(tenant_id) + net_temp_list = [new_net_dict, new_net_dict2] + self.assertEqual(len(net_list), 2) + self.assertTrue(net_list[0] in net_temp_list) + self.assertTrue(net_list[1] in net_temp_list) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + self.tearDownNetwork(tenant_id, new_net_dict2[const.NET_ID]) + LOG.debug("test_list_networks - END") + + def test_list_ports(self, tenant_id='test_network'): + """ + Tests listing of all the Ports. + """ + + LOG.debug("test_list_ports - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + port_dict = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], self.port_state) + port_dict2 = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], self.port_state) + port_list = self._l2network_plugin.get_all_ports( + tenant_id, new_net_dict[const.NET_ID]) + port_temp_list = [port_dict, port_dict2] + self.assertEqual(len(port_list), 2) + self.assertTrue(port_list[0] in port_temp_list) + self.assertTrue(port_list[1] in port_temp_list) + + self.tearDownPortOnly(tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID], + port_dict2[const.PORT_ID]) + LOG.debug("test_list_ports - END") + + def test_create_port(self, tenant_id='test_network', + port_state=const.PORT_UP): + """ + Tests creation of Ports. + """ + + LOG.debug("test_create_port - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + port_dict = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], port_state) + self.assertEqual(port_dict[const.PORT_STATE], port_state) + self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + LOG.debug("test_create_port - END") + + def test_create_port_network_DNE( + self, net_tenant_id=None, net_id='0005', port_state=const.PORT_UP): + + """ + Tests creation of Ports when network does not exist. + """ + + LOG.debug("test_create_port_network_DNE - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + self.assertRaises(exc.NetworkNotFound, + self._l2network_plugin.create_port, + tenant_id, net_id, port_state) + LOG.debug("test_create_port_network_DNE - END:") + + def test_delete_port(self, tenant_id='test_tenant', + port_state=const.PORT_UP): + """ + Tests deletion of Ports + """ + + LOG.debug("test_delete_port - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + port_dict = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], port_state) + delete_port_dict = self._l2network_plugin.delete_port( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + self.assertEqual(delete_port_dict, None) + LOG.debug("test_delete_port - END") + + def test_delete_port_networkDNE(self, tenant_id='test_tenant', + net_id='0005', port_id='p0005'): + """ + Tests deletion of Ports when network does not exist. + """ + + LOG.debug("test_delete_port_networkDNE - START") + self.assertRaises(exc.NetworkNotFound, + self._l2network_plugin.delete_port, tenant_id, + net_id, port_id) + LOG.debug("test_delete_port_networkDNE - END") + + def test_delete_portDNE(self, tenant_id='test_tenant', port_id='p0005'): + """ + Tests deletion of Ports when port does not exist. + """ + + LOG.debug("test_delete_portDNE - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + self.assertRaises(exc.PortNotFound, self._l2network_plugin.delete_port, + tenant_id, new_net_dict[const.NET_ID], port_id) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_delete_portDNE - END") + + def test_delete_portInUse(self, tenant_id='test_tenant'): + """ + Tests deletion of Ports when port is in Use. + """ + + LOG.debug("test_delete_portInUse - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + port_dict = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], + self.port_state) + self._l2network_plugin.plug_interface( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID], self.remote_interface) + self.assertRaises(exc.PortInUse, + self._l2network_plugin.delete_port, tenant_id, + new_net_dict[const.NET_ID], port_dict[const.PORT_ID]) + self.tearDownNetworkPortInterface( + tenant_id, new_net_dict[const.NET_ID], port_dict[const.PORT_ID]) + LOG.debug("test_delete_portInUse - END") + + def test_update_port(self, tenant_id='test_tenant', + port_state=const.PORT_DOWN): + """ + Tests updation of Ports. + """ + + LOG.debug("test_update_port - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + port_dict = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], self.port_state) + update_port_dict = self._l2network_plugin.update_port( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID], port_state) + self.assertEqual(update_port_dict[const.PORT_STATE], port_state) + self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + LOG.debug("test_update_port - END") + + def test_update_port_networkDNE(self, tenant_id='test_tenant', + net_id='0005', port_id='p0005'): + """ + Tests updation of Ports when network does not exist. + """ + + LOG.debug("test_update_port_networkDNE - START") + self.assertRaises(exc.NetworkNotFound, + self._l2network_plugin.update_port, tenant_id, + net_id, port_id, self.port_state) + LOG.debug("test_update_port_networkDNE - END") + + def test_update_portDNE(self, tenant_id='test_tenant', port_id='p0005'): + """ + Tests updation of Ports when port does not exist. + """ + + LOG.debug("test_update_portDNE - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + self.assertRaises( + exc.PortNotFound, self._l2network_plugin.update_port, tenant_id, + new_net_dict[const.NET_ID], port_id, self.port_state) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_update_portDNE - END") + + def test_show_port(self, tenant_id='test_tenant'): + """ + Tests display of Ports + """ + + LOG.debug("test_show_port - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + port_dict = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], self.port_state) + get_port_dict = self._l2network_plugin.get_port_details( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + self.assertEqual(get_port_dict[const.PORT_STATE], self.port_state) + self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + LOG.debug("test_show_port - END") + + def test_show_port_networkDNE(self, tenant_id='test_tenant', + net_id='0005', port_id='p0005'): + """ + Tests display of Ports when network does not exist + """ + + LOG.debug("test_show_port_networkDNE - START") + self.assertRaises(exc.NetworkNotFound, + self._l2network_plugin.get_port_details, + tenant_id, net_id, port_id) + LOG.debug("test_show_port_networkDNE - END") + + def test_show_portDNE(self, tenant_id='test_tenant', port_id='p0005'): + """ + Tests display of Ports when port does not exist + """ + + LOG.debug("test_show_portDNE - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + self.assertRaises(exc.PortNotFound, + self._l2network_plugin.get_port_details, tenant_id, + new_net_dict[const.NET_ID], port_id) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_show_portDNE - END") + + def test_plug_interface(self, tenant_id='test_tenant', + remote_interface='new_interface'): + """ + Tests attachment of interface to the port + """ + + LOG.debug("test_plug_interface - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + port_dict = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], self.port_state) + self._l2network_plugin.plug_interface( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID], remote_interface) + self.assertEqual( + self._l2network_plugin._networks[new_net_dict[const.NET_ID]] + [const.NET_PORTS][port_dict[const.PORT_ID]] + [const.ATTACHMENT], remote_interface) + self.tearDownNetworkPortInterface( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + LOG.debug("test_plug_interface - END") + + def test_plug_interface_networkDNE( + self, tenant_id='test_tenant', net_id='0005', + port_id='p0005', remote_interface='new_interface'): + """ + Tests attachment of interface network does not exist + """ + + LOG.debug("test_plug_interface_networkDNE - START") + self.assertRaises(exc.NetworkNotFound, + self._l2network_plugin.plug_interface, tenant_id, + net_id, port_id, remote_interface) + LOG.debug("test_plug_interface_networkDNE - END") + + def test_plug_interface_portDNE(self, tenant_id='test_tenant', + port_id='p0005', + remote_interface='new_interface'): + """ + Tests attachment of interface port does not exist + """ + + LOG.debug("test_plug_interface_portDNE - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + self.assertRaises( + exc.PortNotFound, self._l2network_plugin.plug_interface, tenant_id, + new_net_dict[const.NET_ID], port_id, remote_interface) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_plug_interface_portDNE - END") + + def test_plug_interface_portInUse(self, tenant_id='test_tenant', + remote_interface='new_interface'): + + """ + Tests attachment of new interface to the port when there is an + existing attachment + """ + + LOG.debug("test_plug_interface_portInUse - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + port_dict = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], self.port_state) + self._l2network_plugin.plug_interface( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID], remote_interface) + self.assertRaises(exc.AlreadyAttached, + self._l2network_plugin.plug_interface, tenant_id, + new_net_dict[const.NET_ID], + port_dict[const.PORT_ID], remote_interface) + self.tearDownNetworkPortInterface( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + LOG.debug("test_plug_interface_portInUse - END") + + def test_unplug_interface(self, tenant_id='test_tenant'): + """ + Tests detaachment of an interface to a port + """ + + LOG.debug("test_unplug_interface - START") + new_net_dict = self._l2network_plugin.create_network( + tenant_id, self.network_name) + port_dict = self._l2network_plugin.create_port( + tenant_id, new_net_dict[const.NET_ID], + self.port_state) + self._l2network_plugin.plug_interface( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID], self.remote_interface) + self._l2network_plugin.unplug_interface( + tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + self.assertEqual(self._l2network_plugin._networks + [new_net_dict[const.NET_ID]][const.NET_PORTS] + [port_dict[const.PORT_ID]][const.ATTACHMENT], None) + self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID], + port_dict[const.PORT_ID]) + LOG.debug("test_unplug_interface - END") + + def test_unplug_interface_networkDNE(self, tenant_id='test_tenant', + net_id='0005', port_id='p0005'): + """ + Tests detaachment of an interface to a port, when the network does + not exist + """ + + LOG.debug("test_unplug_interface_networkDNE - START") + self.assertRaises(exc.NetworkNotFound, + self._l2network_plugin.unplug_interface, + tenant_id, net_id, port_id) + LOG.debug("test_unplug_interface_networkDNE - END") + + def test_unplug_interface_portDNE(self, tenant_id='test_tenant', + port_id='p0005'): + """ + Tests detaachment of an interface to a port, when the port does + not exist + """ + + LOG.debug("test_unplug_interface_portDNE - START") + new_net_dict = self._l2network_plugin.create_network(tenant_id, + self.network_name) + self.assertRaises(exc.PortNotFound, + self._l2network_plugin.unplug_interface, tenant_id, + new_net_dict[const.NET_ID], port_id) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_unplug_interface_portDNE - END") + + def test_create_portprofile(self, net_tenant_id=None, + net_profile_name=None, net_vlan_id=None): + """ + Tests creation of a port-profile + """ + + LOG.debug("test_create_portprofile - tenant id: %s - START", + net_tenant_id) + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + if net_profile_name: + profile_name = net_profile_name + else: + profile_name = self.profile_name + if net_vlan_id: + vlan_id = net_vlan_id + else: + vlan_id = self.vlan_id + port_profile_dict = self._l2network_plugin.create_portprofile( + tenant_id, profile_name, vlan_id) + port_profile_id = port_profile_dict['profile-id'] + self.assertEqual( + self._l2network_plugin._portprofiles[port_profile_id]['vlan-id'], + vlan_id) + self.assertEqual( + self._l2network_plugin._portprofiles[port_profile_id] + ['profile-name'], profile_name) + self.tearDownPortProfile(tenant_id, port_profile_id) + LOG.debug("test_create_portprofile - tenant id: %s - END", + net_tenant_id) + + def test_delete_portprofile(self, net_tenant_id=None): + """ + Tests deletion of a port-profile + """ + + LOG.debug("test_delete_portprofile - tenant id: %s - START", + net_tenant_id) + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + port_profile_dict = self._l2network_plugin.create_portprofile( + tenant_id, self.profile_name, self.vlan_id) + port_profile_id = port_profile_dict['profile-id'] + self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id) + self.assertEqual(self._l2network_plugin._portprofiles, {}) + LOG.debug("test_delete_portprofile - tenant id: %s - END", + net_tenant_id) + + def test_delete_portprofileDNE(self, tenant_id='test_tenant', + profile_id='pr0005'): + """ + Tests deletion of a port-profile when netowrk does not exist + """ + + LOG.debug("test_delete_portprofileDNE - START") + self.assertRaises(cexc.PortProfileNotFound, + self._l2network_plugin.delete_portprofile, + tenant_id, profile_id) + LOG.debug("test_delete_portprofileDNE - END") + + def test_delete_portprofileAssociated(self, tenant_id='test_tenant'): + + """ + Tests deletion of an associatedport-profile + """ + + LOG.debug("test_delete_portprofileAssociated - START") + port_profile_dict = self._l2network_plugin.create_portprofile( + tenant_id, self.profile_name, self.vlan_id) + port_profile_id = port_profile_dict['profile-id'] + self._l2network_plugin.associate_portprofile( + tenant_id, self.net_id, self.port_id, port_profile_id) + self.assertRaises(cexc.PortProfileInvalidDelete, + self._l2network_plugin.delete_portprofile, + tenant_id, port_profile_id) + self.tearDownAssociatePortProfile(tenant_id, self.net_id, + self.port_id, port_profile_id) + LOG.debug("test_delete_portprofileAssociated - END") + + def test_list_portprofile(self, tenant_id='test_tenant'): + """ + Tests listing of port-profiles + """ + + LOG.debug("test_list_portprofile - tenant id: %s - START", tenant_id) + profile_name2 = tenant_id + '_port_profile2' + vlan_id2 = tenant_id + '201' + port_profile_dict1 = self._l2network_plugin.create_portprofile( + tenant_id, self.profile_name, self.vlan_id) + port_profile_dict2 = self._l2network_plugin.create_portprofile( + tenant_id, profile_name2, vlan_id2) + port_profile_id1 = port_profile_dict1['profile-id'] + port_profile_id2 = port_profile_dict2['profile-id'] + list_all_portprofiles = self._l2network_plugin.get_all_portprofiles( + tenant_id) + self.assertEqual(self._l2network_plugin._portprofiles + [port_profile_id1]['vlan-id'], self.vlan_id) + self.assertEqual(self._l2network_plugin._portprofiles + [port_profile_id1]['profile-name'], self.profile_name) + self.assertEqual(self._l2network_plugin._portprofiles + [port_profile_id2]['vlan-id'], vlan_id2) + self.assertEqual(self._l2network_plugin._portprofiles + [port_profile_id2]['profile-name'], profile_name2) + LOG.debug("test_create_portprofile - tenant id: %s - END", tenant_id) + + def test_show_portprofile(self, net_tenant_id=None): + """ + Tests display of a port-profile + """ + + LOG.debug("test_show_portprofile - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + port_profile_dict = self._l2network_plugin.create_portprofile( + tenant_id, self.profile_name, self.vlan_id) + port_profile_id = port_profile_dict['profile-id'] + result_port_profile = self._l2network_plugin.get_portprofile_details( + tenant_id, port_profile_id) + self.assertEqual(result_port_profile[const.PROFILE_VLAN_ID], + self.vlan_id) + self.assertEqual(result_port_profile[const.PROFILE_NAME], + self.profile_name) + self.tearDownPortProfile(tenant_id, port_profile_id) + LOG.debug("test_show_portprofile - tenant id: %s - END", net_tenant_id) + + def test_show_portprofileDNE(self, tenant_id='test_tenant', + profile_id='pr0005'): + """ + Tests display of a port-profile when network does not exist + """ + + LOG.debug("test_show_portprofileDNE - START") + self.assertRaises(cexc.PortProfileNotFound, + self._l2network_plugin.get_portprofile_details, + tenant_id, profile_id) + LOG.debug("test_show_portprofileDNE - END") + + def test_rename_portprofile(self, tenant_id='test_tenant', + new_profile_name='new_profile_name'): + """ + Tests rename of a port-profile + """ + + LOG.debug("test_rename_portprofile - START") + port_profile_dict = self._l2network_plugin.create_portprofile( + tenant_id, self.profile_name, self.vlan_id) + port_profile_id = port_profile_dict['profile-id'] + result_port_profile_dict = self._l2network_plugin.rename_portprofile( + tenant_id, port_profile_id, new_profile_name) + self.assertEqual(result_port_profile_dict[const.PROFILE_NAME], + new_profile_name) + self.tearDownPortProfile(tenant_id, port_profile_id) + LOG.debug("test_show_portprofile - tenant id: %s - END") + + def test_rename_portprofileDNE(self, tenant_id='test_tenant', + profile_id='pr0005', + new_profile_name='new_profile_name'): + """ + Tests rename of a port-profile when network does not exist + """ + + LOG.debug("test_rename_portprofileDNE - START") + self.assertRaises(cexc.PortProfileNotFound, + self._l2network_plugin.rename_portprofile, + tenant_id, profile_id, new_profile_name) + LOG.debug("test_rename_portprofileDNE - END") + + def test_associate_portprofile(self, tenant_id='test_tenant', + net_id='0005', port_id='p00005'): + """ + Tests association of a port-profile + """ + + LOG.debug("test_associate_portprofile - START") + port_profile_dict = self._l2network_plugin.create_portprofile( + tenant_id, self.profile_name, self.vlan_id) + port_profile_id = port_profile_dict['profile-id'] + self._l2network_plugin.associate_portprofile( + tenant_id, net_id, port_id, port_profile_id) + self.assertEqual( + self._l2network_plugin._portprofiles[port_profile_id] + [const.PROFILE_ASSOCIATIONS][0], port_id) + self.tearDownAssociatePortProfile(tenant_id, net_id, + port_id, port_profile_id) + LOG.debug("test_associate_portprofile - END") + + def test_associate_portprofileDNE(self, tenant_id='test_tenant', + net_id='0005', port_id='p00005', + profile_id='pr0005'): + """ + Tests association of a port-profile when a network does not exist + """ + + LOG.debug("test_associate_portprofileDNE - START") + self.assertRaises(cexc.PortProfileNotFound, + self._l2network_plugin.associate_portprofile, + tenant_id, net_id, port_id, profile_id) + LOG.debug("test_associate_portprofileDNE - END") + + def test_disassociate_portprofile(self, tenant_id='test_tenant', + net_id='0005', port_id='p00005'): + """ + Tests disassociation of a port-profile + """ + + LOG.debug("test_disassociate_portprofile - START") + port_profile_dict = self._l2network_plugin.create_portprofile( + tenant_id, self.profile_name, self.vlan_id) + port_profile_id = port_profile_dict['profile-id'] + self._l2network_plugin.associate_portprofile(tenant_id, net_id, + port_id, port_profile_id) + self._l2network_plugin.disassociate_portprofile( + tenant_id, net_id, port_id, port_profile_id) + self.assertEqual(self._l2network_plugin._portprofiles + [port_profile_id][const.PROFILE_ASSOCIATIONS], []) + self.tearDownPortProfile(tenant_id, port_profile_id) + LOG.debug("test_disassociate_portprofile - END") + + def test_disassociate_portprofileDNE(self, tenant_id='test_tenant', + net_id='0005', port_id='p00005', profile_id='pr0005'): + """ + Tests disassociation of a port-profile when network does not exist + """ + + LOG.debug("test_disassociate_portprofileDNE - START") + self.assertRaises(cexc.PortProfileNotFound, + self._l2network_plugin.disassociate_portprofile, + tenant_id, net_id, port_id, profile_id) + LOG.debug("test_disassociate_portprofileDNE - END") + +# def test_disassociate_portprofile_Unassociated + + def test_get_tenant(self, net_tenant_id=None): + """ + Tests get tenant + """ + + LOG.debug("test_get_tenant - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + tenant_dict = self._l2network_plugin._get_tenant(tenant_id) + self.assertEqual(tenant_dict[const.TENANT_ID], tenant_id) + self.assertEqual(tenant_dict[const.TENANT_NAME], tenant_id) + LOG.debug("test_get_tenant - END") + + def test_get_vlan_name(self, net_tenant_id=None, vlan_name="NewVlan", + vlan_prefix=conf.VLAN_NAME_PREFIX): + """ + Tests get vlan name + """ + + LOG.debug("test_get_vlan_name - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + result_vlan_name = self._l2network_plugin._get_vlan_name(tenant_id, + vlan_name) + expected_output = vlan_prefix + tenant_id + "-" + vlan_name + self.assertEqual(result_vlan_name, expected_output) + LOG.debug("test_get_vlan_name - END") + + def test_validate_port_state(self, port_state=const.PORT_UP): + """ + Tests validate port state + """ + + LOG.debug("test_validate_port_state - START") + result = self._l2network_plugin._validate_port_state(port_state) + self.assertEqual(result, True) + LOG.debug("test_validate_port_state - END") + + def test_invalid_port_state(self, port_state="BADSTATE"): + """ + Tests invalidate port state + """ + + LOG.debug("test_validate_port_state - START") + self.assertRaises(exc.StateInvalid, + self._l2network_plugin._validate_port_state, + port_state) + LOG.debug("test_validate_port_state - END") + + def test_validate_attachment(self, net_tenant_id=None, + remote_interface_id="new_interface"): + """ + Tests validate attachment + """ + + LOG.debug("test_validate_attachment - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + net_name = self.network_name + new_network_dict = self._l2network_plugin.create_network(tenant_id, + net_name) + network_id = new_network_dict[const.NET_ID] + new_port_dict = self._l2network_plugin.create_port(tenant_id, + network_id) + port_id = new_port_dict[const.PORT_ID] + self._l2network_plugin.plug_interface( + tenant_id, new_network_dict[const.NET_ID], port_id, + remote_interface_id) + self.assertRaises(exc.AlreadyAttached, + self._l2network_plugin._validate_attachment, + tenant_id, network_id, port_id, remote_interface_id) + self.tearDownNetworkPortInterface( + tenant_id, new_network_dict[const.NET_ID], port_id) + LOG.debug("test_validate_attachment - END") + + def setUp(self): + self.tenant_id = "test_tenant" + self.network_name = "test_network" + self.profile_name = "test_tenant_port_profile" + self.vlan_id = "test_tenant_vlanid300" + self.port_state = const.PORT_UP + self.net_id = '00005' + self.port_id = 'p0005' + self.remote_interface = 'new_interface' + self._l2network_plugin = l2network_plugin.L2Network() + + """ + Clean up functions after the tests + """ + + def tearDownNetwork(self, tenant_id, network_dict_id): + self._l2network_plugin.delete_network(tenant_id, network_dict_id) + + def tearDownPortOnly(self, tenant_id, network_dict_id, port_id): + self._l2network_plugin.delete_port(tenant_id, network_dict_id, port_id) + + def tearDownNetworkPort(self, tenant_id, network_dict_id, port_id): + self._l2network_plugin.delete_port(tenant_id, network_dict_id, port_id) + self.tearDownNetwork(tenant_id, network_dict_id) + + def tearDownNetworkPortInterface(self, tenant_id, network_dict_id, + port_id): + self._l2network_plugin.unplug_interface(tenant_id, + network_dict_id, port_id) + self.tearDownNetworkPort(tenant_id, network_dict_id, port_id) + + def tearDownPortProfile(self, tenant_id, port_profile_id): + self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id) + + def tearDownAssociatePortProfile(self, tenant_id, net_id, port_id, + port_profile_id): + self._l2network_plugin.disassociate_portprofile( + tenant_id, net_id, port_id, port_profile_id) + self.tearDownPortProfile(tenant_id, port_profile_id) diff --git a/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py new file mode 100644 index 0000000000..013d798940 --- /dev/null +++ b/quantum/plugins/cisco/tests/unit/test_nexus_plugin.py @@ -0,0 +1,282 @@ +# copyright 2011 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. +# +# @author: Shweta Padubidri, Peter Strunk, Cisco Systems, Inc. +# +import unittest +import logging +from quantum.common import exceptions as exc +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.nexus import cisco_nexus_plugin + +LOG = logging.getLogger('quantum.tests.test_nexus') + + +class TestNexusPlugin(unittest.TestCase): + + def setUp(self): + + self.tenant_id = "test_tenant_cisco1" + self.net_name = "test_network_cisco1" + self.net_id = 000007 + self.vlan_name = "q-" + str(self.net_id) + "vlan" + self.vlan_id = 267 + self.port_id = "9" + self._cisco_nexus_plugin = cisco_nexus_plugin.NexusPlugin() + + def test_create_network(self, net_tenant_id=None, network_name=None, + network_id=None, net_vlan_name=None, + net_vlan_id=None): + """ + Tests creation of new Virtual Network. + """ + + LOG.debug("test_create_network - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + if network_name: + net_name = network_name + else: + net_name = self.net_name + if network_id: + net_id = network_id + else: + net_id = self.net_id + if net_vlan_name: + vlan_name = net_vlan_name + else: + vlan_name = self.vlan_name + if net_vlan_id: + vlan_id = net_vlan_id + else: + vlan_id = self.vlan_id + + new_net_dict = self._cisco_nexus_plugin.create_network( + tenant_id, net_name, net_id, vlan_name, vlan_id) + + self.assertEqual(new_net_dict[const.NET_ID], self.net_id) + self.assertEqual(new_net_dict[const.NET_NAME], self.net_name) + self.assertEqual(new_net_dict[const.NET_VLAN_NAME], self.vlan_name) + self.assertEqual(new_net_dict[const.NET_VLAN_ID], self.vlan_id) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_create_network - END") + + def test_delete_network(self, net_tenant_id=None, network_id=None): + """ + Tests deletion of a Virtual Network. + """ + + LOG.debug("test_delete_network - START") + + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + if network_id: + net_id = network_id + else: + net_id = self.net_id + + new_net_dict = self._cisco_nexus_plugin.create_network( + tenant_id, self.net_name, net_id, self.vlan_name, self.vlan_id) + deleted_net_dict = self._cisco_nexus_plugin.delete_network( + tenant_id, new_net_dict[const.NET_ID]) + self.assertEqual(deleted_net_dict[const.NET_ID], net_id) + LOG.debug("test_delete_network - END") + + def test_delete_network_DNE(self, net_tenant_id=None, net_id='0005'): + """ + Tests deletion of a Virtual Network when Network does not exist. + """ + + LOG.debug("test_delete_network_DNE - START") + + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + + self.assertRaises(exc.NetworkNotFound, + self._cisco_nexus_plugin.delete_network, + tenant_id, net_id) + + LOG.debug("test_delete_network_DNE - END") + + def test_get_network_details(self, net_tenant_id=None, network_id=None): + """ + Tests displays details of a Virtual Network . + """ + + LOG.debug("test_get_network_details - START") + + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + if network_id: + net_id = network_id + else: + net_id = self.net_id + + new_net_dict = self._cisco_nexus_plugin.create_network( + tenant_id, self.net_name, net_id, self.vlan_name, self.vlan_id) + check_net_dict = self._cisco_nexus_plugin.get_network_details( + tenant_id, net_id) + + self.assertEqual(check_net_dict[const.NET_ID], net_id) + self.assertEqual(check_net_dict[const.NET_NAME], self.net_name) + self.assertEqual(check_net_dict[const.NET_VLAN_NAME], self.vlan_name) + self.assertEqual(check_net_dict[const.NET_VLAN_ID], self.vlan_id) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_get_network_details - END") + + def test_get_networkDNE(self, net_tenant_id=None, net_id='0005'): + """ + Tests display of a Virtual Network when Network does not exist. + """ + + LOG.debug("test_get_network_details_network_does_not_exist - START") + + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + + self.assertRaises(exc.NetworkNotFound, + self._cisco_nexus_plugin.get_network_details, + tenant_id, net_id) + + LOG.debug("test_get_network_details_network_does_not_exist - END") + + def test_rename_network(self, new_name="new_network_name", + net_tenant_id=None, network_id=None): + """ + Tests rename of a Virtual Network . + """ + + LOG.debug("test_rename_network - START") + + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + if network_id: + net_id = network_id + else: + net_id = self.net_id + + new_net_dict = self._cisco_nexus_plugin.create_network( + tenant_id, self.net_name, net_id, self.vlan_name, + self.vlan_id) + rename_net_dict = self._cisco_nexus_plugin.rename_network( + tenant_id, new_net_dict[const.NET_ID], new_name) + self.assertEqual(rename_net_dict[const.NET_NAME], new_name) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_rename_network - END") + + def test_rename_network_DNE(self, new_name="new_network_name", + net_tenant_id=None, network_id='0005'): + """ + Tests rename of a Virtual Network when Network does not exist. + """ + + LOG.debug("test_rename_network_DNE - START") + + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + if network_id: + net_id = network_id + else: + net_id = self.net_id + + self.assertRaises(exc.NetworkNotFound, + self._cisco_nexus_plugin.rename_network, + new_name, tenant_id, net_id) + + LOG.debug("test_rename_network_DNE - END") + + def test_list_all_networks(self, net_tenant_id=None): + """ + Tests listing of all the Virtual Networks . + """ + + LOG.debug("test_list_all_networks - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + new_net_dict1 = self._cisco_nexus_plugin.create_network( + tenant_id, self.net_name, self.net_id, + self.vlan_name, self.vlan_id) + new_net_dict2 = self._cisco_nexus_plugin.create_network( + tenant_id, "New_Network2", "0011", + "second_vlan", "2003") + list_net_dict = self._cisco_nexus_plugin.get_all_networks(tenant_id) + net_temp_list = [new_net_dict1, new_net_dict2] + self.assertEqual(len(list_net_dict), 2) + self.assertTrue(list_net_dict[0] in net_temp_list) + self.assertTrue(list_net_dict[1] in net_temp_list) + self.tearDownNetwork(tenant_id, new_net_dict1[const.NET_ID]) + self.tearDownNetwork(tenant_id, new_net_dict2[const.NET_ID]) + LOG.debug("test_list_all_networks - END") + + def test_get_vlan_id_for_network(self, net_tenant_id=None, + network_id=None): + """ + Tests retrieval of vlan id for a Virtual Networks . + """ + + LOG.debug("test_get_vlan_id_for_network - START") + if net_tenant_id: + tenant_id = net_tenant_id + else: + tenant_id = self.tenant_id + if network_id: + net_id = network_id + else: + net_id = self.net_id + new_net_dict = self._cisco_nexus_plugin.create_network( + tenant_id, self.net_name, net_id, self.vlan_name, + self.vlan_id) + result_vlan_id = self._cisco_nexus_plugin._get_vlan_id_for_network( + tenant_id, net_id) + self.assertEqual(result_vlan_id, self.vlan_id) + self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID]) + LOG.debug("test_get_vlan_id_for_network - END") + + """ + Clean up functions after the tests + """ + + def tearDownNetwork(self, tenant_id, network_dict_id): + self._cisco_nexus_plugin.delete_network(tenant_id, network_dict_id) + +# def test_create_network(self): +# _test_create_network(self._cisco_nexus_plugin) + +# def test_delete_network(self): +# _test_delete_network(self._cisco_nexus_plugin) + +# def test_rename_network(self): +# _test_rename_network(self._cisco_nexus_plugin) + +# def test_show_network(self): +# _test_get_network_details(self._cisco_nexus_plugin) + +# def test_list_networks(self): +# _test_list_all_networks(self._cisco_nexus_plugin) diff --git a/quantum/plugins/cisco/tests/unit/test_ucs_driver.py b/quantum/plugins/cisco/tests/unit/test_ucs_driver.py new file mode 100644 index 0000000000..ab93d778f9 --- /dev/null +++ b/quantum/plugins/cisco/tests/unit/test_ucs_driver.py @@ -0,0 +1,165 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2011 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. +# +# @author: Shweta Padubidri, Cisco Systems, Inc. +# + +import logging +import unittest + +from quantum.plugins.cisco.ucs import cisco_ucs_network_driver + +LOG = logging.getLogger('quantum.tests.test_ucs_driver') + +create_vlan_output = " "\ +" "\ +"" + +create_profile_output = " "\ +" " + +change_vlan_output = " "\ +" "\ +" " + +delete_vlan_output = " "\ +" "\ +" " + +delete_profile_output = " "\ +" " + +associate_profile_output = " "\ +" " \ +" " + + +class TestUCSDriver(unittest.TestCase): + + def setUp(self): + self._ucsmDriver = cisco_ucs_network_driver.CiscoUCSMDriver() + self.vlan_name = 'New Vlan' + self.vlan_id = '200' + self.profile_name = 'New Profile' + self.old_vlan_name = 'Old Vlan' + self.profile_client_name = 'New Profile Client' + + def test_create_vlan_post_data(self, expected_output=create_vlan_output): + """ + Tests creation of vlan post Data + """ + + LOG.debug("test_create_vlan") + vlan_details = self._ucsmDriver._create_vlan_post_data( + self.vlan_name, self.vlan_id) + self.assertEqual(vlan_details, expected_output) + LOG.debug("test_create_vlan - END") + + def test_create_profile_post_data( + self, expected_output=create_profile_output): + """ + Tests creation of profile post Data + """ + + LOG.debug("test_create_profile_post_data - START") + profile_details = self._ucsmDriver._create_profile_post_data( + self.profile_name, self.vlan_name) + self.assertEqual(profile_details, expected_output) + LOG.debug("test_create_profile_post - END") + + def test_change_vlan_in_profile_post_data( + self, expected_output=change_vlan_output): + """ + Tests creation of change vlan in profile post Data + """ + + LOG.debug("test_create_profile_post_data - START") + profile_details = self._ucsmDriver._change_vlan_in_profile_post_data( + self.profile_name, self.old_vlan_name, self.vlan_name) + self.assertEqual(profile_details, expected_output) + LOG.debug("test_create_profile_post - END") + + def test_delete_vlan_post_data(self, expected_output=delete_vlan_output): + LOG.debug("test_create_profile_post_data - START") + """ + Tests deletion of vlan post Data + """ + + vlan_details = self._ucsmDriver._create_vlan_post_data( + self.vlan_name, self.vlan_id) + vlan_delete_details = self._ucsmDriver._delete_vlan_post_data( + self.vlan_name) + self.assertEqual(vlan_delete_details, expected_output) + LOG.debug("test_create_profile_post - END") + + def test_delete_profile_post_data( + self, expected_output=delete_profile_output): + """ + Tests deletion of profile post Data + """ + + LOG.debug("test_create_profile_post_data - START") + profile_details = self._ucsmDriver._create_profile_post_data( + self.profile_name, self.vlan_name) + profile_delete_details = self._ucsmDriver._delete_profile_post_data( + self.profile_name) + self.assertEqual(profile_delete_details, expected_output) + LOG.debug("test_create_profile_post - END") + + def test_create_profile_client_post_data( + self, expected_output=associate_profile_output): + """ + Tests creation of profile client post Data + """ + + LOG.debug("test_create_profile_client_post_data - START") + profile_details = self._ucsmDriver._create_profile_client_post_data( + self.profile_name, self.profile_client_name) + self.assertEqual(profile_details, expected_output) + LOG.debug("test_create_profile_post - END") + + def test_get_next_dynamic_nic(self): + """ + Tests get next dynamic nic + """ + + LOG.debug("test_get_next_dynamic_nic - START") + dynamic_nic_id = self._ucsmDriver._get_next_dynamic_nic() + self.assertTrue(len(dynamic_nic_id) > 0) + LOG.debug("test_get_next_dynamic_nic - END") diff --git a/quantum/plugins/cisco/tests/unit/test_ucs_plugin.py b/quantum/plugins/cisco/tests/unit/test_ucs_plugin.py new file mode 100644 index 0000000000..978c026482 --- /dev/null +++ b/quantum/plugins/cisco/tests/unit/test_ucs_plugin.py @@ -0,0 +1,480 @@ +#vim: tabstop=4 shiftwidth=4 softtabstop=4 +#copyright 2011 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. +# +# @author: Shubhangi Satras, Cisco Systems, Inc. +# +import unittest +import logging as LOG +from quantum.common import exceptions as exc +from quantum.plugins.cisco.common import cisco_constants as const +from quantum.plugins.cisco.ucs import cisco_ucs_plugin +from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf + +LOG.basicConfig(level=LOG.WARN) +LOG.getLogger("cisco_plugin") + + +class UCSVICTestPlugin(unittest.TestCase): + + def setUp(self): + + self.tenant_id = "test_tenant_cisco12" + self.net_name = "test_network_cisco12" + self.net_id = 000007 + self.vlan_name = "q-" + str(self.net_id) + "vlan" + self.vlan_id = 266 + self.port_id = "4" + self._cisco_ucs_plugin = cisco_ucs_plugin.UCSVICPlugin() + + def test_create_network(self): + """ + Tests creation of new Virtual Network. + """ + LOG.debug("UCSVICTestPlugin:_test_create_network() called\n") + new_net_dict = self._cisco_ucs_plugin.create_network( + self.tenant_id, self.net_name, self.net_id, + self.vlan_name, self.vlan_id) + self.assertEqual(new_net_dict[const.NET_ID], self.net_id) + self.assertEqual(new_net_dict[const.NET_NAME], self.net_name) + self.assertEqual(new_net_dict[const.NET_VLAN_NAME], self.vlan_name) + self.assertEqual(new_net_dict[const.NET_VLAN_ID], self.vlan_id) + self.tearDownNetwork(self.tenant_id, self.net_id) + + def test_delete_network(self): + """ + Tests deletion of the network with the specified network identifier + belonging to the specified tenant. + """ + LOG.debug("UCSVICTestPlugin:test_delete_network() called\n") + self._cisco_ucs_plugin.create_network( + self.tenant_id, self.net_name, self.net_id, + self.vlan_name, self.vlan_id) + new_net_dict = self._cisco_ucs_plugin.delete_network( + self.tenant_id, self.net_id) + self.assertEqual(new_net_dict[const.NET_ID], self.net_id) + + def test_get_network_details(self): + """ + Tests the deletion the Virtual Network belonging to a the + spec + """ + LOG.debug("UCSVICTestPlugin:test_get_network_details() called\n") + self._cisco_ucs_plugin.create_network( + self.tenant_id, self.net_name, self.net_id, + self.vlan_name, self.vlan_id) + new_net_dict = self._cisco_ucs_plugin.get_network_details( + self.tenant_id, self.net_id) + self.assertEqual(new_net_dict[const.NET_ID], self.net_id) + self.assertEqual(new_net_dict[const.NET_VLAN_NAME], self.vlan_name) + self.assertEqual(new_net_dict[const.NET_VLAN_ID], self.vlan_id) + self.tearDownNetwork(self.tenant_id, self.net_id) + + def test_get_all_networks(self): + """ + Tests whether dictionary is returned containing all + for + the specified tenant. + """ + LOG.debug("UCSVICTestPlugin:test_get_all_networks() called\n") + new_net_dict1 = self._cisco_ucs_plugin.create_network( + self.tenant_id, self.net_name, self.net_id, + self.vlan_name, self.vlan_id) + new_net_dict2 = self._cisco_ucs_plugin.create_network( + self.tenant_id, "test_network2", + 000006, "q-000006vlan", "6") + net_list = self._cisco_ucs_plugin.get_all_networks(self.tenant_id) + net_id_list = [new_net_dict1, new_net_dict2] + self.assertTrue(net_list[0] in net_id_list) + self.assertTrue(net_list[1] in net_id_list) + self.tearDownNetwork(self.tenant_id, new_net_dict1[const.NET_ID]) + self.tearDownNetwork(self.tenant_id, new_net_dict2[const.NET_ID]) + + def test_get_all_ports(self): + """ + Retrieves all port identifiers belonging to the + specified Virtual Network. + """ + LOG.debug("UCSVICPlugin:get_all_ports() called\n") + new_net_dict = self._cisco_ucs_plugin.create_network( + self.tenant_id, self.net_name, self.net_id, + self.vlan_name, self.vlan_id) + port_dict1 = self._cisco_ucs_plugin.create_port( + self.tenant_id, self.net_id, const.PORT_UP, + self.port_id) + port_dict2 = self._cisco_ucs_plugin.create_port( + self.tenant_id, self.net_id, + const.PORT_UP, "10") + ports_on_net = self._cisco_ucs_plugin.get_all_ports( + self.tenant_id, self.net_id) + port_list = [port_dict1, port_dict2] + self.assertTrue(port_list[0] in ports_on_net) + self.assertTrue(port_list[1] in ports_on_net) + self._cisco_ucs_plugin.delete_port(self.tenant_id, self.net_id, + self.port_id) + self.tearDownNetworkPort(self.tenant_id, new_net_dict[const.NET_ID], + port_dict2[const.PORT_ID]) + + def _test_rename_network(self, new_name): + """ + Tests whether symbolic name is updated for the particular + Virtual Network. + """ + LOG.debug("UCSVICTestPlugin:_test_rename_network() called\n") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + new_net_dict = self._cisco_ucs_plugin.rename_network( + self.tenant_id, self.net_id, new_name) + self.assertEqual(new_net_dict[const.NET_NAME], new_name) + self.tearDownNetwork(self.tenant_id, self.net_id) + + def test_rename_network(self): + self._test_rename_network("new_test_network1") + + def _test_create_port(self, port_state): + """ + Tests creation of a port on the specified Virtual Network. + """ + LOG.debug("UCSVICTestPlugin:_test_create_port() called\n") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + new_port_dict = self._cisco_ucs_plugin.create_port( + self.tenant_id, self.net_id, port_state, self.port_id) + self.assertEqual(new_port_dict[const.PORT_ID], self.port_id) + self.assertEqual(new_port_dict[const.PORT_STATE], port_state) + self.assertEqual(new_port_dict[const.ATTACHMENT], None) + profile_name = self._cisco_ucs_plugin._get_profile_name(self.port_id) + new_port_profile = new_port_dict[const.PORT_PROFILE] + self.assertEqual(new_port_profile[const.PROFILE_NAME], profile_name) + self.assertEqual(new_port_profile[const.PROFILE_VLAN_NAME], + conf.DEFAULT_VLAN_NAME) + self.assertEqual(new_port_profile[const.PROFILE_VLAN_ID], + conf.DEFAULT_VLAN_ID) + self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id) + + def test_create_port(self): + self._test_create_port(const.PORT_UP) + + def _test_delete_port(self, port_state): + """ + Tests Deletion of a port on a specified Virtual Network, + if the port contains a remote interface attachment, + the remote interface should first be un-plugged and + then the port can be deleted. + """ + LOG.debug("UCSVICTestPlugin:_test_delete_port() called\n") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id, + port_state, self.port_id) + self._cisco_ucs_plugin.delete_port(self.tenant_id, self.net_id, + self.port_id) + net = self._cisco_ucs_plugin._get_network(self.tenant_id, self.net_id) + self.assertEqual(net[const.NET_PORTS], {}) + self.tearDownNetwork(self.tenant_id, self.net_id) + + def test_delete_port(self): + self._test_delete_port(const.PORT_UP) + + def _test_update_port(self, port_state): + """ + Tests Updation of the state of a port on the specified Virtual Network. + """ + LOG.debug("UCSVICTestPlugin:_test_update_port() called\n") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id, + port_state, self.port_id) + port = self._cisco_ucs_plugin.update_port( + self.tenant_id, self.net_id, + self.port_id, port_state) + self.assertEqual(port[const.PORT_STATE], port_state) + self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id) + + def test_update_port_state_up(self): + self._test_update_port(const.PORT_UP) + + def test_update_port_state_down(self): + self._test_update_port(const.PORT_DOWN) + + def _test_get_port_details_state_up(self, port_state): + """ + Tests whether user is able to retrieve a remote interface + that is attached to this particular port when port state is Up. + """ + LOG.debug("UCSVICTestPlugin:_test_get_port_details_state_up()" + + "called\n") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id, + port_state, self.port_id) + port = self._cisco_ucs_plugin.get_port_details( + self.tenant_id, self.net_id, self.port_id) + self.assertEqual(port[const.PORT_ID], self.port_id) + self.assertEqual(port[const.PORT_STATE], port_state) + self.assertEqual(port[const.ATTACHMENT], None) + new_port_profile = port[const.PORT_PROFILE] + profile_name = self._cisco_ucs_plugin._get_profile_name(self.port_id) + self.assertEqual(new_port_profile[const.PROFILE_VLAN_NAME], + conf.DEFAULT_VLAN_NAME) + self.assertEqual(new_port_profile[const.PROFILE_VLAN_ID], + conf.DEFAULT_VLAN_ID) + self.assertEqual(new_port_profile[const.PROFILE_NAME], profile_name) + self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id) + + def _test_get_port_details_state_down(self, port_state): + """ + Tests whether user is able to retrieve a remote interface + that is attached to this particular port when port state is down. + """ + LOG.debug("UCSVICTestPlugin:_test_get_port_details_state_down()" + + "called\n") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id, + port_state, self.port_id) + port = self._cisco_ucs_plugin.get_port_details(self.tenant_id, + self.net_id, + self.port_id) + self.assertEqual(port[const.PORT_ID], self.port_id) + self.assertNotEqual(port[const.PORT_STATE], port_state) + self.assertEqual(port[const.ATTACHMENT], None) + new_port_profile = port[const.PORT_PROFILE] + profile_name = self._cisco_ucs_plugin._get_profile_name(self.port_id) + self.assertEqual(new_port_profile[const.PROFILE_VLAN_NAME], + conf.DEFAULT_VLAN_NAME) + self.assertEqual(new_port_profile[const.PROFILE_VLAN_ID], + conf.DEFAULT_VLAN_ID) + self.assertEqual(new_port_profile[const.PROFILE_NAME], profile_name) + self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id) + + def test_get_port_details_state_up(self): + self._test_get_port_details_state_up(const.PORT_UP) + + def test_get_port_details_state_down(self): + self._test_get_port_details_state_down(const.PORT_DOWN) + + def test_create_port_profile(self): + LOG.debug("UCSVICTestPlugin:test_create_port_profile() called\n") + new_port_profile = self._cisco_ucs_plugin._create_port_profile( + self.tenant_id, self.net_id, self.port_id, + self.vlan_name, self.vlan_id) + profile_name = self._cisco_ucs_plugin._get_profile_name(self.port_id) + self.assertEqual(new_port_profile[const.PROFILE_NAME], profile_name) + self.assertEqual(new_port_profile[const.PROFILE_VLAN_NAME], + self.vlan_name) + self.assertEqual(new_port_profile[const.PROFILE_VLAN_ID], self.vlan_id) + self._cisco_ucs_plugin._delete_port_profile(self.port_id, profile_name) + + def test_delete_port_profile(self): + LOG.debug("UCSVICTestPlugin:test_delete_port_profile() called\n") + self._cisco_ucs_plugin._create_port_profile( + self.tenant_id, self.net_id, self.port_id, self.vlan_name, + self.vlan_id) + profile_name = self._cisco_ucs_plugin._get_profile_name(self.port_id) + counter1 = self._cisco_ucs_plugin._port_profile_counter + self._cisco_ucs_plugin._delete_port_profile(self.port_id, + profile_name) + counter2 = self._cisco_ucs_plugin._port_profile_counter + self.assertNotEqual(counter1, counter2) + + def _test_plug_interface(self, remote_interface_id): + """ + Attaches a remote interface to the specified port on the + specified Virtual Network. + """ + LOG.debug("UCSVICTestPlugin:_test_plug_interface() called\n") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id, + const.PORT_UP, self.port_id) + self._cisco_ucs_plugin.plug_interface(self.tenant_id, self.net_id, + self.port_id, + remote_interface_id) + port = self._cisco_ucs_plugin._get_port( + self.tenant_id, self.net_id, self.port_id) + self.assertEqual(port[const.ATTACHMENT], remote_interface_id) + port_profile = port[const.PORT_PROFILE] + profile_name = port_profile[const.PROFILE_NAME] + new_vlan_name = self._cisco_ucs_plugin._get_vlan_name_for_network( + self.tenant_id, self.net_id) + new_vlan_id = self._cisco_ucs_plugin._get_vlan_id_for_network( + self.tenant_id, self.net_id) + self.assertEqual(port_profile[const.PROFILE_VLAN_NAME], new_vlan_name) + self.assertEqual(port_profile[const.PROFILE_VLAN_ID], new_vlan_id) + self.tearDownNetworkPortInterface(self.tenant_id, self.net_id, + self.port_id) + + def test_plug_interface(self): + self._test_plug_interface("4") + + def _test_unplug_interface(self, remote_interface_id): + """ + Tests whether remote interface detaches from the specified port on the + specified Virtual Network. + """ + LOG.debug("UCSVICTestPlugin:_test_unplug_interface() called\n") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id, + const.PORT_UP, self.port_id) + self._cisco_ucs_plugin.plug_interface(self.tenant_id, self.net_id, + self.port_id, + remote_interface_id) + self._cisco_ucs_plugin.unplug_interface(self.tenant_id, self.net_id, + self.port_id) + port = self._cisco_ucs_plugin._get_port( + self.tenant_id, self.net_id, self.port_id) + self.assertEqual(port[const.ATTACHMENT], None) + port_profile = port[const.PORT_PROFILE] + profile_name = port_profile[const.PROFILE_NAME] + self.assertEqual(port_profile[const.PROFILE_VLAN_NAME], + conf.DEFAULT_VLAN_NAME) + self.assertEqual(port_profile[const.PROFILE_VLAN_ID], + conf.DEFAULT_VLAN_ID) + self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id) + + def test_unplug_interface(self): + self._test_unplug_interface("4") + + def test_get_vlan_name_for_network(self): + LOG.debug("UCSVICTestPlugin:test_get_vlan_name_for_network() called\n") + net = self._cisco_ucs_plugin.create_network( + self.tenant_id, self.net_name, self.net_id, + self.vlan_name, self.vlan_id) + self.assertEqual(net[const.NET_VLAN_NAME], self.vlan_name) + self.tearDownNetwork(self.tenant_id, self.net_id) + + def test_get_vlan_id_for_network(self): + LOG.debug("UCSVICTestPlugin:test_get_vlan_id_for_network() called\n") + net = self._cisco_ucs_plugin.create_network( + self.tenant_id, self.net_name, self.net_id, self.vlan_name, + self.vlan_id) + self.assertEqual(net[const.NET_VLAN_ID], self.vlan_id) + self.tearDownNetwork(self.tenant_id, self.net_id) + + def test_get_network(self): + LOG.debug("UCSVICTestPlugin:test_get_network() called\n") + net = self._cisco_ucs_plugin.create_network( + self.tenant_id, self.net_name, self.net_id, self.vlan_name, + self.vlan_id) + self.assertEqual(net[const.NET_ID], self.net_id) + self.tearDownNetwork(self.tenant_id, self.net_id) + + def test_get_port(self): + LOG.debug("UCSVICTestPlugin:test_get_port() called\n") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + new_port_dict = self._cisco_ucs_plugin.create_port( + self.tenant_id, self.net_id, + const.PORT_UP, self.port_id) + self.assertEqual(new_port_dict[const.PORT_ID], self.port_id) + self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id) + + def test_get_network_NetworkNotFound(self): + self.assertRaises(exc.NetworkNotFound, + self._cisco_ucs_plugin._get_network, + *(self.tenant_id, self.net_id)) + + def test_delete_network_NetworkNotFound(self): + self.assertRaises(exc.NetworkNotFound, + self._cisco_ucs_plugin.delete_network, + *(self.tenant_id, self.net_id)) + + def test_delete_port_PortInUse(self): + self._test_delete_port_PortInUse("4") + + def _test_delete_port_PortInUse(self, remote_interface_id): + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id, + const.PORT_UP, self.port_id) + self._cisco_ucs_plugin.plug_interface(self.tenant_id, self.net_id, + self.port_id, + remote_interface_id) + self.assertRaises(exc.PortInUse, self._cisco_ucs_plugin.delete_port, + *(self.tenant_id, self.net_id, self.port_id)) + self.tearDownNetworkPortInterface(self.tenant_id, self.net_id, + self.port_id) + + def test_delete_port_PortNotFound(self): + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + self.assertRaises(exc.PortNotFound, self._cisco_ucs_plugin.delete_port, + *(self.tenant_id, self.net_id, self.port_id)) + self.tearDownNetwork(self.tenant_id, self.net_id) + + def test_plug_interface_PortInUse(self): + self._test_plug_interface_PortInUse("6", "5") + + def _test_plug_interface_PortInUse(self, remote_interface_id1, + remote_interface_id2): + LOG.debug("UCSVICTestPlugin:_test_plug_interface_PortInUse() called\n") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id, + const.PORT_UP, self.port_id) + self._cisco_ucs_plugin.plug_interface(self.tenant_id, self.net_id, + self.port_id, + remote_interface_id1) + self.assertRaises(exc.PortInUse, self._cisco_ucs_plugin.plug_interface, + *(self.tenant_id, self.net_id, self.port_id, + remote_interface_id2)) + self.tearDownNetworkPortInterface(self.tenant_id, self.net_id, + self.port_id) + + def test_validate_attachment_AlreadyAttached(self): + LOG.debug("UCSVICTestPlugin:testValidateAttachmentAlreadyAttached") + self._test_validate_attachment_AlreadyAttached("4") + + def _test_validate_attachment_AlreadyAttached(self, remote_interface_id): + LOG.debug("UCSVICTestPlugin:_test_validate_attachmentAlreadyAttached") + self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name, + self.net_id, self.vlan_name, + self.vlan_id) + self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id, + const.PORT_UP, self.port_id) + self._cisco_ucs_plugin.plug_interface(self.tenant_id, self.net_id, + self.port_id, + remote_interface_id) + self.assertRaises( + exc.AlreadyAttached, self._cisco_ucs_plugin._validate_attachment, + *(self.tenant_id, self.net_id, self.port_id, remote_interface_id)) + self.tearDownNetworkPortInterface(self.tenant_id, self.net_id, + self.port_id) + + def tearDownNetwork(self, tenant_id, net_id): + self._cisco_ucs_plugin.delete_network(tenant_id, net_id) + + def tearDownNetworkPort(self, tenant_id, net_id, port_id): + self._cisco_ucs_plugin.delete_port(tenant_id, net_id, + port_id) + self.tearDownNetwork(tenant_id, net_id) + + def tearDownNetworkPortInterface(self, tenant_id, net_id, port_id): + self._cisco_ucs_plugin.unplug_interface(tenant_id, net_id, + port_id) + self.tearDownNetworkPort(tenant_id, net_id, port_id) From 71dc75bb7bb33a71529b17a28ac149e03770c950 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 8 Aug 2011 11:54:19 -0700 Subject: [PATCH 38/48] Making a check for the presence of UCS/Nexus plugin (earlier it was not in certain cases). With this change, if the UCS/Nexus plugins are not enabled, the core API tests can be run even on Ubuntu (and RHEL without the requirement of any specific network hardware). --- quantum/plugins/cisco/README | 8 ++++---- quantum/plugins/cisco/l2network_model.py | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 5467fb03a9..a5d3146a91 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -60,9 +60,9 @@ mysql -uroot -p nova -e 'create table ports (port_id VARCHA ** Execute the Test cases * The unit tests are located at quantum/plugins/cisco/tests/unit. They are executed from quantum/plugins/cisco/ using the runtests.py script. (Note that to execute the test cases one currently requires the environment setup as outlined in the pre-requisites.) -* Execution of the runtests.py script. +* Execution of the run_tests.py script. All unit tests - python runtests.py unit + python run_tests.py unit Specific Plugin unit test - python runtests.py unit. - e.g. python run_tests.py unit.test_coreApi + python run_tests.py unit. + e.g. python run_tests.py unit.test_l2networkApi diff --git a/quantum/plugins/cisco/l2network_model.py b/quantum/plugins/cisco/l2network_model.py index 3fa986b2a3..e24e0a372f 100644 --- a/quantum/plugins/cisco/l2network_model.py +++ b/quantum/plugins/cisco/l2network_model.py @@ -47,12 +47,14 @@ class L2NetworkModel(L2NetworkModelBase): getattr(pluginObjRef, function_name)(*args, **kwargs) def _invokeUCSPlugin(self, function_name, args, kwargs): - getattr(self._plugins[const.UCS_PLUGIN], - function_name)(*args, **kwargs) + if const.UCS_PLUGIN in self._plugins.keys(): + getattr(self._plugins[const.UCS_PLUGIN], + function_name)(*args, **kwargs) def _invokeNexusPlugin(self, function_name, args, kwargs): - getattr(self._plugins[const.NEXUS_PLUGIN], - function_name)(*args, **kwargs) + if const.NEXUS_PLUGIN in self._plugins.keys(): + getattr(self._plugins[const.NEXUS_PLUGIN], + function_name)(*args, **kwargs) def get_all_networks(self, args): pass From 66d6a1b400b0041ac64df5148429079024f0ed9e Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 8 Aug 2011 12:54:42 -0700 Subject: [PATCH 39/48] Incorporated changes in response to review comments from Ram. --- quantum/plugins/cisco/README | 41 ++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index a5d3146a91..7455c92e69 100644 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -1,23 +1,21 @@ - L2 Network Plugin -================== + L2 Network Plugin Framework +============================ *** Reference implementation of plugin framework for L2 network *** *** Multi-switch (devices and types) capability *** -*** Current support for UCS (blade servers) with M81KR VIC (Palo) for 802.1Qbh *** -*** Also supports Nexus 7k *** +*** Support for UCS (blade servers) with M81KR VIC (Palo) for 802.1Qbh *** +*** Support for Nexus 7000 *** ** Pre-requisities * UCS B200 series blades with M81KR VIC installed. * UCSM 2.0 (Capitola) Build 230 * RHEL 6.1 (Currently UCS support is only on RHEL, Ubuntu will be supporting in upcoming releases) -* UCS & VIC installation (support for KVM) - please consult the accompanying installation guide available at: -http://wikicentral.cisco.com/display/GROUP/SAVBU+Palo+VM-FEX+for+Linux+KVM +* UCS & VIC installation (support for KVM) +* OpenStack Cactus release installation (patch is required, details follow in this document) * Package python-configobj-4.6.0-3.el6.noarch - * If you have a Nexus switch in your topology and decide to turn on Nexus support, you will need: - ncclcient v0.3.1 - Python library for NETCONF clients (http://schmizz.net/ncclient/). - paramiko library (do: yum install python-paramiko.noarch) - * To run Quantum on RHEL, you will need to have the correct version of python-routes (version 1.12.3 or later). The RHEL 6.1 package contains an older version. Do the following and check your python-routes version: rpm -qav | grep "python-routes" @@ -49,20 +47,27 @@ provider = quantum.plugins.cisco.l2network_plugin.L2Network * Create DB Table in Nova DB (On the Cloud Controller) mysql -uroot -p nova -e 'create table ports (port_id VARCHAR(255) primary key, profile_name VARCHAR(255), dynamic_vnic VARCHAR(255), host VARCHAR(255), instance_name VARCHAR(255), instance_nic_name VARCHAR(255), used tinyint(1));' -* Replace the following files with the files from the Cisco Nova branch: +* Replace the following file with the files from the Cisco OpenStack Cactus patch: /usr/lib/python2.6/site-packages/nova/virt/libvirt_conn.py -* Add the following files from the Cisco Nova branch: +* Add the following file from the Cisco OpenStack Cactus patch to your installation: /usr/lib/python2.6/site-packages/nova/virt/cisco_ucs.py * Restart nova-compute service -** Execute the Test cases -* The unit tests are located at quantum/plugins/cisco/tests/unit. They are executed from quantum/plugins/cisco/ using the runtests.py script. (Note that to execute the test cases one currently requires the environment setup as outlined in the pre-requisites.) +* Note that the requirement for the above patch is temporary and will go away with the integration with OpenStack Diablo. A 802.1Qbh-specific VIF driver will be made available as per the specification here: +http://wiki.openstack.org/network-refactoring#VIF_driver -* Execution of the run_tests.py script. - All unit tests - python run_tests.py unit - Specific Plugin unit test - python run_tests.py unit. - e.g. python run_tests.py unit.test_l2networkApi +** Testing +* The unit tests are located at quantum/plugins/cisco/tests/unit. They are executed from quantum/plugins/cisco/ using the run_tests.py script. + +* Execution of the run_tests.py script: + + Testing the core API (without UCS/Nexus/RHEL hardware, can be run on Ubuntu) + - Disable all device-specific plugins by commenting the entries in the quantum/plugins/cisco/conf/plugins.ini configuration file. + $> python run_tests.py unit.test_l2networkApi + + Specific Plugin unit test (needs environment setup as indicated in the pre-requisites) + - python run_tests.py unit. + e.g. + $> python run_tests.py unit.test_ucs_plugin.py + + All unit tests (needs environment setup as indicated in the pre-requisites) + $> python run_tests.py unit From b511b696e0dd4826861d38cea319447a6a2f50dd Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 8 Aug 2011 16:51:58 -0700 Subject: [PATCH 40/48] README file updates (pointer to Nova Cactus branch), and numerous other edits based on Mark's template. --- quantum/plugins/cisco/README | 299 ++++++++++++++++++++++++++--------- 1 file changed, 226 insertions(+), 73 deletions(-) mode change 100644 => 100755 quantum/plugins/cisco/README diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README old mode 100644 new mode 100755 index 7455c92e69..c429bcd601 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -1,73 +1,226 @@ - L2 Network Plugin Framework -============================ - -*** Reference implementation of plugin framework for L2 network *** -*** Multi-switch (devices and types) capability *** -*** Support for UCS (blade servers) with M81KR VIC (Palo) for 802.1Qbh *** -*** Support for Nexus 7000 *** - -** Pre-requisities -* UCS B200 series blades with M81KR VIC installed. -* UCSM 2.0 (Capitola) Build 230 -* RHEL 6.1 (Currently UCS support is only on RHEL, Ubuntu will be supporting in upcoming releases) -* UCS & VIC installation (support for KVM) -* OpenStack Cactus release installation (patch is required, details follow in this document) -* Package python-configobj-4.6.0-3.el6.noarch -* If you have a Nexus switch in your topology and decide to turn on Nexus support, you will need: - - ncclcient v0.3.1 - Python library for NETCONF clients (http://schmizz.net/ncclient/). - - paramiko library (do: yum install python-paramiko.noarch) -* To run Quantum on RHEL, you will need to have the correct version of python-routes (version 1.12.3 or later). The RHEL 6.1 package contains an older version. Do the following and check your python-routes version: -rpm -qav | grep "python-routes" - -If it's an older version, you will need to upgrade to 1.12.3 or later. One quick way to do it as by adding the following to your /etc/yum.repos.d/openstack.repo (assuming that you had installed OpenStack on this host, and hence had this repo; else you could add to any other operational repo config), and then update the python-routes package. That should get you the python-routes-1.12.3-2.el6.noarch package. - -[openstack-deps] -name=OpenStack Nova Compute Dependencies -baseurl=http://yum.griddynamics.net/yum/cactus/deps -enabled=1 -gpgcheck=1 -gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OPENSTACK - - -** Plugin Installation Instructions: -* Make a backup copy of quantum/quantum/plugins.ini, and edit the "provider" entry to point to the L2Network-plugin: -provider = quantum.plugins.cisco.l2network_plugin.L2Network - -* All configuration files are located under quantum/plugins/cisco/conf. Wherever you find kind of placeholder, please replace it entirely with the relevant values (don't forget to remove the angle brackets as well) - -* If you are not running Quantum on the same host as the OpenStack Cloud Controller, you will need to change the db_ip_address configuration in nova.ini - -* If you want to turn on Nexus support, please uncomment the nexus_plugin property in the plugins.ini file, and enter the relevant configuration in the nexus.ini file. In addition, you will require a patch to the ncclient library. Also make sure that the switch's host key is known to the host on which you are running the Quantum service (since the connection to the switch is over ssh). If you are not turning the Nexus support on, your Nexus configuration will be ignored. - -* Check again if you have gone through every conf file and made the required changes (check if all IP addresses are correct, and check if you have entered the credentials correponding to each of those IP addresses in the credentials.ini file). - -* Start the Quantum service - -** Additional installation required on Nova Compute: -* Create DB Table in Nova DB (On the Cloud Controller) -mysql -uroot -p nova -e 'create table ports (port_id VARCHAR(255) primary key, profile_name VARCHAR(255), dynamic_vnic VARCHAR(255), host VARCHAR(255), instance_name VARCHAR(255), instance_nic_name VARCHAR(255), used tinyint(1));' - -* Replace the following file with the files from the Cisco OpenStack Cactus patch: -/usr/lib/python2.6/site-packages/nova/virt/libvirt_conn.py - -* Add the following file from the Cisco OpenStack Cactus patch to your installation: -/usr/lib/python2.6/site-packages/nova/virt/cisco_ucs.py - -* Restart nova-compute service - -* Note that the requirement for the above patch is temporary and will go away with the integration with OpenStack Diablo. A 802.1Qbh-specific VIF driver will be made available as per the specification here: -http://wiki.openstack.org/network-refactoring#VIF_driver - -** Testing -* The unit tests are located at quantum/plugins/cisco/tests/unit. They are executed from quantum/plugins/cisco/ using the run_tests.py script. - -* Execution of the run_tests.py script: - + Testing the core API (without UCS/Nexus/RHEL hardware, can be run on Ubuntu) - - Disable all device-specific plugins by commenting the entries in the quantum/plugins/cisco/conf/plugins.ini configuration file. - $> python run_tests.py unit.test_l2networkApi - + Specific Plugin unit test (needs environment setup as indicated in the pre-requisites) - - python run_tests.py unit. - e.g. - $> python run_tests.py unit.test_ucs_plugin.py - + All unit tests (needs environment setup as indicated in the pre-requisites) - $> python run_tests.py unit +============================================ +README: Quantum L2 Network Plugin Framework +============================================ + +:Author: Sumit Naiksatam, Ram Durairaj, Mark Voelker, Edgar Magana, Shweta Padubidri, Rohit Agarwalla, Ying Liu +:Contact: netstack@lists.launchpad.net +:Web site: https://launchpad.net/~cisco-openstack +:Copyright: 2011 Cisco Systems, Inc. + +.. contents:: + +Introduction +------------ + +This plugin implementation provides the following capabilities +to help you take your Layer 2 network for a Quantum leap: + +* A reference implementation of plugin framework for L2 network +* Supports multiple switches in the network +* Supports multiple models of switches concurrently +* Supports Cisco UCS blade servers with M81KR Virtual Interface Cards + (aka "Palo adapters") via 802.1Qbh. +* Supports the Cisco Nexus family of switches. + +It does not provide: + +* A hologram of Al that only you can see. +* A map to help you find your way through time. +* A cure for amnesia or your swiss-cheesed brain. + +Let's leap in! + +Pre-requisites +-------------- +* One or more UCS B200 series blade servers with M81KR VIC (aka + Palo adapters) installed. +* UCSM 2.0 (Capitola) Build 230 or above. +* OpenStack Cactus release installation (additional patch is required, + details follow in this document) +* RHEL 6.1 (as of this writing, UCS only officially supports RHEL, but + it should be noted that Ubuntu support is planned in coming releases as well) + ** Package: python-configobj-4.6.0-3.el6.noarch (or newer) + ** Package: python-routes-1.12.3-2.el6.noarch (or newer) + +If you are using a Nexus switch in your topology, you'll need the following +packages to enable Nexus support: +* paramiko library - SSHv2 protocol library for python + ** To install on RHEL 6.1, run: yum install python-paramiko +* ncclient v0.3.1 - Python library for NETCONF clients + ** RedHat does not provide a package for ncclient in RHEL 6.1. + ** See http://schmizz.net/ncclient/ for documentation and downloads. + +To verify the version of any package you have installed on your system, +run "rpm -qav | grep ", where is the +package you want to query (for example: python-routes). + +Note that you can get access to recent versions of the packages above +and other OpenStack software packages by adding a new repository to +your yum configuration. To do so, edit or create +/etc/yum.repos.d/openstack.repo and add the following: + +[openstack-deps] +name=OpenStack Nova Compute Dependencies +baseurl=http://yum.griddynamics.net/yum/cactus/deps +enabled=1 +gpgcheck=1 +gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OPENSTACK + +Then run "yum install python-routes". + + +Module Structure: +----------------- +* quantum/plugins/cisco/ - Contains the L2-Network Plugin Framework + /common - Modules common to the entire plugin + /conf - All configuration files + /db - Persistence framework + /nexus - Nexus-specific modules + /ucs - UCS-specific modules + + +Plugin Installation Instructions +---------------------------------- +1. Make a backup copy of quantum/quantum/plugins.ini. + +2. Edit quantum/quantum/plugins.ini and edit the "provider" entry to point + to the L2Network-plugin: + +provider = quantum.plugins.cisco.l2network_plugin.L2Network + +3. If you are not running Quantum on the same host as the OpenStack Cloud + Controller, you will need to change the db_ip_address configuration + in nova.ini. + +4. If you want to turn on support for Cisco Nexus switches: + 4a. Uncomment the nexus_plugin property in + quantum/plugins/cisco/conf/plugins.ini to read: + +nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin + + 4b. Enter the relevant configuration in the + quantum/plugins/cisco/conf/nexus.ini file. Example: + +[SWITCH] +# Change the following to reflect the IP address of the Nexus switch. +# This will be the address at which Quantum sends and receives configuration +# information via SSHv2. +nexus_ip_address=10.0.0.1 +# Port number on the Nexus switch to which the UCSM 6120 is connected +# Use shortened interface syntax, e.g. "3/23" not "Ethernet3/23". +nexus_port=3/23 + +[DRIVER] +name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver + + 4c. Make sure that SSH host key of the Nexus switch is known to the + host on which you are running the Quantum service. You can do + this simply by logging in to your Quantum host as the user that + Quantum runs as and SSHing to the switch at least once. If the + host key changes (e.g. due to replacement of the supervisor or + clearing of the SSH config on the switch), you may need to repeat + this step and remove the old hostkey from ~/.ssh/known_hosts. + +5. Verify that you have the correct credentials for each IP address listed + in quantum/plugins/cisco/conf/credentials.ini. Example: + +# Provide the UCSM credentials +# UCSM IP address, username and password. +[10.0.0.2] +username=admin +password=mySecretPasswordForUCSM + +# Provide the Nova DB credentials. +# The IP address should be the same as in nova.ini. +[10.0.0.3] +username=nova +password=mySecretPasswordForNova + +# Provide the Nexus credentials, if you are using Nexus switches. +# If not this will be ignored. +[10.0.0.1] +username=admin +password=mySecretPasswordForNexus + +6. Start the Quantum service. If something doesn't work, verify that + your configuration of each of the above files hasn't gone a little kaka. + Once you've put right what once went wrong, leap on. + + +How to test the installation +---------------------------- +The unit tests are located at quantum/plugins/cisco/tests/unit. They can be +executed from quantum/plugins/cisco/ using the run_tests.py script. + +1. Testing the core API (without UCS/Nexus/RHEL hardware, and can be run on + Ubuntu): + First disable all device-specific plugins by commenting out the entries in: + quantum/plugins/cisco/conf/plugins.ini + Then run the test script: + +python run_tests.py unit.test_l2networkApi + +2. Specific Plugin unit test (needs environment setup as indicated in the + pre-requisites): + python run_tests.py unit. + E.g.: + +python run_tests.py unit.test_ucs_plugin.py + +3. All unit tests (needs environment setup as indicated in the pre-requisites): + +python run_tests.py unit + + +Additional installation required on Nova Compute +------------------------------------------------ +1. Create a table in the "nova" database for ports. This can be + accomplished with the following SQL statement: + +CREATE TABLE ports ( + port_id VARCHAR(255) PRIMARY KEY, + profile_name VARCHAR(255), + dynamic_vnic VARCHAR(255), + host VARCHAR(255), + instance_name VARCHAR(255), + instance_nic_name VARCHAR(255), + used TINYINT(1) +); + + Assuming you're using MySQL, you can run the following command from a + shell prompt on the Cloud Controller node to create the table: + +mysql -uroot -p nova -e 'create table ports (port_id VARCHAR(255) primary key, profile_name VARCHAR(255), dynamic_vnic VARCHAR(255), host VARCHAR(255), instance_name VARCHAR(255), instance_nic_name VARCHAR(255), used tinyint(1));' + +You'll be prompted for a password. + +2. A patch is available for the Cactus release in this branch: + https://code.launchpad.net/~snaiksat/quantum/cactus-ucs-support + replace the following file in your installation: + /usr/lib/python2.6/site-packages/nova/virt/libvirt_conn.py + with the file from the branch: + nova/virt/libvirt_conn.py + +3. Add the following file from the Cisco Nova branch: + nova/virt/cisco_ucs.py + to: + /usr/lib/python2.6/site-packages/nova/virt/cisco_ucs.py + +4. Add the 802.1Qbh specific libvirt template file, from: + nova/virt/libvirt-qbh.xml.template + tO: + /usr/share/nova/libvirt-qbh.xml.template + +5. Edit /etc/nova.conf to set the libvirt XML template to the above template: + --libvirt_xml_template=/usr/share/nova/libvirt-qbh.xml.template + +6. Restart the nova-compute service. + + (Note that the requirement for the above patch is temporary and will go away + with the integration with OpenStack Diablo. A 802.1Qbh-specific VIF driver + will be made available as per the specification here: + http://wiki.openstack.org/network-refactoring#VIF_driver) + +Bingo bango bongo! That's it! Thanks for taking the leap into Quantum. + +...Oh, boy! From 8ec0f04f667ab341d8751023fc6d3303125b13b4 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 8 Aug 2011 16:57:18 -0700 Subject: [PATCH 41/48] Fixed typo in README --- quantum/plugins/cisco/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index c429bcd601..0e494b188d 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -208,7 +208,7 @@ You'll be prompted for a password. 4. Add the 802.1Qbh specific libvirt template file, from: nova/virt/libvirt-qbh.xml.template - tO: + to: /usr/share/nova/libvirt-qbh.xml.template 5. Edit /etc/nova.conf to set the libvirt XML template to the above template: From 56e702465521c0c5c7cbdb29afb400a7f84ce90c Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Mon, 8 Aug 2011 17:53:21 -0700 Subject: [PATCH 42/48] Adding the required build for Nexus support --- quantum/plugins/cisco/README | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 0e494b188d..44e37a9a4c 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -43,7 +43,8 @@ Pre-requisites ** Package: python-routes-1.12.3-2.el6.noarch (or newer) If you are using a Nexus switch in your topology, you'll need the following -packages to enable Nexus support: +NX-OS version and packages to enable Nexus support: +* NX-OS 5.2.1 (Delhi) Build 69 or above. * paramiko library - SSHv2 protocol library for python ** To install on RHEL 6.1, run: yum install python-paramiko * ncclient v0.3.1 - Python library for NETCONF clients From b95329e94aa4c633c1ba8be7bca06609c41e4d00 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 8 Aug 2011 17:55:00 -0700 Subject: [PATCH 43/48] Added "tests" directory to the list modules in the README file. --- quantum/plugins/cisco/README | 1 + 1 file changed, 1 insertion(+) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 0e494b188d..a9ff3f7ab0 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -76,6 +76,7 @@ Module Structure: /conf - All configuration files /db - Persistence framework /nexus - Nexus-specific modules + /tests - Tests specific to this plugin /ucs - UCS-specific modules From 23dc0ed8cf8322831363dd4e5aa9c145ec17be22 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 8 Aug 2011 23:44:36 -0700 Subject: [PATCH 44/48] Changed to default plugin class name. --- quantum/plugins.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/quantum/plugins.ini b/quantum/plugins.ini index 5192ade26b..307d2b48d2 100644 --- a/quantum/plugins.ini +++ b/quantum/plugins.ini @@ -1,4 +1,3 @@ [PLUGIN] # Quantum plugin provider module -provider = quantum.plugins.cisco.l2network_plugin.L2Network -#provider = quantum.plugins.SamplePlugin.FakePlugin +provider = quantum.plugins.SamplePlugin.FakePlugin From 48349e32d267d0a48f95c963e9094de1ece1d35a Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Tue, 9 Aug 2011 17:14:48 -0700 Subject: [PATCH 45/48] Tiny change to the README file, instructions on how to get ncclient. --- quantum/plugins/cisco/README | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 3275b22311..68d1b5cf42 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -48,8 +48,14 @@ NX-OS version and packages to enable Nexus support: * paramiko library - SSHv2 protocol library for python ** To install on RHEL 6.1, run: yum install python-paramiko * ncclient v0.3.1 - Python library for NETCONF clients - ** RedHat does not provide a package for ncclient in RHEL 6.1. - ** See http://schmizz.net/ncclient/ for documentation and downloads. + ** RedHat does not provide a package for ncclient in RHEL 6.1. Here is how + to get it, from your shell prompt do: + + git clone git@github.com:ddutta/ncclient.git + sudo python ./setup.py install + + ** For more information of ncclient, see: + http://schmizz.net/ncclient/ To verify the version of any package you have installed on your system, run "rpm -qav | grep ", where is the From d8563be5237dbb4720830d2f42fc2e4fb25a5d45 Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Sat, 13 Aug 2011 18:28:02 -0700 Subject: [PATCH 46/48] Removed main from modules as per review comments. --- quantum/plugins/cisco/README | 2 ++ .../cisco/common/cisco_configparser.py | 9 -------- .../plugins/cisco/common/cisco_credentials.py | 8 ------- .../cisco/common/cisco_nova_configuration.py | 7 ------ quantum/plugins/cisco/l2network_model.py | 7 ------ quantum/plugins/cisco/l2network_plugin.py | 13 ----------- .../cisco/l2network_plugin_configuration.py | 7 ------ .../cisco/nexus/cisco_nexus_configuration.py | 7 ------ .../cisco/nexus/cisco_nexus_network_driver.py | 7 ------ quantum/plugins/cisco/ucs/cisco_getvif.py | 5 ----- .../cisco/ucs/cisco_ucs_configuration.py | 7 ------ .../cisco/ucs/cisco_ucs_network_driver.py | 22 ------------------- 12 files changed, 2 insertions(+), 99 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 68d1b5cf42..7b214202e0 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -32,6 +32,8 @@ Let's leap in! Pre-requisites -------------- +(The following are necessary only when using the UCS and/or Nexus devices in your system. +If you plan to just leverage the plugin framework, you do not need these.) * One or more UCS B200 series blade servers with M81KR VIC (aka Palo adapters) installed. * UCSM 2.0 (Capitola) Build 230 or above. diff --git a/quantum/plugins/cisco/common/cisco_configparser.py b/quantum/plugins/cisco/common/cisco_configparser.py index 312c230acb..ec7bae3cf1 100644 --- a/quantum/plugins/cisco/common/cisco_configparser.py +++ b/quantum/plugins/cisco/common/cisco_configparser.py @@ -38,12 +38,3 @@ class CiscoConfigParser(ConfigObj): def dummy(self, section, key): return section[key] - - -def main(): - cp = CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ - + "/" + "test.ini") - print ("%s\n") % cp['PLUGIN']['provider'] - -if __name__ == '__main__': - main() diff --git a/quantum/plugins/cisco/common/cisco_credentials.py b/quantum/plugins/cisco/common/cisco_credentials.py index edc2288cde..74948cd207 100644 --- a/quantum/plugins/cisco/common/cisco_credentials.py +++ b/quantum/plugins/cisco/common/cisco_credentials.py @@ -58,11 +58,3 @@ class Store(object): @staticmethod def deleteCredential(id): return _creds_dictionary.pop(id) - - -def main(): - Store.putCredential("10.10.10.10", "foo", "bar") - print ("%s\n") % Store.getCredentials() - -if __name__ == '__main__': - main() diff --git a/quantum/plugins/cisco/common/cisco_nova_configuration.py b/quantum/plugins/cisco/common/cisco_nova_configuration.py index f1cbf2a1ec..5e6d9e4851 100644 --- a/quantum/plugins/cisco/common/cisco_nova_configuration.py +++ b/quantum/plugins/cisco/common/cisco_nova_configuration.py @@ -33,10 +33,3 @@ DB_USERNAME = section['db_username'] DB_PASSWORD = section['db_password'] NOVA_HOST_NAME = section['nova_host_name'] NOVA_PROJ_NAME = section['nova_proj_name'] - - -def main(): - print NOVA_PROJ_NAME - -if __name__ == '__main__': - main() diff --git a/quantum/plugins/cisco/l2network_model.py b/quantum/plugins/cisco/l2network_model.py index e24e0a372f..ba78701995 100644 --- a/quantum/plugins/cisco/l2network_model.py +++ b/quantum/plugins/cisco/l2network_model.py @@ -98,10 +98,3 @@ class L2NetworkModel(L2NetworkModelBase): def unplug_interface(self, args): deviceParams = {const.DEVICE_IP: ""} self._invokeUCSPlugin(self._funcName(), args, deviceParams) - - -def main(): - client = L2NetworkModel() - -if __name__ == '__main__': - main() diff --git a/quantum/plugins/cisco/l2network_plugin.py b/quantum/plugins/cisco/l2network_plugin.py index f627de2541..3c365d19e7 100644 --- a/quantum/plugins/cisco/l2network_plugin.py +++ b/quantum/plugins/cisco/l2network_plugin.py @@ -388,19 +388,6 @@ class L2Network(QuantumPluginBase): def _funcName(self, offset=0): return inspect.stack()[1 + offset][3] - -def main(): - client = L2Network() - """ - client.create_portprofile("12345", "tpp1", "2") - client.create_portprofile("12345", "tpp2", "3") - print ("%s\n") % client.get_all_portprofiles("12345") - """ - - -if __name__ == '__main__': - main() - """ TODO (Sumit): (1) Persistent storage diff --git a/quantum/plugins/cisco/l2network_plugin_configuration.py b/quantum/plugins/cisco/l2network_plugin_configuration.py index 81f221f039..25df54d381 100644 --- a/quantum/plugins/cisco/l2network_plugin_configuration.py +++ b/quantum/plugins/cisco/l2network_plugin_configuration.py @@ -48,10 +48,3 @@ CONF_FILE = "conf/plugins.ini" cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \ + "/" + CONF_FILE) plugins = cp.walk(cp.dummy) - - -def main(): - print plugins['PLUGINS'] - -if __name__ == '__main__': - main() diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py b/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py index f1ad149028..d43d193f08 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py @@ -33,10 +33,3 @@ NEXUS_PORT = section['nexus_port'] section = cp['DRIVER'] NEXUS_DRIVER = section['name'] - - -def main(): - print NEXUS_PORT - -if __name__ == '__main__': - main() diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py index 78090d5f9c..02380dc9e3 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py @@ -234,10 +234,3 @@ class CiscoNEXUSDriver(): nexus_password) as m: self.disable_vlan(m, vlan_id) self.disable_switch_port(m, nexus_interface) - - -def main(): - client = CiscoNEXUSDriver() - -if __name__ == '__main__': - main() diff --git a/quantum/plugins/cisco/ucs/cisco_getvif.py b/quantum/plugins/cisco/ucs/cisco_getvif.py index f00116ee1f..b80d99a986 100644 --- a/quantum/plugins/cisco/ucs/cisco_getvif.py +++ b/quantum/plugins/cisco/ucs/cisco_getvif.py @@ -49,8 +49,3 @@ def get_next_dynic(argv=[]): if not used: break return eth - -if __name__ == '__main__': - #nic = get_next_dynic(sys.argv) - nic = get_next_dynic() - print nic diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py b/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py index 3053741712..1ff57237c1 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py @@ -35,10 +35,3 @@ PROFILE_NAME_PREFIX = section['profile_name_prefix'] section = cp['DRIVER'] UCSM_DRIVER = section['name'] - - -def main(): - print MAX_UCSM_PORT_PROFILES - -if __name__ == '__main__': - main() diff --git a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py index acf0df100d..5d860ddca6 100644 --- a/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py +++ b/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py @@ -233,25 +233,3 @@ class CiscoUCSMDriver(): def release_dynamic_nic(self, host): # TODO (Sumit): Release on a specific host pass - - -def main(): - client = CiscoUCSMDriver() - #client.create_vlan("quantum-vlan-3", "3","172.20.231.27","admin", - # "c3l12345") - #client.create_profile("q-prof-3", "quantum-vlan-3","172.20.231.27", - # "admin", "c3l12345") - #client.get_dynamic_nic("dummy") - #client.get_dynamic_nic("dummy") - #client.release_dynamic_nic("dummy") - print client.get_dynamic_nic("dummy") - """ - client.change_vlan_in_profile("br100", "default", "test-2", - "172.20.231.27","admin", - "c3l12345") - client.change_vlan_in_profile("br100", "test-2", "default", - "172.20.231.27", "admin", "c3l12345") - """ - -if __name__ == '__main__': - main() From ff74c1deb0914530231582081ab2e736fe9ce443 Mon Sep 17 00:00:00 2001 From: Edgar Magana Date: Mon, 15 Aug 2011 09:02:24 -0700 Subject: [PATCH 47/48] Removing extra testing function on Nexus Driver --- .../plugins/cisco/nexus/cisco_nexus_network_driver.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py index 02380dc9e3..c7b4d801a4 100644 --- a/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py +++ b/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py @@ -210,16 +210,6 @@ class CiscoNEXUSDriver(): print confstr mgr.edit_config(target='running', config=confstr) - def test_nxos_api(self, host, user, password): - with self.nxos_connect(host, port=22, user=user, - password=password) as m: - #enable_vlan(m, '100', 'ccn1') - #enable_vlan_on_trunk_int(m, '2/1', '100') - #disable_vlan_on_trunk_int(m, '2/1', '100') - #disable_vlan(m, '100') - result = m.get(("subtree", filter_show_vlan_brief_snippet)) - print result - def create_vlan(self, vlan_name, vlan_id, nexus_host, nexus_user, nexus_password, nexus_interface): #TODO (Edgar) Move the SSH port to the configuration file From 9c6bfadfaeec0dee815df345bd5f36d696724fda Mon Sep 17 00:00:00 2001 From: Sumit Naiksatam Date: Mon, 15 Aug 2011 10:13:08 -0700 Subject: [PATCH 48/48] Changes in the README file to incorporate Somik's comments. --- quantum/plugins/cisco/README | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/quantum/plugins/cisco/README b/quantum/plugins/cisco/README index 7b214202e0..b2ecf449a9 100755 --- a/quantum/plugins/cisco/README +++ b/quantum/plugins/cisco/README @@ -1,6 +1,6 @@ -============================================ -README: Quantum L2 Network Plugin Framework -============================================ +===================================================================== +README: A Framework for a Quantum Plugin Supporting Multiple Switches +===================================================================== :Author: Sumit Naiksatam, Ram Durairaj, Mark Voelker, Edgar Magana, Shweta Padubidri, Rohit Agarwalla, Ying Liu :Contact: netstack@lists.launchpad.net @@ -15,8 +15,8 @@ Introduction This plugin implementation provides the following capabilities to help you take your Layer 2 network for a Quantum leap: -* A reference implementation of plugin framework for L2 network -* Supports multiple switches in the network +* A reference implementation a framework for a Quantum Plugin +to use multiple devices/switches in a L2 network * Supports multiple models of switches concurrently * Supports Cisco UCS blade servers with M81KR Virtual Interface Cards (aka "Palo adapters") via 802.1Qbh.