Merge lp:~cisco-openstack/neutron/l2network-plugin into lp:neutron/diablo

Proposed by Sumit Naiksatam
Status: Merged
Merged at revision: 41
Proposed branch: lp:~cisco-openstack/neutron/l2network-plugin
Merge into: lp:neutron/diablo
Diff against target: 4999 lines (+4806/-0)
37 files modified
quantum/plugins/cisco/README (+236/-0)
quantum/plugins/cisco/__init__.py (+18/-0)
quantum/plugins/cisco/common/__init__.py (+18/-0)
quantum/plugins/cisco/common/cisco_configparser.py (+40/-0)
quantum/plugins/cisco/common/cisco_constants.py (+103/-0)
quantum/plugins/cisco/common/cisco_credentials.py (+60/-0)
quantum/plugins/cisco/common/cisco_exceptions.py (+57/-0)
quantum/plugins/cisco/common/cisco_nova_configuration.py (+35/-0)
quantum/plugins/cisco/common/cisco_utils.py (+59/-0)
quantum/plugins/cisco/conf/credentials.ini (+15/-0)
quantum/plugins/cisco/conf/l2network_plugin.ini (+16/-0)
quantum/plugins/cisco/conf/nexus.ini (+8/-0)
quantum/plugins/cisco/conf/nova.ini (+8/-0)
quantum/plugins/cisco/conf/plugins.ini (+3/-0)
quantum/plugins/cisco/conf/ucs.ini (+10/-0)
quantum/plugins/cisco/db/__init__.py (+18/-0)
quantum/plugins/cisco/l2device_plugin_base.py (+152/-0)
quantum/plugins/cisco/l2network_model.py (+100/-0)
quantum/plugins/cisco/l2network_model_base.py (+150/-0)
quantum/plugins/cisco/l2network_plugin.py (+394/-0)
quantum/plugins/cisco/l2network_plugin_configuration.py (+50/-0)
quantum/plugins/cisco/nexus/__init__.py (+18/-0)
quantum/plugins/cisco/nexus/cisco_nexus_configuration.py (+35/-0)
quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py (+226/-0)
quantum/plugins/cisco/nexus/cisco_nexus_plugin.py (+168/-0)
quantum/plugins/cisco/run_tests.py (+301/-0)
quantum/plugins/cisco/tests/__init__.py (+18/-0)
quantum/plugins/cisco/tests/unit/__init__.py (+32/-0)
quantum/plugins/cisco/tests/unit/test_l2networkApi.py (+892/-0)
quantum/plugins/cisco/tests/unit/test_nexus_plugin.py (+282/-0)
quantum/plugins/cisco/tests/unit/test_ucs_driver.py (+165/-0)
quantum/plugins/cisco/tests/unit/test_ucs_plugin.py (+480/-0)
quantum/plugins/cisco/ucs/__init__.py (+18/-0)
quantum/plugins/cisco/ucs/cisco_getvif.py (+51/-0)
quantum/plugins/cisco/ucs/cisco_ucs_configuration.py (+37/-0)
quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py (+235/-0)
quantum/plugins/cisco/ucs/cisco_ucs_plugin.py (+298/-0)
To merge this branch: bzr merge lp:~cisco-openstack/neutron/l2network-plugin
Reviewer Review Type Date Requested Status
Salvatore Orlando Approve
Somik Behera netstack-core Approve
dan wendlandt Approve
Review via email: mp+70804@code.launchpad.net

Description of the change

This plugin implementation provides the following capabilities:

* 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.

All modules checked in are new (see quantum/plugins/cisco). No existing modules are modified, existing functionality is not affected.

Unit tests are provided under quantum/plugins/cisco/tests. Tests can be performed on the core API even in the absence of requisite hardware. Other tests require a more specific setup.

For details, please see: quantum/plugins/cisco/README

The following is output from unit tests run on the core API (all tests pass successfully):

CoreAPITestFunc
    test_associate_portprofile 2011-08-08 16:48:54,093 DEBUG test_associate_portprofile - START
2011-08-08 16:48:54,093 DEBUG Creating new tenant record with tenant id test_tenant

2011-08-08 16:48:54,093 DEBUG test_associate_portprofile - END
OK
    test_associate_portprofileDNE 2011-08-08 16:48:54,093 DEBUG test_associate_portprofileDNE - START
2011-08-08 16:48:54,093 DEBUG test_associate_portprofileDNE - END
OK
    test_create_network 2011-08-08 16:48:54,094 DEBUG test_create_network - START
2011-08-08 16:48:54,094 DEBUG create_network() called

2011-08-08 16:48:54,107 DEBUG delete_network() called

2011-08-08 16:48:54,109 DEBUG test_create_network - END
OK
    test_create_port 2011-08-08 16:48:54,109 DEBUG test_create_port - START
2011-08-08 16:48:54,109 DEBUG create_network() called

2011-08-08 16:48:54,112 DEBUG Creating new tenant record with tenant id test_network

2011-08-08 16:48:54,112 DEBUG create_port() called

2011-08-08 16:48:54,115 DEBUG delete_port() called

2011-08-08 16:48:54,117 DEBUG delete_network() called

2011-08-08 16:48:54,120 DEBUG test_create_port - END
OK
    test_create_port_network_DNE 2011-08-08 16:48:54,120 DEBUG test_create_port_network_DNE - START
2011-08-08 16:48:54,120 DEBUG create_port() called

2011-08-08 16:48:54,120 DEBUG test_create_port_network_DNE - END:
OK
    test_create_portprofile 2011-08-08 16:48:54,120 DEBUG test_create_portprofile - tenant id: None - START
2011-08-08 16:48:54,121 DEBUG test_create_portprofile - tenant id: None - END
OK
    test_delete_network 2011-08-08 16:48:54,121 DEBUG test_delete_network - START
2011-08-08 16:48:54,121 DEBUG create_network() called

2011-08-08 16:48:54,123 DEBUG delete_network() called

2011-08-08 16:48:54,126 DEBUG test_delete_network - END
OK
    test_delete_networkDNE 2011-08-08 16:48:54,126 DEBUG test_delete_network_not_found - START
2011-08-08 16:48:54,126 DEBUG delete_network() called

2011-08-08 16:48:54,126 DEBUG test_delete_network_not_found - END
OK
    test_delete_networkInUse 2011-08-08 16:48:54,126 DEBUG test_delete_networkInUse - START
2011-08-08 16:48:54,126 DEBUG create_network() called

2011-08-08 16:48:54,128 DEBUG create_port() called

2011-08-08 16:48:54,131 DEBUG plug_interface() called

2011-08-08 16:48:54,133 DEBUG delete_network() called

2011-08-08 16:48:54,133 DEBUG unplug_interface() called

2011-08-08 16:48:54,136 DEBUG delete_port() called

2011-08-08 16:48:54,138 DEBUG delete_network() called

2011-08-08 16:48:54,141 DEBUG test_delete_networkInUse - END
OK
    test_delete_port 2011-08-08 16:48:54,141 DEBUG test_delete_port - START
2011-08-08 16:48:54,141 DEBUG create_network() called

2011-08-08 16:48:54,144 DEBUG create_port() called

2011-08-08 16:48:54,146 DEBUG delete_port() called

2011-08-08 16:48:54,148 DEBUG delete_network() called

2011-08-08 16:48:54,151 DEBUG test_delete_port - END
OK
    test_delete_portDNE 2011-08-08 16:48:54,151 DEBUG test_delete_portDNE - START
2011-08-08 16:48:54,151 DEBUG create_network() called

2011-08-08 16:48:54,154 DEBUG delete_port() called

2011-08-08 16:48:54,154 DEBUG delete_network() called

2011-08-08 16:48:54,156 DEBUG test_delete_portDNE - END
OK
    test_delete_portInUse 2011-08-08 16:48:54,156 DEBUG test_delete_portInUse - START
2011-08-08 16:48:54,156 DEBUG create_network() called

2011-08-08 16:48:54,159 DEBUG create_port() called

2011-08-08 16:48:54,161 DEBUG plug_interface() called

2011-08-08 16:48:54,164 DEBUG delete_port() called

2011-08-08 16:48:54,164 DEBUG unplug_interface() called

2011-08-08 16:48:54,166 DEBUG delete_port() called

2011-08-08 16:48:54,169 DEBUG delete_network() called

2011-08-08 16:48:54,171 DEBUG test_delete_portInUse - END
OK
    test_delete_port_networkDNE 2011-08-08 16:48:54,171 DEBUG test_delete_port_networkDNE - START
2011-08-08 16:48:54,172 DEBUG delete_port() called

2011-08-08 16:48:54,172 DEBUG test_delete_port_networkDNE - END
OK
    test_delete_portprofile 2011-08-08 16:48:54,172 DEBUG test_delete_portprofile - tenant id: None - START
2011-08-08 16:48:54,172 DEBUG test_delete_portprofile - tenant id: None - END
OK
    test_delete_portprofileAssociated 2011-08-08 16:48:54,172 DEBUG test_delete_portprofileAssociated - START
2011-08-08 16:48:54,172 DEBUG test_delete_portprofileAssociated - END
OK
    test_delete_portprofileDNE 2011-08-08 16:48:54,172 DEBUG test_delete_portprofileDNE - START
2011-08-08 16:48:54,172 DEBUG test_delete_portprofileDNE - END
OK
    test_disassociate_portprofile 2011-08-08 16:48:54,172 DEBUG test_disassociate_portprofile - START
2011-08-08 16:48:54,173 DEBUG test_disassociate_portprofile - END
OK
    test_disassociate_portprofileDNE 2011-08-08 16:48:54,173 DEBUG test_disassociate_portprofileDNE - START
2011-08-08 16:48:54,173 DEBUG test_disassociate_portprofileDNE - END
OK
    test_get_tenant 2011-08-08 16:48:54,173 DEBUG test_get_tenant - START
2011-08-08 16:48:54,173 DEBUG test_get_tenant - END
OK
    test_get_vlan_name 2011-08-08 16:48:54,173 DEBUG test_get_vlan_name - START
2011-08-08 16:48:54,173 DEBUG test_get_vlan_name - END
OK
    test_invalid_port_state 2011-08-08 16:48:54,173 DEBUG test_validate_port_state - START
2011-08-08 16:48:54,173 DEBUG test_validate_port_state - END
OK
    test_list_networks 2011-08-08 16:48:54,174 DEBUG test_list_networks - START
2011-08-08 16:48:54,174 DEBUG create_network() called

2011-08-08 16:48:54,176 DEBUG create_network() called

2011-08-08 16:48:54,178 DEBUG get_all_networks() called

2011-08-08 16:48:54,180 DEBUG delete_network() called

2011-08-08 16:48:54,182 DEBUG delete_network() called

2011-08-08 16:48:54,185 DEBUG test_list_networks - END
OK
    test_list_portprofile 2011-08-08 16:48:54,185 DEBUG test_list_portprofile - tenant id: test_tenant - START
2011-08-08 16:48:54,185 DEBUG test_create_portprofile - tenant id: test_tenant - END
OK
    test_list_ports 2011-08-08 16:48:54,185 DEBUG test_list_ports - START
2011-08-08 16:48:54,185 DEBUG create_network() called

2011-08-08 16:48:54,187 DEBUG create_port() called

2011-08-08 16:48:54,190 DEBUG create_port() called

2011-08-08 16:48:54,192 DEBUG get_all_ports() called

2011-08-08 16:48:54,193 DEBUG delete_port() called

2011-08-08 16:48:54,196 DEBUG delete_port() called

2011-08-08 16:48:54,198 DEBUG delete_network() called

2011-08-08 16:48:54,201 DEBUG test_list_ports - END
OK
    test_plug_interface 2011-08-08 16:48:54,201 DEBUG test_plug_interface - START
2011-08-08 16:48:54,201 DEBUG create_network() called

2011-08-08 16:48:54,204 DEBUG create_port() called

2011-08-08 16:48:54,206 DEBUG plug_interface() called

2011-08-08 16:48:54,208 DEBUG unplug_interface() called

2011-08-08 16:48:54,211 DEBUG delete_port() called

2011-08-08 16:48:54,214 DEBUG delete_network() called

2011-08-08 16:48:54,217 DEBUG test_plug_interface - END
OK
    test_plug_interface_networkDNE 2011-08-08 16:48:54,217 DEBUG test_plug_interface_networkDNE - START
2011-08-08 16:48:54,217 DEBUG plug_interface() called

2011-08-08 16:48:54,217 DEBUG test_plug_interface_networkDNE - END
OK
    test_plug_interface_portDNE 2011-08-08 16:48:54,217 DEBUG test_plug_interface_portDNE - START
2011-08-08 16:48:54,217 DEBUG create_network() called

2011-08-08 16:48:54,219 DEBUG plug_interface() called

2011-08-08 16:48:54,220 DEBUG delete_network() called

2011-08-08 16:48:54,222 DEBUG test_plug_interface_portDNE - END
OK
    test_plug_interface_portInUse 2011-08-08 16:48:54,222 DEBUG test_plug_interface_portInUse - START
2011-08-08 16:48:54,222 DEBUG create_network() called

2011-08-08 16:48:54,225 DEBUG create_port() called

2011-08-08 16:48:54,227 DEBUG plug_interface() called

2011-08-08 16:48:54,229 DEBUG plug_interface() called

2011-08-08 16:48:54,230 DEBUG unplug_interface() called

2011-08-08 16:48:54,232 DEBUG delete_port() called

2011-08-08 16:48:54,235 DEBUG delete_network() called

2011-08-08 16:48:54,237 DEBUG test_plug_interface_portInUse - END
OK
    test_rename_network 2011-08-08 16:48:54,237 DEBUG test_rename_network - START
2011-08-08 16:48:54,237 DEBUG create_network() called

2011-08-08 16:48:54,240 DEBUG rename_network() called

2011-08-08 16:48:54,242 DEBUG delete_network() called

2011-08-08 16:48:54,245 DEBUG test_rename_network - END
OK
    test_rename_networkDNE 2011-08-08 16:48:54,245 DEBUG test_rename_network_not_found - START
2011-08-08 16:48:54,245 DEBUG rename_network() called

2011-08-08 16:48:54,247 DEBUG test_rename_network_not_found - END
OK
    test_rename_portprofile 2011-08-08 16:48:54,248 DEBUG test_rename_portprofile - START
2011-08-08 16:48:54,248 DEBUG test_show_portprofile - tenant id: %s - END
OK
    test_rename_portprofileDNE 2011-08-08 16:48:54,248 DEBUG test_rename_portprofileDNE - START
2011-08-08 16:48:54,248 DEBUG test_rename_portprofileDNE - END
OK
    test_show_network 2011-08-08 16:48:54,248 DEBUG test_show_network - START
2011-08-08 16:48:54,248 DEBUG create_network() called

2011-08-08 16:48:54,250 DEBUG get_network_details() called

2011-08-08 16:48:54,252 DEBUG delete_network() called

2011-08-08 16:48:54,254 DEBUG test_show_network - END
OK
    test_show_networkDNE 2011-08-08 16:48:54,254 DEBUG test_show_network_not_found - START
2011-08-08 16:48:54,254 DEBUG get_network_details() called

2011-08-08 16:48:54,256 DEBUG test_show_network_not_found - END
OK
    test_show_port 2011-08-08 16:48:54,256 DEBUG test_show_port - START
2011-08-08 16:48:54,256 DEBUG create_network() called

2011-08-08 16:48:54,258 DEBUG create_port() called

2011-08-08 16:48:54,261 DEBUG get_port_details() called

2011-08-08 16:48:54,262 DEBUG delete_port() called

2011-08-08 16:48:54,264 DEBUG delete_network() called

2011-08-08 16:48:54,267 DEBUG test_show_port - END
OK
    test_show_portDNE 2011-08-08 16:48:54,267 DEBUG test_show_portDNE - START
2011-08-08 16:48:54,267 DEBUG create_network() called

2011-08-08 16:48:54,269 DEBUG get_port_details() called

2011-08-08 16:48:54,271 DEBUG delete_network() called

2011-08-08 16:48:54,273 DEBUG test_show_portDNE - END
OK
    test_show_port_networkDNE 2011-08-08 16:48:54,273 DEBUG test_show_port_networkDNE - START
2011-08-08 16:48:54,273 DEBUG get_port_details() called

2011-08-08 16:48:54,275 DEBUG test_show_port_networkDNE - END
OK
    test_show_portprofile 2011-08-08 16:48:54,275 DEBUG test_show_portprofile - START
2011-08-08 16:48:54,275 DEBUG test_show_portprofile - tenant id: None - END
OK
    test_show_portprofileDNE 2011-08-08 16:48:54,275 DEBUG test_show_portprofileDNE - START
2011-08-08 16:48:54,275 DEBUG test_show_portprofileDNE - END
OK
    test_unplug_interface 2011-08-08 16:48:54,275 DEBUG test_unplug_interface - START
2011-08-08 16:48:54,275 DEBUG create_network() called

2011-08-08 16:48:54,278 DEBUG create_port() called

2011-08-08 16:48:54,280 DEBUG plug_interface() called

2011-08-08 16:48:54,283 DEBUG unplug_interface() called

2011-08-08 16:48:54,285 DEBUG delete_port() called

2011-08-08 16:48:54,287 DEBUG delete_network() called

2011-08-08 16:48:54,290 DEBUG test_unplug_interface - END
OK
    test_unplug_interface_networkDNE 2011-08-08 16:48:54,290 DEBUG test_unplug_interface_networkDNE - START
2011-08-08 16:48:54,290 DEBUG unplug_interface() called

2011-08-08 16:48:54,290 DEBUG test_unplug_interface_networkDNE - END
OK
    test_unplug_interface_portDNE 2011-08-08 16:48:54,290 DEBUG test_unplug_interface_portDNE - START
2011-08-08 16:48:54,291 DEBUG create_network() called

2011-08-08 16:48:54,293 DEBUG unplug_interface() called

2011-08-08 16:48:54,293 DEBUG delete_network() called

2011-08-08 16:48:54,296 DEBUG test_unplug_interface_portDNE - END
OK
    test_update_port 2011-08-08 16:48:54,296 DEBUG test_update_port - START
2011-08-08 16:48:54,296 DEBUG create_network() called

2011-08-08 16:48:54,298 DEBUG create_port() called

2011-08-08 16:48:54,301 DEBUG update_port() called

2011-08-08 16:48:54,302 DEBUG delete_port() called

2011-08-08 16:48:54,304 DEBUG delete_network() called

2011-08-08 16:48:54,307 DEBUG test_update_port - END
OK
    test_update_portDNE 2011-08-08 16:48:54,307 DEBUG test_update_portDNE - START
2011-08-08 16:48:54,307 DEBUG create_network() called

2011-08-08 16:48:54,309 DEBUG update_port() called

2011-08-08 16:48:54,311 DEBUG delete_network() called

2011-08-08 16:48:54,313 DEBUG test_update_portDNE - END
OK
    test_update_port_networkDNE 2011-08-08 16:48:54,313 DEBUG test_update_port_networkDNE - START
2011-08-08 16:48:54,313 DEBUG update_port() called

2011-08-08 16:48:54,315 DEBUG test_update_port_networkDNE - END
OK
    test_validate_attachment 2011-08-08 16:48:54,315 DEBUG test_validate_attachment - START
2011-08-08 16:48:54,315 DEBUG create_network() called

2011-08-08 16:48:54,318 DEBUG create_port() called

2011-08-08 16:48:54,320 DEBUG plug_interface() called

2011-08-08 16:48:54,323 DEBUG unplug_interface() called

2011-08-08 16:48:54,325 DEBUG delete_port() called

2011-08-08 16:48:54,328 DEBUG delete_network() called

2011-08-08 16:48:54,330 DEBUG test_validate_attachment - END
OK
    test_validate_port_state 2011-08-08 16:48:54,330 DEBUG test_validate_port_state - START
2011-08-08 16:48:54,330 DEBUG test_validate_port_state - END
OK

----------------------------------------------------------------------
Ran 47 tests in 0.238s

OK

To post a comment you must log in.
58. By Sumit Naiksatam on 2011-08-09

Changed to default plugin class name.

59. By Sumit Naiksatam on 2011-08-10

Tiny change to the README file, instructions on how to get ncclient.

Hi Sumit,

This is a massive piece of work, well done!
The code looks great. It is well written and easily understandable.

- README states that this plugin provides "A reference implementation of plugin framework for L2 network". My understanding of a "reference implementation" is that it should be a relatively basic implementation of a standardized interface, which could be executed by a large number of users. Probably the cisco plugin should not be considered a "reference" implementation for Quantum, as it has pretty much strict sw & hw requirements.

- It would be great if you can improve a bit pylint score for your branch. Your branch scores 6.53/10, it would be great if could bring that result to at leasr 7.5/10. We are already doing some work for improving pylint in trunk code.

-As you pointed out in comments, the plugin currently does not work on multi-host. This should be explictly noted in the README file.

- Several modules have a main method, which was probably used for testing during developed. From what I see from the code, this main methods can be removed.

Before approving for merge, it would be great if you could answer some questions:

- README mentions some changes are required to nova, and that these changes should be merged in nova in time for diablo release. Are you referring to nova-refactoring work led by Ryu? Are these changes specific for the Cisco plugin?

- How does this branch implement the blue print for the Quantum plugin interface? It contains only code specific for the Cisco plugin.

- It seems to be possible to configure the Cisco plugin to work with the Nexus sub-plugin only excluding the UCS one; however in that case the plugin will not work correctly as some operations need the UCS plugin. Would it be the case to make the UCS compulsory?

- id generation - Looks like you're using absolute counters. Have you considered using per-tenant counters?

- Plugin returns some extra parameters which will be ignored by API. Is there a plan to make these parameters available through extensions?

- A single logger if being used for the whole plugin. As there are several thousands lines of code, it may be the case to have per-module loggers. This is not really important, but it would improved debugging.

review: Needs Information
Sumit Naiksatam (snaiksat) wrote :
Download full text (6.2 KiB)

Thanks Salvatore for your in-depth review. I will be happy to provide the information you need. My responses are embedded inline.

> Hi Sumit,
>
> This is a massive piece of work, well done!
> The code looks great. It is well written and easily understandable.
>
> - README states that this plugin provides "A reference implementation of
> plugin framework for L2 network". My understanding of a "reference
> implementation" is that it should be a relatively basic implementation of a
> standardized interface, which could be executed by a large number of users.
> Probably the cisco plugin should not be considered a "reference"
> implementation for Quantum, as it has pretty much strict sw & hw requirements.
>

<Sumit> It seems the presence of the "Pre-requisites" section at the top of the README misleads the reader into thinking that the L2Network-plugin framework presented here can be only run with those specific requirements. We wanted to convey that the requirements mentioned in the pre-requisites were necessary when using the UCS and/or Nexus hardware. However, in the absence of the specific hardware and software, the plugin framework presented here can still be deployed and used.

