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

Proposed by Rohit Agarwalla
Status: Merged
Approved by: Salvatore Orlando
Approved revision: 76
Merged at revision: 48
Proposed branch: lp:~cisco-openstack/neutron/l2network-plugin-persistence
Merge into: lp:neutron/diablo
Diff against target: 5302 lines (+2779/-936)
37 files modified
quantum/plugins/cisco/README (+57/-14)
quantum/plugins/cisco/__init__.py (+2/-0)
quantum/plugins/cisco/common/__init__.py (+2/-0)
quantum/plugins/cisco/common/cisco_configparser.py (+4/-5)
quantum/plugins/cisco/common/cisco_constants.py (+20/-1)
quantum/plugins/cisco/common/cisco_credentials.py (+11/-1)
quantum/plugins/cisco/common/cisco_exceptions.py (+53/-6)
quantum/plugins/cisco/common/cisco_nova_configuration.py (+10/-8)
quantum/plugins/cisco/common/cisco_utils.py (+16/-4)
quantum/plugins/cisco/conf/db_conn.ini (+5/-0)
quantum/plugins/cisco/conf/nexus.ini (+2/-0)
quantum/plugins/cisco/db/api.py (+254/-0)
quantum/plugins/cisco/db/l2network_db.py (+346/-0)
quantum/plugins/cisco/db/l2network_models.py (+147/-0)
quantum/plugins/cisco/db/models.py (+102/-0)
quantum/plugins/cisco/l2device_plugin_base.py (+9/-1)
quantum/plugins/cisco/l2network_model.py (+47/-24)
quantum/plugins/cisco/l2network_model_base.py (+10/-1)
quantum/plugins/cisco/l2network_plugin.py (+208/-195)
quantum/plugins/cisco/l2network_plugin_configuration.py (+40/-23)
quantum/plugins/cisco/nexus/__init__.py (+4/-1)
quantum/plugins/cisco/nexus/cisco_nexus_configuration.py (+12/-7)
quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py (+73/-167)
quantum/plugins/cisco/nexus/cisco_nexus_plugin.py (+20/-6)
quantum/plugins/cisco/nexus/cisco_nexus_snippets.py (+156/-0)
quantum/plugins/cisco/run_tests.py (+40/-252)
quantum/plugins/cisco/tests/unit/test_database.py (+840/-0)
quantum/plugins/cisco/tests/unit/test_l2networkApi.py (+180/-110)
quantum/plugins/cisco/tests/unit/test_nexus_plugin.py (+3/-4)
quantum/plugins/cisco/tests/unit/test_ucs_driver.py (+29/-26)
quantum/plugins/cisco/tests/unit/test_ucs_plugin.py (+16/-18)
quantum/plugins/cisco/ucs/__init__.py (+2/-0)
quantum/plugins/cisco/ucs/cisco_getvif.py (+4/-1)
quantum/plugins/cisco/ucs/cisco_ucs_configuration.py (+11/-9)
quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py (+26/-10)
quantum/plugins/cisco/ucs/cisco_ucs_plugin.py (+17/-5)
tests/unit/test_api.py (+1/-37)
To merge this branch: bzr merge lp:~cisco-openstack/neutron/l2network-plugin-persistence
Reviewer Review Type Date Requested Status
Salvatore Orlando Approve
Brad Hall (community) Approve
Review via email: mp+71779@code.launchpad.net

Description of the change

This branch has two main changes over the earlier approved branch (lp:~cisco-openstack/quantum/l2network-plugin):

• Addition of persistence support and framework
• Enhancements/fixes to increase the pylint score. (The pylint score for the modules checked under quantum/plugins/cisco now stands as 8.29, above the target of 7.5 set for us by Salvatore. :-))

The changes proposed in this branch are again contained within the quantum/plugins/cisco directory (with the exception of some test related artifacts to comply with Dan's framework), and as such do not affect any other Quantum functionality. Branch has been tested, and all tests pass successfully.

We have also made changes to address the review comments provided for the earlier branch, most notably,
• We address the ID generation issue, as suggested by Salvatore
• We have cleaned up the XML snippets in the nexus driver, as recommended by Dan (we still use them in the ucs driver since it's more convenient to that right now, but we will move them in the future)
• We have moved ssh port-specific details to the conf files
• We have added more descriptive comments so that the network model and device plugin base classes can be better understood. We have also enhanced the README file.
• We still have a single logging component, and we will change that in an upcoming merge.

More specifically on the persistence support in this branch - We would hope that some of the practices we have followed can be promoted to the core Quantum framework. For instance, we found it useful to use the "InnoDB" engine to enforce foreign key constraints. This and other such details related to the persistence framework are highlighted below:
- persistence framework for quantum/plugins/cisco/l2network_plugin
                - implementation - mysql as the database and sqlalchmey as the ORM
                - quantum/plugins/cisco/db/ consists the persistent framework code
                - l2network_plugin specific new models and db methods have been defined
                - vlan_id management implementation using the db has been implemented
                - quantum core models and api (for network & port) have been reused within the plugin with the following changes -
                    - specify mysql engine for models (InnoDB) - this engine imposes foreign key constraints
                    - early loading of tables using joinedload in queries - this allows to exercise the relation attribute defined between network & port tables
                - README contains instructions on how to perform the database configurations
- plugin specific changes -
                - refactored plugins/cisco/l2network_plugin methods
                     - to perform necessary actions against the db for various methods
                     - to return dictionary items from method as per api expectations
- tests specific changes -
                - refactored plugins/cisco/tests/unit/test_l2networkapi test cases to check results with the db for various methods
                - independent database tests added in plugins/cisco/tests/unit/test_database.py to test core and l2network_plugin models

Thanks
Sumit, Shweta, Rohit

To post a comment you must log in.
Revision history for this message
Salvatore Orlando (salvatore-orlando) wrote :

Hi Sumit/Rohit,

I apologise for the "needs fixing" without a proper review, but it seems your branch has several conflict with trunk!

review: Needs Fixing
70. By Sumit Naiksatam

Pulling in changes from lp:quantum.

Revision history for this message
Sumit Naiksatam (snaiksat) wrote :

> Hi Sumit/Rohit,
>
> I apologise for the "needs fixing" without a proper review, but it seems your
> branch has several conflict with trunk!

Our apologies as well, the conflicts have been fixed.

Revision history for this message
Brad Hall (bgh) wrote :

1171 + return vlanid
1172 + except exc.NoResultFound:
1173 + pass

Indentation is off there

1244 + except exc.NoResultFound:
1245 + pass

Same here

1315 + return pp
1316 + except exc.NoResultFound:
1317 + pass

And here

1320 +def update_portprofile(tenantid, ppid, newppname=None, newvlanid=None, \
1321 + newqos=None):

You don't need the "\" there

2454 + res[const.NET_PORTS] = ports

I think you want const.NETWORKPORTS there?

1975 + const.NET_PORTS: []}

(and here)

4911 + def _make_net_dict(self, net_id, net_name, ports):
4912 + res = {const.NET_ID: net_id, const.NET_NAME: net_name}
4913 + res[const.NET_PORTS] = ports
4914 + return res

(and here)

2460 + res[const.NET_ID] = net_id

There is const.NET_ID used in a lot of places when I think it should be
const.NETWORKID .. but I could be missing something here. Maybe const.NET_ID
is still defined somewher else.

3182 +"""Unittest runner for quantum OVS plugin

Might want to change that to Cisco plugin ;)

3438 +#from quantum.plugins.openvswitch.tests.test_vlan_map import VlanMapTest

Might as well nuke that line.. don't think its ever going to be used in this
file.

3740 +class QuantumDB(object):
3741 + """Class conisting of methods to call Quantum db methods"""
3742 + def get_all_networks(self, tenant_id):

We should probably move this type of stuff into a library since other plugins
will want to use it. Not an issue for this merge though.

review: Needs Fixing
71. By Rohit Agarwalla

Fixed indentation and changed file comments

Revision history for this message
Rohit Agarwalla (rohitagarwalla) wrote :

Thanks for the review and comments Brad.

> 1171 + return vlanid
> 1172 + except exc.NoResultFound:
> 1173 + pass
>
> Indentation is off there
>
> 1244 + except exc.NoResultFound:
> 1245 + pass
>
> Same here
>
> 1315 + return pp
> 1316 + except exc.NoResultFound:
> 1317 + pass
>
> And here
>
> 1320 +def update_portprofile(tenantid, ppid, newppname=None,
> newvlanid=None, \
> 1321 + newqos=None):
>
> You don't need the "\" there
>

Fixed.

> 2454 + res[const.NET_PORTS] = ports
>
> I think you want const.NETWORKPORTS there?
>
> 1975 + const.NET_PORTS: []}
>
> (and here)
>
> 4911 + def _make_net_dict(self, net_id, net_name, ports):
> 4912 + res = {const.NET_ID: net_id, const.NET_NAME: net_name}
> 4913 + res[const.NET_PORTS] = ports
> 4914 + return res
>
> (and here)
>
> 2460 + res[const.NET_ID] = net_id
>
> There is const.NET_ID used in a lot of places when I think it should be
> const.NETWORKID .. but I could be missing something here. Maybe const.NET_ID
> is still defined somewher else.
>

NETWORKPORTS = 'ports'
NET_PORTS = 'net-ports'

NETWORKID = 'network_id'
NET_ID = 'net-id'

There are two different constants defined in cisco/common/cisco_constants.py.
As you would have seen, the make_dict methods create a dictionary with keys as excepted by the api (net-id in this case)
We couldn't define net-id (and others containing '-' ) as variables for the database models and therefore had to use different variables.

> 3182 +"""Unittest runner for quantum OVS plugin
>
> Might want to change that to Cisco plugin ;)
>
> 3438 +#from quantum.plugins.openvswitch.tests.test_vlan_map import
> VlanMapTest
>
> Might as well nuke that line.. don't think its ever going to be used in this
> file.
>
> 3740 +class QuantumDB(object):
> 3741 + """Class conisting of methods to call Quantum db methods"""
> 3742 + def get_all_networks(self, tenant_id):
>
> We should probably move this type of stuff into a library since other plugins
> will want to use it. Not an issue for this merge though.