For instance we have run this on an Ubuntu box by disabling the UCS and Nexus device-plugins (disabling is a matter of configuring the quantum/plugins/cisco/conf/plugins.ini file). One could envision writing a Linux bridge device-plugin based on the device-plugin interface proposed in this framework (l2device_plugin_base.py). Similarly, we are proposing the notion of a network "model" which represents the actual physical interconnection of network devices. To that end, we have proposed a base class definition of this model (l2network_model_based.py), which can be extended on a per-deployment basis. When taken together, these artifacts, namely:
l2network_plugin.py, l2network_model_base.py, l2device_plugin_base.py, common/*, and conf/*,
embody a framework which is not specific to any hardware or software, and can be easily reused and adapted to any other combination of devices and networks.
This notion of the framework is also elaborated in the design document for the blueprint:
http://wiki.openstack.org/quantum-multi-switch-plugin

To summarize, it should be noted that there are two distinct broad contributions in this branch (1) a device/technology/vendor independent L2 network plugin framework proposal/implementation, (2) specific support for UCS and Nexus adhering to the framework outlined in (1). The comment on the reference implementation is in the context of (1).

Coming back to your comment, would it be ok if we qualify the "Pre-requisites" section with the additional information that those are needed only in the case of UCS and/or Nexus hardware/software? (I have modified the README file to reflect this.)</Sumit>

> - It would be great if you can improve a bit pylint score for your branch.
> Your branch scores 6.53/10, it would be great if could bring that result to at
> leasr 7.5/10. We are already doing some work for improving pylint in trunk
> code.
>

<Sumit> Would it be acceptable if we achieve this in an upcoming merge (which we are waiting to pro...

Read more...

dan wendlandt (danwent) wrote :
Download full text (5.7 KiB)

Very cool to see this code is ready for merge. Having a Cisco plugin is an important step for the project as a whole, so I'd like to see this code get in ASAP.

I have a good number of comments below, but for the most part they are just suggestions for how you could improve the readability of the code for developers (like me!) that are looking at it for the first time. I don't see any of them as blockers and since this code is entirely self-contained, I'm voting to approve for merge right away. Getting the pylint score up is a good goal, but as long as you take care of that with the next merge I'm cool with it.

Great work :)

Dan

'quantum/plugins/cisco/README'

* The notion of a "reference implementation" vs. the Palo/Nexus specific functionality makes sense, since you've explained it to me before. Perhaps separate out the audiences would make it more clear though. For quantum administrators, this code is useful because they can us it with UCS/Nexus based networks. For quantum developers this code is useful because they may want to base their own plugin on it.

* If you are using a special branch of nova, it may be cleaner + easier to just add a sqlalchemy migrate script to automatically create this table with the user syncs the DB.
200
+1. Create a table in the "nova" database for ports. This can be
201
+ accomplished with the following SQL statement:

quantum/plugins/cisco/common/cisco_constants.py

* Currently, the rest of the Quantum codebase uses "ACTIVE" instead of "UP". While I'm personally in favor of "UP", its probably best to be consistent, then we can switch all of them at the same time if we decide that's the right thing to do.

+PORT_UP = "UP"

* it strikes me that some of these constants are not plugin specific, so ideally we'd actually have those in quantum/common, so they can be leveraged by all plugins, clients, tests, etc. This isn't required, but would be a nice thing to do at some point.

quantum/plugins/cisco/common/cisco_credentials.py

* I'm guessing your OK with this, but it struck me as a bit odd that you had methods for modifying the store, but those modifications where not persisted. Just wanted to make sure that is what you intended.

quantum/plugins/cisco/l2device_plugin_base.py

It took me a bit of glancing to figure out how this file differed from the standard quantum/quantum_plugin_base.py. Main difference is that create_network takes vlan arguments, though there is also a **kwargs added to each method. Its probably worth having a comment at the top of the class describing the difference.

quantum/plugins/cisco/l2network_model.py

* Its not obvious to a reader why certain methods are implemented here while others aren't. A comment could help clarify why methods like update_port(), get_all_ports(), etc are not implemented (e.g., must they be implemented by a child class? If so, raising a NotImplemented exception might be better than silently passing).

quantum/plugins/cisco/l2network_model_base.py

* use of the term "model" threw me at first, as in nova and the main quantum code-base "model" tends to refer to an sqlalchemy database model, whereas this code (I don't think) is rel...

Read more...

review: Approve
60. By Sumit Naiksatam on 2011-08-14

Removed main from modules as per review comments.

Sumit Naiksatam (snaiksat) wrote :
Download full text (9.3 KiB)

Thanks Dan for the thorough review, and the words of appreciation. My responses inline, pretty much in agreement with most of your suggestions (and a lot of the changes have already gone into the ongoing work). Some of the points which you have raised are better clarified in the document posted here:
http://wiki.openstack.org/quantum-multi-switch-plugin (we should have made this available sooner).

> Very cool to see this code is ready for merge. Having a Cisco plugin is an
> important step for the project as a whole, so I'd like to see this code get in
> ASAP.
>
> I have a good number of comments below, but for the most part they are just
> suggestions for how you could improve the readability of the code for
> developers (like me!) that are looking at it for the first time. I don't see
> any of them as blockers and since this code is entirely self-contained, I'm
> voting to approve for merge right away. Getting the pylint score up is a good
> goal, but as long as you take care of that with the next merge I'm cool with
> it.
>
> Great work :)
>
> Dan
>
> 'quantum/plugins/cisco/README'
>
> * The notion of a "reference implementation" vs. the Palo/Nexus specific
> functionality makes sense, since you've explained it to me before. Perhaps
> separate out the audiences would make it more clear though. For quantum
> administrators, this code is useful because they can us it with UCS/Nexus
> based networks. For quantum developers this code is useful because they may
> want to base their own plugin on it.
>

<Sumit> Agreed. We will try to do a better job of highlighting the L2 Network Plugin Framework (to support multiple devices/switches) versus the specific support for UCS/Nexus, both of which have gone into this branch. The former is intended to be useful for anyone using the Quantum service, and faced with the issue of handling multiple types of devices.</Sumit>

> * If you are using a special branch of nova, it may be cleaner + easier to
> just add a sqlalchemy migrate script to automatically create this table with
> the user syncs the DB.
> 200
> +1. Create a table in the "nova" database for ports. This can be
> 201
> + accomplished with the following SQL statement:
>

<Sumit> Agree. This is actually a temporary requirement, and should go away altogether. </Sumit>

> quantum/plugins/cisco/common/cisco_constants.py
>
> * Currently, the rest of the Quantum codebase uses "ACTIVE" instead of "UP".
> While I'm personally in favor of "UP", its probably best to be consistent,
> then we can switch all of them at the same time if we decide that's the right
> thing to do.
>
> +PORT_UP = "UP"

<Sumit> Agree. This has already been changed in a new branch. </Sumit>

>
> * it strikes me that some of these constants are not plugin specific, so
> ideally we'd actually have those in quantum/common, so they can be leveraged
> by all plugins, clients, tests, etc. This isn't required, but would be a nice
> thing to do at some point.
>

<Sumit> Ok, will look into it. </Sumit>

> quantum/plugins/cisco/common/cisco_credentials.py
>
> * I'm guessing your OK with this, but it struck me as a bit odd that you had
> methods for modifying the store...

Read more...

dan wendlandt (danwent) wrote :
Download full text (10.6 KiB)

Ok, sounds like we're in good shape with this branch. I know Salvatore said
he was at least partially out-of-office this week, but it doesn't sound like
there were any blockers from his end, so hopefully we can get this merged
early this week.

Dan

p.s. the diagram in the document does indeed make things more clear. Its
funny, as I had almost added a comment to my review saying that a diagram
would be helpful :)

On Mon, Aug 15, 2011 at 2:31 AM, Sumit Naiksatam <email address hidden> wrote:

> Thanks Dan for the thorough review, and the words of appreciation. My
> responses inline, pretty much in agreement with most of your suggestions
> (and a lot of the changes have already gone into the ongoing work). Some of
> the points which you have raised are better clarified in the document posted
> here:
> http://wiki.openstack.org/quantum-multi-switch-plugin (we should have made
> this available sooner).
>
> > Very cool to see this code is ready for merge. Having a Cisco plugin is
> an
> > important step for the project as a whole, so I'd like to see this code
> get in
> > ASAP.
> >
> > I have a good number of comments below, but for the most part they are
> just
> > suggestions for how you could improve the readability of the code for
> > developers (like me!) that are looking at it for the first time. I don't
> see
> > any of them as blockers and since this code is entirely self-contained,
> I'm
> > voting to approve for merge right away. Getting the pylint score up is a
> good
> > goal, but as long as you take care of that with the next merge I'm cool
> with
> > it.
> >
> > Great work :)
> >
> > Dan
> >
> > 'quantum/plugins/cisco/README'
> >
> > * The notion of a "reference implementation" vs. the Palo/Nexus specific
> > functionality makes sense, since you've explained it to me before.
> Perhaps
> > separate out the audiences would make it more clear though. For quantum
> > administrators, this code is useful because they can us it with UCS/Nexus
> > based networks. For quantum developers this code is useful because they
> may
> > want to base their own plugin on it.
> >
>
> <Sumit> Agreed. We will try to do a better job of highlighting the L2
> Network Plugin Framework (to support multiple devices/switches) versus the
> specific support for UCS/Nexus, both of which have gone into this branch.
> The former is intended to be useful for anyone using the Quantum service,
> and faced with the issue of handling multiple types of devices.</Sumit>
>
> > * If you are using a special branch of nova, it may be cleaner + easier
> to
> > just add a sqlalchemy migrate script to automatically create this table
> with
> > the user syncs the DB.
> > 200
> > +1. Create a table in the "nova" database for ports. This can be
> > 201
> > + accomplished with the following SQL statement:
> >
>
> <Sumit> Agree. This is actually a temporary requirement, and should go away
> altogether. </Sumit>
>
> > quantum/plugins/cisco/common/cisco_constants.py
> >
> > * Currently, the rest of the Quantum codebase uses "ACTIVE" instead of
> "UP".
> > While I'm personally in favor of "UP", its probably best to be
> consistent,
> > then we can switch all of them at the sam...

61. By Edgar Magana on 2011-08-15

Removing extra testing function on Nexus Driver

Somik Behera (somikbehera) wrote :

Hi Sumit,

First of all, Congratulations! to you, Edgar, Shweta and all others that have worked on creating this hunk of code. I concur the feelings of Salvatore and Dan and overall it looks well done!

I believe, Salvatore and Dan have done a extensive review and I believe everything looks pretty good. I did have one small comment regarding this merge-prop and "Define Quantum Plugin Interface for Python" blueprint.

At this point, the above referenced blueprint, which is a non vendor implementation specific, generic Quantum plugin, is already implemented and complete.

I was never under the impression the work contained in this merge-prop was specified under "Define Quantum Plugin Interface for Python" blueprint.

I do like the idea of "multi-switch plugin framework" that you guys have implemented as a generic framework for others to leverage, but I would unlink this branch from "Define Quantum Plugin Interface for Python" blueprint.

Reading the README, I believe we should call this a reference implementation of "Multi-switch plugin framework for a Quantum plugin using Cisco platform components" not "A reference implementation of plugin framework for L2 network."

An "reference implementation" is something that can be used by the end-user without requiring any specific HW/SW (something that cannot be obtained in the public domain).

This ambiguity threw me off as to what we are actually providing is not a plugin framework for Quantum, but a framework for a Quantum Plugin to use multiple devices/switches, which is great! but we just have better elucidate the fact.

Thanks,
Somik

review: Needs Information (netstack-core)
62. By Sumit Naiksatam on 2011-08-15

Changes in the README file to incorporate Somik's comments.

Sumit Naiksatam (snaiksat) wrote :

Thanks Somik for your review and words of encouragement. I have incorporate both your comments (1) removed the link to one of the blueprints, (2) changed the wording in the README as per your suggestion. Kindly check, and if found satisfactory, please approve.

> Hi Sumit,
>
> First of all, Congratulations! to you, Edgar, Shweta and all others that have
> worked on creating this hunk of code. I concur the feelings of Salvatore and
> Dan and overall it looks well done!
>
> I believe, Salvatore and Dan have done a extensive review and I believe
> everything looks pretty good. I did have one small comment regarding this
> merge-prop and "Define Quantum Plugin Interface for Python" blueprint.
>
> At this point, the above referenced blueprint, which is a non vendor
> implementation specific, generic Quantum plugin, is already implemented and
> complete.
>
> I was never under the impression the work contained in this merge-prop was
> specified under "Define Quantum Plugin Interface for Python" blueprint.
>
> I do like the idea of "multi-switch plugin framework" that you guys have
> implemented as a generic framework for others to leverage, but I would unlink
> this branch from "Define Quantum Plugin Interface for Python" blueprint.
>
> Reading the README, I believe we should call this a reference implementation
> of "Multi-switch plugin framework for a Quantum plugin using Cisco platform
> components" not "A reference implementation of plugin framework for L2
> network."
>
> An "reference implementation" is something that can be used by the end-user
> without requiring any specific HW/SW (something that cannot be obtained in the
> public domain).
>
>
> This ambiguity threw me off as to what we are actually providing is not a
> plugin framework for Quantum, but a framework for a Quantum Plugin to use
> multiple devices/switches, which is great! but we just have better elucidate
> the fact.
>
> Thanks,
> Somik

Sumit Naiksatam (snaiksat) wrote :

Typo: incorporate > incorporated :-)

Thanks,
~Sumit.

> Thanks Somik for your review and words of encouragement. I have incorporate
> both your comments (1) removed the link to one of the blueprints, (2) changed
> the wording in the README as per your suggestion. Kindly check, and if found
> satisfactory, please approve.
>
> > Hi Sumit,
> >
> > First of all, Congratulations! to you, Edgar, Shweta and all others that
> have
> > worked on creating this hunk of code. I concur the feelings of Salvatore and
> > Dan and overall it looks well done!
> >
> > I believe, Salvatore and Dan have done a extensive review and I believe
> > everything looks pretty good. I did have one small comment regarding this
> > merge-prop and "Define Quantum Plugin Interface for Python" blueprint.
> >
> > At this point, the above referenced blueprint, which is a non vendor
> > implementation specific, generic Quantum plugin, is already implemented and
> > complete.
> >
> > I was never under the impression the work contained in this merge-prop was
> > specified under "Define Quantum Plugin Interface for Python" blueprint.
> >
> > I do like the idea of "multi-switch plugin framework" that you guys have
> > implemented as a generic framework for others to leverage, but I would
> unlink
> > this branch from "Define Quantum Plugin Interface for Python" blueprint.
> >
> > Reading the README, I believe we should call this a reference implementation
> > of "Multi-switch plugin framework for a Quantum plugin using Cisco platform
> > components" not "A reference implementation of plugin framework for L2
> > network."
> >
> > An "reference implementation" is something that can be used by the end-user
> > without requiring any specific HW/SW (something that cannot be obtained in
> the
> > public domain).
> >
> >
> > This ambiguity threw me off as to what we are actually providing is not a
> > plugin framework for Quantum, but a framework for a Quantum Plugin to use
> > multiple devices/switches, which is great! but we just have better elucidate
> > the fact.
> >
> > Thanks,
> > Somik

Somik Behera (somikbehera) wrote :

Looks good!

review: Approve (netstack-core)

Comments addressed.
I'm ok to improve pylint score in subsequent merge.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'etc/quantum.conf'
2=== added directory 'quantum/plugins/cisco'
3=== added file 'quantum/plugins/cisco/README'
4--- quantum/plugins/cisco/README 1970-01-01 00:00:00 +0000
5+++ quantum/plugins/cisco/README 2011-08-15 17:33:23 +0000
6@@ -0,0 +1,236 @@
7+=====================================================================
8+README: A Framework for a Quantum Plugin Supporting Multiple Switches
9+=====================================================================
10+
11+:Author: Sumit Naiksatam, Ram Durairaj, Mark Voelker, Edgar Magana, Shweta Padubidri, Rohit Agarwalla, Ying Liu
12+:Contact: netstack@lists.launchpad.net
13+:Web site: https://launchpad.net/~cisco-openstack
14+:Copyright: 2011 Cisco Systems, Inc.
15+
16+.. contents::
17+
18+Introduction
19+------------
20+
21+This plugin implementation provides the following capabilities
22+to help you take your Layer 2 network for a Quantum leap:
23+
24+* A reference implementation a framework for a Quantum Plugin
25+to use multiple devices/switches in a L2 network
26+* Supports multiple models of switches concurrently
27+* Supports Cisco UCS blade servers with M81KR Virtual Interface Cards
28+ (aka "Palo adapters") via 802.1Qbh.
29+* Supports the Cisco Nexus family of switches.
30+
31+It does not provide:
32+
33+* A hologram of Al that only you can see.
34+* A map to help you find your way through time.
35+* A cure for amnesia or your swiss-cheesed brain.
36+
37+Let's leap in!
38+
39+Pre-requisites
40+--------------
41+(The following are necessary only when using the UCS and/or Nexus devices in your system.
42+If you plan to just leverage the plugin framework, you do not need these.)
43+* One or more UCS B200 series blade servers with M81KR VIC (aka
44+ Palo adapters) installed.
45+* UCSM 2.0 (Capitola) Build 230 or above.
46+* OpenStack Cactus release installation (additional patch is required,
47+ details follow in this document)
48+* RHEL 6.1 (as of this writing, UCS only officially supports RHEL, but
49+ it should be noted that Ubuntu support is planned in coming releases as well)
50+ ** Package: python-configobj-4.6.0-3.el6.noarch (or newer)
51+ ** Package: python-routes-1.12.3-2.el6.noarch (or newer)
52+
53+If you are using a Nexus switch in your topology, you'll need the following
54+NX-OS version and packages to enable Nexus support:
55+* NX-OS 5.2.1 (Delhi) Build 69 or above.
56+* paramiko library - SSHv2 protocol library for python
57+ ** To install on RHEL 6.1, run: yum install python-paramiko
58+* ncclient v0.3.1 - Python library for NETCONF clients
59+ ** RedHat does not provide a package for ncclient in RHEL 6.1. Here is how
60+ to get it, from your shell prompt do:
61+
62+ git clone git@github.com:ddutta/ncclient.git
63+ sudo python ./setup.py install
64+
65+ ** For more information of ncclient, see:
66+ http://schmizz.net/ncclient/
67+
68+To verify the version of any package you have installed on your system,
69+run "rpm -qav | grep <package name>", where <package name> is the
70+package you want to query (for example: python-routes).
71+
72+Note that you can get access to recent versions of the packages above
73+and other OpenStack software packages by adding a new repository to
74+your yum configuration. To do so, edit or create
75+/etc/yum.repos.d/openstack.repo and add the following:
76+
77+[openstack-deps]
78+name=OpenStack Nova Compute Dependencies
79+baseurl=http://yum.griddynamics.net/yum/cactus/deps
80+enabled=1
81+gpgcheck=1
82+gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-OPENSTACK
83+
84+Then run "yum install python-routes".
85+
86+
87+Module Structure:
88+-----------------
89+* quantum/plugins/cisco/ - Contains the L2-Network Plugin Framework
90+ /common - Modules common to the entire plugin
91+ /conf - All configuration files
92+ /db - Persistence framework
93+ /nexus - Nexus-specific modules
94+ /tests - Tests specific to this plugin
95+ /ucs - UCS-specific modules
96+
97+
98+Plugin Installation Instructions
99+----------------------------------
100+1. Make a backup copy of quantum/quantum/plugins.ini.
101+
102+2. Edit quantum/quantum/plugins.ini and edit the "provider" entry to point
103+ to the L2Network-plugin:
104+
105+provider = quantum.plugins.cisco.l2network_plugin.L2Network
106+
107+3. If you are not running Quantum on the same host as the OpenStack Cloud
108+ Controller, you will need to change the db_ip_address configuration
109+ in nova.ini.
110+
111+4. If you want to turn on support for Cisco Nexus switches:
112+ 4a. Uncomment the nexus_plugin property in
113+ quantum/plugins/cisco/conf/plugins.ini to read:
114+
115+nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin
116+
117+ 4b. Enter the relevant configuration in the
118+ quantum/plugins/cisco/conf/nexus.ini file. Example:
119+
120+[SWITCH]
121+# Change the following to reflect the IP address of the Nexus switch.
122+# This will be the address at which Quantum sends and receives configuration
123+# information via SSHv2.
124+nexus_ip_address=10.0.0.1
125+# Port number on the Nexus switch to which the UCSM 6120 is connected
126+# Use shortened interface syntax, e.g. "3/23" not "Ethernet3/23".
127+nexus_port=3/23
128+
129+[DRIVER]
130+name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver
131+
132+ 4c. Make sure that SSH host key of the Nexus switch is known to the
133+ host on which you are running the Quantum service. You can do
134+ this simply by logging in to your Quantum host as the user that
135+ Quantum runs as and SSHing to the switch at least once. If the
136+ host key changes (e.g. due to replacement of the supervisor or
137+ clearing of the SSH config on the switch), you may need to repeat
138+ this step and remove the old hostkey from ~/.ssh/known_hosts.
139+
140+5. Verify that you have the correct credentials for each IP address listed
141+ in quantum/plugins/cisco/conf/credentials.ini. Example:
142+
143+# Provide the UCSM credentials
144+# UCSM IP address, username and password.
145+[10.0.0.2]
146+username=admin
147+password=mySecretPasswordForUCSM
148+
149+# Provide the Nova DB credentials.
150+# The IP address should be the same as in nova.ini.
151+[10.0.0.3]
152+username=nova
153+password=mySecretPasswordForNova
154+
155+# Provide the Nexus credentials, if you are using Nexus switches.
156+# If not this will be ignored.
157+[10.0.0.1]
158+username=admin
159+password=mySecretPasswordForNexus
160+
161+6. Start the Quantum service. If something doesn't work, verify that
162+ your configuration of each of the above files hasn't gone a little kaka.
163+ Once you've put right what once went wrong, leap on.
164+
165+
166+How to test the installation
167+----------------------------
168+The unit tests are located at quantum/plugins/cisco/tests/unit. They can be
169+executed from quantum/plugins/cisco/ using the run_tests.py script.
170+
171+1. Testing the core API (without UCS/Nexus/RHEL hardware, and can be run on
172+ Ubuntu):
173+ First disable all device-specific plugins by commenting out the entries in:
174+ quantum/plugins/cisco/conf/plugins.ini
175+ Then run the test script:
176+
177+python run_tests.py unit.test_l2networkApi
178+
179+2. Specific Plugin unit test (needs environment setup as indicated in the
180+ pre-requisites):
181+ python run_tests.py unit.<name_of_the file>
182+ E.g.:
183+
184+python run_tests.py unit.test_ucs_plugin.py
185+
186+3. All unit tests (needs environment setup as indicated in the pre-requisites):
187+
188+python run_tests.py unit
189+
190+
191+Additional installation required on Nova Compute
192+------------------------------------------------
193+1. Create a table in the "nova" database for ports. This can be
194+ accomplished with the following SQL statement:
195+
196+CREATE TABLE ports (
197+ port_id VARCHAR(255) PRIMARY KEY,
198+ profile_name VARCHAR(255),
199+ dynamic_vnic VARCHAR(255),
200+ host VARCHAR(255),
201+ instance_name VARCHAR(255),
202+ instance_nic_name VARCHAR(255),
203+ used TINYINT(1)
204+);
205+
206+ Assuming you're using MySQL, you can run the following command from a
207+ shell prompt on the Cloud Controller node to create the table:
208+
209+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));'
210+
211+You'll be prompted for a password.
212+
213+2. A patch is available for the Cactus release in this branch:
214+ https://code.launchpad.net/~snaiksat/quantum/cactus-ucs-support
215+ replace the following file in your installation:
216+ /usr/lib/python2.6/site-packages/nova/virt/libvirt_conn.py
217+ with the file from the branch:
218+ nova/virt/libvirt_conn.py
219+
220+3. Add the following file from the Cisco Nova branch:
221+ nova/virt/cisco_ucs.py
222+ to:
223+ /usr/lib/python2.6/site-packages/nova/virt/cisco_ucs.py
224+
225+4. Add the 802.1Qbh specific libvirt template file, from:
226+ nova/virt/libvirt-qbh.xml.template
227+ to:
228+ /usr/share/nova/libvirt-qbh.xml.template
229+
230+5. Edit /etc/nova.conf to set the libvirt XML template to the above template:
231+ --libvirt_xml_template=/usr/share/nova/libvirt-qbh.xml.template
232+
233+6. Restart the nova-compute service.
234+
235+ (Note that the requirement for the above patch is temporary and will go away
236+ with the integration with OpenStack Diablo. A 802.1Qbh-specific VIF driver
237+ will be made available as per the specification here:
238+ http://wiki.openstack.org/network-refactoring#VIF_driver)
239+
240+Bingo bango bongo! That's it! Thanks for taking the leap into Quantum.
241+
242+...Oh, boy!
243
244=== added file 'quantum/plugins/cisco/__init__.py'
245--- quantum/plugins/cisco/__init__.py 1970-01-01 00:00:00 +0000
246+++ quantum/plugins/cisco/__init__.py 2011-08-15 17:33:23 +0000
247@@ -0,0 +1,18 @@
248+# vim: tabstop=4 shiftwidth=4 softtabstop=4
249+#
250+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
251+#
252+# Licensed under the Apache License, Version 2.0 (the "License"); you may
253+# not use this file except in compliance with the License. You may obtain
254+# a copy of the License at
255+#
256+# http://www.apache.org/licenses/LICENSE-2.0
257+#
258+# Unless required by applicable law or agreed to in writing, software
259+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
260+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
261+# License for the specific language governing permissions and limitations
262+# under the License.
263+#
264+# @author: Sumit Naiksatam, Cisco Systems, Inc.
265+#
266
267=== added directory 'quantum/plugins/cisco/common'
268=== added file 'quantum/plugins/cisco/common/__init__.py'
269--- quantum/plugins/cisco/common/__init__.py 1970-01-01 00:00:00 +0000
270+++ quantum/plugins/cisco/common/__init__.py 2011-08-15 17:33:23 +0000
271@@ -0,0 +1,18 @@
272+# vim: tabstop=4 shiftwidth=4 softtabstop=4
273+#
274+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
275+#
276+# Licensed under the Apache License, Version 2.0 (the "License"); you may
277+# not use this file except in compliance with the License. You may obtain
278+# a copy of the License at
279+#
280+# http://www.apache.org/licenses/LICENSE-2.0
281+#
282+# Unless required by applicable law or agreed to in writing, software
283+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
284+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
285+# License for the specific language governing permissions and limitations
286+# under the License.
287+#
288+# @author: Sumit Naiksatam, Cisco Systems, Inc.
289+#
290
291=== added file 'quantum/plugins/cisco/common/cisco_configparser.py'
292--- quantum/plugins/cisco/common/cisco_configparser.py 1970-01-01 00:00:00 +0000
293+++ quantum/plugins/cisco/common/cisco_configparser.py 2011-08-15 17:33:23 +0000
294@@ -0,0 +1,40 @@
295+# vim: tabstop=4 shiftwidth=4 softtabstop=4
296+#
297+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
298+#
299+# Licensed under the Apache License, Version 2.0 (the "License"); you may
300+# not use this file except in compliance with the License. You may obtain
301+# a copy of the License at
302+#
303+# http://www.apache.org/licenses/LICENSE-2.0
304+#
305+# Unless required by applicable law or agreed to in writing, software
306+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
307+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
308+# License for the specific language governing permissions and limitations
309+# under the License.
310+#
311+# @author: Sumit Naiksatam, Cisco Systems, Inc.
312+#
313+
314+import logging as LOG
315+import os
316+
317+from configobj import ConfigObj
318+from validate import Validator
319+
320+from quantum.plugins.cisco.common import cisco_constants as const
321+from quantum.plugins.cisco.common import cisco_exceptions as cexc
322+
323+LOG.basicConfig(level=LOG.WARN)
324+LOG.getLogger(const.LOGGER_COMPONENT_NAME)
325+
326+
327+class CiscoConfigParser(ConfigObj):
328+
329+ def __init__(self, filename):
330+ super(CiscoConfigParser, self).__init__(filename, raise_errors=True,
331+ file_error=True)
332+
333+ def dummy(self, section, key):
334+ return section[key]
335
336=== added file 'quantum/plugins/cisco/common/cisco_constants.py'
337--- quantum/plugins/cisco/common/cisco_constants.py 1970-01-01 00:00:00 +0000
338+++ quantum/plugins/cisco/common/cisco_constants.py 2011-08-15 17:33:23 +0000
339@@ -0,0 +1,103 @@
340+# vim: tabstop=4 shiftwidth=4 softtabstop=4
341+#
342+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
343+#
344+# Licensed under the Apache License, Version 2.0 (the "License"); you may
345+# not use this file except in compliance with the License. You may obtain
346+# a copy of the License at
347+#
348+# http://www.apache.org/licenses/LICENSE-2.0
349+#
350+# Unless required by applicable law or agreed to in writing, software
351+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
352+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
353+# License for the specific language governing permissions and limitations
354+# under the License.
355+#
356+# @author: Sumit Naiksatam, Cisco Systems, Inc.
357+#
358+
359+PLUGINS = 'PLUGINS'
360+
361+PORT_STATE = 'port-state'
362+PORT_UP = "UP"
363+PORT_DOWN = "DOWN"
364+
365+ATTACHMENT = 'attachment'
366+PORT_ID = 'port-id'
367+
368+NET_ID = 'net-id'
369+NET_NAME = 'net-name'
370+NET_PORTS = 'net-ports'
371+NET_VLAN_NAME = 'net-vlan-name'
372+NET_VLAN_ID = 'net-vlan-id'
373+NET_TENANTS = 'net-tenants'
374+
375+TENANT_ID = 'tenant-id'
376+TENANT_NETWORKS = 'tenant-networks'
377+TENANT_NAME = 'tenant-name'
378+TENANT_PORTPROFILES = 'tenant-portprofiles'
379+TENANT_QOS_LEVELS = 'tenant-qos-levels'
380+TENANT_CREDENTIALS = 'tenant-credentials'
381+
382+PORT_PROFILE = 'port-profile'
383+PROFILE_ID = 'profile-id'
384+PROFILE_NAME = 'profile-name'
385+PROFILE_VLAN_NAME = 'profile-vlan-name'
386+PROFILE_VLAN_ID = 'vlan-id'
387+PROFILE_QOS = 'profile-qos'
388+PROFILE_ASSOCIATIONS = 'assignment'
389+
390+QOS_LEVEL_ID = 'qos-id'
391+QOS_LEVEL_NAME = 'qos-name'
392+QOS_LEVEL_ASSOCIATIONS = 'qos-level-associations'
393+QOS_LEVEL_DESCRIPTION = 'qos-desc'
394+
395+CREDENTIAL_ID = 'credential-id'
396+CREDENTIAL_NAME = 'credential-name'
397+CREDENTIAL_USERNAME = 'credential-username'
398+CREDENTIAL_PASSWORD = 'credential-password'
399+MASKED_PASSWORD = '********'
400+
401+USERNAME = 'username'
402+PASSWORD = 'password'
403+
404+LOGGER_COMPONENT_NAME = "cisco_plugin"
405+
406+BLADE_INTF_DN = "blade-intf-distinguished-name"
407+BLADE_INTF_ORDER = "blade-intf-order"
408+BLADE_INTF_LINK_STATE = "blade-intf-link-state"
409+BLADE_INTF_OPER_STATE = "blade-intf-operational-state"
410+BLADE_INTF_INST_TYPE = "blade-intf-inst-type"
411+BLADE_INTF_RHEL_DEVICE_NAME = "blade-intf-rhel-device-name"
412+BLADE_INTF_DYNAMIC = "dynamic"
413+BLADE_INTF_STATE_UNKNOWN = "unknown"
414+BLADE_INTF_STATE_UNALLOCATED = "unallocated"
415+BLADE_INTF_RESERVED = "blade-intf-reserved"
416+BLADE_INTF_UNRESERVED = "blade-intf-unreserved"
417+BLADE_INTF_RESERVATION = "blade-intf-reservation-status"
418+BLADE_UNRESERVED_INTF_COUNT = "blade-unreserved-interfaces-count"
419+BLADE_INTF_DATA = "blade-intf-data"
420+
421+LEAST_RSVD_BLADE_UCSM = "least-reserved-blade-ucsm"
422+LEAST_RSVD_BLADE_CHASSIS = "least-reserved-blade-chassis"
423+LEAST_RSVD_BLADE_ID = "least-reserved-blade-id"
424+LEAST_RSVD_BLADE_DATA = "least-reserved-blade-data"
425+
426+RESERVED_NIC_HOSTNAME = "reserved-dynamic-nic-hostname"
427+RESERVED_NIC_NAME = "reserved-dynamic-nic-device-name"
428+
429+RESERVED_INTERFACE_UCSM = "reserved-interface-ucsm-ip"
430+RESERVED_INTERFACE_CHASSIS = "reserved-interface-chassis"
431+RESERVED_INTERFACE_BLADE = "reserved-interface-blade"
432+RESERVED_INTERFACE_DN = "reserved-interface-dn"
433+
434+RHEL_DEVICE_NAME_REPFIX = "eth"
435+
436+UCS_PLUGIN = 'ucs_plugin'
437+NEXUS_PLUGIN = 'nexus_plugin'
438+
439+PLUGIN_OBJ_REF = 'plugin-obj-ref'
440+PARAM_LIST = 'param-list'
441+
442+DEVICE_IP = 'device-ip'
443
444=== added file 'quantum/plugins/cisco/common/cisco_credentials.py'
445--- quantum/plugins/cisco/common/cisco_credentials.py 1970-01-01 00:00:00 +0000
446+++ quantum/plugins/cisco/common/cisco_credentials.py 2011-08-15 17:33:23 +0000
447@@ -0,0 +1,60 @@
448+# vim: tabstop=4 shiftwidth=4 softtabstop=4
449+#
450+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
451+#
452+# Licensed under the Apache License, Version 2.0 (the "License"); you may
453+# not use this file except in compliance with the License. You may obtain
454+# a copy of the License at
455+#
456+# http://www.apache.org/licenses/LICENSE-2.0
457+#
458+# Unless required by applicable law or agreed to in writing, software
459+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
460+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
461+# License for the specific language governing permissions and limitations
462+# under the License.
463+#
464+# @author: Sumit Naiksatam, Cisco Systems, Inc.
465+#
466+
467+import logging as LOG
468+import os
469+
470+from quantum.plugins.cisco.common import cisco_constants as const
471+from quantum.plugins.cisco.common import cisco_configparser as confp
472+
473+LOG.basicConfig(level=LOG.WARN)
474+LOG.getLogger(const.LOGGER_COMPONENT_NAME)
475+
476+CREDENTIALS_FILE = "../conf/credentials.ini"
477+
478+cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
479+ + "/" + CREDENTIALS_FILE)
480+_creds_dictionary = cp.walk(cp.dummy)
481+
482+
483+class Store(object):
484+ @staticmethod
485+ def putCredential(id, username, password):
486+ _creds_dictionary[id] = {const.USERNAME: username,
487+ const.PASSWORD: password}
488+
489+ @staticmethod
490+ def getUsername(id):
491+ return _creds_dictionary[id][const.USERNAME]
492+
493+ @staticmethod
494+ def getPassword(id):
495+ return _creds_dictionary[id][const.PASSWORD]
496+
497+ @staticmethod
498+ def getCredential(id):
499+ return _creds_dictionary[id]
500+
501+ @staticmethod
502+ def getCredentials():
503+ return _creds_dictionary
504+
505+ @staticmethod
506+ def deleteCredential(id):
507+ return _creds_dictionary.pop(id)
508
509=== added file 'quantum/plugins/cisco/common/cisco_exceptions.py'
510--- quantum/plugins/cisco/common/cisco_exceptions.py 1970-01-01 00:00:00 +0000
511+++ quantum/plugins/cisco/common/cisco_exceptions.py 2011-08-15 17:33:23 +0000
512@@ -0,0 +1,57 @@
513+# vim: tabstop=4 shiftwidth=4 softtabstop=4
514+#
515+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
516+#
517+# Licensed under the Apache License, Version 2.0 (the "License"); you may
518+# not use this file except in compliance with the License. You may obtain
519+# a copy of the License at
520+#
521+# http://www.apache.org/licenses/LICENSE-2.0
522+#
523+# Unless required by applicable law or agreed to in writing, software
524+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
525+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
526+# License for the specific language governing permissions and limitations
527+# under the License.
528+#
529+# @author: Sumit Naiksatam, Cisco Systems, Inc.
530+#
531+
532+"""
533+Exceptions used by the Cisco plugin
534+"""
535+
536+from quantum.common import exceptions
537+
538+
539+class NoMoreNics(exceptions.QuantumException):
540+ message = _("Unable to complete operation on port %(port_id)s " \
541+ "for network %(net_id)s. No more dynamic nics are available" \
542+ "in the system.")
543+
544+
545+class PortProfileLimit(exceptions.QuantumException):
546+ message = _("Unable to complete operation on port %(port_id)s " \
547+ "for network %(net_id)s. The system has reached the maximum" \
548+ "limit of allowed port profiles.")
549+
550+
551+class UCSMPortProfileLimit(exceptions.QuantumException):
552+ message = _("Unable to complete operation on port %(port_id)s " \
553+ "for network %(net_id)s. The system has reached the maximum" \
554+ "limit of allowed UCSM port profiles.")
555+
556+
557+class NetworksLimit(exceptions.QuantumException):
558+ message = _("Unable to create new network. Number of networks" \
559+ "for the system has exceeded the limit")
560+
561+
562+class PortProfileNotFound(exceptions.QuantumException):
563+ message = _("Port profile %(portprofile_id)s could not be found " \
564+ "for tenant %(tenant_id)s")
565+
566+
567+class PortProfileInvalidDelete(exceptions.QuantumException):
568+ message = _("Port profile %(profile_id)s could not be deleted " \
569+ "for tenant %(tenant_id)s since port associations exist")
570
571=== added file 'quantum/plugins/cisco/common/cisco_nova_configuration.py'
572--- quantum/plugins/cisco/common/cisco_nova_configuration.py 1970-01-01 00:00:00 +0000
573+++ quantum/plugins/cisco/common/cisco_nova_configuration.py 2011-08-15 17:33:23 +0000
574@@ -0,0 +1,35 @@
575+# vim: tabstop=4 shiftwidth=4 softtabstop=4
576+#
577+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
578+#
579+# Licensed under the Apache License, Version 2.0 (the "License"); you may
580+# not use this file except in compliance with the License. You may obtain
581+# a copy of the License at
582+#
583+# http://www.apache.org/licenses/LICENSE-2.0
584+#
585+# Unless required by applicable law or agreed to in writing, software
586+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
587+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
588+# License for the specific language governing permissions and limitations
589+# under the License.
590+#
591+# @author: Sumit Naiksatam, Cisco Systems, Inc.
592+#
593+
594+import os
595+
596+from quantum.plugins.cisco.common import cisco_configparser as confp
597+
598+CONF_FILE = "../conf/nova.ini"
599+
600+cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
601+ + "/" + CONF_FILE)
602+
603+section = cp['NOVA']
604+DB_SERVER_IP = section['db_server_ip']
605+DB_NAME = section['db_name']
606+DB_USERNAME = section['db_username']
607+DB_PASSWORD = section['db_password']
608+NOVA_HOST_NAME = section['nova_host_name']
609+NOVA_PROJ_NAME = section['nova_proj_name']
610
611=== added file 'quantum/plugins/cisco/common/cisco_utils.py'
612--- quantum/plugins/cisco/common/cisco_utils.py 1970-01-01 00:00:00 +0000
613+++ quantum/plugins/cisco/common/cisco_utils.py 2011-08-15 17:33:23 +0000
614@@ -0,0 +1,59 @@
615+# vim: tabstop=4 shiftwidth=4 softtabstop=4
616+#
617+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
618+#
619+# Licensed under the Apache License, Version 2.0 (the "License"); you may
620+# not use this file except in compliance with the License. You may obtain
621+# a copy of the License at
622+#
623+# http://www.apache.org/licenses/LICENSE-2.0
624+#
625+# Unless required by applicable law or agreed to in writing, software
626+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
627+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
628+# License for the specific language governing permissions and limitations
629+# under the License.
630+#
631+# @author: Sumit Naiksatam, Cisco Systems, Inc.
632+#
633+
634+import MySQLdb
635+import logging as LOG
636+import sys
637+import traceback
638+
639+from quantum.common import exceptions as exc
640+from quantum.plugins.cisco.common import cisco_constants as const
641+from quantum.plugins.cisco.common import cisco_credentials as cred
642+from quantum.plugins.cisco.common import cisco_nova_configuration as conf
643+
644+LOG.basicConfig(level=LOG.WARN)
645+LOG.getLogger(const.LOGGER_COMPONENT_NAME)
646+
647+
648+class DBUtils(object):
649+
650+ def __init__(self):
651+ pass
652+
653+ def _get_db_connection(self):
654+ db_ip = conf.DB_SERVER_IP
655+ db_username = conf.DB_USERNAME
656+ db_password = conf.DB_PASSWORD
657+ self.db = MySQLdb.connect(db_ip, db_username, db_password,
658+ conf.DB_NAME)
659+ return self.db
660+
661+ def execute_db_query(self, sql_query):
662+ db = self._get_db_connection()
663+ cursor = db.cursor()
664+ try:
665+ cursor.execute(sql_query)
666+ results = cursor.fetchall()
667+ db.commit()
668+ LOG.debug("DB query execution succeeded: %s" % sql_query)
669+ except:
670+ db.rollback()
671+ LOG.debug("DB query execution failed: %s" % sql_query)
672+ traceback.print_exc()
673+ db.close()
674
675=== added directory 'quantum/plugins/cisco/conf'
676=== added file 'quantum/plugins/cisco/conf/credentials.ini'
677--- quantum/plugins/cisco/conf/credentials.ini 1970-01-01 00:00:00 +0000
678+++ quantum/plugins/cisco/conf/credentials.ini 2011-08-15 17:33:23 +0000
679@@ -0,0 +1,15 @@
680+#Provide the UCSM credentials
681+[<put_ucsm_ip_address_here>]
682+username=<put_user_name_here>
683+password=<put_password_here>
684+
685+#Provide the Nova DB credentials, the IP address should be the same as in nova.ini
686+[<put_nova_db_ip_here>]
687+username=<put_user_name_here>
688+password=<put_password_here>
689+
690+#Provide the Nexus credentials, if you are using Nexus
691+[<put_nexus_ip_address_here>]
692+username=<put_user_name_here>
693+password=<put_password_here>
694+
695
696=== added file 'quantum/plugins/cisco/conf/l2network_plugin.ini'
697--- quantum/plugins/cisco/conf/l2network_plugin.ini 1970-01-01 00:00:00 +0000
698+++ quantum/plugins/cisco/conf/l2network_plugin.ini 2011-08-15 17:33:23 +0000
699@@ -0,0 +1,16 @@
700+[VLANS]
701+vlan_start=<put_vlan_id_range_start_here>
702+vlan_end=<put_vlan_id_range_end_here>
703+vlan_name_prefix=q-
704+
705+[PORTS]
706+max_ports=100
707+
708+[PORTPROFILES]
709+max_port_profiles=65568
710+
711+[NETWORKS]
712+max_networks=65568
713+
714+[MODEL]
715+model_class=quantum.plugins.cisco.l2network_model.L2NetworkModel
716
717=== added file 'quantum/plugins/cisco/conf/nexus.ini'
718--- quantum/plugins/cisco/conf/nexus.ini 1970-01-01 00:00:00 +0000
719+++ quantum/plugins/cisco/conf/nexus.ini 2011-08-15 17:33:23 +0000
720@@ -0,0 +1,8 @@
721+[SWITCH]
722+# Change the following to reflect the Nexus switch details
723+nexus_ip_address=<put_nexus_switch_ip_address_here>
724+#Port number of the Interface connected from the Nexus 7K Switch to UCSM 6120, e.g.: 3/23
725+nexus_port=<put_interface_name_here>
726+
727+[DRIVER]
728+name=quantum.plugins.cisco.nexus.cisco_nexus_network_driver.CiscoNEXUSDriver
729
730=== added file 'quantum/plugins/cisco/conf/nova.ini'
731--- quantum/plugins/cisco/conf/nova.ini 1970-01-01 00:00:00 +0000
732+++ quantum/plugins/cisco/conf/nova.ini 2011-08-15 17:33:23 +0000
733@@ -0,0 +1,8 @@
734+[NOVA]
735+#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.
736+db_server_ip=127.0.0.1
737+db_name=nova
738+db_username=<put_db_user_name_here>
739+db_password=<put_db_password_here>
740+nova_host_name=<put_openstack_cloud_controller_hostname_here>
741+nova_proj_name=<put_openstack_project_name_here>
742
743=== added file 'quantum/plugins/cisco/conf/plugins.ini'
744--- quantum/plugins/cisco/conf/plugins.ini 1970-01-01 00:00:00 +0000
745+++ quantum/plugins/cisco/conf/plugins.ini 2011-08-15 17:33:23 +0000
746@@ -0,0 +1,3 @@
747+[PLUGINS]
748+ucs_plugin=quantum.plugins.cisco.ucs.cisco_ucs_plugin.UCSVICPlugin
749+#nexus_plugin=quantum.plugins.cisco.nexus.cisco_nexus_plugin.NexusPlugin
750
751=== added file 'quantum/plugins/cisco/conf/ucs.ini'
752--- quantum/plugins/cisco/conf/ucs.ini 1970-01-01 00:00:00 +0000
753+++ quantum/plugins/cisco/conf/ucs.ini 2011-08-15 17:33:23 +0000
754@@ -0,0 +1,10 @@
755+[UCSM]
756+#change the following to the appropriate UCSM IP address
757+ip_address=<put_ucsm_ip_address_here>
758+default_vlan_name=default
759+default_vlan_id=1
760+max_ucsm_port_profiles=1024
761+profile_name_prefix=q-
762+
763+[DRIVER]
764+name=quantum.plugins.cisco.ucs.cisco_ucs_network_driver.CiscoUCSMDriver
765
766=== added directory 'quantum/plugins/cisco/db'
767=== added file 'quantum/plugins/cisco/db/__init__.py'
768--- quantum/plugins/cisco/db/__init__.py 1970-01-01 00:00:00 +0000
769+++ quantum/plugins/cisco/db/__init__.py 2011-08-15 17:33:23 +0000
770@@ -0,0 +1,18 @@
771+# vim: tabstop=4 shiftwidth=4 softtabstop=4
772+#
773+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
774+#
775+# Licensed under the Apache License, Version 2.0 (the "License"); you may
776+# not use this file except in compliance with the License. You may obtain
777+# a copy of the License at
778+#
779+# http://www.apache.org/licenses/LICENSE-2.0
780+#
781+# Unless required by applicable law or agreed to in writing, software
782+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
783+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
784+# License for the specific language governing permissions and limitations
785+# under the License.
786+#
787+# @author: Sumit Naiksatam, Cisco Systems, Inc.
788+#
789
790=== added file 'quantum/plugins/cisco/l2device_plugin_base.py'
791--- quantum/plugins/cisco/l2device_plugin_base.py 1970-01-01 00:00:00 +0000
792+++ quantum/plugins/cisco/l2device_plugin_base.py 2011-08-15 17:33:23 +0000
793@@ -0,0 +1,152 @@
794+# vim: tabstop=4 shiftwidth=4 softtabstop=4
795+#
796+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
797+#
798+# Licensed under the Apache License, Version 2.0 (the "License"); you may
799+# not use this file except in compliance with the License. You may obtain
800+# a copy of the License at
801+#
802+# http://www.apache.org/licenses/LICENSE-2.0
803+#
804+# Unless required by applicable law or agreed to in writing, software
805+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
806+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
807+# License for the specific language governing permissions and limitations
808+# under the License.
809+#
810+# @author: Sumit Naiksatam, Cisco Systems, Inc.
811+#
812+
813+import inspect
814+from abc import ABCMeta, abstractmethod
815+
816+
817+class L2DevicePluginBase(object):
818+
819+ __metaclass__ = ABCMeta
820+
821+ @abstractmethod
822+ def get_all_networks(self, tenant_id, **kwargs):
823+ """
824+ :returns:
825+ :raises:
826+ """
827+ pass
828+
829+ @abstractmethod
830+ def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id,
831+ **kwargs):
832+ """
833+ :returns:
834+ :raises:
835+ """
836+ pass
837+
838+ @abstractmethod
839+ def delete_network(self, tenant_id, net_id, **kwargs):
840+ """
841+ :returns:
842+ :raises:
843+ """
844+ pass
845+
846+ @abstractmethod
847+ def get_network_details(self, tenant_id, net_id, **kwargs):
848+ """
849+ :returns:
850+ :raises:
851+ """
852+ pass
853+
854+ @abstractmethod
855+ def rename_network(self, tenant_id, net_id, new_name, **kwargs):
856+ """
857+ :returns:
858+ :raises:
859+ """
860+ pass
861+
862+ @abstractmethod
863+ def get_all_ports(self, tenant_id, net_id, **kwargs):
864+ """
865+ :returns:
866+ :raises:
867+ """
868+ pass
869+
870+ @abstractmethod
871+ def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs):
872+ """
873+ :returns:
874+ :raises:
875+ """
876+ pass
877+
878+ @abstractmethod
879+ def delete_port(self, tenant_id, net_id, port_id, **kwargs):
880+ """
881+ :returns:
882+ :raises:
883+ """
884+ pass
885+
886+ @abstractmethod
887+ def update_port(self, tenant_id, net_id, port_id, port_state, **kwargs):
888+ """
889+ :returns:
890+ :raises:
891+ """
892+ pass
893+
894+ @abstractmethod
895+ def get_port_details(self, tenant_id, net_id, port_id, **kwargs):
896+ """
897+ :returns:
898+ :raises:
899+ """
900+ pass
901+
902+ @abstractmethod
903+ def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id,
904+ **kwargs):
905+ """
906+ :returns:
907+ :raises:
908+ """
909+ pass
910+
911+ @abstractmethod
912+ def unplug_interface(self, tenant_id, net_id, port_id, **kwargs):
913+ """
914+ :returns:
915+ :raises:
916+ """
917+ pass
918+
919+ @classmethod
920+ def __subclasshook__(cls, klass):
921+ """
922+ The __subclasshook__ method is a class method
923+ that will be called everytime a class is tested
924+ using issubclass(klass, Plugin).
925+ In that case, it will check that every method
926+ marked with the abstractmethod decorator is
927+ provided by the plugin class.
928+ """
929+ if cls is QuantumPluginBase:
930+ for method in cls.__abstractmethods__:
931+ method_ok = False
932+ for base in klass.__mro__:
933+ if method in base.__dict__:
934+ fn_obj = base.__dict__[method]
935+ if inspect.isfunction(fn_obj):
936+ abstract_fn_obj = cls.__dict__[method]
937+ arg_count = fn_obj.func_code.co_argcount
938+ expected_arg_count = \
939+ abstract_fn_obj.func_code.co_argcount
940+ method_ok = arg_count == expected_arg_count
941+ if method_ok:
942+ continue
943+ return NotImplemented
944+ return True
945+ return NotImplemented
946
947=== added file 'quantum/plugins/cisco/l2network_model.py'
948--- quantum/plugins/cisco/l2network_model.py 1970-01-01 00:00:00 +0000
949+++ quantum/plugins/cisco/l2network_model.py 2011-08-15 17:33:23 +0000
950@@ -0,0 +1,100 @@
951+# vim: tabstop=4 shiftwidth=4 softtabstop=4
952+#
953+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
954+#
955+# Licensed under the Apache License, Version 2.0 (the "License"); you may
956+# not use this file except in compliance with the License. You may obtain
957+# a copy of the License at
958+#
959+# http://www.apache.org/licenses/LICENSE-2.0
960+#
961+# Unless required by applicable law or agreed to in writing, software
962+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
963+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
964+# License for the specific language governing permissions and limitations
965+# under the License.
966+#
967+# @author: Sumit Naiksatam, Cisco Systems, Inc.
968+#
969+
970+import inspect
971+import logging as LOG
972+
973+from quantum.common import utils
974+from quantum.plugins.cisco.l2network_model_base import L2NetworkModelBase
975+from quantum.plugins.cisco import l2network_plugin_configuration as conf
976+from quantum.plugins.cisco.common import cisco_constants as const
977+
978+LOG.basicConfig(level=LOG.WARN)
979+LOG.getLogger(const.LOGGER_COMPONENT_NAME)
980+
981+
982+class L2NetworkModel(L2NetworkModelBase):
983+ _plugins = {}
984+
985+ def __init__(self):
986+ for key in conf.plugins[const.PLUGINS].keys():
987+ self._plugins[key] = utils.import_object(
988+ conf.plugins[const.PLUGINS][key])
989+ LOG.debug("Loaded device plugin %s\n" % \
990+ conf.plugins[const.PLUGINS][key])
991+
992+ def _funcName(self, offset=0):
993+ return inspect.stack()[1 + offset][3]
994+
995+ def _invokeAllDevicePlugins(self, function_name, args, kwargs):
996+ for pluginObjRef in self._plugins.values():
997+ getattr(pluginObjRef, function_name)(*args, **kwargs)
998+
999+ def _invokeUCSPlugin(self, function_name, args, kwargs):
1000+ if const.UCS_PLUGIN in self._plugins.keys():
1001+ getattr(self._plugins[const.UCS_PLUGIN],
1002+ function_name)(*args, **kwargs)
1003+
1004+ def _invokeNexusPlugin(self, function_name, args, kwargs):
1005+ if const.NEXUS_PLUGIN in self._plugins.keys():
1006+ getattr(self._plugins[const.NEXUS_PLUGIN],
1007+ function_name)(*args, **kwargs)
1008+
1009+ def get_all_networks(self, args):
1010+ pass
1011+
1012+ def create_network(self, args):
1013+ deviceParams = {const.DEVICE_IP: ""}
1014+ self._invokeAllDevicePlugins(self._funcName(), args, deviceParams)
1015+
1016+ def delete_network(self, args):
1017+ deviceParams = {const.DEVICE_IP: ""}
1018+ self._invokeAllDevicePlugins(self._funcName(), args, deviceParams)
1019+
1020+ def get_network_details(self, args):
1021+ pass
1022+
1023+ def rename_network(self, args):
1024+ deviceParams = {const.DEVICE_IP: ""}
1025+ self._invokeAllDevicePlugins(self._funcName(), args, deviceParams)
1026+
1027+ def get_all_ports(self, args):
1028+ pass
1029+
1030+ def create_port(self, args):
1031+ deviceParams = {const.DEVICE_IP: ""}
1032+ self._invokeUCSPlugin(self._funcName(), args, deviceParams)
1033+
1034+ def delete_port(self, args):
1035+ deviceParams = {const.DEVICE_IP: ""}
1036+ self._invokeUCSPlugin(self._funcName(), args, deviceParams)
1037+
1038+ def update_port(self, args):
1039+ pass
1040+
1041+ def get_port_details(self, args):
1042+ pass
1043+
1044+ def plug_interface(self, args):
1045+ deviceParams = {const.DEVICE_IP: ""}
1046+ self._invokeUCSPlugin(self._funcName(), args, deviceParams)
1047+
1048+ def unplug_interface(self, args):
1049+ deviceParams = {const.DEVICE_IP: ""}
1050+ self._invokeUCSPlugin(self._funcName(), args, deviceParams)
1051
1052=== added file 'quantum/plugins/cisco/l2network_model_base.py'
1053--- quantum/plugins/cisco/l2network_model_base.py 1970-01-01 00:00:00 +0000
1054+++ quantum/plugins/cisco/l2network_model_base.py 2011-08-15 17:33:23 +0000
1055@@ -0,0 +1,150 @@
1056+# vim: tabstop=4 shiftwidth=4 softtabstop=4
1057+#
1058+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
1059+#
1060+# Licensed under the Apache License, Version 2.0 (the "License"); you may
1061+# not use this file except in compliance with the License. You may obtain
1062+# a copy of the License at
1063+#
1064+# http://www.apache.org/licenses/LICENSE-2.0
1065+#
1066+# Unless required by applicable law or agreed to in writing, software
1067+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1068+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1069+# License for the specific language governing permissions and limitations
1070+# under the License.
1071+#
1072+# @author: Sumit Naiksatam, Cisco Systems, Inc.
1073+#
1074+
1075+import inspect
1076+from abc import ABCMeta, abstractmethod
1077+
1078+
1079+class L2NetworkModelBase(object):
1080+
1081+ __metaclass__ = ABCMeta
1082+
1083+ @abstractmethod
1084+ def get_all_networks(self, args):
1085+ """
1086+ :returns:
1087+ :raises:
1088+ """
1089+ pass
1090+
1091+ @abstractmethod
1092+ def create_network(self, args):
1093+ """
1094+ :returns:
1095+ :raises:
1096+ """
1097+ pass
1098+
1099+ @abstractmethod
1100+ def delete_network(self, args):
1101+ """
1102+ :returns:
1103+ :raises:
1104+ """
1105+ pass
1106+
1107+ @abstractmethod
1108+ def get_network_details(self, args):
1109+ """
1110+ :returns:
1111+ :raises:
1112+ """
1113+ pass
1114+
1115+ @abstractmethod
1116+ def rename_network(self, args):
1117+ """
1118+ :returns:
1119+ :raises:
1120+ """
1121+ pass
1122+
1123+ @abstractmethod
1124+ def get_all_ports(self, args):
1125+ """
1126+ :returns:
1127+ :raises:
1128+ """
1129+ pass
1130+
1131+ @abstractmethod
1132+ def create_port(self, args):
1133+ """
1134+ :returns:
1135+ :raises:
1136+ """
1137+ pass
1138+
1139+ @abstractmethod
1140+ def delete_port(self, args):
1141+ """
1142+ :returns:
1143+ :raises:
1144+ """
1145+ pass
1146+
1147+ @abstractmethod
1148+ def update_port(self, args):
1149+ """
1150+ :returns:
1151+ :raises:
1152+ """
1153+ pass
1154+
1155+ @abstractmethod
1156+ def get_port_details(self, args):
1157+ """
1158+ :returns:
1159+ :raises:
1160+ """
1161+ pass
1162+
1163+ @abstractmethod
1164+ def plug_interface(self, args):
1165+ """
1166+ :returns:
1167+ :raises:
1168+ """
1169+ pass
1170+
1171+ @abstractmethod
1172+ def unplug_interface(self, args):
1173+ """
1174+ :returns:
1175+ :raises:
1176+ """
1177+ pass
1178+
1179+ @classmethod
1180+ def __subclasshook__(cls, klass):
1181+ """
1182+ The __subclasshook__ method is a class method
1183+ that will be called everytime a class is tested
1184+ using issubclass(klass, Plugin).
1185+ In that case, it will check that every method
1186+ marked with the abstractmethod decorator is
1187+ provided by the plugin class.
1188+ """
1189+ if cls is QuantumPluginBase:
1190+ for method in cls.__abstractmethods__:
1191+ method_ok = False
1192+ for base in klass.__mro__:
1193+ if method in base.__dict__:
1194+ fn_obj = base.__dict__[method]
1195+ if inspect.isfunction(fn_obj):
1196+ abstract_fn_obj = cls.__dict__[method]
1197+ arg_count = fn_obj.func_code.co_argcount
1198+ expected_arg_count = \
1199+ abstract_fn_obj.func_code.co_argcount
1200+ method_ok = arg_count == expected_arg_count
1201+ if method_ok:
1202+ continue
1203+ return NotImplemented
1204+ return True
1205+ return NotImplemented
1206
1207=== added file 'quantum/plugins/cisco/l2network_plugin.py'
1208--- quantum/plugins/cisco/l2network_plugin.py 1970-01-01 00:00:00 +0000
1209+++ quantum/plugins/cisco/l2network_plugin.py 2011-08-15 17:33:23 +0000
1210@@ -0,0 +1,394 @@
1211+# vim: tabstop=4 shiftwidth=4 softtabstop=4
1212+#
1213+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
1214+#
1215+# Licensed under the Apache License, Version 2.0 (the "License"); you may
1216+# not use this file except in compliance with the License. You may obtain
1217+# a copy of the License at
1218+#
1219+# http://www.apache.org/licenses/LICENSE-2.0
1220+#
1221+# Unless required by applicable law or agreed to in writing, software
1222+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1223+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1224+# License for the specific language governing permissions and limitations
1225+# under the License.
1226+#
1227+# @author: Sumit Naiksatam, Cisco Systems, Inc.
1228+#
1229+
1230+import inspect
1231+import logging as LOG
1232+
1233+from quantum.common import exceptions as exc
1234+from quantum.common import utils
1235+from quantum.quantum_plugin_base import QuantumPluginBase
1236+from quantum.plugins.cisco import l2network_plugin_configuration as conf
1237+from quantum.plugins.cisco.common import cisco_constants as const
1238+from quantum.plugins.cisco.common import cisco_exceptions as cexc
1239+
1240+LOG.basicConfig(level=LOG.WARN)
1241+LOG.getLogger(const.LOGGER_COMPONENT_NAME)
1242+
1243+
1244+class L2Network(QuantumPluginBase):
1245+ _networks = {}
1246+ _tenants = {}
1247+ _portprofiles = {}
1248+
1249+ def __init__(self):
1250+ self._net_counter = 0
1251+ self._portprofile_counter = 0
1252+ self._port_counter = 0
1253+ self._vlan_counter = int(conf.VLAN_START) - 1
1254+ self._model = utils.import_object(conf.MODEL_CLASS)
1255+
1256+ """
1257+ Core API implementation
1258+ """
1259+ def get_all_networks(self, tenant_id):
1260+ """
1261+ Returns a dictionary containing all
1262+ <network_uuid, network_name> for
1263+ the specified tenant.
1264+ """
1265+ LOG.debug("get_all_networks() called\n")
1266+ self._invokeDevicePlugins(self._funcName(), [tenant_id])
1267+ return self._networks.values()
1268+
1269+ def create_network(self, tenant_id, net_name):
1270+ """
1271+ Creates a new Virtual Network, and assigns it
1272+ a symbolic name.
1273+ """
1274+ LOG.debug("create_network() called\n")
1275+ new_net_id = self._get_unique_net_id(tenant_id)
1276+ vlan_id = self._get_vlan_for_tenant(tenant_id, net_name)
1277+ vlan_name = self._get_vlan_name(new_net_id, str(vlan_id))
1278+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_name,
1279+ new_net_id, vlan_name,
1280+ vlan_id])
1281+ new_net_dict = {const.NET_ID: new_net_id,
1282+ const.NET_NAME: net_name,
1283+ const.NET_PORTS: {},
1284+ const.NET_VLAN_NAME: vlan_name,
1285+ const.NET_VLAN_ID: vlan_id,
1286+ const.NET_TENANTS: [tenant_id]}
1287+ self._networks[new_net_id] = new_net_dict
1288+ tenant = self._get_tenant(tenant_id)
1289+ tenant_networks = tenant[const.TENANT_NETWORKS]
1290+ tenant_networks[new_net_id] = new_net_dict
1291+ return new_net_dict
1292+
1293+ def delete_network(self, tenant_id, net_id):
1294+ """
1295+ Deletes the network with the specified network identifier
1296+ belonging to the specified tenant.
1297+ """
1298+ LOG.debug("delete_network() called\n")
1299+ net = self._networks.get(net_id)
1300+ if net:
1301+ if len(net[const.NET_PORTS].values()) > 0:
1302+ ports_on_net = net[const.NET_PORTS].values()
1303+ for port in ports_on_net:
1304+ if port[const.ATTACHMENT]:
1305+ raise exc.NetworkInUse(net_id=net_id)
1306+ for port in ports_on_net:
1307+ self.delete_port(tenant_id, net_id, port[const.PORT_ID])
1308+
1309+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id])
1310+ self._networks.pop(net_id)
1311+ tenant = self._get_tenant(tenant_id)
1312+ tenant_networks = tenant[const.TENANT_NETWORKS]
1313+ tenant_networks.pop(net_id)
1314+ return net
1315+ # Network not found
1316+ raise exc.NetworkNotFound(net_id=net_id)
1317+
1318+ def get_network_details(self, tenant_id, net_id):
1319+ """
1320+ Gets the details of a particular network
1321+ """
1322+ LOG.debug("get_network_details() called\n")
1323+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id])
1324+ network = self._get_network(tenant_id, net_id)
1325+ ports_on_net = network[const.NET_PORTS].values()
1326+ return {const.NET_ID: network[const.NET_ID],
1327+ const.NET_NAME: network[const.NET_NAME],
1328+ const.NET_PORTS: ports_on_net}
1329+
1330+ def rename_network(self, tenant_id, net_id, new_name):
1331+ """
1332+ Updates the symbolic name belonging to a particular
1333+ Virtual Network.
1334+ """
1335+ LOG.debug("rename_network() called\n")
1336+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
1337+ new_name])
1338+ network = self._get_network(tenant_id, net_id)
1339+ network[const.NET_NAME] = new_name
1340+ return network
1341+
1342+ def get_all_ports(self, tenant_id, net_id):
1343+ """
1344+ Retrieves all port identifiers belonging to the
1345+ specified Virtual Network.
1346+ """
1347+ LOG.debug("get_all_ports() called\n")
1348+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id])
1349+ network = self._get_network(tenant_id, net_id)
1350+ ports_on_net = network[const.NET_PORTS].values()
1351+ return ports_on_net
1352+
1353+ def create_port(self, tenant_id, net_id, port_state=None):
1354+ """
1355+ Creates a port on the specified Virtual Network.
1356+ """
1357+ LOG.debug("create_port() called\n")
1358+ net = self._get_network(tenant_id, net_id)
1359+ ports = net[const.NET_PORTS]
1360+ unique_port_id_string = self._get_unique_port_id(tenant_id, net_id)
1361+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
1362+ port_state,
1363+ unique_port_id_string])
1364+ new_port_dict = {const.PORT_ID: unique_port_id_string,
1365+ const.PORT_STATE: const.PORT_UP,
1366+ const.ATTACHMENT: None}
1367+ ports[unique_port_id_string] = new_port_dict
1368+ return new_port_dict
1369+
1370+ def delete_port(self, tenant_id, net_id, port_id):
1371+ """
1372+ Deletes a port on a specified Virtual Network,
1373+ if the port contains a remote interface attachment,
1374+ the remote interface should first be un-plugged and
1375+ then the port can be deleted.
1376+ """
1377+ LOG.debug("delete_port() called\n")
1378+ port = self._get_port(tenant_id, net_id, port_id)
1379+ if port[const.ATTACHMENT]:
1380+ raise exc.PortInUse(net_id=net_id, port_id=port_id,
1381+ att_id=port[const.ATTACHMENT])
1382+ try:
1383+ #TODO (Sumit): Before deleting port profile make sure that there
1384+ # is no VM using this port profile
1385+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
1386+ port_id])
1387+ net = self._get_network(tenant_id, net_id)
1388+ net[const.NET_PORTS].pop(port_id)
1389+ except KeyError:
1390+ raise exc.PortNotFound(net_id=net_id, port_id=port_id)
1391+
1392+ def update_port(self, tenant_id, net_id, port_id, port_state):
1393+ """
1394+ Updates the state of a port on the specified Virtual Network.
1395+ """
1396+ LOG.debug("update_port() called\n")
1397+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
1398+ port_id, port_state])
1399+ port = self._get_port(tenant_id, net_id, port_id)
1400+ self._validate_port_state(port_state)
1401+ port[const.PORT_STATE] = port_state
1402+ return port
1403+
1404+ def get_port_details(self, tenant_id, net_id, port_id):
1405+ """
1406+ This method allows the user to retrieve a remote interface
1407+ that is attached to this particular port.
1408+ """
1409+ LOG.debug("get_port_details() called\n")
1410+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
1411+ port_id])
1412+ return self._get_port(tenant_id, net_id, port_id)
1413+
1414+ def plug_interface(self, tenant_id, net_id, port_id,
1415+ remote_interface_id):
1416+ """
1417+ Attaches a remote interface to the specified port on the
1418+ specified Virtual Network.
1419+ """
1420+ LOG.debug("plug_interface() called\n")
1421+ self._validate_attachment(tenant_id, net_id, port_id,
1422+ remote_interface_id)
1423+ port = self._get_port(tenant_id, net_id, port_id)
1424+ if port[const.ATTACHMENT]:
1425+ raise exc.PortInUse(net_id=net_id, port_id=port_id,
1426+ att_id=port[const.ATTACHMENT])
1427+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
1428+ port_id,
1429+ remote_interface_id])
1430+ port[const.ATTACHMENT] = remote_interface_id
1431+
1432+ def unplug_interface(self, tenant_id, net_id, port_id):
1433+ """
1434+ Detaches a remote interface from the specified port on the
1435+ specified Virtual Network.
1436+ """
1437+ LOG.debug("unplug_interface() called\n")
1438+ port = self._get_port(tenant_id, net_id, port_id)
1439+ self._invokeDevicePlugins(self._funcName(), [tenant_id, net_id,
1440+ port_id])
1441+ port[const.ATTACHMENT] = None
1442+
1443+ """
1444+ Extension API implementation
1445+ """
1446+ def get_all_portprofiles(self, tenant_id):
1447+ return self._portprofiles.values()
1448+
1449+ def get_portprofile_details(self, tenant_id, profile_id):
1450+ return self._get_portprofile(tenant_id, profile_id)
1451+
1452+ def create_portprofile(self, tenant_id, profile_name, vlan_id):
1453+ profile_id = self._get_unique_profile_id(tenant_id)
1454+ new_port_profile_dict = {const.PROFILE_ID: profile_id,
1455+ const.PROFILE_NAME: profile_name,
1456+ const.PROFILE_ASSOCIATIONS: [],
1457+ const.PROFILE_VLAN_ID: vlan_id,
1458+ const.PROFILE_QOS: None}
1459+ self._portprofiles[profile_id] = new_port_profile_dict
1460+ tenant = self._get_tenant(tenant_id)
1461+ portprofiles = tenant[const.TENANT_PORTPROFILES]
1462+ portprofiles[profile_id] = new_port_profile_dict
1463+ return new_port_profile_dict
1464+
1465+ def delete_portprofile(self, tenant_id, profile_id):
1466+ portprofile = self._get_portprofile(tenant_id, profile_id)
1467+ associations = portprofile[const.PROFILE_ASSOCIATIONS]
1468+ if len(associations) > 0:
1469+ raise cexc.PortProfileInvalidDelete(tenant_id=tenant_id,
1470+ profile_id=profile_id)
1471+ else:
1472+ self._portprofiles.pop(profile_id)
1473+ tenant = self._get_tenant(tenant_id)
1474+ tenant[const.TENANT_PORTPROFILES].pop(profile_id)
1475+
1476+ def rename_portprofile(self, tenant_id, profile_id, new_name):
1477+ portprofile = self._get_portprofile(tenant_id, profile_id)
1478+ portprofile[const.PROFILE_NAME] = new_name
1479+ return portprofile
1480+
1481+ def associate_portprofile(self, tenant_id, net_id,
1482+ port_id, portprofile_id):
1483+ portprofile = self._get_portprofile(tenant_id, portprofile_id)
1484+ associations = portprofile[const.PROFILE_ASSOCIATIONS]
1485+ associations.append(port_id)
1486+
1487+ def disassociate_portprofile(self, tenant_id, net_id,
1488+ port_id, portprofile_id):
1489+ portprofile = self._get_portprofile(tenant_id, portprofile_id)
1490+ associations = portprofile[const.PROFILE_ASSOCIATIONS]
1491+ associations.remove(port_id)
1492+
1493+ def create_defaultPProfile(self, tenant_id, network_id, profile_name,
1494+ vlan_id):
1495+ pass
1496+
1497+ """
1498+ Private functions
1499+ """
1500+ def _invokeDevicePlugins(self, function_name, args):
1501+ """
1502+ All device-specific calls are delegate to the model
1503+ """
1504+ getattr(self._model, function_name)(args)
1505+
1506+ def _get_vlan_for_tenant(self, tenant_id, net_name):
1507+ # TODO (Sumit):
1508+ # The VLAN ID for a tenant might need to be obtained from
1509+ # somewhere (from Donabe/Melange?)
1510+ # Also need to make sure that the VLAN ID is not being used already
1511+ # Currently, just a wrap-around counter ranging from VLAN_START to
1512+ # VLAN_END
1513+ self._vlan_counter += 1
1514+ self._vlan_counter %= int(conf.VLAN_END)
1515+ if self._vlan_counter < int(conf.VLAN_START):
1516+ self._vlan_counter = int(conf.VLAN_START)
1517+ return self._vlan_counter
1518+
1519+ def _get_vlan_name(self, net_id, vlan):
1520+ vlan_name = conf.VLAN_NAME_PREFIX + net_id + "-" + vlan
1521+ return vlan_name
1522+
1523+ def _validate_port_state(self, port_state):
1524+ if port_state.upper() not in (const.PORT_UP, const.PORT_DOWN):
1525+ raise exc.StateInvalid(port_state=port_state)
1526+ return True
1527+
1528+ def _validate_attachment(self, tenant_id, network_id, port_id,
1529+ remote_interface_id):
1530+ network = self._get_network(tenant_id, network_id)
1531+ for port in network[const.NET_PORTS].values():
1532+ if port[const.ATTACHMENT] == remote_interface_id:
1533+ raise exc.AlreadyAttached(net_id=network_id,
1534+ port_id=port_id,
1535+ att_id=port[const.ATTACHMENT],
1536+ att_port_id=port[const.PORT_ID])
1537+
1538+ def _get_network(self, tenant_id, network_id):
1539+ network = self._networks.get(network_id)
1540+ if not network:
1541+ raise exc.NetworkNotFound(net_id=network_id)
1542+ return network
1543+
1544+ def _get_tenant(self, tenant_id):
1545+ tenant = self._tenants.get(tenant_id)
1546+ if not tenant:
1547+ LOG.debug("Creating new tenant record with tenant id %s\n" %
1548+ tenant_id)
1549+ tenant = {const.TENANT_ID: tenant_id,
1550+ const.TENANT_NAME: tenant_id,
1551+ const.TENANT_NETWORKS: {},
1552+ const.TENANT_PORTPROFILES: {}}
1553+ self._tenants[tenant_id] = tenant
1554+ return tenant
1555+
1556+ def _get_port(self, tenant_id, network_id, port_id):
1557+ net = self._get_network(tenant_id, network_id)
1558+ port = net[const.NET_PORTS].get(port_id)
1559+ if not port:
1560+ raise exc.PortNotFound(net_id=network_id, port_id=port_id)
1561+ return port
1562+
1563+ def _get_portprofile(self, tenant_id, portprofile_id):
1564+ portprofile = self._portprofiles.get(portprofile_id)
1565+ if not portprofile:
1566+ raise cexc.PortProfileNotFound(tenant_id=tenant_id,
1567+ portprofile_id=portprofile_id)
1568+ return portprofile
1569+
1570+ def _get_unique_net_id(self, tenant_id):
1571+ self._net_counter += 1
1572+ self._net_counter %= int(conf.MAX_NETWORKS)
1573+ id = tenant_id[:3] + \
1574+ "-n-" + ("0" * (6 - len(str(self._net_counter)))) + \
1575+ str(self._net_counter)
1576+ # TODO (Sumit): Need to check if the ID has already been allocated
1577+ # ID will be generated by DB
1578+ return id
1579+
1580+ def _get_unique_port_id(self, tenant_id, net_id):
1581+ self._port_counter += 1
1582+ self._port_counter %= int(conf.MAX_PORTS)
1583+ id = net_id + "-p-" + str(self._port_counter)
1584+ # TODO (Sumit): Need to check if the ID has already been allocated
1585+ # ID will be generated by DB
1586+ return id
1587+
1588+ def _get_unique_profile_id(self, tenant_id):
1589+ self._portprofile_counter += 1
1590+ self._portprofile_counter %= int(conf.MAX_PORT_PROFILES)
1591+ id = tenant_id[:3] + "-pp-" + \
1592+ ("0" * (6 - len(str(self._net_counter)))) \
1593+ + str(self._portprofile_counter)
1594+ # TODO (Sumit): Need to check if the ID has already been allocated
1595+ # ID will be generated by DB
1596+ return id
1597+
1598+ def _funcName(self, offset=0):
1599+ return inspect.stack()[1 + offset][3]
1600+
1601+"""
1602+TODO (Sumit):
1603+(1) Persistent storage
1604+"""
1605
1606=== added file 'quantum/plugins/cisco/l2network_plugin_configuration.py'
1607--- quantum/plugins/cisco/l2network_plugin_configuration.py 1970-01-01 00:00:00 +0000
1608+++ quantum/plugins/cisco/l2network_plugin_configuration.py 2011-08-15 17:33:23 +0000
1609@@ -0,0 +1,50 @@
1610+# vim: tabstop=4 shiftwidth=4 softtabstop=4
1611+#
1612+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
1613+#
1614+# Licensed under the Apache License, Version 2.0 (the "License"); you may
1615+# not use this file except in compliance with the License. You may obtain
1616+# a copy of the License at
1617+#
1618+# http://www.apache.org/licenses/LICENSE-2.0
1619+#
1620+# Unless required by applicable law or agreed to in writing, software
1621+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1622+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1623+# License for the specific language governing permissions and limitations
1624+# under the License.
1625+#
1626+# @author: Sumit Naiksatam, Cisco Systems, Inc.
1627+#
1628+
1629+import os
1630+
1631+from quantum.plugins.cisco.common import cisco_configparser as confp
1632+
1633+CONF_FILE = "conf/l2network_plugin.ini"
1634+
1635+cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
1636+ + "/" + CONF_FILE)
1637+
1638+section = cp['VLANS']
1639+VLAN_NAME_PREFIX = section['vlan_name_prefix']
1640+VLAN_START = section['vlan_start']
1641+VLAN_END = section['vlan_end']
1642+
1643+section = cp['PORTS']
1644+MAX_PORTS = section['max_ports']
1645+
1646+section = cp['PORTPROFILES']
1647+MAX_PORT_PROFILES = section['max_port_profiles']
1648+
1649+section = cp['NETWORKS']
1650+MAX_NETWORKS = section['max_networks']
1651+
1652+section = cp['MODEL']
1653+MODEL_CLASS = section['model_class']
1654+
1655+CONF_FILE = "conf/plugins.ini"
1656+
1657+cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
1658+ + "/" + CONF_FILE)
1659+plugins = cp.walk(cp.dummy)
1660
1661=== added directory 'quantum/plugins/cisco/nexus'
1662=== added file 'quantum/plugins/cisco/nexus/__init__.py'
1663--- quantum/plugins/cisco/nexus/__init__.py 1970-01-01 00:00:00 +0000
1664+++ quantum/plugins/cisco/nexus/__init__.py 2011-08-15 17:33:23 +0000
1665@@ -0,0 +1,18 @@
1666+# vim: tabstop=4 shiftwidth=4 softtabstop=4
1667+#
1668+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
1669+#
1670+# Licensed under the Apache License, Version 2.0 (the "License"); you may
1671+# not use this file except in compliance with the License. You may obtain
1672+# a copy of the License at
1673+#
1674+# http://www.apache.org/licenses/LICENSE-2.0
1675+#
1676+# Unless required by applicable law or agreed to in writing, software
1677+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1678+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1679+# License for the specific language governing permissions and limitations
1680+# under the License.
1681+#
1682+# @author: Sumit Naiksatam, Cisco Systems, Inc.
1683+#
1684
1685=== added file 'quantum/plugins/cisco/nexus/cisco_nexus_configuration.py'
1686--- quantum/plugins/cisco/nexus/cisco_nexus_configuration.py 1970-01-01 00:00:00 +0000
1687+++ quantum/plugins/cisco/nexus/cisco_nexus_configuration.py 2011-08-15 17:33:23 +0000
1688@@ -0,0 +1,35 @@
1689+# vim: tabstop=4 shiftwidth=4 softtabstop=4
1690+#
1691+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
1692+#
1693+# Licensed under the Apache License, Version 2.0 (the "License"); you may
1694+# not use this file except in compliance with the License. You may obtain
1695+# a copy of the License at
1696+#
1697+# http://www.apache.org/licenses/LICENSE-2.0
1698+#
1699+# Unless required by applicable law or agreed to in writing, software
1700+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1701+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1702+# License for the specific language governing permissions and limitations
1703+# under the License.
1704+#
1705+# @author: Sumit Naiksatam, Cisco Systems, Inc.
1706+# @author: Edgar Magana, Cisco Systems, Inc.
1707+#
1708+
1709+import os
1710+
1711+from quantum.plugins.cisco.common import cisco_configparser as confp
1712+
1713+CONF_FILE = "../conf/nexus.ini"
1714+
1715+cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
1716+ + "/" + CONF_FILE)
1717+
1718+section = cp['SWITCH']
1719+NEXUS_IP_ADDRESS = section['nexus_ip_address']
1720+NEXUS_PORT = section['nexus_port']
1721+
1722+section = cp['DRIVER']
1723+NEXUS_DRIVER = section['name']
1724
1725=== added file 'quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py'
1726--- quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py 1970-01-01 00:00:00 +0000
1727+++ quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py 2011-08-15 17:33:23 +0000
1728@@ -0,0 +1,226 @@
1729+# vim: tabstop=4 shiftwidth=4 softtabstop=4
1730+#
1731+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
1732+#
1733+# Licensed under the Apache License, Version 2.0 (the "License"); you may
1734+# not use this file except in compliance with the License. You may obtain
1735+# a copy of the License at
1736+#
1737+# http://www.apache.org/licenses/LICENSE-2.0
1738+#
1739+# Unless required by applicable law or agreed to in writing, software
1740+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1741+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1742+# License for the specific language governing permissions and limitations
1743+# under the License.
1744+#
1745+# @author: Debojyoti Dutta, Cisco Systems, Inc.
1746+# @author: Edgar Magana, Cisco Systems Inc.
1747+#
1748+"""
1749+Implements a Nexus-OS NETCONF over SSHv2 API Client
1750+"""
1751+
1752+import logging as LOG
1753+import string
1754+import subprocess
1755+
1756+from quantum.plugins.cisco.common import cisco_constants as const
1757+from quantum.plugins.cisco.common import cisco_exceptions as cexc
1758+
1759+from ncclient import manager
1760+
1761+LOG.basicConfig(level=LOG.WARN)
1762+LOG.getLogger(const.LOGGER_COMPONENT_NAME)
1763+
1764+
1765+# The following are standard strings, messages used to communicate with Nexus,
1766+#only place holder values change for each message
1767+exec_conf_prefix = """
1768+ <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
1769+ <configure xmlns="http://www.cisco.com/nxos:1.0:vlan_mgr_cli">
1770+ <__XML__MODE__exec_configure>
1771+"""
1772+
1773+
1774+exec_conf_postfix = """
1775+ </__XML__MODE__exec_configure>
1776+ </configure>
1777+ </config>
1778+"""
1779+
1780+
1781+cmd_vlan_conf_snippet = """
1782+ <vlan>
1783+ <vlan-id-create-delete>
1784+ <__XML__PARAM_value>%s</__XML__PARAM_value>
1785+ <__XML__MODE_vlan>
1786+ <name>
1787+ <vlan-name>%s</vlan-name>
1788+ </name>
1789+ <state>
1790+ <vstate>active</vstate>
1791+ </state>
1792+ <no>
1793+ <shutdown/>
1794+ </no>
1795+ </__XML__MODE_vlan>
1796+ </vlan-id-create-delete>
1797+ </vlan>
1798+"""
1799+
1800+cmd_no_vlan_conf_snippet = """
1801+ <no>
1802+ <vlan>
1803+ <vlan-id-create-delete>
1804+ <__XML__PARAM_value>%s</__XML__PARAM_value>
1805+ </vlan-id-create-delete>
1806+ </vlan>
1807+ </no>
1808+"""
1809+
1810+cmd_vlan_int_snippet = """
1811+ <interface>
1812+ <ethernet>
1813+ <interface>%s</interface>
1814+ <__XML__MODE_if-ethernet-switch>
1815+ <switchport></switchport>
1816+ <switchport>
1817+ <trunk>
1818+ <allowed>
1819+ <vlan>
1820+ <__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
1821+ <allow-vlans>%s</allow-vlans>
1822+ </__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
1823+ </vlan>
1824+ </allowed>
1825+ </trunk>
1826+ </switchport>
1827+ </__XML__MODE_if-ethernet-switch>
1828+ </ethernet>
1829+ </interface>
1830+"""
1831+
1832+cmd_port_trunk = """
1833+ <interface>
1834+ <ethernet>
1835+ <interface>%s</interface>
1836+ <__XML__MODE_if-ethernet-switch>
1837+ <switchport></switchport>
1838+ <switchport>
1839+ <mode>
1840+ <trunk>
1841+ </trunk>
1842+ </mode>
1843+ </switchport>
1844+ </__XML__MODE_if-ethernet-switch>
1845+ </ethernet>
1846+ </interface>
1847+"""
1848+
1849+cmd_no_switchport = """
1850+ <interface>
1851+ <ethernet>
1852+ <interface>%s</interface>
1853+ <__XML__MODE_if-ethernet-switch>
1854+ <no>
1855+ <switchport>
1856+ </switchport>
1857+ </no>
1858+ </__XML__MODE_if-ethernet-switch>
1859+ </ethernet>
1860+ </interface>
1861+"""
1862+
1863+
1864+cmd_no_vlan_int_snippet = """
1865+ <interface>
1866+ <ethernet>
1867+ <interface>%s</interface>
1868+ <__XML__MODE_if-ethernet-switch>
1869+ <switchport></switchport>
1870+ <no>
1871+ <switchport>
1872+ <trunk>
1873+ <allowed>
1874+ <vlan>
1875+ <__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
1876+ <allow-vlans>%s</allow-vlans>
1877+ </__XML__BLK_Cmd_switchport_trunk_allowed_allow-vlans>
1878+ </vlan>
1879+ </allowed>
1880+ </trunk>
1881+ </switchport>
1882+ </no>
1883+ </__XML__MODE_if-ethernet-switch>
1884+ </ethernet>
1885+ </interface>
1886+"""
1887+
1888+
1889+filter_show_vlan_brief_snippet = """
1890+ <show xmlns="http://www.cisco.com/nxos:1.0:vlan_mgr_cli">
1891+ <vlan>
1892+ <brief/>
1893+ </vlan>
1894+ </show> """
1895+
1896+
1897+class CiscoNEXUSDriver():
1898+
1899+ def __init__(self):
1900+ pass
1901+
1902+ def nxos_connect(self, nexus_host, port, nexus_user, nexus_password):
1903+ m = manager.connect(host=nexus_host, port=22, username=nexus_user,
1904+ password=nexus_password)
1905+ return m
1906+
1907+ def enable_vlan(self, mgr, vlanid, vlanname):
1908+ confstr = cmd_vlan_conf_snippet % (vlanid, vlanname)
1909+ confstr = exec_conf_prefix + confstr + exec_conf_postfix
1910+ mgr.edit_config(target='running', config=confstr)
1911+
1912+ def disable_vlan(self, mgr, vlanid):
1913+ confstr = cmd_no_vlan_conf_snippet % vlanid
1914+ confstr = exec_conf_prefix + confstr + exec_conf_postfix
1915+ mgr.edit_config(target='running', config=confstr)
1916+
1917+ def enable_port_trunk(self, mgr, interface):
1918+ confstr = cmd_port_trunk % (interface)
1919+ confstr = exec_conf_prefix + confstr + exec_conf_postfix
1920+ print confstr
1921+ mgr.edit_config(target='running', config=confstr)
1922+
1923+ def disable_switch_port(self, mgr, interface):
1924+ confstr = cmd_no_switchport % (interface)
1925+ confstr = exec_conf_prefix + confstr + exec_conf_postfix
1926+ print confstr
1927+ mgr.edit_config(target='running', config=confstr)
1928+
1929+ def enable_vlan_on_trunk_int(self, mgr, interface, vlanid):
1930+ confstr = cmd_vlan_int_snippet % (interface, vlanid)
1931+ confstr = exec_conf_prefix + confstr + exec_conf_postfix
1932+ print confstr
1933+ mgr.edit_config(target='running', config=confstr)
1934+
1935+ def disable_vlan_on_trunk_int(self, mgr, interface, vlanid):
1936+ confstr = cmd_no_vlan_int_snippet % (interface, vlanid)
1937+ confstr = exec_conf_prefix + confstr + exec_conf_postfix
1938+ print confstr
1939+ mgr.edit_config(target='running', config=confstr)
1940+
1941+ def create_vlan(self, vlan_name, vlan_id, nexus_host, nexus_user,
1942+ nexus_password, nexus_interface):
1943+ #TODO (Edgar) Move the SSH port to the configuration file
1944+ with self.nxos_connect(nexus_host, 22, nexus_user,
1945+ nexus_password) as m:
1946+ self.enable_vlan(m, vlan_id, vlan_name)
1947+ self.enable_vlan_on_trunk_int(m, nexus_interface, vlan_id)
1948+
1949+ def delete_vlan(self, vlan_id, nexus_host, nexus_user,
1950+ nexus_password, nexus_interface):
1951+ with self.nxos_connect(nexus_host, 22, nexus_user,
1952+ nexus_password) as m:
1953+ self.disable_vlan(m, vlan_id)
1954+ self.disable_switch_port(m, nexus_interface)
1955
1956=== added file 'quantum/plugins/cisco/nexus/cisco_nexus_plugin.py'
1957--- quantum/plugins/cisco/nexus/cisco_nexus_plugin.py 1970-01-01 00:00:00 +0000
1958+++ quantum/plugins/cisco/nexus/cisco_nexus_plugin.py 2011-08-15 17:33:23 +0000
1959@@ -0,0 +1,168 @@
1960+# vim: tabstop=4 shiftwidth=4 softtabstop=4
1961+#
1962+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
1963+#
1964+# Licensed under the Apache License, Version 2.0 (the "License"); you may
1965+# not use this file except in compliance with the License. You may obtain
1966+# a copy of the License at
1967+#
1968+# http://www.apache.org/licenses/LICENSE-2.0
1969+#
1970+# Unless required by applicable law or agreed to in writing, software
1971+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
1972+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
1973+# License for the specific language governing permissions and limitations
1974+# under the License.
1975+#
1976+# @author: Sumit Naiksatam, Cisco Systems, Inc.
1977+# @author: Edgar Magana, Cisco Systems, Inc.
1978+#
1979+import logging as LOG
1980+
1981+from quantum.common import exceptions as exc
1982+from quantum.common import utils
1983+from quantum.plugins.cisco.common import cisco_constants as const
1984+from quantum.plugins.cisco.common import cisco_credentials as cred
1985+from quantum.plugins.cisco.common import cisco_exceptions as cexc
1986+from quantum.plugins.cisco.common import cisco_utils as cutil
1987+from quantum.plugins.cisco.l2device_plugin_base import L2DevicePluginBase
1988+from quantum.plugins.cisco.nexus import cisco_nexus_configuration as conf
1989+
1990+LOG.basicConfig(level=LOG.WARN)
1991+LOG.getLogger(const.LOGGER_COMPONENT_NAME)
1992+
1993+
1994+class NexusPlugin(L2DevicePluginBase):
1995+ _networks = {}
1996+
1997+ def __init__(self):
1998+ self._client = utils.import_object(conf.NEXUS_DRIVER)
1999+ LOG.debug("Loaded driver %s\n" % conf.NEXUS_DRIVER)
2000+ #TODO (Edgar) Using just one Nexus 7K Switch and Port
2001+ self._nexus_ip = conf.NEXUS_IP_ADDRESS
2002+ self._nexus_username = cred.Store.getUsername(conf.NEXUS_IP_ADDRESS)
2003+ self._nexus_password = cred.Store.getPassword(conf.NEXUS_IP_ADDRESS)
2004+ self._nexus_port = conf.NEXUS_PORT
2005+
2006+ def get_all_networks(self, tenant_id):
2007+ """
2008+ Returns a dictionary containing all
2009+ <network_uuid, network_name> for
2010+ the specified tenant.
2011+ """
2012+ LOG.debug("NexusPlugin:get_all_networks() called\n")
2013+ return self._networks.values()
2014+
2015+ def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id,
2016+ **kwargs):
2017+ """
2018+ Create a VLAN in the switch, and configure the appropriate interfaces
2019+ for this VLAN
2020+ """
2021+ LOG.debug("NexusPlugin:create_network() called\n")
2022+ self._client.create_vlan(vlan_name, str(vlan_id), self._nexus_ip,
2023+ self._nexus_username, self._nexus_password, self._nexus_port)
2024+
2025+ new_net_dict = {const.NET_ID: net_id,
2026+ const.NET_NAME: net_name,
2027+ const.NET_PORTS: {},
2028+ const.NET_VLAN_NAME: vlan_name,
2029+ const.NET_VLAN_ID: vlan_id}
2030+ self._networks[net_id] = new_net_dict
2031+ return new_net_dict
2032+
2033+ def delete_network(self, tenant_id, net_id, **kwargs):
2034+ """
2035+ Deletes a VLAN in the switch, and removes the VLAN configuration
2036+ from the relevant interfaces
2037+ """
2038+ LOG.debug("NexusPlugin:delete_network() called\n")
2039+ net = self._networks.get(net_id)
2040+ vlan_id = self._get_vlan_id_for_network(tenant_id, net_id)
2041+ if net:
2042+ self._client.delete_vlan(str(vlan_id), self._nexus_ip,
2043+ self._nexus_username, self._nexus_password, self._nexus_port)
2044+ self._networks.pop(net_id)
2045+ return net
2046+ # Network not found
2047+ raise exc.NetworkNotFound(net_id=net_id)
2048+
2049+ def get_network_details(self, tenant_id, net_id, **kwargs):
2050+ """
2051+ Returns the details of a particular network
2052+ """
2053+ LOG.debug("NexusPlugin:get_network_details() called\n")
2054+ network = self._get_network(tenant_id, net_id)
2055+ return network
2056+
2057+ def rename_network(self, tenant_id, net_id, new_name, **kwargs):
2058+ """
2059+ Updates the symbolic name belonging to a particular
2060+ Virtual Network.
2061+ """
2062+ #TODO (Edgar) We need to add an update method in the Nexus Driver
2063+ LOG.debug("NexusPlugin:rename_network() called\n")
2064+ network = self._get_network(tenant_id, net_id)
2065+ network[const.NET_NAME] = new_name
2066+ return network
2067+
2068+ def get_all_ports(self, tenant_id, net_id, **kwargs):
2069+ """
2070+ This is probably not applicable to the Nexus plugin.
2071+ Delete if not required.
2072+ """
2073+ LOG.debug("NexusPlugin:get_all_ports() called\n")
2074+
2075+ def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs):
2076+ """
2077+ This is probably not applicable to the Nexus plugin.
2078+ Delete if not required.
2079+ """
2080+ LOG.debug("NexusPlugin:create_port() called\n")
2081+
2082+ def delete_port(self, tenant_id, net_id, port_id, **kwargs):
2083+ """
2084+ This is probably not applicable to the Nexus plugin.
2085+ Delete if not required.
2086+ """
2087+ LOG.debug("NexusPlugin:delete_port() called\n")
2088+
2089+ def update_port(self, tenant_id, net_id, port_id, port_state, **kwargs):
2090+ """
2091+ This is probably not applicable to the Nexus plugin.
2092+ Delete if not required.
2093+ """
2094+ LOG.debug("NexusPlugin:update_port() called\n")
2095+
2096+ def get_port_details(self, tenant_id, net_id, port_id, **kwargs):
2097+ """
2098+ This is probably not applicable to the Nexus plugin.
2099+ Delete if not required.
2100+ """
2101+ LOG.debug("NexusPlugin:get_port_details() called\n")
2102+
2103+ def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id,
2104+ **kwargs):
2105+ """
2106+ This is probably not applicable to the Nexus plugin.
2107+ Delete if not required.
2108+ """
2109+ LOG.debug("NexusPlugin:plug_interface() called\n")
2110+
2111+ def unplug_interface(self, tenant_id, net_id, port_id, **kwargs):
2112+ """
2113+ This is probably not applicable to the Nexus plugin.
2114+ Delete if not required.
2115+ """
2116+ LOG.debug("NexusPlugin:unplug_interface() called\n")
2117+
2118+ def _get_vlan_id_for_network(self, tenant_id, network_id):
2119+ net = self._get_network(tenant_id, network_id)
2120+ vlan_id = net[const.NET_VLAN_ID]
2121+ return vlan_id
2122+
2123+ def _get_network(self, tenant_id, network_id):
2124+ network = self._networks.get(network_id)
2125+ if not network:
2126+ raise exc.NetworkNotFound(net_id=network_id)
2127+ return network
2128
2129=== added file 'quantum/plugins/cisco/run_tests.py'
2130--- quantum/plugins/cisco/run_tests.py 1970-01-01 00:00:00 +0000
2131+++ quantum/plugins/cisco/run_tests.py 2011-08-15 17:33:23 +0000
2132@@ -0,0 +1,301 @@
2133+#!/usr/bin/env python
2134+# vim: tabstop=4 shiftwidth=4 softtabstop=4
2135+
2136+# Copyright 2010 OpenStack, LLC
2137+# All Rights Reserved.
2138+#
2139+# Licensed under the Apache License, Version 2.0 (the "License");
2140+# you may not use this file except in compliance with the License.
2141+# You may obtain a copy of the License at
2142+#
2143+# http://www.apache.org/licenses/LICENSE-2.0
2144+#
2145+# Unless required by applicable law or agreed to in writing, software
2146+# distributed under the License is distributed on an "AS IS" BASIS,
2147+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2148+# See the License for the specific language governing permissions and
2149+# limitations under the License.
2150+
2151+# Colorizer Code is borrowed from Twisted:
2152+# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
2153+#
2154+# Permission is hereby granted, free of charge, to any person obtaining
2155+# a copy of this software and associated documentation files (the
2156+# "Software"), to deal in the Software without restriction, including
2157+# without limitation the rights to use, copy, modify, merge, publish,
2158+# distribute, sublicense, and/or sell copies of the Software, and to
2159+# permit persons to whom the Software is furnished to do so, subject to
2160+# the following conditions:
2161+#
2162+# The above copyright notice and this permission notice shall be
2163+# included in all copies or substantial portions of the Software.
2164+#
2165+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2166+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2167+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2168+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2169+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2170+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2171+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2172+
2173+"""Unittest runner for quantum
2174+
2175+To run all test::
2176+ python run_tests.py
2177+
2178+To run all unit tests::
2179+ python run_tests.py unit
2180+
2181+To run all functional tests::
2182+ python run_tests.py functional
2183+
2184+To run a single unit test::
2185+ python run_tests.py unit.test_stores:TestSwiftBackend.test_get
2186+
2187+To run a single functional test::
2188+ python run_tests.py functional.test_service:TestController.test_create
2189+
2190+To run a single unit test module::
2191+ python run_tests.py unit.test_stores
2192+
2193+To run a single functional test module::
2194+ python run_tests.py functional.test_stores
2195+"""
2196+
2197+import gettext
2198+import logging
2199+import os
2200+import unittest
2201+import sys
2202+
2203+from nose import config
2204+from nose import result
2205+from nose import core
2206+
2207+
2208+class _AnsiColorizer(object):
2209+ """
2210+ A colorizer is an object that loosely wraps around a stream, allowing
2211+ callers to write text to the stream in a particular color.
2212+
2213+ Colorizer classes must implement C{supported()} and C{write(text, color)}.
2214+ """
2215+ _colors = dict(black=30, red=31, green=32, yellow=33,
2216+ blue=34, magenta=35, cyan=36, white=37)
2217+
2218+ def __init__(self, stream):
2219+ self.stream = stream
2220+
2221+ def supported(cls, stream=sys.stdout):
2222+ """
2223+ A class method that returns True if the current platform supports
2224+ coloring terminal output using this method. Returns False otherwise.
2225+ """
2226+ if not stream.isatty():
2227+ return False # auto color only on TTYs
2228+ try:
2229+ import curses
2230+ except ImportError:
2231+ return False
2232+ else:
2233+ try:
2234+ try:
2235+ return curses.tigetnum("colors") > 2
2236+ except curses.error:
2237+ curses.setupterm()
2238+ return curses.tigetnum("colors") > 2
2239+ except:
2240+ raise
2241+ # guess false in case of error
2242+ return False
2243+ supported = classmethod(supported)
2244+
2245+ def write(self, text, color):
2246+ """
2247+ Write the given text to the stream in the given color.
2248+
2249+ @param text: Text to be written to the stream.
2250+
2251+ @param color: A string label for a color. e.g. 'red', 'white'.
2252+ """
2253+ color = self._colors[color]
2254+ self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text))
2255+
2256+
2257+class _Win32Colorizer(object):
2258+ """
2259+ See _AnsiColorizer docstring.
2260+ """
2261+ def __init__(self, stream):
2262+ from win32console import GetStdHandle, STD_OUT_HANDLE, \
2263+ FOREGROUND_RED, FOREGROUND_BLUE, FOREGROUND_GREEN, \
2264+ FOREGROUND_INTENSITY
2265+ red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN,
2266+ FOREGROUND_BLUE, FOREGROUND_INTENSITY)
2267+ self.stream = stream
2268+ self.screenBuffer = GetStdHandle(STD_OUT_HANDLE)
2269+ self._colors = {
2270+ 'normal': red | green | blue,
2271+ 'red': red | bold,
2272+ 'green': green | bold,
2273+ 'blue': blue | bold,
2274+ 'yellow': red | green | bold,
2275+ 'magenta': red | blue | bold,
2276+ 'cyan': green | blue | bold,
2277+ 'white': red | green | blue | bold}
2278+
2279+ def supported(cls, stream=sys.stdout):
2280+ try:
2281+ import win32console
2282+ screenBuffer = win32console.GetStdHandle(
2283+ win32console.STD_OUT_HANDLE)
2284+ except ImportError:
2285+ return False
2286+ import pywintypes
2287+ try:
2288+ screenBuffer.SetConsoleTextAttribute(
2289+ win32console.FOREGROUND_RED |
2290+ win32console.FOREGROUND_GREEN |
2291+ win32console.FOREGROUND_BLUE)
2292+ except pywintypes.error:
2293+ return False
2294+ else:
2295+ return True
2296+ supported = classmethod(supported)
2297+
2298+ def write(self, text, color):
2299+ color = self._colors[color]
2300+ self.screenBuffer.SetConsoleTextAttribute(color)
2301+ self.stream.write(text)
2302+ self.screenBuffer.SetConsoleTextAttribute(self._colors['normal'])
2303+
2304+
2305+class _NullColorizer(object):
2306+ """
2307+ See _AnsiColorizer docstring.
2308+ """
2309+ def __init__(self, stream):
2310+ self.stream = stream
2311+
2312+ def supported(cls, stream=sys.stdout):
2313+ return True
2314+ supported = classmethod(supported)
2315+
2316+ def write(self, text, color):
2317+ self.stream.write(text)
2318+
2319+
2320+class QuantumTestResult(result.TextTestResult):
2321+ def __init__(self, *args, **kw):
2322+ result.TextTestResult.__init__(self, *args, **kw)
2323+ self._last_case = None
2324+ self.colorizer = None
2325+ # NOTE(vish, tfukushima): reset stdout for the terminal check
2326+ stdout = sys.__stdout__
2327+ for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]:
2328+ if colorizer.supported():
2329+ self.colorizer = colorizer(self.stream)
2330+ break
2331+ sys.stdout = stdout
2332+
2333+ def getDescription(self, test):
2334+ return str(test)
2335+
2336+ # NOTE(vish, tfukushima): copied from unittest with edit to add color
2337+ def addSuccess(self, test):
2338+ unittest.TestResult.addSuccess(self, test)
2339+ if self.showAll:
2340+ self.colorizer.write("OK", 'green')
2341+ self.stream.writeln()
2342+ elif self.dots:
2343+ self.stream.write('.')
2344+ self.stream.flush()
2345+
2346+ # NOTE(vish, tfukushima): copied from unittest with edit to add color
2347+ def addFailure(self, test, err):
2348+ unittest.TestResult.addFailure(self, test, err)
2349+ if self.showAll:
2350+ self.colorizer.write("FAIL", 'red')
2351+ self.stream.writeln()
2352+ elif self.dots:
2353+ self.stream.write('F')
2354+ self.stream.flush()
2355+
2356+ # NOTE(vish, tfukushima): copied from unittest with edit to add color
2357+ def addError(self, test, err):
2358+ """Overrides normal addError to add support for errorClasses.
2359+ If the exception is a registered class, the error will be added
2360+ to the list for that class, not errors.
2361+ """
2362+ stream = getattr(self, 'stream', None)
2363+ ec, ev, tb = err
2364+ try:
2365+ exc_info = self._exc_info_to_string(err, test)
2366+ except TypeError:
2367+ # This is for compatibility with Python 2.3.
2368+ exc_info = self._exc_info_to_string(err)
2369+ for cls, (storage, label, isfail) in self.errorClasses.items():
2370+ if result.isclass(ec) and issubclass(ec, cls):
2371+ if isfail:
2372+ test.passwd = False
2373+ storage.append((test, exc_info))
2374+ # Might get patched into a streamless result
2375+ if stream is not None:
2376+ if self.showAll:
2377+ message = [label]
2378+ detail = result._exception_details(err[1])
2379+ if detail:
2380+ message.append(detail)
2381+ stream.writeln(": ".join(message))
2382+ elif self.dots:
2383+ stream.write(label[:1])
2384+ return
2385+ self.errors.append((test, exc_info))
2386+ test.passed = False
2387+ if stream is not None:
2388+ if self.showAll:
2389+ self.colorizer.write("ERROR", 'red')
2390+ self.stream.writeln()
2391+ elif self.dots:
2392+ stream.write('E')
2393+
2394+ def startTest(self, test):
2395+ unittest.TestResult.startTest(self, test)
2396+ current_case = test.test.__class__.__name__
2397+
2398+ if self.showAll:
2399+ if current_case != self._last_case:
2400+ self.stream.writeln(current_case)
2401+ self._last_case = current_case
2402+
2403+ self.stream.write(
2404+ ' %s' % str(test.test._testMethodName).ljust(60))
2405+ self.stream.flush()
2406+
2407+
2408+class QuantumTestRunner(core.TextTestRunner):
2409+ def _makeResult(self):
2410+ return QuantumTestResult(self.stream,
2411+ self.descriptions,
2412+ self.verbosity,
2413+ self.config)
2414+
2415+
2416+if __name__ == '__main__':
2417+ # Set up test logger.
2418+ logger = logging.getLogger()
2419+ hdlr = logging.StreamHandler()
2420+ formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
2421+ hdlr.setFormatter(formatter)
2422+ logger.addHandler(hdlr)
2423+ logger.setLevel(logging.DEBUG)
2424+
2425+ working_dir = os.path.abspath("tests")
2426+ c = config.Config(stream=sys.stdout,
2427+ env=os.environ,
2428+ verbosity=3,
2429+ workingDir=working_dir)
2430+ runner = QuantumTestRunner(stream=c.stream,
2431+ verbosity=c.verbosity,
2432+ config=c)
2433+ sys.exit(not core.run(config=c, testRunner=runner))
2434
2435=== added directory 'quantum/plugins/cisco/tests'
2436=== added file 'quantum/plugins/cisco/tests/__init__.py'
2437--- quantum/plugins/cisco/tests/__init__.py 1970-01-01 00:00:00 +0000
2438+++ quantum/plugins/cisco/tests/__init__.py 2011-08-15 17:33:23 +0000
2439@@ -0,0 +1,18 @@
2440+# vim: tabstop=4 shiftwidth=4 softtabstop=4
2441+#
2442+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
2443+#
2444+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2445+# not use this file except in compliance with the License. You may obtain
2446+# a copy of the License at
2447+#
2448+# http://www.apache.org/licenses/LICENSE-2.0
2449+#
2450+# Unless required by applicable law or agreed to in writing, software
2451+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2452+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2453+# License for the specific language governing permissions and limitations
2454+# under the License.
2455+#
2456+# @author: Sumit Naiksatam, Cisco Systems, Inc.
2457+#
2458
2459=== added directory 'quantum/plugins/cisco/tests/unit'
2460=== added file 'quantum/plugins/cisco/tests/unit/__init__.py'
2461--- quantum/plugins/cisco/tests/unit/__init__.py 1970-01-01 00:00:00 +0000
2462+++ quantum/plugins/cisco/tests/unit/__init__.py 2011-08-15 17:33:23 +0000
2463@@ -0,0 +1,32 @@
2464+# vim: tabstop=4 shiftwidth=4 softtabstop=4
2465+
2466+# Copyright 2011 OpenStack LLC.
2467+# All Rights Reserved.
2468+#
2469+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2470+# not use this file except in compliance with the License. You may obtain
2471+# a copy of the License at
2472+#
2473+# http://www.apache.org/licenses/LICENSE-2.0
2474+#
2475+# Unless required by applicable law or agreed to in writing, software
2476+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2477+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2478+# License for the specific language governing permissions and limitations
2479+# under the License.
2480+
2481+# See http://code.google.com/p/python-nose/issues/detail?id=373
2482+# The code below enables nosetests to work with i18n _() blocks
2483+import __builtin__
2484+import unittest
2485+setattr(__builtin__, '_', lambda x: x)
2486+
2487+
2488+class BaseTest(unittest.TestCase):
2489+
2490+ def setUp(self):
2491+ pass
2492+
2493+
2494+def setUp():
2495+ pass
2496
2497=== added file 'quantum/plugins/cisco/tests/unit/test_l2networkApi.py'
2498--- quantum/plugins/cisco/tests/unit/test_l2networkApi.py 1970-01-01 00:00:00 +0000
2499+++ quantum/plugins/cisco/tests/unit/test_l2networkApi.py 2011-08-15 17:33:23 +0000
2500@@ -0,0 +1,892 @@
2501+# vim: tabstop=4 shiftwidth=4 softtabstop=4
2502+#
2503+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
2504+#
2505+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2506+# not use this file except in compliance with the License. You may obtain
2507+# a copy of the License at
2508+#
2509+# http://www.apache.org/licenses/LICENSE-2.0
2510+#
2511+# Unless required by applicable law or agreed to in writing, software
2512+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
2513+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
2514+# License for the specific language governing permissions and limitations
2515+# under the License.
2516+#
2517+# @author: Shweta Padubidri, Cisco Systems, Inc.
2518+#
2519+
2520+import logging
2521+import unittest
2522+from quantum.common import exceptions as exc
2523+from quantum.plugins.cisco.common import cisco_constants as const
2524+from quantum.plugins.cisco.common import cisco_exceptions as cexc
2525+from quantum.plugins.cisco import l2network_plugin
2526+from quantum.plugins.cisco import l2network_plugin_configuration as conf
2527+
2528+LOG = logging.getLogger('quantum.tests.test_core_api_func')
2529+
2530+
2531+class CoreAPITestFunc(unittest.TestCase):
2532+
2533+ def test_create_network(self, net_tenant_id=None, net_name=None):
2534+
2535+ """
2536+ Tests creation of new Virtual Network.
2537+ """
2538+
2539+ LOG.debug("test_create_network - START")
2540+ if net_tenant_id:
2541+ tenant_id = net_tenant_id
2542+ else:
2543+ tenant_id = self.tenant_id
2544+ if net_name:
2545+ network_name = net_name
2546+ else:
2547+ network_name = self.network_name
2548+ new_net_dict = self._l2network_plugin.create_network(
2549+ tenant_id, network_name)
2550+ self.assertEqual(new_net_dict[const.NET_NAME], network_name)
2551+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
2552+ LOG.debug("test_create_network - END")
2553+
2554+ def test_delete_network(self, net_tenant_id=None):
2555+ """
2556+ Tests deletion of a Virtual Network.
2557+ """
2558+ LOG.debug("test_delete_network - START")
2559+ if net_tenant_id:
2560+ tenant_id = net_tenant_id
2561+ else:
2562+ tenant_id = self.tenant_id
2563+ new_net_dict = self._l2network_plugin.create_network(
2564+ tenant_id, self.network_name)
2565+ delete_net_dict = self._l2network_plugin.delete_network(
2566+ tenant_id, new_net_dict[const.NET_ID])
2567+ self.assertEqual(
2568+ new_net_dict[const.NET_ID], delete_net_dict[const.NET_ID])
2569+ LOG.debug("test_delete_network - END")
2570+
2571+ def test_delete_networkDNE(self, net_tenant_id=None, net_id='0005'):
2572+ """
2573+ Tests deletion of a Virtual Network when Network does not exist.
2574+ """
2575+ LOG.debug("test_delete_network_not_found - START")
2576+ if net_tenant_id:
2577+ tenant_id = net_tenant_id
2578+ else:
2579+ tenant_id = self.tenant_id
2580+ self.assertRaises(
2581+ exc.NetworkNotFound, self._l2network_plugin.delete_network,
2582+ tenant_id, net_id)
2583+ LOG.debug("test_delete_network_not_found - END")
2584+
2585+ def test_delete_networkInUse(self, tenant_id='test_network'):
2586+ """
2587+ Tests deletion of a Virtual Network when Network is in Use.
2588+ """
2589+ LOG.debug("test_delete_networkInUse - START")
2590+
2591+ new_net_dict = self._l2network_plugin.create_network(
2592+ tenant_id, self.network_name)
2593+ port_dict = self._l2network_plugin.create_port(
2594+ tenant_id, new_net_dict[const.NET_ID], self.port_state)
2595+ self._l2network_plugin.plug_interface(
2596+ tenant_id, new_net_dict[const.NET_ID],
2597+ port_dict[const.PORT_ID], self.remote_interface)
2598+ self.assertRaises(exc.NetworkInUse,
2599+ self._l2network_plugin.delete_network, tenant_id,
2600+ new_net_dict[const.NET_ID])
2601+ self.tearDownNetworkPortInterface(
2602+ tenant_id, new_net_dict[const.NET_ID],
2603+ port_dict[const.PORT_ID])
2604+ LOG.debug("test_delete_networkInUse - END")
2605+
2606+ def test_show_network(self, net_tenant_id=None):
2607+ """
2608+ Tests display of details of a Virtual Network .
2609+ """
2610+
2611+ LOG.debug("test_show_network - START")
2612+ if net_tenant_id:
2613+ tenant_id = net_tenant_id
2614+ else:
2615+ tenant_id = self.tenant_id
2616+ new_net_dict = self._l2network_plugin.create_network(
2617+ tenant_id, self.network_name)
2618+ result_net_dict = self._l2network_plugin.get_network_details(
2619+ tenant_id, new_net_dict[const.NET_ID])
2620+ self.assertEqual(
2621+ new_net_dict[const.NET_ID], result_net_dict[const.NET_ID])
2622+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
2623+ LOG.debug("test_show_network - END")
2624+
2625+ def test_show_networkDNE(self, net_tenant_id=None, net_id='0005'):
2626+ """
2627+ Tests display of a Virtual Network when Network does not exist.
2628+ """
2629+
2630+ LOG.debug("test_show_network_not_found - START")
2631+ if net_tenant_id:
2632+ tenant_id = net_tenant_id
2633+ else:
2634+ tenant_id = self.tenant_id
2635+ self.assertRaises(exc.NetworkNotFound,
2636+ self._l2network_plugin.get_network_details,
2637+ tenant_id, net_id)
2638+ LOG.debug("test_show_network_not_found - END")
2639+
2640+ def test_rename_network(self, net_tenant_id=None,
2641+ new_name='new_test_network'):
2642+ """
2643+ Tests rename of a Virtual Network .
2644+ """
2645+
2646+ LOG.debug("test_rename_network - START")
2647+ if net_tenant_id:
2648+ tenant_id = net_tenant_id
2649+ else:
2650+ tenant_id = self.tenant_id
2651+ new_net_dict = self._l2network_plugin.create_network(
2652+ tenant_id, self.network_name)
2653+ rename_net_dict = self._l2network_plugin.rename_network(
2654+ tenant_id, new_net_dict[const.NET_ID], new_name)
2655+ self.assertEqual(new_name, rename_net_dict[const.NET_NAME])
2656+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
2657+ LOG.debug("test_rename_network - END")
2658+
2659+ def test_rename_networkDNE(self, net_tenant_id=None,
2660+ net_id='0005', new_name='new_test_network'):
2661+ """
2662+ Tests rename of a Virtual Network when Network does not exist.
2663+ """
2664+
2665+ LOG.debug("test_rename_network_not_found - START")
2666+ if net_tenant_id:
2667+ tenant_id = net_tenant_id
2668+ else:
2669+ tenant_id = self.tenant_id
2670+ self.assertRaises(exc.NetworkNotFound,
2671+ self._l2network_plugin.rename_network,
2672+ tenant_id, net_id, new_name)
2673+ LOG.debug("test_rename_network_not_found - END")
2674+
2675+ def test_list_networks(self, tenant_id='test_network'):
2676+ """
2677+ Tests listing of all the Virtual Networks .
2678+ """
2679+
2680+ LOG.debug("test_list_networks - START")
2681+ new_net_dict = self._l2network_plugin.create_network(
2682+ tenant_id, self.network_name)
2683+ new_net_dict2 = self._l2network_plugin.create_network(
2684+ tenant_id, 'test_net2')
2685+ net_list = self._l2network_plugin.get_all_networks(tenant_id)
2686+ net_temp_list = [new_net_dict, new_net_dict2]
2687+ self.assertEqual(len(net_list), 2)
2688+ self.assertTrue(net_list[0] in net_temp_list)
2689+ self.assertTrue(net_list[1] in net_temp_list)
2690+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
2691+ self.tearDownNetwork(tenant_id, new_net_dict2[const.NET_ID])
2692+ LOG.debug("test_list_networks - END")
2693+
2694+ def test_list_ports(self, tenant_id='test_network'):
2695+ """
2696+ Tests listing of all the Ports.
2697+ """
2698+
2699+ LOG.debug("test_list_ports - START")
2700+ new_net_dict = self._l2network_plugin.create_network(
2701+ tenant_id, self.network_name)
2702+ port_dict = self._l2network_plugin.create_port(
2703+ tenant_id, new_net_dict[const.NET_ID], self.port_state)
2704+ port_dict2 = self._l2network_plugin.create_port(
2705+ tenant_id, new_net_dict[const.NET_ID], self.port_state)
2706+ port_list = self._l2network_plugin.get_all_ports(
2707+ tenant_id, new_net_dict[const.NET_ID])
2708+ port_temp_list = [port_dict, port_dict2]
2709+ self.assertEqual(len(port_list), 2)
2710+ self.assertTrue(port_list[0] in port_temp_list)
2711+ self.assertTrue(port_list[1] in port_temp_list)
2712+
2713+ self.tearDownPortOnly(tenant_id, new_net_dict[const.NET_ID],
2714+ port_dict[const.PORT_ID])
2715+ self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
2716+ port_dict2[const.PORT_ID])
2717+ LOG.debug("test_list_ports - END")
2718+
2719+ def test_create_port(self, tenant_id='test_network',
2720+ port_state=const.PORT_UP):
2721+ """
2722+ Tests creation of Ports.
2723+ """
2724+
2725+ LOG.debug("test_create_port - START")
2726+ new_net_dict = self._l2network_plugin.create_network(
2727+ tenant_id, self.network_name)
2728+ port_dict = self._l2network_plugin.create_port(
2729+ tenant_id, new_net_dict[const.NET_ID], port_state)
2730+ self.assertEqual(port_dict[const.PORT_STATE], port_state)
2731+ self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
2732+ port_dict[const.PORT_ID])
2733+ LOG.debug("test_create_port - END")
2734+
2735+ def test_create_port_network_DNE(
2736+ self, net_tenant_id=None, net_id='0005', port_state=const.PORT_UP):
2737+
2738+ """
2739+ Tests creation of Ports when network does not exist.
2740+ """
2741+
2742+ LOG.debug("test_create_port_network_DNE - START")
2743+ if net_tenant_id:
2744+ tenant_id = net_tenant_id
2745+ else:
2746+ tenant_id = self.tenant_id
2747+ self.assertRaises(exc.NetworkNotFound,
2748+ self._l2network_plugin.create_port,
2749+ tenant_id, net_id, port_state)
2750+ LOG.debug("test_create_port_network_DNE - END:")
2751+
2752+ def test_delete_port(self, tenant_id='test_tenant',
2753+ port_state=const.PORT_UP):
2754+ """
2755+ Tests deletion of Ports
2756+ """
2757+
2758+ LOG.debug("test_delete_port - START")
2759+ new_net_dict = self._l2network_plugin.create_network(
2760+ tenant_id, self.network_name)
2761+ port_dict = self._l2network_plugin.create_port(
2762+ tenant_id, new_net_dict[const.NET_ID], port_state)
2763+ delete_port_dict = self._l2network_plugin.delete_port(
2764+ tenant_id, new_net_dict[const.NET_ID],
2765+ port_dict[const.PORT_ID])
2766+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
2767+ self.assertEqual(delete_port_dict, None)
2768+ LOG.debug("test_delete_port - END")
2769+
2770+ def test_delete_port_networkDNE(self, tenant_id='test_tenant',
2771+ net_id='0005', port_id='p0005'):
2772+ """
2773+ Tests deletion of Ports when network does not exist.
2774+ """
2775+
2776+ LOG.debug("test_delete_port_networkDNE - START")
2777+ self.assertRaises(exc.NetworkNotFound,
2778+ self._l2network_plugin.delete_port, tenant_id,
2779+ net_id, port_id)
2780+ LOG.debug("test_delete_port_networkDNE - END")
2781+
2782+ def test_delete_portDNE(self, tenant_id='test_tenant', port_id='p0005'):
2783+ """
2784+ Tests deletion of Ports when port does not exist.
2785+ """
2786+
2787+ LOG.debug("test_delete_portDNE - START")
2788+ new_net_dict = self._l2network_plugin.create_network(
2789+ tenant_id, self.network_name)
2790+ self.assertRaises(exc.PortNotFound, self._l2network_plugin.delete_port,
2791+ tenant_id, new_net_dict[const.NET_ID], port_id)
2792+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
2793+ LOG.debug("test_delete_portDNE - END")
2794+
2795+ def test_delete_portInUse(self, tenant_id='test_tenant'):
2796+ """
2797+ Tests deletion of Ports when port is in Use.
2798+ """
2799+
2800+ LOG.debug("test_delete_portInUse - START")
2801+ new_net_dict = self._l2network_plugin.create_network(
2802+ tenant_id, self.network_name)
2803+ port_dict = self._l2network_plugin.create_port(
2804+ tenant_id, new_net_dict[const.NET_ID],
2805+ self.port_state)
2806+ self._l2network_plugin.plug_interface(
2807+ tenant_id, new_net_dict[const.NET_ID],
2808+ port_dict[const.PORT_ID], self.remote_interface)
2809+ self.assertRaises(exc.PortInUse,
2810+ self._l2network_plugin.delete_port, tenant_id,
2811+ new_net_dict[const.NET_ID], port_dict[const.PORT_ID])
2812+ self.tearDownNetworkPortInterface(
2813+ tenant_id, new_net_dict[const.NET_ID], port_dict[const.PORT_ID])
2814+ LOG.debug("test_delete_portInUse - END")
2815+
2816+ def test_update_port(self, tenant_id='test_tenant',
2817+ port_state=const.PORT_DOWN):
2818+ """
2819+ Tests updation of Ports.
2820+ """
2821+
2822+ LOG.debug("test_update_port - START")
2823+ new_net_dict = self._l2network_plugin.create_network(
2824+ tenant_id, self.network_name)
2825+ port_dict = self._l2network_plugin.create_port(
2826+ tenant_id, new_net_dict[const.NET_ID], self.port_state)
2827+ update_port_dict = self._l2network_plugin.update_port(
2828+ tenant_id, new_net_dict[const.NET_ID],
2829+ port_dict[const.PORT_ID], port_state)
2830+ self.assertEqual(update_port_dict[const.PORT_STATE], port_state)
2831+ self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
2832+ port_dict[const.PORT_ID])
2833+ LOG.debug("test_update_port - END")
2834+
2835+ def test_update_port_networkDNE(self, tenant_id='test_tenant',
2836+ net_id='0005', port_id='p0005'):
2837+ """
2838+ Tests updation of Ports when network does not exist.
2839+ """
2840+
2841+ LOG.debug("test_update_port_networkDNE - START")
2842+ self.assertRaises(exc.NetworkNotFound,
2843+ self._l2network_plugin.update_port, tenant_id,
2844+ net_id, port_id, self.port_state)
2845+ LOG.debug("test_update_port_networkDNE - END")
2846+
2847+ def test_update_portDNE(self, tenant_id='test_tenant', port_id='p0005'):
2848+ """
2849+ Tests updation of Ports when port does not exist.
2850+ """
2851+
2852+ LOG.debug("test_update_portDNE - START")
2853+ new_net_dict = self._l2network_plugin.create_network(
2854+ tenant_id, self.network_name)
2855+ self.assertRaises(
2856+ exc.PortNotFound, self._l2network_plugin.update_port, tenant_id,
2857+ new_net_dict[const.NET_ID], port_id, self.port_state)
2858+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
2859+ LOG.debug("test_update_portDNE - END")
2860+
2861+ def test_show_port(self, tenant_id='test_tenant'):
2862+ """
2863+ Tests display of Ports
2864+ """
2865+
2866+ LOG.debug("test_show_port - START")
2867+ new_net_dict = self._l2network_plugin.create_network(
2868+ tenant_id, self.network_name)
2869+ port_dict = self._l2network_plugin.create_port(
2870+ tenant_id, new_net_dict[const.NET_ID], self.port_state)
2871+ get_port_dict = self._l2network_plugin.get_port_details(
2872+ tenant_id, new_net_dict[const.NET_ID],
2873+ port_dict[const.PORT_ID])
2874+ self.assertEqual(get_port_dict[const.PORT_STATE], self.port_state)
2875+ self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
2876+ port_dict[const.PORT_ID])
2877+ LOG.debug("test_show_port - END")
2878+
2879+ def test_show_port_networkDNE(self, tenant_id='test_tenant',
2880+ net_id='0005', port_id='p0005'):
2881+ """
2882+ Tests display of Ports when network does not exist
2883+ """
2884+
2885+ LOG.debug("test_show_port_networkDNE - START")
2886+ self.assertRaises(exc.NetworkNotFound,
2887+ self._l2network_plugin.get_port_details,
2888+ tenant_id, net_id, port_id)
2889+ LOG.debug("test_show_port_networkDNE - END")
2890+
2891+ def test_show_portDNE(self, tenant_id='test_tenant', port_id='p0005'):
2892+ """
2893+ Tests display of Ports when port does not exist
2894+ """
2895+
2896+ LOG.debug("test_show_portDNE - START")
2897+ new_net_dict = self._l2network_plugin.create_network(
2898+ tenant_id, self.network_name)
2899+ self.assertRaises(exc.PortNotFound,
2900+ self._l2network_plugin.get_port_details, tenant_id,
2901+ new_net_dict[const.NET_ID], port_id)
2902+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
2903+ LOG.debug("test_show_portDNE - END")
2904+
2905+ def test_plug_interface(self, tenant_id='test_tenant',
2906+ remote_interface='new_interface'):
2907+ """
2908+ Tests attachment of interface to the port
2909+ """
2910+
2911+ LOG.debug("test_plug_interface - START")
2912+ new_net_dict = self._l2network_plugin.create_network(
2913+ tenant_id, self.network_name)
2914+ port_dict = self._l2network_plugin.create_port(
2915+ tenant_id, new_net_dict[const.NET_ID], self.port_state)
2916+ self._l2network_plugin.plug_interface(
2917+ tenant_id, new_net_dict[const.NET_ID],
2918+ port_dict[const.PORT_ID], remote_interface)
2919+ self.assertEqual(
2920+ self._l2network_plugin._networks[new_net_dict[const.NET_ID]]
2921+ [const.NET_PORTS][port_dict[const.PORT_ID]]
2922+ [const.ATTACHMENT], remote_interface)
2923+ self.tearDownNetworkPortInterface(
2924+ tenant_id, new_net_dict[const.NET_ID],
2925+ port_dict[const.PORT_ID])
2926+ LOG.debug("test_plug_interface - END")
2927+
2928+ def test_plug_interface_networkDNE(
2929+ self, tenant_id='test_tenant', net_id='0005',
2930+ port_id='p0005', remote_interface='new_interface'):
2931+ """
2932+ Tests attachment of interface network does not exist
2933+ """
2934+
2935+ LOG.debug("test_plug_interface_networkDNE - START")
2936+ self.assertRaises(exc.NetworkNotFound,
2937+ self._l2network_plugin.plug_interface, tenant_id,
2938+ net_id, port_id, remote_interface)
2939+ LOG.debug("test_plug_interface_networkDNE - END")
2940+
2941+ def test_plug_interface_portDNE(self, tenant_id='test_tenant',
2942+ port_id='p0005',
2943+ remote_interface='new_interface'):
2944+ """
2945+ Tests attachment of interface port does not exist
2946+ """
2947+
2948+ LOG.debug("test_plug_interface_portDNE - START")
2949+ new_net_dict = self._l2network_plugin.create_network(
2950+ tenant_id, self.network_name)
2951+ self.assertRaises(
2952+ exc.PortNotFound, self._l2network_plugin.plug_interface, tenant_id,
2953+ new_net_dict[const.NET_ID], port_id, remote_interface)
2954+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
2955+ LOG.debug("test_plug_interface_portDNE - END")
2956+
2957+ def test_plug_interface_portInUse(self, tenant_id='test_tenant',
2958+ remote_interface='new_interface'):
2959+
2960+ """
2961+ Tests attachment of new interface to the port when there is an
2962+ existing attachment
2963+ """
2964+
2965+ LOG.debug("test_plug_interface_portInUse - START")
2966+ new_net_dict = self._l2network_plugin.create_network(
2967+ tenant_id, self.network_name)
2968+ port_dict = self._l2network_plugin.create_port(
2969+ tenant_id, new_net_dict[const.NET_ID], self.port_state)
2970+ self._l2network_plugin.plug_interface(
2971+ tenant_id, new_net_dict[const.NET_ID],
2972+ port_dict[const.PORT_ID], remote_interface)
2973+ self.assertRaises(exc.AlreadyAttached,
2974+ self._l2network_plugin.plug_interface, tenant_id,
2975+ new_net_dict[const.NET_ID],
2976+ port_dict[const.PORT_ID], remote_interface)
2977+ self.tearDownNetworkPortInterface(
2978+ tenant_id, new_net_dict[const.NET_ID],
2979+ port_dict[const.PORT_ID])
2980+ LOG.debug("test_plug_interface_portInUse - END")
2981+
2982+ def test_unplug_interface(self, tenant_id='test_tenant'):
2983+ """
2984+ Tests detaachment of an interface to a port
2985+ """
2986+
2987+ LOG.debug("test_unplug_interface - START")
2988+ new_net_dict = self._l2network_plugin.create_network(
2989+ tenant_id, self.network_name)
2990+ port_dict = self._l2network_plugin.create_port(
2991+ tenant_id, new_net_dict[const.NET_ID],
2992+ self.port_state)
2993+ self._l2network_plugin.plug_interface(
2994+ tenant_id, new_net_dict[const.NET_ID],
2995+ port_dict[const.PORT_ID], self.remote_interface)
2996+ self._l2network_plugin.unplug_interface(
2997+ tenant_id, new_net_dict[const.NET_ID],
2998+ port_dict[const.PORT_ID])
2999+ self.assertEqual(self._l2network_plugin._networks
3000+ [new_net_dict[const.NET_ID]][const.NET_PORTS]
3001+ [port_dict[const.PORT_ID]][const.ATTACHMENT], None)
3002+ self.tearDownNetworkPort(tenant_id, new_net_dict[const.NET_ID],
3003+ port_dict[const.PORT_ID])
3004+ LOG.debug("test_unplug_interface - END")
3005+
3006+ def test_unplug_interface_networkDNE(self, tenant_id='test_tenant',
3007+ net_id='0005', port_id='p0005'):
3008+ """
3009+ Tests detaachment of an interface to a port, when the network does
3010+ not exist
3011+ """
3012+
3013+ LOG.debug("test_unplug_interface_networkDNE - START")
3014+ self.assertRaises(exc.NetworkNotFound,
3015+ self._l2network_plugin.unplug_interface,
3016+ tenant_id, net_id, port_id)
3017+ LOG.debug("test_unplug_interface_networkDNE - END")
3018+
3019+ def test_unplug_interface_portDNE(self, tenant_id='test_tenant',
3020+ port_id='p0005'):
3021+ """
3022+ Tests detaachment of an interface to a port, when the port does
3023+ not exist
3024+ """
3025+
3026+ LOG.debug("test_unplug_interface_portDNE - START")
3027+ new_net_dict = self._l2network_plugin.create_network(tenant_id,
3028+ self.network_name)
3029+ self.assertRaises(exc.PortNotFound,
3030+ self._l2network_plugin.unplug_interface, tenant_id,
3031+ new_net_dict[const.NET_ID], port_id)
3032+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
3033+ LOG.debug("test_unplug_interface_portDNE - END")
3034+
3035+ def test_create_portprofile(self, net_tenant_id=None,
3036+ net_profile_name=None, net_vlan_id=None):
3037+ """
3038+ Tests creation of a port-profile
3039+ """
3040+
3041+ LOG.debug("test_create_portprofile - tenant id: %s - START",
3042+ net_tenant_id)
3043+ if net_tenant_id:
3044+ tenant_id = net_tenant_id
3045+ else:
3046+ tenant_id = self.tenant_id
3047+ if net_profile_name:
3048+ profile_name = net_profile_name
3049+ else:
3050+ profile_name = self.profile_name
3051+ if net_vlan_id:
3052+ vlan_id = net_vlan_id
3053+ else:
3054+ vlan_id = self.vlan_id
3055+ port_profile_dict = self._l2network_plugin.create_portprofile(
3056+ tenant_id, profile_name, vlan_id)
3057+ port_profile_id = port_profile_dict['profile-id']
3058+ self.assertEqual(
3059+ self._l2network_plugin._portprofiles[port_profile_id]['vlan-id'],
3060+ vlan_id)
3061+ self.assertEqual(
3062+ self._l2network_plugin._portprofiles[port_profile_id]
3063+ ['profile-name'], profile_name)
3064+ self.tearDownPortProfile(tenant_id, port_profile_id)
3065+ LOG.debug("test_create_portprofile - tenant id: %s - END",
3066+ net_tenant_id)
3067+
3068+ def test_delete_portprofile(self, net_tenant_id=None):
3069+ """
3070+ Tests deletion of a port-profile
3071+ """
3072+
3073+ LOG.debug("test_delete_portprofile - tenant id: %s - START",
3074+ net_tenant_id)
3075+ if net_tenant_id:
3076+ tenant_id = net_tenant_id
3077+ else:
3078+ tenant_id = self.tenant_id
3079+ port_profile_dict = self._l2network_plugin.create_portprofile(
3080+ tenant_id, self.profile_name, self.vlan_id)
3081+ port_profile_id = port_profile_dict['profile-id']
3082+ self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id)
3083+ self.assertEqual(self._l2network_plugin._portprofiles, {})
3084+ LOG.debug("test_delete_portprofile - tenant id: %s - END",
3085+ net_tenant_id)
3086+
3087+ def test_delete_portprofileDNE(self, tenant_id='test_tenant',
3088+ profile_id='pr0005'):
3089+ """
3090+ Tests deletion of a port-profile when netowrk does not exist
3091+ """
3092+
3093+ LOG.debug("test_delete_portprofileDNE - START")
3094+ self.assertRaises(cexc.PortProfileNotFound,
3095+ self._l2network_plugin.delete_portprofile,
3096+ tenant_id, profile_id)
3097+ LOG.debug("test_delete_portprofileDNE - END")
3098+
3099+ def test_delete_portprofileAssociated(self, tenant_id='test_tenant'):
3100+
3101+ """
3102+ Tests deletion of an associatedport-profile
3103+ """
3104+
3105+ LOG.debug("test_delete_portprofileAssociated - START")
3106+ port_profile_dict = self._l2network_plugin.create_portprofile(
3107+ tenant_id, self.profile_name, self.vlan_id)
3108+ port_profile_id = port_profile_dict['profile-id']
3109+ self._l2network_plugin.associate_portprofile(
3110+ tenant_id, self.net_id, self.port_id, port_profile_id)
3111+ self.assertRaises(cexc.PortProfileInvalidDelete,
3112+ self._l2network_plugin.delete_portprofile,
3113+ tenant_id, port_profile_id)
3114+ self.tearDownAssociatePortProfile(tenant_id, self.net_id,
3115+ self.port_id, port_profile_id)
3116+ LOG.debug("test_delete_portprofileAssociated - END")
3117+
3118+ def test_list_portprofile(self, tenant_id='test_tenant'):
3119+ """
3120+ Tests listing of port-profiles
3121+ """
3122+
3123+ LOG.debug("test_list_portprofile - tenant id: %s - START", tenant_id)
3124+ profile_name2 = tenant_id + '_port_profile2'
3125+ vlan_id2 = tenant_id + '201'
3126+ port_profile_dict1 = self._l2network_plugin.create_portprofile(
3127+ tenant_id, self.profile_name, self.vlan_id)
3128+ port_profile_dict2 = self._l2network_plugin.create_portprofile(
3129+ tenant_id, profile_name2, vlan_id2)
3130+ port_profile_id1 = port_profile_dict1['profile-id']
3131+ port_profile_id2 = port_profile_dict2['profile-id']
3132+ list_all_portprofiles = self._l2network_plugin.get_all_portprofiles(
3133+ tenant_id)
3134+ self.assertEqual(self._l2network_plugin._portprofiles
3135+ [port_profile_id1]['vlan-id'], self.vlan_id)
3136+ self.assertEqual(self._l2network_plugin._portprofiles
3137+ [port_profile_id1]['profile-name'], self.profile_name)
3138+ self.assertEqual(self._l2network_plugin._portprofiles
3139+ [port_profile_id2]['vlan-id'], vlan_id2)
3140+ self.assertEqual(self._l2network_plugin._portprofiles
3141+ [port_profile_id2]['profile-name'], profile_name2)
3142+ LOG.debug("test_create_portprofile - tenant id: %s - END", tenant_id)
3143+
3144+ def test_show_portprofile(self, net_tenant_id=None):
3145+ """
3146+ Tests display of a port-profile
3147+ """
3148+
3149+ LOG.debug("test_show_portprofile - START")
3150+ if net_tenant_id:
3151+ tenant_id = net_tenant_id
3152+ else:
3153+ tenant_id = self.tenant_id
3154+ port_profile_dict = self._l2network_plugin.create_portprofile(
3155+ tenant_id, self.profile_name, self.vlan_id)
3156+ port_profile_id = port_profile_dict['profile-id']
3157+ result_port_profile = self._l2network_plugin.get_portprofile_details(
3158+ tenant_id, port_profile_id)
3159+ self.assertEqual(result_port_profile[const.PROFILE_VLAN_ID],
3160+ self.vlan_id)
3161+ self.assertEqual(result_port_profile[const.PROFILE_NAME],
3162+ self.profile_name)
3163+ self.tearDownPortProfile(tenant_id, port_profile_id)
3164+ LOG.debug("test_show_portprofile - tenant id: %s - END", net_tenant_id)
3165+
3166+ def test_show_portprofileDNE(self, tenant_id='test_tenant',
3167+ profile_id='pr0005'):
3168+ """
3169+ Tests display of a port-profile when network does not exist
3170+ """
3171+
3172+ LOG.debug("test_show_portprofileDNE - START")
3173+ self.assertRaises(cexc.PortProfileNotFound,
3174+ self._l2network_plugin.get_portprofile_details,
3175+ tenant_id, profile_id)
3176+ LOG.debug("test_show_portprofileDNE - END")
3177+
3178+ def test_rename_portprofile(self, tenant_id='test_tenant',
3179+ new_profile_name='new_profile_name'):
3180+ """
3181+ Tests rename of a port-profile
3182+ """
3183+
3184+ LOG.debug("test_rename_portprofile - START")
3185+ port_profile_dict = self._l2network_plugin.create_portprofile(
3186+ tenant_id, self.profile_name, self.vlan_id)
3187+ port_profile_id = port_profile_dict['profile-id']
3188+ result_port_profile_dict = self._l2network_plugin.rename_portprofile(
3189+ tenant_id, port_profile_id, new_profile_name)
3190+ self.assertEqual(result_port_profile_dict[const.PROFILE_NAME],
3191+ new_profile_name)
3192+ self.tearDownPortProfile(tenant_id, port_profile_id)
3193+ LOG.debug("test_show_portprofile - tenant id: %s - END")
3194+
3195+ def test_rename_portprofileDNE(self, tenant_id='test_tenant',
3196+ profile_id='pr0005',
3197+ new_profile_name='new_profile_name'):
3198+ """
3199+ Tests rename of a port-profile when network does not exist
3200+ """
3201+
3202+ LOG.debug("test_rename_portprofileDNE - START")
3203+ self.assertRaises(cexc.PortProfileNotFound,
3204+ self._l2network_plugin.rename_portprofile,
3205+ tenant_id, profile_id, new_profile_name)
3206+ LOG.debug("test_rename_portprofileDNE - END")
3207+
3208+ def test_associate_portprofile(self, tenant_id='test_tenant',
3209+ net_id='0005', port_id='p00005'):
3210+ """
3211+ Tests association of a port-profile
3212+ """
3213+
3214+ LOG.debug("test_associate_portprofile - START")
3215+ port_profile_dict = self._l2network_plugin.create_portprofile(
3216+ tenant_id, self.profile_name, self.vlan_id)
3217+ port_profile_id = port_profile_dict['profile-id']
3218+ self._l2network_plugin.associate_portprofile(
3219+ tenant_id, net_id, port_id, port_profile_id)
3220+ self.assertEqual(
3221+ self._l2network_plugin._portprofiles[port_profile_id]
3222+ [const.PROFILE_ASSOCIATIONS][0], port_id)
3223+ self.tearDownAssociatePortProfile(tenant_id, net_id,
3224+ port_id, port_profile_id)
3225+ LOG.debug("test_associate_portprofile - END")
3226+
3227+ def test_associate_portprofileDNE(self, tenant_id='test_tenant',
3228+ net_id='0005', port_id='p00005',
3229+ profile_id='pr0005'):
3230+ """
3231+ Tests association of a port-profile when a network does not exist
3232+ """
3233+
3234+ LOG.debug("test_associate_portprofileDNE - START")
3235+ self.assertRaises(cexc.PortProfileNotFound,
3236+ self._l2network_plugin.associate_portprofile,
3237+ tenant_id, net_id, port_id, profile_id)
3238+ LOG.debug("test_associate_portprofileDNE - END")
3239+
3240+ def test_disassociate_portprofile(self, tenant_id='test_tenant',
3241+ net_id='0005', port_id='p00005'):
3242+ """
3243+ Tests disassociation of a port-profile
3244+ """
3245+
3246+ LOG.debug("test_disassociate_portprofile - START")
3247+ port_profile_dict = self._l2network_plugin.create_portprofile(
3248+ tenant_id, self.profile_name, self.vlan_id)
3249+ port_profile_id = port_profile_dict['profile-id']
3250+ self._l2network_plugin.associate_portprofile(tenant_id, net_id,
3251+ port_id, port_profile_id)
3252+ self._l2network_plugin.disassociate_portprofile(
3253+ tenant_id, net_id, port_id, port_profile_id)
3254+ self.assertEqual(self._l2network_plugin._portprofiles
3255+ [port_profile_id][const.PROFILE_ASSOCIATIONS], [])
3256+ self.tearDownPortProfile(tenant_id, port_profile_id)
3257+ LOG.debug("test_disassociate_portprofile - END")
3258+
3259+ def test_disassociate_portprofileDNE(self, tenant_id='test_tenant',
3260+ net_id='0005', port_id='p00005', profile_id='pr0005'):
3261+ """
3262+ Tests disassociation of a port-profile when network does not exist
3263+ """
3264+
3265+ LOG.debug("test_disassociate_portprofileDNE - START")
3266+ self.assertRaises(cexc.PortProfileNotFound,
3267+ self._l2network_plugin.disassociate_portprofile,
3268+ tenant_id, net_id, port_id, profile_id)
3269+ LOG.debug("test_disassociate_portprofileDNE - END")
3270+
3271+# def test_disassociate_portprofile_Unassociated
3272+
3273+ def test_get_tenant(self, net_tenant_id=None):
3274+ """
3275+ Tests get tenant
3276+ """
3277+
3278+ LOG.debug("test_get_tenant - START")
3279+ if net_tenant_id:
3280+ tenant_id = net_tenant_id
3281+ else:
3282+ tenant_id = self.tenant_id
3283+ tenant_dict = self._l2network_plugin._get_tenant(tenant_id)
3284+ self.assertEqual(tenant_dict[const.TENANT_ID], tenant_id)
3285+ self.assertEqual(tenant_dict[const.TENANT_NAME], tenant_id)
3286+ LOG.debug("test_get_tenant - END")
3287+
3288+ def test_get_vlan_name(self, net_tenant_id=None, vlan_name="NewVlan",
3289+ vlan_prefix=conf.VLAN_NAME_PREFIX):
3290+ """
3291+ Tests get vlan name
3292+ """
3293+
3294+ LOG.debug("test_get_vlan_name - START")
3295+ if net_tenant_id:
3296+ tenant_id = net_tenant_id
3297+ else:
3298+ tenant_id = self.tenant_id
3299+ result_vlan_name = self._l2network_plugin._get_vlan_name(tenant_id,
3300+ vlan_name)
3301+ expected_output = vlan_prefix + tenant_id + "-" + vlan_name
3302+ self.assertEqual(result_vlan_name, expected_output)
3303+ LOG.debug("test_get_vlan_name - END")
3304+
3305+ def test_validate_port_state(self, port_state=const.PORT_UP):
3306+ """
3307+ Tests validate port state
3308+ """
3309+
3310+ LOG.debug("test_validate_port_state - START")
3311+ result = self._l2network_plugin._validate_port_state(port_state)
3312+ self.assertEqual(result, True)
3313+ LOG.debug("test_validate_port_state - END")
3314+
3315+ def test_invalid_port_state(self, port_state="BADSTATE"):
3316+ """
3317+ Tests invalidate port state
3318+ """
3319+
3320+ LOG.debug("test_validate_port_state - START")
3321+ self.assertRaises(exc.StateInvalid,
3322+ self._l2network_plugin._validate_port_state,
3323+ port_state)
3324+ LOG.debug("test_validate_port_state - END")
3325+
3326+ def test_validate_attachment(self, net_tenant_id=None,
3327+ remote_interface_id="new_interface"):
3328+ """
3329+ Tests validate attachment
3330+ """
3331+
3332+ LOG.debug("test_validate_attachment - START")
3333+ if net_tenant_id:
3334+ tenant_id = net_tenant_id
3335+ else:
3336+ tenant_id = self.tenant_id
3337+ net_name = self.network_name
3338+ new_network_dict = self._l2network_plugin.create_network(tenant_id,
3339+ net_name)
3340+ network_id = new_network_dict[const.NET_ID]
3341+ new_port_dict = self._l2network_plugin.create_port(tenant_id,
3342+ network_id)
3343+ port_id = new_port_dict[const.PORT_ID]
3344+ self._l2network_plugin.plug_interface(
3345+ tenant_id, new_network_dict[const.NET_ID], port_id,
3346+ remote_interface_id)
3347+ self.assertRaises(exc.AlreadyAttached,
3348+ self._l2network_plugin._validate_attachment,
3349+ tenant_id, network_id, port_id, remote_interface_id)
3350+ self.tearDownNetworkPortInterface(
3351+ tenant_id, new_network_dict[const.NET_ID], port_id)
3352+ LOG.debug("test_validate_attachment - END")
3353+
3354+ def setUp(self):
3355+ self.tenant_id = "test_tenant"
3356+ self.network_name = "test_network"
3357+ self.profile_name = "test_tenant_port_profile"
3358+ self.vlan_id = "test_tenant_vlanid300"
3359+ self.port_state = const.PORT_UP
3360+ self.net_id = '00005'
3361+ self.port_id = 'p0005'
3362+ self.remote_interface = 'new_interface'
3363+ self._l2network_plugin = l2network_plugin.L2Network()
3364+
3365+ """
3366+ Clean up functions after the tests
3367+ """
3368+
3369+ def tearDownNetwork(self, tenant_id, network_dict_id):
3370+ self._l2network_plugin.delete_network(tenant_id, network_dict_id)
3371+
3372+ def tearDownPortOnly(self, tenant_id, network_dict_id, port_id):
3373+ self._l2network_plugin.delete_port(tenant_id, network_dict_id, port_id)
3374+
3375+ def tearDownNetworkPort(self, tenant_id, network_dict_id, port_id):
3376+ self._l2network_plugin.delete_port(tenant_id, network_dict_id, port_id)
3377+ self.tearDownNetwork(tenant_id, network_dict_id)
3378+
3379+ def tearDownNetworkPortInterface(self, tenant_id, network_dict_id,
3380+ port_id):
3381+ self._l2network_plugin.unplug_interface(tenant_id,
3382+ network_dict_id, port_id)
3383+ self.tearDownNetworkPort(tenant_id, network_dict_id, port_id)
3384+
3385+ def tearDownPortProfile(self, tenant_id, port_profile_id):
3386+ self._l2network_plugin.delete_portprofile(tenant_id, port_profile_id)
3387+
3388+ def tearDownAssociatePortProfile(self, tenant_id, net_id, port_id,
3389+ port_profile_id):
3390+ self._l2network_plugin.disassociate_portprofile(
3391+ tenant_id, net_id, port_id, port_profile_id)
3392+ self.tearDownPortProfile(tenant_id, port_profile_id)
3393
3394=== added file 'quantum/plugins/cisco/tests/unit/test_nexus_plugin.py'
3395--- quantum/plugins/cisco/tests/unit/test_nexus_plugin.py 1970-01-01 00:00:00 +0000
3396+++ quantum/plugins/cisco/tests/unit/test_nexus_plugin.py 2011-08-15 17:33:23 +0000
3397@@ -0,0 +1,282 @@
3398+# copyright 2011 Cisco Systems, Inc. All rights reserved.
3399+#
3400+# Licensed under the Apache License, Version 2.0 (the "License"); you may
3401+# not use this file except in compliance with the License. You may obtain
3402+# a copy of the License at
3403+#
3404+# http://www.apache.org/licenses/LICENSE-2.0
3405+#
3406+# Unless required by applicable law or agreed to in writing, software
3407+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
3408+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3409+# License for the specific language governing permissions and limitations
3410+# under the License.
3411+#
3412+# @author: Shweta Padubidri, Peter Strunk, Cisco Systems, Inc.
3413+#
3414+import unittest
3415+import logging
3416+from quantum.common import exceptions as exc
3417+from quantum.plugins.cisco.common import cisco_constants as const
3418+from quantum.plugins.cisco.nexus import cisco_nexus_plugin
3419+
3420+LOG = logging.getLogger('quantum.tests.test_nexus')
3421+
3422+
3423+class TestNexusPlugin(unittest.TestCase):
3424+
3425+ def setUp(self):
3426+
3427+ self.tenant_id = "test_tenant_cisco1"
3428+ self.net_name = "test_network_cisco1"
3429+ self.net_id = 000007
3430+ self.vlan_name = "q-" + str(self.net_id) + "vlan"
3431+ self.vlan_id = 267
3432+ self.port_id = "9"
3433+ self._cisco_nexus_plugin = cisco_nexus_plugin.NexusPlugin()
3434+
3435+ def test_create_network(self, net_tenant_id=None, network_name=None,
3436+ network_id=None, net_vlan_name=None,
3437+ net_vlan_id=None):
3438+ """
3439+ Tests creation of new Virtual Network.
3440+ """
3441+
3442+ LOG.debug("test_create_network - START")
3443+ if net_tenant_id:
3444+ tenant_id = net_tenant_id
3445+ else:
3446+ tenant_id = self.tenant_id
3447+ if network_name:
3448+ net_name = network_name
3449+ else:
3450+ net_name = self.net_name
3451+ if network_id:
3452+ net_id = network_id
3453+ else:
3454+ net_id = self.net_id
3455+ if net_vlan_name:
3456+ vlan_name = net_vlan_name
3457+ else:
3458+ vlan_name = self.vlan_name
3459+ if net_vlan_id:
3460+ vlan_id = net_vlan_id
3461+ else:
3462+ vlan_id = self.vlan_id
3463+
3464+ new_net_dict = self._cisco_nexus_plugin.create_network(
3465+ tenant_id, net_name, net_id, vlan_name, vlan_id)
3466+
3467+ self.assertEqual(new_net_dict[const.NET_ID], self.net_id)
3468+ self.assertEqual(new_net_dict[const.NET_NAME], self.net_name)
3469+ self.assertEqual(new_net_dict[const.NET_VLAN_NAME], self.vlan_name)
3470+ self.assertEqual(new_net_dict[const.NET_VLAN_ID], self.vlan_id)
3471+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
3472+ LOG.debug("test_create_network - END")
3473+
3474+ def test_delete_network(self, net_tenant_id=None, network_id=None):
3475+ """
3476+ Tests deletion of a Virtual Network.
3477+ """
3478+
3479+ LOG.debug("test_delete_network - START")
3480+
3481+ if net_tenant_id:
3482+ tenant_id = net_tenant_id
3483+ else:
3484+ tenant_id = self.tenant_id
3485+ if network_id:
3486+ net_id = network_id
3487+ else:
3488+ net_id = self.net_id
3489+
3490+ new_net_dict = self._cisco_nexus_plugin.create_network(
3491+ tenant_id, self.net_name, net_id, self.vlan_name, self.vlan_id)
3492+ deleted_net_dict = self._cisco_nexus_plugin.delete_network(
3493+ tenant_id, new_net_dict[const.NET_ID])
3494+ self.assertEqual(deleted_net_dict[const.NET_ID], net_id)
3495+ LOG.debug("test_delete_network - END")
3496+
3497+ def test_delete_network_DNE(self, net_tenant_id=None, net_id='0005'):
3498+ """
3499+ Tests deletion of a Virtual Network when Network does not exist.
3500+ """
3501+
3502+ LOG.debug("test_delete_network_DNE - START")
3503+
3504+ if net_tenant_id:
3505+ tenant_id = net_tenant_id
3506+ else:
3507+ tenant_id = self.tenant_id
3508+
3509+ self.assertRaises(exc.NetworkNotFound,
3510+ self._cisco_nexus_plugin.delete_network,
3511+ tenant_id, net_id)
3512+
3513+ LOG.debug("test_delete_network_DNE - END")
3514+
3515+ def test_get_network_details(self, net_tenant_id=None, network_id=None):
3516+ """
3517+ Tests displays details of a Virtual Network .
3518+ """
3519+
3520+ LOG.debug("test_get_network_details - START")
3521+
3522+ if net_tenant_id:
3523+ tenant_id = net_tenant_id
3524+ else:
3525+ tenant_id = self.tenant_id
3526+ if network_id:
3527+ net_id = network_id
3528+ else:
3529+ net_id = self.net_id
3530+
3531+ new_net_dict = self._cisco_nexus_plugin.create_network(
3532+ tenant_id, self.net_name, net_id, self.vlan_name, self.vlan_id)
3533+ check_net_dict = self._cisco_nexus_plugin.get_network_details(
3534+ tenant_id, net_id)
3535+
3536+ self.assertEqual(check_net_dict[const.NET_ID], net_id)
3537+ self.assertEqual(check_net_dict[const.NET_NAME], self.net_name)
3538+ self.assertEqual(check_net_dict[const.NET_VLAN_NAME], self.vlan_name)
3539+ self.assertEqual(check_net_dict[const.NET_VLAN_ID], self.vlan_id)
3540+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
3541+ LOG.debug("test_get_network_details - END")
3542+
3543+ def test_get_networkDNE(self, net_tenant_id=None, net_id='0005'):
3544+ """
3545+ Tests display of a Virtual Network when Network does not exist.
3546+ """
3547+
3548+ LOG.debug("test_get_network_details_network_does_not_exist - START")
3549+
3550+ if net_tenant_id:
3551+ tenant_id = net_tenant_id
3552+ else:
3553+ tenant_id = self.tenant_id
3554+
3555+ self.assertRaises(exc.NetworkNotFound,
3556+ self._cisco_nexus_plugin.get_network_details,
3557+ tenant_id, net_id)
3558+
3559+ LOG.debug("test_get_network_details_network_does_not_exist - END")
3560+
3561+ def test_rename_network(self, new_name="new_network_name",
3562+ net_tenant_id=None, network_id=None):
3563+ """
3564+ Tests rename of a Virtual Network .
3565+ """
3566+
3567+ LOG.debug("test_rename_network - START")
3568+
3569+ if net_tenant_id:
3570+ tenant_id = net_tenant_id
3571+ else:
3572+ tenant_id = self.tenant_id
3573+ if network_id:
3574+ net_id = network_id
3575+ else:
3576+ net_id = self.net_id
3577+
3578+ new_net_dict = self._cisco_nexus_plugin.create_network(
3579+ tenant_id, self.net_name, net_id, self.vlan_name,
3580+ self.vlan_id)
3581+ rename_net_dict = self._cisco_nexus_plugin.rename_network(
3582+ tenant_id, new_net_dict[const.NET_ID], new_name)
3583+ self.assertEqual(rename_net_dict[const.NET_NAME], new_name)
3584+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
3585+ LOG.debug("test_rename_network - END")
3586+
3587+ def test_rename_network_DNE(self, new_name="new_network_name",
3588+ net_tenant_id=None, network_id='0005'):
3589+ """
3590+ Tests rename of a Virtual Network when Network does not exist.
3591+ """
3592+
3593+ LOG.debug("test_rename_network_DNE - START")
3594+
3595+ if net_tenant_id:
3596+ tenant_id = net_tenant_id
3597+ else:
3598+ tenant_id = self.tenant_id
3599+ if network_id:
3600+ net_id = network_id
3601+ else:
3602+ net_id = self.net_id
3603+
3604+ self.assertRaises(exc.NetworkNotFound,
3605+ self._cisco_nexus_plugin.rename_network,
3606+ new_name, tenant_id, net_id)
3607+
3608+ LOG.debug("test_rename_network_DNE - END")
3609+
3610+ def test_list_all_networks(self, net_tenant_id=None):
3611+ """
3612+ Tests listing of all the Virtual Networks .
3613+ """
3614+
3615+ LOG.debug("test_list_all_networks - START")
3616+ if net_tenant_id:
3617+ tenant_id = net_tenant_id
3618+ else:
3619+ tenant_id = self.tenant_id
3620+ new_net_dict1 = self._cisco_nexus_plugin.create_network(
3621+ tenant_id, self.net_name, self.net_id,
3622+ self.vlan_name, self.vlan_id)
3623+ new_net_dict2 = self._cisco_nexus_plugin.create_network(
3624+ tenant_id, "New_Network2", "0011",
3625+ "second_vlan", "2003")
3626+ list_net_dict = self._cisco_nexus_plugin.get_all_networks(tenant_id)
3627+ net_temp_list = [new_net_dict1, new_net_dict2]
3628+ self.assertEqual(len(list_net_dict), 2)
3629+ self.assertTrue(list_net_dict[0] in net_temp_list)
3630+ self.assertTrue(list_net_dict[1] in net_temp_list)
3631+ self.tearDownNetwork(tenant_id, new_net_dict1[const.NET_ID])
3632+ self.tearDownNetwork(tenant_id, new_net_dict2[const.NET_ID])
3633+ LOG.debug("test_list_all_networks - END")
3634+
3635+ def test_get_vlan_id_for_network(self, net_tenant_id=None,
3636+ network_id=None):
3637+ """
3638+ Tests retrieval of vlan id for a Virtual Networks .
3639+ """
3640+
3641+ LOG.debug("test_get_vlan_id_for_network - START")
3642+ if net_tenant_id:
3643+ tenant_id = net_tenant_id
3644+ else:
3645+ tenant_id = self.tenant_id
3646+ if network_id:
3647+ net_id = network_id
3648+ else:
3649+ net_id = self.net_id
3650+ new_net_dict = self._cisco_nexus_plugin.create_network(
3651+ tenant_id, self.net_name, net_id, self.vlan_name,
3652+ self.vlan_id)
3653+ result_vlan_id = self._cisco_nexus_plugin._get_vlan_id_for_network(
3654+ tenant_id, net_id)
3655+ self.assertEqual(result_vlan_id, self.vlan_id)
3656+ self.tearDownNetwork(tenant_id, new_net_dict[const.NET_ID])
3657+ LOG.debug("test_get_vlan_id_for_network - END")
3658+
3659+ """
3660+ Clean up functions after the tests
3661+ """
3662+
3663+ def tearDownNetwork(self, tenant_id, network_dict_id):
3664+ self._cisco_nexus_plugin.delete_network(tenant_id, network_dict_id)
3665+
3666+# def test_create_network(self):
3667+# _test_create_network(self._cisco_nexus_plugin)
3668+
3669+# def test_delete_network(self):
3670+# _test_delete_network(self._cisco_nexus_plugin)
3671+
3672+# def test_rename_network(self):
3673+# _test_rename_network(self._cisco_nexus_plugin)
3674+
3675+# def test_show_network(self):
3676+# _test_get_network_details(self._cisco_nexus_plugin)
3677+
3678+# def test_list_networks(self):
3679+# _test_list_all_networks(self._cisco_nexus_plugin)
3680
3681=== added file 'quantum/plugins/cisco/tests/unit/test_ucs_driver.py'
3682--- quantum/plugins/cisco/tests/unit/test_ucs_driver.py 1970-01-01 00:00:00 +0000
3683+++ quantum/plugins/cisco/tests/unit/test_ucs_driver.py 2011-08-15 17:33:23 +0000
3684@@ -0,0 +1,165 @@
3685+# vim: tabstop=4 shiftwidth=4 softtabstop=4
3686+#
3687+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
3688+#
3689+# Licensed under the Apache License, Version 2.0 (the "License"); you may
3690+# not use this file except in compliance with the License. You may obtain
3691+# a copy of the License at
3692+#
3693+# http://www.apache.org/licenses/LICENSE-2.0
3694+#
3695+# Unless required by applicable law or agreed to in writing, software
3696+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
3697+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3698+# License for the specific language governing permissions and limitations
3699+# under the License.
3700+#
3701+# @author: Shweta Padubidri, Cisco Systems, Inc.
3702+#
3703+
3704+import logging
3705+import unittest
3706+
3707+from quantum.plugins.cisco.ucs import cisco_ucs_network_driver
3708+
3709+LOG = logging.getLogger('quantum.tests.test_ucs_driver')
3710+
3711+create_vlan_output = "<configConfMos cookie=\"cookie_placeholder\" "\
3712+"inHierarchical=\"true\"> <inConfigs><pair key=\"fabric/lan/net-New Vlan\"> "\
3713+"<fabricVlan defaultNet=\"no\" dn=\"fabric/lan/net-New Vlan\" id=\"200\" "\
3714+"name=\"New Vlan\" status=\"created\"></fabricVlan> </pair> </inConfigs> "\
3715+"</configConfMos>"
3716+
3717+create_profile_output = "<configConfMos cookie=\"cookie_placeholder\" "\
3718+"inHierarchical=\"true\"> <inConfigs><pair key=\"fabric/lan/profiles/vnic-"\
3719+"New Profile\"> <vnicProfile descr=\"Profile created by Cisco OpenStack "\
3720+"Quantum Plugin\" dn=\"fabric/lan/profiles/vnic-New Profile\" maxPorts="\
3721+"\"64\" name=\"New Profile\" nwCtrlPolicyName=\"\" pinToGroupName=\"\" "\
3722+"qosPolicyName=\"\" status=\"created\"> <vnicEtherIf defaultNet=\"yes\" "\
3723+"name=\"New Vlan\" rn=\"if-New Vlan\" > </vnicEtherIf> </vnicProfile> "\
3724+"</pair> </inConfigs> </configConfMos>"
3725+
3726+change_vlan_output = "<configConfMos cookie=\"cookie_placeholder\" "\
3727+"inHierarchical=\"true\"> <inConfigs><pair key=\""\
3728+"fabric/lan/profiles/vnic-New Profile\"> <vnicProfile descr=\"Profile "\
3729+"created by Cisco OpenStack Quantum Plugin\" "\
3730+"dn=\"fabric/lan/profiles/vnic-New Profile\" maxPorts=\"64\" "\
3731+"name=\"New Profile\" nwCtrlPolicyName=\"\" pinToGroupName=\"\" "\
3732+"qosPolicyName=\"\" status=\"created,modified\"><vnicEtherIf "\
3733+"rn=\"if-Old Vlan\" status=\"deleted\"> </vnicEtherIf> "\
3734+"<vnicEtherIf defaultNet=\"yes\" name=\"New Vlan\" rn=\"if-New Vlan\" > "\
3735+"</vnicEtherIf> </vnicProfile> </pair></inConfigs> </configConfMos>"
3736+
3737+delete_vlan_output = "<configConfMos cookie=\"cookie_placeholder\" "\
3738+"inHierarchical=\"true\"> <inConfigs><pair key=\"fabric/lan/net-New Vlan\"> "\
3739+"<fabricVlan dn=\"fabric/lan/net-New Vlan\" status=\"deleted\"> "\
3740+"</fabricVlan> </pair> </inConfigs></configConfMos>"
3741+
3742+delete_profile_output = "<configConfMos cookie=\"cookie_placeholder\" "\
3743+"inHierarchical=\"false\"> <inConfigs><pair key=\""\
3744+"fabric/lan/profiles/vnic-New Profile\"> <vnicProfile "\
3745+"dn=\"fabric/lan/profiles/vnic-New Profile\" status=\"deleted\"> "\
3746+"</vnicProfile></pair> </inConfigs> </configConfMos>"
3747+
3748+associate_profile_output = "<configConfMos cookie=\"cookie_placeholder\" "\
3749+"inHierarchical=\"true\"> <inConfigs> <pair key="\
3750+"\"fabric/lan/profiles/vnic-New Profile/cl-New Profile Client\">"\
3751+" <vmVnicProfCl dcName=\".*\" descr=\"\" dn=\"fabric/lan/profiles/vnic-"\
3752+"New Profile/cl-New Profile Client\"name=\"New Profile Client\" "\
3753+"orgPath=\".*\" status=\"created\" swName=\"default$\"> </vmVnicProfCl>" \
3754+"</pair> </inConfigs> </configConfMos>"
3755+
3756+
3757+class TestUCSDriver(unittest.TestCase):
3758+
3759+ def setUp(self):
3760+ self._ucsmDriver = cisco_ucs_network_driver.CiscoUCSMDriver()
3761+ self.vlan_name = 'New Vlan'
3762+ self.vlan_id = '200'
3763+ self.profile_name = 'New Profile'
3764+ self.old_vlan_name = 'Old Vlan'
3765+ self.profile_client_name = 'New Profile Client'
3766+
3767+ def test_create_vlan_post_data(self, expected_output=create_vlan_output):
3768+ """
3769+ Tests creation of vlan post Data
3770+ """
3771+
3772+ LOG.debug("test_create_vlan")
3773+ vlan_details = self._ucsmDriver._create_vlan_post_data(
3774+ self.vlan_name, self.vlan_id)
3775+ self.assertEqual(vlan_details, expected_output)
3776+ LOG.debug("test_create_vlan - END")
3777+
3778+ def test_create_profile_post_data(
3779+ self, expected_output=create_profile_output):
3780+ """
3781+ Tests creation of profile post Data
3782+ """
3783+
3784+ LOG.debug("test_create_profile_post_data - START")
3785+ profile_details = self._ucsmDriver._create_profile_post_data(
3786+ self.profile_name, self.vlan_name)
3787+ self.assertEqual(profile_details, expected_output)
3788+ LOG.debug("test_create_profile_post - END")
3789+
3790+ def test_change_vlan_in_profile_post_data(
3791+ self, expected_output=change_vlan_output):
3792+ """
3793+ Tests creation of change vlan in profile post Data
3794+ """
3795+
3796+ LOG.debug("test_create_profile_post_data - START")
3797+ profile_details = self._ucsmDriver._change_vlan_in_profile_post_data(
3798+ self.profile_name, self.old_vlan_name, self.vlan_name)
3799+ self.assertEqual(profile_details, expected_output)
3800+ LOG.debug("test_create_profile_post - END")
3801+
3802+ def test_delete_vlan_post_data(self, expected_output=delete_vlan_output):
3803+ LOG.debug("test_create_profile_post_data - START")
3804+ """
3805+ Tests deletion of vlan post Data
3806+ """
3807+
3808+ vlan_details = self._ucsmDriver._create_vlan_post_data(
3809+ self.vlan_name, self.vlan_id)
3810+ vlan_delete_details = self._ucsmDriver._delete_vlan_post_data(
3811+ self.vlan_name)
3812+ self.assertEqual(vlan_delete_details, expected_output)
3813+ LOG.debug("test_create_profile_post - END")
3814+
3815+ def test_delete_profile_post_data(
3816+ self, expected_output=delete_profile_output):
3817+ """
3818+ Tests deletion of profile post Data
3819+ """
3820+
3821+ LOG.debug("test_create_profile_post_data - START")
3822+ profile_details = self._ucsmDriver._create_profile_post_data(
3823+ self.profile_name, self.vlan_name)
3824+ profile_delete_details = self._ucsmDriver._delete_profile_post_data(
3825+ self.profile_name)
3826+ self.assertEqual(profile_delete_details, expected_output)
3827+ LOG.debug("test_create_profile_post - END")
3828+
3829+ def test_create_profile_client_post_data(
3830+ self, expected_output=associate_profile_output):
3831+ """
3832+ Tests creation of profile client post Data
3833+ """
3834+
3835+ LOG.debug("test_create_profile_client_post_data - START")
3836+ profile_details = self._ucsmDriver._create_profile_client_post_data(
3837+ self.profile_name, self.profile_client_name)
3838+ self.assertEqual(profile_details, expected_output)
3839+ LOG.debug("test_create_profile_post - END")
3840+
3841+ def test_get_next_dynamic_nic(self):
3842+ """
3843+ Tests get next dynamic nic
3844+ """
3845+
3846+ LOG.debug("test_get_next_dynamic_nic - START")
3847+ dynamic_nic_id = self._ucsmDriver._get_next_dynamic_nic()
3848+ self.assertTrue(len(dynamic_nic_id) > 0)
3849+ LOG.debug("test_get_next_dynamic_nic - END")
3850
3851=== added file 'quantum/plugins/cisco/tests/unit/test_ucs_plugin.py'
3852--- quantum/plugins/cisco/tests/unit/test_ucs_plugin.py 1970-01-01 00:00:00 +0000
3853+++ quantum/plugins/cisco/tests/unit/test_ucs_plugin.py 2011-08-15 17:33:23 +0000
3854@@ -0,0 +1,480 @@
3855+#vim: tabstop=4 shiftwidth=4 softtabstop=4
3856+#copyright 2011 Cisco Systems, Inc. All rights reserved.
3857+#
3858+# Licensed under the Apache License, Version 2.0(the "License"); you may
3859+# not use this file except in compliance with the License. You may obtain
3860+# a copy of the License at
3861+#
3862+# http://www.apache.org/licenses/LICENSE-2.0
3863+#
3864+# Unless required by applicable law or agreed to in writing, software
3865+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
3866+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
3867+# License for the specific language governing permissions and limitations
3868+# under the License.
3869+#
3870+# @author: Shubhangi Satras, Cisco Systems, Inc.
3871+#
3872+import unittest
3873+import logging as LOG
3874+from quantum.common import exceptions as exc
3875+from quantum.plugins.cisco.common import cisco_constants as const
3876+from quantum.plugins.cisco.ucs import cisco_ucs_plugin
3877+from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf
3878+
3879+LOG.basicConfig(level=LOG.WARN)
3880+LOG.getLogger("cisco_plugin")
3881+
3882+
3883+class UCSVICTestPlugin(unittest.TestCase):
3884+
3885+ def setUp(self):
3886+
3887+ self.tenant_id = "test_tenant_cisco12"
3888+ self.net_name = "test_network_cisco12"
3889+ self.net_id = 000007
3890+ self.vlan_name = "q-" + str(self.net_id) + "vlan"
3891+ self.vlan_id = 266
3892+ self.port_id = "4"
3893+ self._cisco_ucs_plugin = cisco_ucs_plugin.UCSVICPlugin()
3894+
3895+ def test_create_network(self):
3896+ """
3897+ Tests creation of new Virtual Network.
3898+ """
3899+ LOG.debug("UCSVICTestPlugin:_test_create_network() called\n")
3900+ new_net_dict = self._cisco_ucs_plugin.create_network(
3901+ self.tenant_id, self.net_name, self.net_id,
3902+ self.vlan_name, self.vlan_id)
3903+ self.assertEqual(new_net_dict[const.NET_ID], self.net_id)
3904+ self.assertEqual(new_net_dict[const.NET_NAME], self.net_name)
3905+ self.assertEqual(new_net_dict[const.NET_VLAN_NAME], self.vlan_name)
3906+ self.assertEqual(new_net_dict[const.NET_VLAN_ID], self.vlan_id)
3907+ self.tearDownNetwork(self.tenant_id, self.net_id)
3908+
3909+ def test_delete_network(self):
3910+ """
3911+ Tests deletion of the network with the specified network identifier
3912+ belonging to the specified tenant.
3913+ """
3914+ LOG.debug("UCSVICTestPlugin:test_delete_network() called\n")
3915+ self._cisco_ucs_plugin.create_network(
3916+ self.tenant_id, self.net_name, self.net_id,
3917+ self.vlan_name, self.vlan_id)
3918+ new_net_dict = self._cisco_ucs_plugin.delete_network(
3919+ self.tenant_id, self.net_id)
3920+ self.assertEqual(new_net_dict[const.NET_ID], self.net_id)
3921+
3922+ def test_get_network_details(self):
3923+ """
3924+ Tests the deletion the Virtual Network belonging to a the
3925+ spec
3926+ """
3927+ LOG.debug("UCSVICTestPlugin:test_get_network_details() called\n")
3928+ self._cisco_ucs_plugin.create_network(
3929+ self.tenant_id, self.net_name, self.net_id,
3930+ self.vlan_name, self.vlan_id)
3931+ new_net_dict = self._cisco_ucs_plugin.get_network_details(
3932+ self.tenant_id, self.net_id)
3933+ self.assertEqual(new_net_dict[const.NET_ID], self.net_id)
3934+ self.assertEqual(new_net_dict[const.NET_VLAN_NAME], self.vlan_name)
3935+ self.assertEqual(new_net_dict[const.NET_VLAN_ID], self.vlan_id)
3936+ self.tearDownNetwork(self.tenant_id, self.net_id)
3937+
3938+ def test_get_all_networks(self):
3939+ """
3940+ Tests whether dictionary is returned containing all
3941+ <network_uuid, network_name> for
3942+ the specified tenant.
3943+ """
3944+ LOG.debug("UCSVICTestPlugin:test_get_all_networks() called\n")
3945+ new_net_dict1 = self._cisco_ucs_plugin.create_network(
3946+ self.tenant_id, self.net_name, self.net_id,
3947+ self.vlan_name, self.vlan_id)
3948+ new_net_dict2 = self._cisco_ucs_plugin.create_network(
3949+ self.tenant_id, "test_network2",
3950+ 000006, "q-000006vlan", "6")
3951+ net_list = self._cisco_ucs_plugin.get_all_networks(self.tenant_id)
3952+ net_id_list = [new_net_dict1, new_net_dict2]
3953+ self.assertTrue(net_list[0] in net_id_list)
3954+ self.assertTrue(net_list[1] in net_id_list)
3955+ self.tearDownNetwork(self.tenant_id, new_net_dict1[const.NET_ID])
3956+ self.tearDownNetwork(self.tenant_id, new_net_dict2[const.NET_ID])
3957+
3958+ def test_get_all_ports(self):
3959+ """
3960+ Retrieves all port identifiers belonging to the
3961+ specified Virtual Network.
3962+ """
3963+ LOG.debug("UCSVICPlugin:get_all_ports() called\n")
3964+ new_net_dict = self._cisco_ucs_plugin.create_network(
3965+ self.tenant_id, self.net_name, self.net_id,
3966+ self.vlan_name, self.vlan_id)
3967+ port_dict1 = self._cisco_ucs_plugin.create_port(
3968+ self.tenant_id, self.net_id, const.PORT_UP,
3969+ self.port_id)
3970+ port_dict2 = self._cisco_ucs_plugin.create_port(
3971+ self.tenant_id, self.net_id,
3972+ const.PORT_UP, "10")
3973+ ports_on_net = self._cisco_ucs_plugin.get_all_ports(
3974+ self.tenant_id, self.net_id)
3975+ port_list = [port_dict1, port_dict2]
3976+ self.assertTrue(port_list[0] in ports_on_net)
3977+ self.assertTrue(port_list[1] in ports_on_net)
3978+ self._cisco_ucs_plugin.delete_port(self.tenant_id, self.net_id,
3979+ self.port_id)
3980+ self.tearDownNetworkPort(self.tenant_id, new_net_dict[const.NET_ID],
3981+ port_dict2[const.PORT_ID])
3982+
3983+ def _test_rename_network(self, new_name):
3984+ """
3985+ Tests whether symbolic name is updated for the particular
3986+ Virtual Network.
3987+ """
3988+ LOG.debug("UCSVICTestPlugin:_test_rename_network() called\n")
3989+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
3990+ self.net_id, self.vlan_name,
3991+ self.vlan_id)
3992+ new_net_dict = self._cisco_ucs_plugin.rename_network(
3993+ self.tenant_id, self.net_id, new_name)
3994+ self.assertEqual(new_net_dict[const.NET_NAME], new_name)
3995+ self.tearDownNetwork(self.tenant_id, self.net_id)
3996+
3997+ def test_rename_network(self):
3998+ self._test_rename_network("new_test_network1")
3999+
4000+ def _test_create_port(self, port_state):
4001+ """
4002+ Tests creation of a port on the specified Virtual Network.
4003+ """
4004+ LOG.debug("UCSVICTestPlugin:_test_create_port() called\n")
4005+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4006+ self.net_id, self.vlan_name,
4007+ self.vlan_id)
4008+ new_port_dict = self._cisco_ucs_plugin.create_port(
4009+ self.tenant_id, self.net_id, port_state, self.port_id)
4010+ self.assertEqual(new_port_dict[const.PORT_ID], self.port_id)
4011+ self.assertEqual(new_port_dict[const.PORT_STATE], port_state)
4012+ self.assertEqual(new_port_dict[const.ATTACHMENT], None)
4013+ profile_name = self._cisco_ucs_plugin._get_profile_name(self.port_id)
4014+ new_port_profile = new_port_dict[const.PORT_PROFILE]
4015+ self.assertEqual(new_port_profile[const.PROFILE_NAME], profile_name)
4016+ self.assertEqual(new_port_profile[const.PROFILE_VLAN_NAME],
4017+ conf.DEFAULT_VLAN_NAME)
4018+ self.assertEqual(new_port_profile[const.PROFILE_VLAN_ID],
4019+ conf.DEFAULT_VLAN_ID)
4020+ self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
4021+
4022+ def test_create_port(self):
4023+ self._test_create_port(const.PORT_UP)
4024+
4025+ def _test_delete_port(self, port_state):
4026+ """
4027+ Tests Deletion of a port on a specified Virtual Network,
4028+ if the port contains a remote interface attachment,
4029+ the remote interface should first be un-plugged and
4030+ then the port can be deleted.
4031+ """
4032+ LOG.debug("UCSVICTestPlugin:_test_delete_port() called\n")
4033+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4034+ self.net_id, self.vlan_name,
4035+ self.vlan_id)
4036+ self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id,
4037+ port_state, self.port_id)
4038+ self._cisco_ucs_plugin.delete_port(self.tenant_id, self.net_id,
4039+ self.port_id)
4040+ net = self._cisco_ucs_plugin._get_network(self.tenant_id, self.net_id)
4041+ self.assertEqual(net[const.NET_PORTS], {})
4042+ self.tearDownNetwork(self.tenant_id, self.net_id)
4043+
4044+ def test_delete_port(self):
4045+ self._test_delete_port(const.PORT_UP)
4046+
4047+ def _test_update_port(self, port_state):
4048+ """
4049+ Tests Updation of the state of a port on the specified Virtual Network.
4050+ """
4051+ LOG.debug("UCSVICTestPlugin:_test_update_port() called\n")
4052+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4053+ self.net_id, self.vlan_name,
4054+ self.vlan_id)
4055+ self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id,
4056+ port_state, self.port_id)
4057+ port = self._cisco_ucs_plugin.update_port(
4058+ self.tenant_id, self.net_id,
4059+ self.port_id, port_state)
4060+ self.assertEqual(port[const.PORT_STATE], port_state)
4061+ self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
4062+
4063+ def test_update_port_state_up(self):
4064+ self._test_update_port(const.PORT_UP)
4065+
4066+ def test_update_port_state_down(self):
4067+ self._test_update_port(const.PORT_DOWN)
4068+
4069+ def _test_get_port_details_state_up(self, port_state):
4070+ """
4071+ Tests whether user is able to retrieve a remote interface
4072+ that is attached to this particular port when port state is Up.
4073+ """
4074+ LOG.debug("UCSVICTestPlugin:_test_get_port_details_state_up()" +
4075+ "called\n")
4076+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4077+ self.net_id, self.vlan_name,
4078+ self.vlan_id)
4079+ self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id,
4080+ port_state, self.port_id)
4081+ port = self._cisco_ucs_plugin.get_port_details(
4082+ self.tenant_id, self.net_id, self.port_id)
4083+ self.assertEqual(port[const.PORT_ID], self.port_id)
4084+ self.assertEqual(port[const.PORT_STATE], port_state)
4085+ self.assertEqual(port[const.ATTACHMENT], None)
4086+ new_port_profile = port[const.PORT_PROFILE]
4087+ profile_name = self._cisco_ucs_plugin._get_profile_name(self.port_id)
4088+ self.assertEqual(new_port_profile[const.PROFILE_VLAN_NAME],
4089+ conf.DEFAULT_VLAN_NAME)
4090+ self.assertEqual(new_port_profile[const.PROFILE_VLAN_ID],
4091+ conf.DEFAULT_VLAN_ID)
4092+ self.assertEqual(new_port_profile[const.PROFILE_NAME], profile_name)
4093+ self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
4094+
4095+ def _test_get_port_details_state_down(self, port_state):
4096+ """
4097+ Tests whether user is able to retrieve a remote interface
4098+ that is attached to this particular port when port state is down.
4099+ """
4100+ LOG.debug("UCSVICTestPlugin:_test_get_port_details_state_down()" +
4101+ "called\n")
4102+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4103+ self.net_id, self.vlan_name,
4104+ self.vlan_id)
4105+ self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id,
4106+ port_state, self.port_id)
4107+ port = self._cisco_ucs_plugin.get_port_details(self.tenant_id,
4108+ self.net_id,
4109+ self.port_id)
4110+ self.assertEqual(port[const.PORT_ID], self.port_id)
4111+ self.assertNotEqual(port[const.PORT_STATE], port_state)
4112+ self.assertEqual(port[const.ATTACHMENT], None)
4113+ new_port_profile = port[const.PORT_PROFILE]
4114+ profile_name = self._cisco_ucs_plugin._get_profile_name(self.port_id)
4115+ self.assertEqual(new_port_profile[const.PROFILE_VLAN_NAME],
4116+ conf.DEFAULT_VLAN_NAME)
4117+ self.assertEqual(new_port_profile[const.PROFILE_VLAN_ID],
4118+ conf.DEFAULT_VLAN_ID)
4119+ self.assertEqual(new_port_profile[const.PROFILE_NAME], profile_name)
4120+ self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
4121+
4122+ def test_get_port_details_state_up(self):
4123+ self._test_get_port_details_state_up(const.PORT_UP)
4124+
4125+ def test_get_port_details_state_down(self):
4126+ self._test_get_port_details_state_down(const.PORT_DOWN)
4127+
4128+ def test_create_port_profile(self):
4129+ LOG.debug("UCSVICTestPlugin:test_create_port_profile() called\n")
4130+ new_port_profile = self._cisco_ucs_plugin._create_port_profile(
4131+ self.tenant_id, self.net_id, self.port_id,
4132+ self.vlan_name, self.vlan_id)
4133+ profile_name = self._cisco_ucs_plugin._get_profile_name(self.port_id)
4134+ self.assertEqual(new_port_profile[const.PROFILE_NAME], profile_name)
4135+ self.assertEqual(new_port_profile[const.PROFILE_VLAN_NAME],
4136+ self.vlan_name)
4137+ self.assertEqual(new_port_profile[const.PROFILE_VLAN_ID], self.vlan_id)
4138+ self._cisco_ucs_plugin._delete_port_profile(self.port_id, profile_name)
4139+
4140+ def test_delete_port_profile(self):
4141+ LOG.debug("UCSVICTestPlugin:test_delete_port_profile() called\n")
4142+ self._cisco_ucs_plugin._create_port_profile(
4143+ self.tenant_id, self.net_id, self.port_id, self.vlan_name,
4144+ self.vlan_id)
4145+ profile_name = self._cisco_ucs_plugin._get_profile_name(self.port_id)
4146+ counter1 = self._cisco_ucs_plugin._port_profile_counter
4147+ self._cisco_ucs_plugin._delete_port_profile(self.port_id,
4148+ profile_name)
4149+ counter2 = self._cisco_ucs_plugin._port_profile_counter
4150+ self.assertNotEqual(counter1, counter2)
4151+
4152+ def _test_plug_interface(self, remote_interface_id):
4153+ """
4154+ Attaches a remote interface to the specified port on the
4155+ specified Virtual Network.
4156+ """
4157+ LOG.debug("UCSVICTestPlugin:_test_plug_interface() called\n")
4158+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4159+ self.net_id, self.vlan_name,
4160+ self.vlan_id)
4161+ self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id,
4162+ const.PORT_UP, self.port_id)
4163+ self._cisco_ucs_plugin.plug_interface(self.tenant_id, self.net_id,
4164+ self.port_id,
4165+ remote_interface_id)
4166+ port = self._cisco_ucs_plugin._get_port(
4167+ self.tenant_id, self.net_id, self.port_id)
4168+ self.assertEqual(port[const.ATTACHMENT], remote_interface_id)
4169+ port_profile = port[const.PORT_PROFILE]
4170+ profile_name = port_profile[const.PROFILE_NAME]
4171+ new_vlan_name = self._cisco_ucs_plugin._get_vlan_name_for_network(
4172+ self.tenant_id, self.net_id)
4173+ new_vlan_id = self._cisco_ucs_plugin._get_vlan_id_for_network(
4174+ self.tenant_id, self.net_id)
4175+ self.assertEqual(port_profile[const.PROFILE_VLAN_NAME], new_vlan_name)
4176+ self.assertEqual(port_profile[const.PROFILE_VLAN_ID], new_vlan_id)
4177+ self.tearDownNetworkPortInterface(self.tenant_id, self.net_id,
4178+ self.port_id)
4179+
4180+ def test_plug_interface(self):
4181+ self._test_plug_interface("4")
4182+
4183+ def _test_unplug_interface(self, remote_interface_id):
4184+ """
4185+ Tests whether remote interface detaches from the specified port on the
4186+ specified Virtual Network.
4187+ """
4188+ LOG.debug("UCSVICTestPlugin:_test_unplug_interface() called\n")
4189+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4190+ self.net_id, self.vlan_name,
4191+ self.vlan_id)
4192+ self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id,
4193+ const.PORT_UP, self.port_id)
4194+ self._cisco_ucs_plugin.plug_interface(self.tenant_id, self.net_id,
4195+ self.port_id,
4196+ remote_interface_id)
4197+ self._cisco_ucs_plugin.unplug_interface(self.tenant_id, self.net_id,
4198+ self.port_id)
4199+ port = self._cisco_ucs_plugin._get_port(
4200+ self.tenant_id, self.net_id, self.port_id)
4201+ self.assertEqual(port[const.ATTACHMENT], None)
4202+ port_profile = port[const.PORT_PROFILE]
4203+ profile_name = port_profile[const.PROFILE_NAME]
4204+ self.assertEqual(port_profile[const.PROFILE_VLAN_NAME],
4205+ conf.DEFAULT_VLAN_NAME)
4206+ self.assertEqual(port_profile[const.PROFILE_VLAN_ID],
4207+ conf.DEFAULT_VLAN_ID)
4208+ self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
4209+
4210+ def test_unplug_interface(self):
4211+ self._test_unplug_interface("4")
4212+
4213+ def test_get_vlan_name_for_network(self):
4214+ LOG.debug("UCSVICTestPlugin:test_get_vlan_name_for_network() called\n")
4215+ net = self._cisco_ucs_plugin.create_network(
4216+ self.tenant_id, self.net_name, self.net_id,
4217+ self.vlan_name, self.vlan_id)
4218+ self.assertEqual(net[const.NET_VLAN_NAME], self.vlan_name)
4219+ self.tearDownNetwork(self.tenant_id, self.net_id)
4220+
4221+ def test_get_vlan_id_for_network(self):
4222+ LOG.debug("UCSVICTestPlugin:test_get_vlan_id_for_network() called\n")
4223+ net = self._cisco_ucs_plugin.create_network(
4224+ self.tenant_id, self.net_name, self.net_id, self.vlan_name,
4225+ self.vlan_id)
4226+ self.assertEqual(net[const.NET_VLAN_ID], self.vlan_id)
4227+ self.tearDownNetwork(self.tenant_id, self.net_id)
4228+
4229+ def test_get_network(self):
4230+ LOG.debug("UCSVICTestPlugin:test_get_network() called\n")
4231+ net = self._cisco_ucs_plugin.create_network(
4232+ self.tenant_id, self.net_name, self.net_id, self.vlan_name,
4233+ self.vlan_id)
4234+ self.assertEqual(net[const.NET_ID], self.net_id)
4235+ self.tearDownNetwork(self.tenant_id, self.net_id)
4236+
4237+ def test_get_port(self):
4238+ LOG.debug("UCSVICTestPlugin:test_get_port() called\n")
4239+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4240+ self.net_id, self.vlan_name,
4241+ self.vlan_id)
4242+ new_port_dict = self._cisco_ucs_plugin.create_port(
4243+ self.tenant_id, self.net_id,
4244+ const.PORT_UP, self.port_id)
4245+ self.assertEqual(new_port_dict[const.PORT_ID], self.port_id)
4246+ self.tearDownNetworkPort(self.tenant_id, self.net_id, self.port_id)
4247+
4248+ def test_get_network_NetworkNotFound(self):
4249+ self.assertRaises(exc.NetworkNotFound,
4250+ self._cisco_ucs_plugin._get_network,
4251+ *(self.tenant_id, self.net_id))
4252+
4253+ def test_delete_network_NetworkNotFound(self):
4254+ self.assertRaises(exc.NetworkNotFound,
4255+ self._cisco_ucs_plugin.delete_network,
4256+ *(self.tenant_id, self.net_id))
4257+
4258+ def test_delete_port_PortInUse(self):
4259+ self._test_delete_port_PortInUse("4")
4260+
4261+ def _test_delete_port_PortInUse(self, remote_interface_id):
4262+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4263+ self.net_id, self.vlan_name,
4264+ self.vlan_id)
4265+ self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id,
4266+ const.PORT_UP, self.port_id)
4267+ self._cisco_ucs_plugin.plug_interface(self.tenant_id, self.net_id,
4268+ self.port_id,
4269+ remote_interface_id)
4270+ self.assertRaises(exc.PortInUse, self._cisco_ucs_plugin.delete_port,
4271+ *(self.tenant_id, self.net_id, self.port_id))
4272+ self.tearDownNetworkPortInterface(self.tenant_id, self.net_id,
4273+ self.port_id)
4274+
4275+ def test_delete_port_PortNotFound(self):
4276+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4277+ self.net_id, self.vlan_name,
4278+ self.vlan_id)
4279+ self.assertRaises(exc.PortNotFound, self._cisco_ucs_plugin.delete_port,
4280+ *(self.tenant_id, self.net_id, self.port_id))
4281+ self.tearDownNetwork(self.tenant_id, self.net_id)
4282+
4283+ def test_plug_interface_PortInUse(self):
4284+ self._test_plug_interface_PortInUse("6", "5")
4285+
4286+ def _test_plug_interface_PortInUse(self, remote_interface_id1,
4287+ remote_interface_id2):
4288+ LOG.debug("UCSVICTestPlugin:_test_plug_interface_PortInUse() called\n")
4289+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4290+ self.net_id, self.vlan_name,
4291+ self.vlan_id)
4292+ self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id,
4293+ const.PORT_UP, self.port_id)
4294+ self._cisco_ucs_plugin.plug_interface(self.tenant_id, self.net_id,
4295+ self.port_id,
4296+ remote_interface_id1)
4297+ self.assertRaises(exc.PortInUse, self._cisco_ucs_plugin.plug_interface,
4298+ *(self.tenant_id, self.net_id, self.port_id,
4299+ remote_interface_id2))
4300+ self.tearDownNetworkPortInterface(self.tenant_id, self.net_id,
4301+ self.port_id)
4302+
4303+ def test_validate_attachment_AlreadyAttached(self):
4304+ LOG.debug("UCSVICTestPlugin:testValidateAttachmentAlreadyAttached")
4305+ self._test_validate_attachment_AlreadyAttached("4")
4306+
4307+ def _test_validate_attachment_AlreadyAttached(self, remote_interface_id):
4308+ LOG.debug("UCSVICTestPlugin:_test_validate_attachmentAlreadyAttached")
4309+ self._cisco_ucs_plugin.create_network(self.tenant_id, self.net_name,
4310+ self.net_id, self.vlan_name,
4311+ self.vlan_id)
4312+ self._cisco_ucs_plugin.create_port(self.tenant_id, self.net_id,
4313+ const.PORT_UP, self.port_id)
4314+ self._cisco_ucs_plugin.plug_interface(self.tenant_id, self.net_id,
4315+ self.port_id,
4316+ remote_interface_id)
4317+ self.assertRaises(
4318+ exc.AlreadyAttached, self._cisco_ucs_plugin._validate_attachment,
4319+ *(self.tenant_id, self.net_id, self.port_id, remote_interface_id))
4320+ self.tearDownNetworkPortInterface(self.tenant_id, self.net_id,
4321+ self.port_id)
4322+
4323+ def tearDownNetwork(self, tenant_id, net_id):
4324+ self._cisco_ucs_plugin.delete_network(tenant_id, net_id)
4325+
4326+ def tearDownNetworkPort(self, tenant_id, net_id, port_id):
4327+ self._cisco_ucs_plugin.delete_port(tenant_id, net_id,
4328+ port_id)
4329+ self.tearDownNetwork(tenant_id, net_id)
4330+
4331+ def tearDownNetworkPortInterface(self, tenant_id, net_id, port_id):
4332+ self._cisco_ucs_plugin.unplug_interface(tenant_id, net_id,
4333+ port_id)
4334+ self.tearDownNetworkPort(tenant_id, net_id, port_id)
4335
4336=== added directory 'quantum/plugins/cisco/ucs'
4337=== added file 'quantum/plugins/cisco/ucs/__init__.py'
4338--- quantum/plugins/cisco/ucs/__init__.py 1970-01-01 00:00:00 +0000
4339+++ quantum/plugins/cisco/ucs/__init__.py 2011-08-15 17:33:23 +0000
4340@@ -0,0 +1,18 @@
4341+# vim: tabstop=4 shiftwidth=4 softtabstop=4
4342+#
4343+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
4344+#
4345+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4346+# not use this file except in compliance with the License. You may obtain
4347+# a copy of the License at
4348+#
4349+# http://www.apache.org/licenses/LICENSE-2.0
4350+#
4351+# Unless required by applicable law or agreed to in writing, software
4352+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
4353+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
4354+# License for the specific language governing permissions and limitations
4355+# under the License.
4356+#
4357+# @author: Sumit Naiksatam, Cisco Systems, Inc.
4358+#
4359
4360=== added file 'quantum/plugins/cisco/ucs/cisco_getvif.py'
4361--- quantum/plugins/cisco/ucs/cisco_getvif.py 1970-01-01 00:00:00 +0000
4362+++ quantum/plugins/cisco/ucs/cisco_getvif.py 2011-08-15 17:33:23 +0000
4363@@ -0,0 +1,51 @@
4364+# vim: tabstop=4 shiftwidth=4 softtabstop=4
4365+#
4366+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
4367+#
4368+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4369+# not use this file except in compliance with the License. You may obtain
4370+# a copy of the License at
4371+#
4372+# http://www.apache.org/licenses/LICENSE-2.0
4373+#
4374+# Unless required by applicable law or agreed to in writing, software
4375+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
4376+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
4377+# License for the specific language governing permissions and limitations
4378+# under the License.
4379+#
4380+# @author: Rohit Agarwalla, Cisco Systems Inc.
4381+#
4382+import sys
4383+import subprocess
4384+
4385+
4386+def get_next_dynic(argv=[]):
4387+ cmd = ["ifconfig", "-a"]
4388+ f_cmd_output = subprocess.Popen(cmd, stdout=subprocess.PIPE).\
4389+ communicate()[0]
4390+ eths = [lines.split(' ')[0] for lines in f_cmd_output.splitlines() \
4391+ if "eth" in lines]
4392+ #print eths
4393+ for eth in eths:
4394+ cmd = ["ethtool", "-i", eth]
4395+ f_cmd_output = subprocess.Popen(cmd, stdout=subprocess.PIPE).\
4396+ communicate()[0]
4397+ bdf = [lines.split(' ')[1] for lines in f_cmd_output.splitlines() \
4398+ if "bus-info" in lines]
4399+ #print bdf
4400+ cmd = ["lspci", "-n", "-s", bdf[0]]
4401+ f_cmd_output = subprocess.Popen(cmd, stdout=subprocess.PIPE).\
4402+ communicate()[0]
4403+ deviceid = [(lines.split(':')[3]).split(' ')[0] \
4404+ for lines in f_cmd_output.splitlines()]
4405+ #print deviceid
4406+ if deviceid[0] == "0044":
4407+ cmd = ["/sbin/ip", "link", "show", eth]
4408+ f_cmd_output = subprocess.Popen(cmd, stdout=subprocess.PIPE).\
4409+ communicate()[0]
4410+ used = [lines for lines in f_cmd_output.splitlines() \
4411+ if "UP" in lines]
4412+ if not used:
4413+ break
4414+ return eth
4415
4416=== added file 'quantum/plugins/cisco/ucs/cisco_ucs_configuration.py'
4417--- quantum/plugins/cisco/ucs/cisco_ucs_configuration.py 1970-01-01 00:00:00 +0000
4418+++ quantum/plugins/cisco/ucs/cisco_ucs_configuration.py 2011-08-15 17:33:23 +0000
4419@@ -0,0 +1,37 @@
4420+# vim: tabstop=4 shiftwidth=4 softtabstop=4
4421+#
4422+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
4423+#
4424+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4425+# not use this file except in compliance with the License. You may obtain
4426+# a copy of the License at
4427+#
4428+# http://www.apache.org/licenses/LICENSE-2.0
4429+#
4430+# Unless required by applicable law or agreed to in writing, software
4431+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
4432+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
4433+# License for the specific language governing permissions and limitations
4434+# under the License.
4435+#
4436+# @author: Sumit Naiksatam, Cisco Systems, Inc.
4437+#
4438+
4439+import os
4440+
4441+from quantum.plugins.cisco.common import cisco_configparser as confp
4442+
4443+CONF_FILE = "../conf/ucs.ini"
4444+
4445+cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
4446+ + "/" + CONF_FILE)
4447+
4448+section = cp['UCSM']
4449+UCSM_IP_ADDRESS = section['ip_address']
4450+DEFAULT_VLAN_NAME = section['default_vlan_name']
4451+DEFAULT_VLAN_ID = section['default_vlan_id']
4452+MAX_UCSM_PORT_PROFILES = section['max_ucsm_port_profiles']
4453+PROFILE_NAME_PREFIX = section['profile_name_prefix']
4454+
4455+section = cp['DRIVER']
4456+UCSM_DRIVER = section['name']
4457
4458=== added file 'quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py'
4459--- quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py 1970-01-01 00:00:00 +0000
4460+++ quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py 2011-08-15 17:33:23 +0000
4461@@ -0,0 +1,235 @@
4462+# vim: tabstop=4 shiftwidth=4 softtabstop=4
4463+#
4464+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
4465+#
4466+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4467+# not use this file except in compliance with the License. You may obtain
4468+# a copy of the License at
4469+#
4470+# http://www.apache.org/licenses/LICENSE-2.0
4471+#
4472+# Unless required by applicable law or agreed to in writing, software
4473+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
4474+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
4475+# License for the specific language governing permissions and limitations
4476+# under the License.
4477+#
4478+# @author: Sumit Naiksatam, Cisco Systems Inc.
4479+#
4480+"""
4481+Implements a UCSM XML API Client
4482+"""
4483+
4484+import httplib
4485+import logging as LOG
4486+import string
4487+import subprocess
4488+from xml.etree import ElementTree as et
4489+import urllib
4490+
4491+from quantum.plugins.cisco.common import cisco_constants as const
4492+from quantum.plugins.cisco.common import cisco_exceptions as cexc
4493+from quantum.plugins.cisco.ucs import cisco_getvif as gvif
4494+
4495+
4496+LOG.basicConfig(level=LOG.WARN)
4497+LOG.getLogger(const.LOGGER_COMPONENT_NAME)
4498+
4499+COOKIE_VALUE = "cookie_placeholder"
4500+PROFILE_NAME = "profilename_placeholder"
4501+PROFILE_CLIENT = "profileclient_placeholder"
4502+VLAN_NAME = "vlanname_placeholder"
4503+VLAN_ID = "vlanid_placeholder"
4504+OLD_VLAN_NAME = "old_vlanname_placeholder"
4505+DYNAMIC_NIC_PREFIX = "eth"
4506+
4507+# The following are standard strings, messages used to communicate with UCSM,
4508+#only place holder values change for each message
4509+HEADERS = {"Content-Type": "text/xml"}
4510+METHOD = "POST"
4511+URL = "/nuova"
4512+
4513+CREATE_VLAN = "<configConfMos cookie=\"" + COOKIE_VALUE + \
4514+"\" inHierarchical=\"true\"> <inConfigs>" \
4515+"<pair key=\"fabric/lan/net-" + VLAN_NAME + \
4516+"\"> <fabricVlan defaultNet=\"no\" " \
4517+"dn=\"fabric/lan/net-" + VLAN_NAME + \
4518+"\" id=\"" + VLAN_ID + "\" name=\"" + \
4519+VLAN_NAME + "\" status=\"created\">" \
4520+"</fabricVlan> </pair> </inConfigs> </configConfMos>"
4521+
4522+CREATE_PROFILE = "<configConfMos cookie=\"" + COOKIE_VALUE + \
4523+"\" inHierarchical=\"true\"> <inConfigs>" \
4524+"<pair key=\"fabric/lan/profiles/vnic-" + PROFILE_NAME + \
4525+"\"> <vnicProfile descr=\"Profile created by " \
4526+"Cisco OpenStack Quantum Plugin\" " \
4527+"dn=\"fabric/lan/profiles/vnic-" + PROFILE_NAME + \
4528+"\" maxPorts=\"64\" name=\"" + PROFILE_NAME + \
4529+"\" nwCtrlPolicyName=\"\" pinToGroupName=\"\" " \
4530+"qosPolicyName=\"\" status=\"created\"> " \
4531+"<vnicEtherIf defaultNet=\"yes\" name=\"" + VLAN_NAME + \
4532+"\" rn=\"if-" + VLAN_NAME + "\" > </vnicEtherIf> " \
4533+"</vnicProfile> </pair> </inConfigs> </configConfMos>"
4534+
4535+ASSOCIATE_PROFILE = "<configConfMos cookie=\"" + COOKIE_VALUE + \
4536+"\" inHierarchical=\"true\"> <inConfigs> <pair " \
4537+"key=\"fabric/lan/profiles/vnic-" + PROFILE_NAME + \
4538+"/cl-" + PROFILE_CLIENT + "\"> <vmVnicProfCl dcName=\".*\" " \
4539+"descr=\"\" dn=\"fabric/lan/profiles/vnic-" + \
4540+PROFILE_NAME + "/cl-" + PROFILE_CLIENT + \
4541+"\"name=\"" + PROFILE_CLIENT + "\" orgPath=\".*\" " \
4542+"status=\"created\" swName=\"default$\"> </vmVnicProfCl>" \
4543+"</pair> </inConfigs> </configConfMos>"
4544+
4545+CHANGE_VLAN_IN_PROFILE = "<configConfMos cookie=\"" + COOKIE_VALUE + \
4546+"\" inHierarchical=\"true\"> <inConfigs>" \
4547+"<pair key=\"fabric/lan/profiles/vnic-" + \
4548+PROFILE_NAME + "\"> <vnicProfile descr=\"Profile " \
4549+"created by Cisco OpenStack Quantum Plugin\" " \
4550+"dn=\"fabric/lan/profiles/vnic-" + \
4551+PROFILE_NAME + "\" maxPorts=\"64\" name=\"" + \
4552+PROFILE_NAME + "\" nwCtrlPolicyName=\"\" " \
4553+"pinToGroupName=\"\" qosPolicyName=\"\" " \
4554+"status=\"created,modified\">" \
4555+"<vnicEtherIf rn=\"if-" + OLD_VLAN_NAME + \
4556+"\" status=\"deleted\"> </vnicEtherIf> <vnicEtherIf " \
4557+"defaultNet=\"yes\" name=\"" + \
4558+VLAN_NAME + "\" rn=\"if-" + VLAN_NAME + \
4559+"\" > </vnicEtherIf> </vnicProfile> </pair>" \
4560+"</inConfigs> </configConfMos>"
4561+
4562+DELETE_VLAN = "<configConfMos cookie=\"" + COOKIE_VALUE + \
4563+"\" inHierarchical=\"true\"> <inConfigs>" \
4564+"<pair key=\"fabric/lan/net-" + VLAN_NAME + \
4565+"\"> <fabricVlan dn=\"fabric/lan/net-" + VLAN_NAME + \
4566+"\" status=\"deleted\"> </fabricVlan> </pair> </inConfigs>" \
4567+"</configConfMos>"
4568+
4569+DELETE_PROFILE = "<configConfMos cookie=\"" + COOKIE_VALUE + \
4570+"\" inHierarchical=\"false\"> <inConfigs>" \
4571+"<pair key=\"fabric/lan/profiles/vnic-" + PROFILE_NAME + \
4572+"\"> <vnicProfile dn=\"fabric/lan/profiles/vnic-" + \
4573+PROFILE_NAME + "\" status=\"deleted\"> </vnicProfile>" \
4574+"</pair> </inConfigs> </configConfMos>"
4575+
4576+
4577+class CiscoUCSMDriver():
4578+
4579+ def __init__(self):
4580+ pass
4581+
4582+ def _post_data(self, ucsm_ip, ucsm_username, ucsm_password, data):
4583+ conn = httplib.HTTPConnection(ucsm_ip)
4584+ login_data = "<aaaLogin inName=\"" + ucsm_username + \
4585+ "\" inPassword=\"" + ucsm_password + "\" />"
4586+ conn.request(METHOD, URL, login_data, HEADERS)
4587+ response = conn.getresponse()
4588+ response_data = response.read()
4589+ LOG.debug(response.status)
4590+ LOG.debug(response.reason)
4591+ LOG.debug(response_data)
4592+ # TODO (Sumit): If login is not successful, throw exception
4593+ xmlTree = et.XML(response_data)
4594+ cookie = xmlTree.attrib["outCookie"]
4595+
4596+ data = data.replace(COOKIE_VALUE, cookie)
4597+ LOG.debug("POST: %s" % data)
4598+ conn.request(METHOD, URL, data, HEADERS)
4599+ response = conn.getresponse()
4600+ response_data = response.read()
4601+ LOG.debug(response.status)
4602+ LOG.debug(response.reason)
4603+ LOG.debug("UCSM Response: %s" % response_data)
4604+
4605+ logout_data = "<aaaLogout inCookie=\"" + cookie + "\" />"
4606+ conn.request(METHOD, URL, logout_data, HEADERS)
4607+ response = conn.getresponse()
4608+ response_data = response.read()
4609+ LOG.debug(response.status)
4610+ LOG.debug(response.reason)
4611+ LOG.debug(response_data)
4612+
4613+ def _create_vlan_post_data(self, vlan_name, vlan_id):
4614+ data = CREATE_VLAN.replace(VLAN_NAME, vlan_name)
4615+ data = data.replace(VLAN_ID, vlan_id)
4616+ return data
4617+
4618+ def _create_profile_post_data(self, profile_name, vlan_name):
4619+ data = CREATE_PROFILE.replace(PROFILE_NAME, profile_name)
4620+ data = data.replace(VLAN_NAME, vlan_name)
4621+ return data
4622+
4623+ def _create_profile_client_post_data(self, profile_name,
4624+ profile_client_name):
4625+ data = ASSOCIATE_PROFILE.replace(PROFILE_NAME, profile_name)
4626+ data = data.replace(PROFILE_CLIENT, profile_client_name)
4627+ return data
4628+
4629+ def _change_vlan_in_profile_post_data(self, profile_name, old_vlan_name,
4630+ new_vlan_name):
4631+ data = CHANGE_VLAN_IN_PROFILE.replace(PROFILE_NAME, profile_name)
4632+ data = data.replace(OLD_VLAN_NAME, old_vlan_name)
4633+ data = data.replace(VLAN_NAME, new_vlan_name)
4634+ return data
4635+
4636+ def _delete_vlan_post_data(self, vlan_name):
4637+ data = DELETE_VLAN.replace(VLAN_NAME, vlan_name)
4638+ return data
4639+
4640+ def _delete_profile_post_data(self, profile_name):
4641+ data = DELETE_PROFILE.replace(PROFILE_NAME, profile_name)
4642+ return data
4643+
4644+ def _get_next_dynamic_nic(self):
4645+ dynamic_nic_id = gvif.get_next_dynic()
4646+ if len(dynamic_nic_id) > 0:
4647+ return dynamic_nic_id
4648+ else:
4649+ raise cisco_exceptions.NoMoreNics(net_id=net_id, port_id=port_id)
4650+
4651+ def create_vlan(self, vlan_name, vlan_id, ucsm_ip, ucsm_username,
4652+ ucsm_password):
4653+ data = self._create_vlan_post_data(vlan_name, vlan_id)
4654+ self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
4655+
4656+ def create_profile(self, profile_name, vlan_name, ucsm_ip, ucsm_username,
4657+ ucsm_password):
4658+ data = self._create_profile_post_data(profile_name, vlan_name)
4659+ self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
4660+ data = self._create_profile_client_post_data(profile_name,
4661+ profile_name[-16:])
4662+ self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
4663+
4664+ def change_vlan_in_profile(self, profile_name, old_vlan_name,
4665+ new_vlan_name, ucsm_ip, ucsm_username,
4666+ ucsm_password):
4667+ data = self._change_vlan_in_profile_post_data(profile_name,
4668+ old_vlan_name,
4669+ new_vlan_name)
4670+ self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
4671+
4672+ def get_dynamic_nic(self, host):
4673+ # TODO (Sumit): Check availability per host
4674+ # TODO (Sumit): If not available raise exception
4675+ # TODO (Sumit): This simple logic assumes that create-port and
4676+ # spawn-VM happens in lock-step
4677+ # But we should support multiple create-port calls,
4678+ # followed by spawn-VM calls
4679+ # That would require managing a pool of available
4680+ # dynamic vnics per host
4681+ dynamic_nic_name = self._get_next_dynamic_nic()
4682+ LOG.debug("Reserving dynamic nic %s" % dynamic_nic_name)
4683+ return dynamic_nic_name
4684+
4685+ def delete_vlan(self, vlan_name, ucsm_ip, ucsm_username, ucsm_password):
4686+ data = self._delete_vlan_post_data(vlan_name)
4687+ self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
4688+
4689+ def delete_profile(self, profile_name, ucsm_ip, ucsm_username,
4690+ ucsm_password):
4691+ data = self._delete_profile_post_data(profile_name)
4692+ self._post_data(ucsm_ip, ucsm_username, ucsm_password, data)
4693+
4694+ def release_dynamic_nic(self, host):
4695+ # TODO (Sumit): Release on a specific host
4696+ pass
4697
4698=== added file 'quantum/plugins/cisco/ucs/cisco_ucs_plugin.py'
4699--- quantum/plugins/cisco/ucs/cisco_ucs_plugin.py 1970-01-01 00:00:00 +0000
4700+++ quantum/plugins/cisco/ucs/cisco_ucs_plugin.py 2011-08-15 17:33:23 +0000
4701@@ -0,0 +1,298 @@
4702+# vim: tabstop=4 shiftwidth=4 softtabstop=4
4703+#
4704+# Copyright 2011 Cisco Systems, Inc. All rights reserved.
4705+#
4706+# Licensed under the Apache License, Version 2.0 (the "License"); you may
4707+# not use this file except in compliance with the License. You may obtain
4708+# a copy of the License at
4709+#
4710+# http://www.apache.org/licenses/LICENSE-2.0
4711+#
4712+# Unless required by applicable law or agreed to in writing, software
4713+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
4714+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
4715+# License for the specific language governing permissions and limitations
4716+# under the License.
4717+#
4718+# @author: Sumit Naiksatam, Cisco Systems, Inc.
4719+#
4720+
4721+import logging as LOG
4722+
4723+from quantum.common import exceptions as exc
4724+from quantum.common import utils
4725+from quantum.plugins.cisco.common import cisco_constants as const
4726+from quantum.plugins.cisco.common import cisco_credentials as cred
4727+from quantum.plugins.cisco.common import cisco_exceptions as cexc
4728+from quantum.plugins.cisco.common import cisco_utils as cutil
4729+from quantum.plugins.cisco.l2device_plugin_base import L2DevicePluginBase
4730+from quantum.plugins.cisco.ucs import cisco_ucs_configuration as conf
4731+
4732+LOG.basicConfig(level=LOG.WARN)
4733+LOG.getLogger(const.LOGGER_COMPONENT_NAME)
4734+
4735+
4736+class UCSVICPlugin(L2DevicePluginBase):
4737+ _networks = {}
4738+
4739+ def __init__(self):
4740+ self._client = utils.import_object(conf.UCSM_DRIVER)
4741+ LOG.debug("Loaded driver %s\n" % conf.UCSM_DRIVER)
4742+ self._utils = cutil.DBUtils()
4743+ # TODO (Sumit) This is for now, when using only one chassis
4744+ self._ucsm_ip = conf.UCSM_IP_ADDRESS
4745+ self._ucsm_username = cred.Store.getUsername(conf.UCSM_IP_ADDRESS)
4746+ self._ucsm_password = cred.Store.getPassword(conf.UCSM_IP_ADDRESS)
4747+ # TODO (Sumit) Make the counter per UCSM
4748+ self._port_profile_counter = 0
4749+
4750+ def get_all_networks(self, tenant_id, **kwargs):
4751+ """
4752+ Returns a dictionary containing all
4753+ <network_uuid, network_name> for
4754+ the specified tenant.
4755+ """
4756+ LOG.debug("UCSVICPlugin:get_all_networks() called\n")
4757+ return self._networks.values()
4758+
4759+ def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id,
4760+ **kwargs):
4761+ """
4762+ Creates a new Virtual Network, and assigns it
4763+ a symbolic name.
4764+ """
4765+ LOG.debug("UCSVICPlugin:create_network() called\n")
4766+ self._client.create_vlan(vlan_name, str(vlan_id), self._ucsm_ip,
4767+ self._ucsm_username, self._ucsm_password)
4768+ new_net_dict = {const.NET_ID: net_id,
4769+ const.NET_NAME: net_name,
4770+ const.NET_PORTS: {},
4771+ const.NET_VLAN_NAME: vlan_name,
4772+ const.NET_VLAN_ID: vlan_id}
4773+ self._networks[net_id] = new_net_dict
4774+ return new_net_dict
4775+
4776+ def delete_network(self, tenant_id, net_id, **kwargs):
4777+ """
4778+ Deletes the network with the specified network identifier
4779+ belonging to the specified tenant.
4780+ """
4781+ LOG.debug("UCSVICPlugin:delete_network() called\n")
4782+ net = self._networks.get(net_id)
4783+ # TODO (Sumit) : Verify that no attachments are plugged into the
4784+ # network
4785+ if net:
4786+ # TODO (Sumit) : Before deleting the network, make sure all the
4787+ # ports associated with this network are also deleted
4788+ self._client.delete_vlan(net[const.NET_VLAN_NAME], self._ucsm_ip,
4789+ self._ucsm_username, self._ucsm_password)
4790+ self._networks.pop(net_id)
4791+ return net
4792+ raise exc.NetworkNotFound(net_id=net_id)
4793+
4794+ def get_network_details(self, tenant_id, net_id, **kwargs):
4795+ """
4796+ Deletes the Virtual Network belonging to a the
4797+ spec
4798+ """
4799+ LOG.debug("UCSVICPlugin:get_network_details() called\n")
4800+ network = self._get_network(tenant_id, net_id)
4801+ return network
4802+
4803+ def rename_network(self, tenant_id, net_id, new_name, **kwargs):
4804+ """
4805+ Updates the symbolic name belonging to a particular
4806+ Virtual Network.
4807+ """
4808+ LOG.debug("UCSVICPlugin:rename_network() called\n")
4809+ network = self._get_network(tenant_id, net_id)
4810+ network[const.NET_NAME] = new_name
4811+ return network
4812+
4813+ def get_all_ports(self, tenant_id, net_id, **kwargs):
4814+ """
4815+ Retrieves all port identifiers belonging to the
4816+ specified Virtual Network.
4817+ """
4818+ LOG.debug("UCSVICPlugin:get_all_ports() called\n")
4819+ network = self._get_network(tenant_id, net_id)
4820+ ports_on_net = network[const.NET_PORTS].values()
4821+ return ports_on_net
4822+
4823+ def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs):
4824+ """
4825+ Creates a port on the specified Virtual Network.
4826+ """
4827+ LOG.debug("UCSVICPlugin:create_port() called\n")
4828+ net = self._get_network(tenant_id, net_id)
4829+ ports = net[const.NET_PORTS]
4830+ # TODO (Sumit): This works on a single host deployment,
4831+ # in multi-host environment, dummy needs to be replaced with the
4832+ # hostname
4833+ dynamic_nic_name = self._client.get_dynamic_nic("dummy")
4834+ new_port_profile = self._create_port_profile(tenant_id, net_id,
4835+ port_id,
4836+ conf.DEFAULT_VLAN_NAME,
4837+ conf.DEFAULT_VLAN_ID)
4838+ profile_name = new_port_profile[const.PROFILE_NAME]
4839+ sql_query = "INSERT INTO ports (port_id, profile_name, dynamic_vnic," \
4840+ "host, instance_name, instance_nic_name, used) VALUES" \
4841+ "('%s', '%s', '%s', 'dummy', NULL, NULL, 0)" % \
4842+ (port_id, profile_name, dynamic_nic_name)
4843+ self._utils.execute_db_query(sql_query)
4844+ new_port_dict = {const.PORT_ID: port_id,
4845+ const.PORT_STATE: const.PORT_UP,
4846+ const.ATTACHMENT: None,
4847+ const.PORT_PROFILE: new_port_profile}
4848+ ports[port_id] = new_port_dict
4849+ return new_port_dict
4850+
4851+ def delete_port(self, tenant_id, net_id, port_id, **kwargs):
4852+ """
4853+ Deletes a port on a specified Virtual Network,
4854+ if the port contains a remote interface attachment,
4855+ the remote interface should first be un-plugged and
4856+ then the port can be deleted.
4857+ """
4858+ LOG.debug("UCSVICPlugin:delete_port() called\n")
4859+ port = self._get_port(tenant_id, net_id, port_id)
4860+ if port[const.ATTACHMENT]:
4861+ raise exc.PortInUse(net_id=net_id, port_id=port_id,
4862+ att_id=port[const.ATTACHMENT])
4863+ try:
4864+ #TODO (Sumit): Before deleting port profile make sure that there
4865+ # is no VM using this port profile
4866+ self._client.release_dynamic_nic("dummy")
4867+ port_profile = port[const.PORT_PROFILE]
4868+ self._delete_port_profile(port_id,
4869+ port_profile[const.PROFILE_NAME])
4870+ sql_query = "delete from ports where port_id = \"%s\"" % \
4871+ (port[const.PORT_ID])
4872+ self._utils.execute_db_query(sql_query)
4873+ net = self._get_network(tenant_id, net_id)
4874+ net[const.NET_PORTS].pop(port_id)
4875+ except KeyError:
4876+ raise exc.PortNotFound(net_id=net_id, port_id=port_id)
4877+
4878+ def update_port(self, tenant_id, net_id, port_id, port_state, **kwargs):
4879+ """
4880+ Updates the state of a port on the specified Virtual Network.
4881+ """
4882+ LOG.debug("UCSVICPlugin:update_port() called\n")
4883+ port = self._get_port(tenant_id, net_id, port_id)
4884+ self._validate_port_state(port_state)
4885+ port[const.PORT_STATE] = port_state
4886+ return port
4887+
4888+ def get_port_details(self, tenant_id, net_id, port_id, **kwargs):
4889+ """
4890+ This method allows the user to retrieve a remote interface
4891+ that is attached to this particular port.
4892+ """
4893+ LOG.debug("UCSVICPlugin:get_port_details() called\n")
4894+ return self._get_port(tenant_id, net_id, port_id)
4895+
4896+ def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id,
4897+ **kwargs):
4898+ """
4899+ Attaches a remote interface to the specified port on the
4900+ specified Virtual Network.
4901+ """
4902+ LOG.debug("UCSVICPlugin:plug_interface() called\n")
4903+ self._validate_attachment(tenant_id, net_id, port_id,
4904+ remote_interface_id)
4905+ port = self._get_port(tenant_id, net_id, port_id)
4906+ if port[const.ATTACHMENT]:
4907+ raise exc.PortInUse(net_id=net_id, port_id=port_id,
4908+ att_id=port[const.ATTACHMENT])
4909+ port[const.ATTACHMENT] = remote_interface_id
4910+ port_profile = port[const.PORT_PROFILE]
4911+ profile_name = port_profile[const.PROFILE_NAME]
4912+ old_vlan_name = port_profile[const.PROFILE_VLAN_NAME]
4913+ new_vlan_name = self._get_vlan_name_for_network(tenant_id, net_id)
4914+ new_vlan_id = self._get_vlan_id_for_network(tenant_id, net_id)
4915+ self._client.change_vlan_in_profile(profile_name, old_vlan_name,
4916+ new_vlan_name, self._ucsm_ip,
4917+ self._ucsm_username,
4918+ self._ucsm_password)
4919+ port_profile[const.PROFILE_VLAN_NAME] = new_vlan_name
4920+ port_profile[const.PROFILE_VLAN_ID] = new_vlan_id
4921+
4922+ def unplug_interface(self, tenant_id, net_id, port_id, **kwargs):
4923+ """
4924+ Detaches a remote interface from the specified port on the
4925+ specified Virtual Network.
4926+ """
4927+ LOG.debug("UCSVICPlugin:unplug_interface() called\n")
4928+ port = self._get_port(tenant_id, net_id, port_id)
4929+ port[const.ATTACHMENT] = None
4930+ port_profile = port[const.PORT_PROFILE]
4931+ profile_name = port_profile[const.PROFILE_NAME]
4932+ old_vlan_name = port_profile[const.PROFILE_VLAN_NAME]
4933+ new_vlan_name = conf.DEFAULT_VLAN_NAME
4934+ self._client.change_vlan_in_profile(profile_name, old_vlan_name,
4935+ new_vlan_name, self._ucsm_ip,
4936+ self._ucsm_username,
4937+ self._ucsm_password)
4938+ port_profile[const.PROFILE_VLAN_NAME] = conf.DEFAULT_VLAN_NAME
4939+ port_profile[const.PROFILE_VLAN_ID] = conf.DEFAULT_VLAN_ID
4940+
4941+ def _get_profile_name(self, port_id):
4942+ profile_name = conf.PROFILE_NAME_PREFIX + port_id
4943+ return profile_name
4944+
4945+ def _validate_port_state(self, port_state):
4946+ if port_state.upper() not in (const.PORT_UP, const.PORT_DOWN):
4947+ raise exc.StateInvalid(port_state=port_state)
4948+ return True
4949+
4950+ def _validate_attachment(self, tenant_id, network_id, port_id,
4951+ remote_interface_id):
4952+ network = self._get_network(tenant_id, network_id)
4953+ for port in network[const.NET_PORTS].values():
4954+ if port[const.ATTACHMENT] == remote_interface_id:
4955+ raise exc.AlreadyAttached(net_id=network_id,
4956+ port_id=port_id,
4957+ att_id=port[const.ATTACHMENT],
4958+ att_port_id=port[const.PORT_ID])
4959+
4960+ def _get_network(self, tenant_id, network_id):
4961+ network = self._networks.get(network_id)
4962+ if not network:
4963+ raise exc.NetworkNotFound(net_id=network_id)
4964+ return network
4965+
4966+ def _get_vlan_name_for_network(self, tenant_id, network_id):
4967+ net = self._get_network(tenant_id, network_id)
4968+ vlan_name = net[const.NET_VLAN_NAME]
4969+ return vlan_name
4970+
4971+ def _get_vlan_id_for_network(self, tenant_id, network_id):
4972+ net = self._get_network(tenant_id, network_id)
4973+ vlan_id = net[const.NET_VLAN_ID]
4974+ return vlan_id
4975+
4976+ def _get_port(self, tenant_id, network_id, port_id):
4977+ net = self._get_network(tenant_id, network_id)
4978+ port = net[const.NET_PORTS].get(port_id)
4979+ if not port:
4980+ raise exc.PortNotFound(net_id=network_id, port_id=port_id)
4981+ return port
4982+
4983+ def _create_port_profile(self, tenant_id, net_id, port_id, vlan_name,
4984+ vlan_id):
4985+ if self._port_profile_counter >= int(conf.MAX_UCSM_PORT_PROFILES):
4986+ raise cexc.UCSMPortProfileLimit(net_id=net_id, port_id=port_id)
4987+ profile_name = self._get_profile_name(port_id)
4988+ self._client.create_profile(profile_name, vlan_name, self._ucsm_ip,
4989+ self._ucsm_username, self._ucsm_password)
4990+ self._port_profile_counter += 1
4991+ new_port_profile = {const.PROFILE_NAME: profile_name,
4992+ const.PROFILE_VLAN_NAME: vlan_name,
4993+ const.PROFILE_VLAN_ID: vlan_id}
4994+ return new_port_profile
4995+
4996+ def _delete_port_profile(self, port_id, profile_name):
4997+ self._client.delete_profile(profile_name, self._ucsm_ip,
4998+ self._ucsm_username, self._ucsm_password)
4999+ self._port_profile_counter -= 1

Subscribers

People subscribed via source and target branches