Sure, we'll take this an action item.

Revision history for this message
Brad Hall (bgh) wrote :

> Thanks for the review and comments Brad.
>
> > 1171 + return vlanid
> > 1172 + except exc.NoResultFound:
> > 1173 + pass
> >
> > Indentation is off there
> >
> > 1244 + except exc.NoResultFound:
> > 1245 + pass
> >
> > Same here
> >
> > 1315 + return pp
> > 1316 + except exc.NoResultFound:
> > 1317 + pass
> >
> > And here
> >
> > 1320 +def update_portprofile(tenantid, ppid, newppname=None,
> > newvlanid=None, \
> > 1321 + newqos=None):
> >
> > You don't need the "\" there
> >
>
> Fixed.

Great, thanks!

>
> > 2454 + res[const.NET_PORTS] = ports
> >
> > I think you want const.NETWORKPORTS there?
> >
> > 1975 + const.NET_PORTS: []}
> >
> > (and here)
> >
> > 4911 + def _make_net_dict(self, net_id, net_name, ports):
> > 4912 + res = {const.NET_ID: net_id, const.NET_NAME: net_name}
> > 4913 + res[const.NET_PORTS] = ports
> > 4914 + return res
> >
> > (and here)
> >
> > 2460 + res[const.NET_ID] = net_id
> >
> > There is const.NET_ID used in a lot of places when I think it should be
> > const.NETWORKID .. but I could be missing something here. Maybe
> const.NET_ID
> > is still defined somewher else.
> >
>
> NETWORKPORTS = 'ports'
> NET_PORTS = 'net-ports'
>
> NETWORKID = 'network_id'
> NET_ID = 'net-id'
>
> There are two different constants defined in cisco/common/cisco_constants.py.
> As you would have seen, the make_dict methods create a dictionary with keys as
> excepted by the api (net-id in this case)
> We couldn't define net-id (and others containing '-' ) as variables for the
> database models and therefore had to use different variables.

OK, I understand now.. I just didn't see NET_ID in the diff.

> > 3182 +"""Unittest runner for quantum OVS plugin
> >
> > Might want to change that to Cisco plugin ;)
> >
> > 3438 +#from quantum.plugins.openvswitch.tests.test_vlan_map import
> > VlanMapTest
> >
> > Might as well nuke that line.. don't think its ever going to be used in this
> > file.
> >
> > 3740 +class QuantumDB(object):
> > 3741 + """Class conisting of methods to call Quantum db methods"""
> > 3742 + def get_all_networks(self, tenant_id):
> >
> > We should probably move this type of stuff into a library since other
> plugins
> > will want to use it. Not an issue for this merge though.
>
> Sure, we'll take this an action item.

Awesome, thanks.

review: Approve
72. By Rohit Agarwalla

pep8 error fixed for l2network_db.py

Revision history for this message
Salvatore Orlando (salvatore-orlando) wrote :
Download full text (4.3 KiB)

Hi Rohit,

thanks a lot for proposing this significant improvement on the Cisco plugin.
The code looks good, and, as usual, it is very well written and easy to understand.

I have a few comments below aimed at improving it or understanding whether some bits of it can be "promoted" to quantum core. Please let me know if you have any question.

(Relatively) Major comments:

1 === added file 'quantum/common/test_lib.py'
2 --- quantum/common/test_lib.py 1970-01-01 00:00:00 +0000
3 +++ quantum/common/test_lib.py 2011-08-18 18:13:27 +0000

This is strange. quantum/common/test_lib.py is already in trunk, and it seems it is identical to the one in this branch.

1104 +def create_vlanids():
1105 + """Prepopulates the vlan_bindings table"""
1106 + session = db.get_session()
1107 + try:
1108 + vlanid = session.query(l2network_models.VlanID).\
1109 + one()
1110 + except exc.MultipleResultsFound:
1111 + pass
1112 + except exc.NoResultFound:
1113 + start = int(conf.VLAN_START)
1114 + end = int(conf.VLAN_END)
1115 + while start <= end:
1116 + vlanid = l2network_models.VlanID(start)
1117 + session.add(vlanid)
1118 + start += 1
1119 + session.flush()
1120 + return

IMHO this routine could be improved. Pre-population is skipped if a single record is found in the DB. This means that if I change VLAN_START or VLAN_END and I do not destroy the DB, the DB will not be updated.

4168 -4323: These are unit tests specific for quantum.db. I'd propose to have them in a separate file in /tests/unit. Thank you very much for implementing these much-needed unit tests!!!

Minor comments:

335 + 5b. Enter the quantum_l2netowrk database configuration info in the
336 + quantum/plugins/cisco/conf/db_conn.ini file.

There's a typo in the first line (should be quantum_l2network)

348 your configuration of each of the above files hasn't gone a little kaka

'kaka'? Are you referring to the Real Madrid's Brazilian player :) ? I guess it means something like "screwed". No need to change it, it is just that this term is totally new to me.

1093 +import l2network_models

Please avoid relative imports

1180 + vlanids = session.query(l2network_models.VlanID).\
1181 + filter_by(vlan_used=False).\
1182 + all()
1183 + rvlan = vlanids[0]

IMHO using first() instead of all() will improve the efficiency of this routine.

1747 + LOG.debug("Loaded device plugin %s\n" % \

Python logging already adds newline at the end of line. This newline is therefore redundant, unless we need it for other reasons.

2788 -2789 : Indentation can be improved here

2798 + confstr = snipp.CMD_VLAN_CONF_SNIPPET % (vlanid, vlanname)
2799 + confstr = snipp.EXEC_CONF_PREFIX + confstr + snipp.EXEC_CONF_POSTFIX

Consider merging EXEC_CONF_PREFIX and POSTIFIX into a EXEC_CONF_SNIPPET.
Also, since line 2799 is repeated several times, consider moving it into a subroutine.

3144 +FILTER_SHOW_VLAN_BRIEF_SNIPPET = """
3145 + <show xmlns="http://www.cisco.com/nxos:1.0:vlan_mgr_cli">
3146 + <vlan>
3147 + <brief/>
3148 + </vlan>
3149 + </show> """

End delimiter for a docstring is usually in a new line, as you did for other docstrings in the same module.

3517 - 3905: L2NetworkDB and QuantumDB are wrappers around database apis...

Read more...

review: Needs Fixing
73. By Rohit Agarwalla

Fixes based on review comments

Revision history for this message
Rohit Agarwalla (rohitagarwalla) wrote :
Download full text (7.1 KiB)

Hi Salvatore,

Thank you very much for the meticulous review. Appreciate all of your comments. Please find responses in line.

> Hi Rohit,
>
> thanks a lot for proposing this significant improvement on the Cisco plugin.
> The code looks good, and, as usual, it is very well written and easy to
> understand.
>
Thank you !

> I have a few comments below aimed at improving it or understanding whether
> some bits of it can be "promoted" to quantum core. Please let me know if you
> have any question.
>
> (Relatively) Major comments:
>
> 1 === added file 'quantum/common/test_lib.py'
> 2 --- quantum/common/test_lib.py 1970-01-01 00:00:00 +0000
> 3 +++ quantum/common/test_lib.py 2011-08-18 18:13:27 +0000
>
> This is strange. quantum/common/test_lib.py is already in trunk, and it seems
> it is identical to the one in this branch.
>
This file wasn't touched at all in this branch. I have made a checkin based on some of the changes proposed below. I'll try to sync this branch with top of quantum and see if this diff file goes away.

> 1104 +def create_vlanids():
> 1105 + """Prepopulates the vlan_bindings table"""
> 1106 + session = db.get_session()
> 1107 + try:
> 1108 + vlanid = session.query(l2network_models.VlanID).\
> 1109 + one()
> 1110 + except exc.MultipleResultsFound:
> 1111 + pass
> 1112 + except exc.NoResultFound:
> 1113 + start = int(conf.VLAN_START)
> 1114 + end = int(conf.VLAN_END)
> 1115 + while start <= end:
> 1116 + vlanid = l2network_models.VlanID(start)
> 1117 + session.add(vlanid)
> 1118 + start += 1
> 1119 + session.flush()
> 1120 + return
>
> IMHO this routine could be improved. Pre-population is skipped if a single
> record is found in the DB. This means that if I change VLAN_START or VLAN_END
> and I do not destroy the DB, the DB will not be updated.
>

Fine observation. Currently, a changed config would require to start on a clean slate as the cleanup of the old config needs to happen at other levels as well. We realize this limitation and have made a note in the cisco plugins README file.

> 4168 -4323: These are unit tests specific for quantum.db. I'd propose to have
> them in a separate file in /tests/unit. Thank you very much for implementing
> these much-needed unit tests!!!
>

Thank you. I'd be very motivated to place them in the quantum framework structure. To begin with, we didn't want to propose directly and wanted to get comments if such tests could be useful (which seems like they are). Also, currently, at the quantum layer we dont have a mysql database that these tests need. I'm thinking of using in-memory database for these tests to run at the quantum level. I also have some extra tests within this class that needs changes at the db/api module (mentioned below). If you think the way it is currently is ok, then I already have this as an action item to followup/work on this as a separate activity.

>
> Minor comments:
>
> 335 + 5b. Enter the quantum_l2netowrk database configuration info in the
> 336 + quantum/plugins/cisco/conf/db_conn.ini file.
>
> There's a typo in the first line (should be quantum_l2network)
>
> 348 your conf...

Read more...

74. By Rohit Agarwalla

merging from lp:quantum

75. By Rohit Agarwalla

merging with lp:quantum

76. By Edgar Magana

Code changed base on Reviews
pep8 passed
pylint 9.10

Revision history for this message
Edgar Magana (emagana) wrote :

Salvatore and Brad,

Thank you so much for your review. Regarding the reviews on the Nexus these are my changes:

> 2788 -2789 : Indentation can be improved here
>
> 2798 + confstr = snipp.CMD_VLAN_CONF_SNIPPET % (vlanid, vlanname)
> 2799 + confstr = snipp.EXEC_CONF_PREFIX + confstr + snipp.EXEC_CONF_POSTFIX
>
> Consider merging EXEC_CONF_PREFIX and POSTIFIX into a EXEC_CONF_SNIPPET.
> Also, since line 2799 is repeated several times, consider moving it into a
> subroutine.

<Edgar> I did both, merged post and pre-fixs and also moved it to a subroutine.

>
> 3144 +FILTER_SHOW_VLAN_BRIEF_SNIPPET = """
> 3145 + <show xmlns="http://www.cisco.com/nxos:1.0:vlan_mgr_cli">
> 3146 + <vlan>
> 3147 + <brief/>
> 3148 + </vlan>
> 3149 + </show> """
> End delimiter for a docstring is usually in a new line, as you did for other
> docstrings in the same module.
>

<Edgar> I did add an extra line after "show" as salvatore suggested.

Thanks!

Revision history for this message
Salvatore Orlando (salvatore-orlando) wrote :
Download full text (8.4 KiB)

> Hi Salvatore,
>
> Thank you very much for the meticulous review. Appreciate all of your
> comments. Please find responses in line.
>
> > Hi Rohit,
> >
> > thanks a lot for proposing this significant improvement on the Cisco plugin.
> > The code looks good, and, as usual, it is very well written and easy to
> > understand.
> >
> Thank you !
>
> > I have a few comments below aimed at improving it or understanding whether
> > some bits of it can be "promoted" to quantum core. Please let me know if you
> > have any question.
> >
> > (Relatively) Major comments:
> >
> > 1 === added file 'quantum/common/test_lib.py'
> > 2 --- quantum/common/test_lib.py 1970-01-01 00:00:00 +0000
> > 3 +++ quantum/common/test_lib.py 2011-08-18 18:13:27 +0000
> >
> > This is strange. quantum/common/test_lib.py is already in trunk, and it
> seems
> > it is identical to the one in this branch.
> >
> This file wasn't touched at all in this branch. I have made a checkin based on
> some of the changes proposed below. I'll try to sync this branch with top of
> quantum and see if this diff file goes away.

It seems the problem disappeared with your latest push.

>
> > 1104 +def create_vlanids():
> > 1105 + """Prepopulates the vlan_bindings table"""
> > 1106 + session = db.get_session()
> > 1107 + try:
> > 1108 + vlanid = session.query(l2network_models.VlanID).\
> > 1109 + one()
> > 1110 + except exc.MultipleResultsFound:
> > 1111 + pass
> > 1112 + except exc.NoResultFound:
> > 1113 + start = int(conf.VLAN_START)
> > 1114 + end = int(conf.VLAN_END)
> > 1115 + while start <= end:
> > 1116 + vlanid = l2network_models.VlanID(start)
> > 1117 + session.add(vlanid)
> > 1118 + start += 1
> > 1119 + session.flush()
> > 1120 + return
> >
> > IMHO this routine could be improved. Pre-population is skipped if a single
> > record is found in the DB. This means that if I change VLAN_START or
> VLAN_END
> > and I do not destroy the DB, the DB will not be updated.
> >
>
> Fine observation. Currently, a changed config would require to start on a
> clean slate as the cleanup of the old config needs to happen at other levels
> as well. We realize this limitation and have made a note in the cisco plugins
> README file.

Fine.

>
> > 4168 -4323: These are unit tests specific for quantum.db. I'd propose to
> have
> > them in a separate file in /tests/unit. Thank you very much for implementing
> > these much-needed unit tests!!!
> >
>
> Thank you. I'd be very motivated to place them in the quantum framework
> structure. To begin with, we didn't want to propose directly and wanted to get
> comments if such tests could be useful (which seems like they are). Also,
> currently, at the quantum layer we dont have a mysql database that these tests
> need. I'm thinking of using in-memory database for these tests to run at the
> quantum level. I also have some extra tests within this class that needs
> changes at the db/api module (mentioned below). If you think the way it is
> currently is ok, then I already have this as an action item to followup/work
> on this as a separate activity.
>

I think they can stay in the cisco dir...

Read more...

review: Approve
Revision history for this message
Rohit Agarwalla (rohitagarwalla) wrote :
Download full text (4.4 KiB)

> > (Relatively) Major comments:
> >
> > 1 === added file 'quantum/common/test_lib.py'
> > 2 --- quantum/common/test_lib.py 1970-01-01 00:00:00 +0000
> > 3 +++ quantum/common/test_lib.py 2011-08-18 18:13:27 +0000
> >
> > This is strange. quantum/common/test_lib.py is already in trunk, and it
> seems
> > it is identical to the one in this branch.
> >
> This file wasn't touched at all in this branch. I have made a checkin based on
> some of the changes proposed below. I'll try to sync this branch with top of
> quantum and see if this diff file goes away.

It seems the problem disappeared with your latest push.

Rohit: Yes, a new test_lib.py seems to have been added in one of the revisions on lp:quantum. So, we had to ensure that the cisco branch had that new file to avoid the conflict.

>
> > 4168 -4323: These are unit tests specific for quantum.db. I'd propose to
> have
> > them in a separate file in /tests/unit. Thank you very much for implementing
> > these much-needed unit tests!!!
> >
>
> Thank you. I'd be very motivated to place them in the quantum framework
> structure. To begin with, we didn't want to propose directly and wanted to get
> comments if such tests could be useful (which seems like they are). Also,
> currently, at the quantum layer we dont have a mysql database that these tests
> need. I'm thinking of using in-memory database for these tests to run at the
> quantum level. I also have some extra tests within this class that needs
> changes at the db/api module (mentioned below). If you think the way it is
> currently is ok, then I already have this as an action item to followup/work
> on this as a separate activity.
>

I think they can stay in the cisco directory at the moment. I think we should move them into the main "tests" folder before diablo release though. I will post to the mailing list in order to decide together the best course of action.

Rohit: Sounds like a plan.

>
> > 3517 - 3905: L2NetworkDB and QuantumDB are wrappers around database apis
> uses
> > by test cases. For improve code readability, these classes are typycally put
> > in a separate module. (see /tests/unit/extensions)
> >
>
> Absolutely, I'd make this activity as part of moving the reusable tests to the
> quantum level (mentioned in the above comment)
>

No problem.

Rohit: Thanks.

> > Curiosities:
> >
> > 807 === added file 'quantum/plugins/cisco/db/api.py'
> >
> > Have you considered re-using the code in quantum/db/api.py? If yes, why
> wasn't
> > this code suitable for your needs? I'm asking because it seems this module
> > seems very similar to the db api in quantum.
> >
> > Similar comment for the module quantum/plugins/cisco/db/models.py
> > If the reason is the InnoDB engine then we can try and improve modules in
> > quantum/db, thus avoiding code duplication.
> >
>
> Yes, we have indeed considered to reuse this code. We have also preserved the
> credits/authors so that the reviewers are aware of it. Like its mentioned in
> the merge proposal, we made couple of changes in these modules -
> * specify mysql engine for models (InnoDB) - this engine imposes foreign key
> constraints
> * early loading of tables...

Read more...

Preview Diff

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

Subscribers

People subscribed via source and target branches