]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
blueprint quantum-packaging
authorTyler Smith <tylesmit@cisco.com>
Wed, 23 Feb 2011 01:42:24 +0000 (20:42 -0500)
committerTyler Smith <tylesmit@cisco.com>
Mon, 7 Mar 2011 23:02:05 +0000 (18:02 -0500)
Change-Id: Ica19170540b06ecddb0fbb6d340ee7a6819c1708

185 files changed:
README
bin/__init__.py [moved from quantum/common/__init__.py with 81% similarity]
bin/quantum
bin/quantum-server [new file with mode: 0755]
client/lib/__init__.py [moved from quantum/plugins/cisco/nova/__init__.py with 100% similarity]
client/lib/quantum/__init__.py [new file with mode: 0644]
client/lib/quantum/cli.py [moved from bin/cli with 99% similarity]
client/lib/quantum/cli_lib.py [moved from quantum/cli_lib.py with 100% similarity]
client/lib/quantum/client.py [moved from quantum/client.py with 99% similarity]
client/lib/quantum/tests/__init__.py [moved from tests/__init__.py with 100% similarity]
client/lib/quantum/tests/unit/__init__.py [moved from quantum/plugins/cisco/tests/unit/__init__.py with 85% similarity]
client/lib/quantum/tests/unit/test_clientlib.py [moved from tests/unit/test_clientlib.py with 99% similarity]
client/setup.py [new file with mode: 0644]
common/README [new file with mode: 0644]
common/lib/__init__.py [moved from quantum/plugins/openvswitch/__init__.py with 100% similarity]
common/lib/quantum/__init__.py [new file with mode: 0644]
common/lib/quantum/common/__init__.py [moved from quantum/__init__.py with 100% similarity]
common/lib/quantum/common/bufferedhttp.py [moved from quantum/common/bufferedhttp.py with 100% similarity]
common/lib/quantum/common/config.py [moved from quantum/common/config.py with 90% similarity]
common/lib/quantum/common/exceptions.py [moved from quantum/common/exceptions.py with 100% similarity]
common/lib/quantum/common/extensions.py [moved from quantum/common/extensions.py with 99% similarity]
common/lib/quantum/common/flags.py [moved from quantum/common/flags.py with 100% similarity]
common/lib/quantum/common/serializer.py [new file with mode: 0644]
common/lib/quantum/common/test_lib.py [moved from quantum/common/test_lib.py with 100% similarity]
common/lib/quantum/common/utils.py [moved from quantum/common/utils.py with 76% similarity]
common/lib/quantum/run_tests.py [new file with mode: 0644]
common/setup.py [new file with mode: 0644]
plugins/cisco-plugin/MANIFEST.in [new file with mode: 0644]
plugins/cisco-plugin/README [moved from quantum/plugins/cisco/README with 100% similarity]
plugins/cisco-plugin/etc/cisco_plugins.ini [moved from quantum/plugins/cisco/conf/plugins.ini with 100% similarity]
plugins/cisco-plugin/etc/credentials.ini [moved from quantum/plugins/cisco/conf/credentials.ini with 100% similarity]
plugins/cisco-plugin/etc/db_conn.ini [moved from quantum/plugins/cisco/conf/db_conn.ini with 100% similarity]
plugins/cisco-plugin/etc/l2network_plugin.ini [moved from quantum/plugins/cisco/conf/l2network_plugin.ini with 100% similarity]
plugins/cisco-plugin/etc/nexus.ini [moved from quantum/plugins/cisco/conf/nexus.ini with 100% similarity]
plugins/cisco-plugin/etc/quantum.conf.ciscoext [moved from quantum/plugins/cisco/conf/quantum.conf.ciscoext with 100% similarity]
plugins/cisco-plugin/etc/ucs.ini [moved from quantum/plugins/cisco/conf/ucs.ini with 100% similarity]
plugins/cisco-plugin/etc/ucs_inventory.ini [moved from quantum/plugins/cisco/conf/ucs_inventory.ini with 100% similarity]
plugins/cisco-plugin/lib/__init__.py [moved from quantum/plugins/openvswitch/tests/__init__.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/__init__.py [new file with mode: 0644]
plugins/cisco-plugin/lib/quantum/plugins/__init__.py [new file with mode: 0644]
plugins/cisco-plugin/lib/quantum/plugins/cisco/__init__.py [moved from quantum/plugins/cisco/__init__.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/client/cli.py [moved from quantum/plugins/cisco/client/cli.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/common/__init__.py [moved from quantum/plugins/cisco/common/__init__.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/common/cisco_configparser.py [moved from quantum/plugins/cisco/common/cisco_configparser.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/common/cisco_constants.py [moved from quantum/plugins/cisco/common/cisco_constants.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/common/cisco_credentials.py [moved from quantum/plugins/cisco/common/cisco_credentials.py with 91% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/common/cisco_exceptions.py [moved from quantum/plugins/cisco/common/cisco_exceptions.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/common/cisco_faults.py [moved from quantum/plugins/cisco/common/cisco_faults.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/common/cisco_utils.py [moved from quantum/plugins/cisco/common/cisco_utils.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/db/__init__.py [moved from quantum/plugins/cisco/db/__init__.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/db/api.py [moved from quantum/plugins/cisco/db/api.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/db/l2network_db.py [moved from quantum/plugins/cisco/db/l2network_db.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/db/l2network_models.py [moved from quantum/plugins/cisco/db/l2network_models.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/db/models.py [moved from quantum/plugins/cisco/db/models.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/db/nexus_db.py [moved from quantum/plugins/cisco/db/nexus_db.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/db/nexus_models.py [moved from quantum/plugins/cisco/db/nexus_models.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/db/ucs_db.py [moved from quantum/plugins/cisco/db/ucs_db.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/db/ucs_models.py [moved from quantum/plugins/cisco/db/ucs_models.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/l2device_inventory_base.py [moved from quantum/plugins/cisco/l2device_inventory_base.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/l2device_plugin_base.py [moved from quantum/plugins/cisco/l2device_plugin_base.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/l2network_model_base.py [moved from quantum/plugins/cisco/l2network_model_base.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/l2network_plugin.py [moved from quantum/plugins/cisco/l2network_plugin.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/l2network_plugin_configuration.py [moved from quantum/plugins/cisco/l2network_plugin_configuration.py with 81% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/l2network_segmentation_base.py [moved from quantum/plugins/cisco/l2network_segmentation_base.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/models/__init__.py [moved from quantum/plugins/cisco/models/__init__.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/models/l2network_multi_blade.py [moved from quantum/plugins/cisco/models/l2network_multi_blade.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/models/l2network_single_blade.py [moved from quantum/plugins/cisco/models/l2network_single_blade.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/nexus/__init__.py [moved from quantum/plugins/cisco/nexus/__init__.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/nexus/cisco_nexus_configuration.py [moved from quantum/plugins/cisco/nexus/cisco_nexus_configuration.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py [moved from quantum/plugins/cisco/nexus/cisco_nexus_network_driver.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/nexus/cisco_nexus_plugin.py [moved from quantum/plugins/cisco/nexus/cisco_nexus_plugin.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/nexus/cisco_nexus_snippets.py [moved from quantum/plugins/cisco/nexus/cisco_nexus_snippets.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/nova/__init__.py [new file with mode: 0644]
plugins/cisco-plugin/lib/quantum/plugins/cisco/nova/quantum_port_aware_scheduler.py [moved from quantum/plugins/cisco/nova/quantum_port_aware_scheduler.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/nova/vifdirect.py [moved from quantum/plugins/cisco/nova/vifdirect.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/segmentation/__init__.py [moved from quantum/plugins/cisco/segmentation/__init__.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py [moved from quantum/plugins/cisco/segmentation/l2network_vlan_mgr.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/ucs/__init__.py [moved from quantum/plugins/cisco/ucs/__init__.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/ucs/cisco_getvif.py [moved from quantum/plugins/cisco/ucs/cisco_getvif.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py [moved from quantum/plugins/cisco/ucs/cisco_ucs_configuration.py with 78% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/ucs/cisco_ucs_inventory.py [moved from quantum/plugins/cisco/ucs/cisco_ucs_inventory.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/ucs/cisco_ucs_inventory_configuration.py [moved from quantum/plugins/cisco/ucs/cisco_ucs_inventory_configuration.py with 83% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py [moved from quantum/plugins/cisco/ucs/cisco_ucs_network_driver.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/plugins/cisco/ucs/cisco_ucs_plugin.py [moved from quantum/plugins/cisco/ucs/cisco_ucs_plugin.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/tests/__init__.py [moved from quantum/plugins/cisco/tests/__init__.py with 81% similarity]
plugins/cisco-plugin/lib/quantum/tests/unit/__init__.py [moved from tests/unit/__init__.py with 85% similarity]
plugins/cisco-plugin/lib/quantum/tests/unit/test_cisco_extension.py [moved from quantum/plugins/cisco/tests/unit/test_cisco_extension.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/tests/unit/test_database.py [moved from quantum/plugins/cisco/tests/unit/test_database.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/tests/unit/test_l2networkApi.py [moved from quantum/plugins/cisco/tests/unit/test_l2networkApi.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/tests/unit/test_l2network_multi_blade.py [moved from quantum/plugins/cisco/tests/unit/test_l2network_multi_blade.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/tests/unit/test_nexus_plugin.py [moved from quantum/plugins/cisco/tests/unit/test_nexus_plugin.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/tests/unit/test_ucs_driver.py [moved from quantum/plugins/cisco/tests/unit/test_ucs_driver.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/tests/unit/test_ucs_inventory.py [moved from quantum/plugins/cisco/tests/unit/test_ucs_inventory.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/tests/unit/test_ucs_plugin.py [moved from quantum/plugins/cisco/tests/unit/test_ucs_plugin.py with 100% similarity]
plugins/cisco-plugin/lib/quantum/tests/unit/test_vlan_mgr.py [moved from quantum/plugins/cisco/tests/unit/test_vlan_mgr.py with 100% similarity]
plugins/cisco-plugin/setup.py [new file with mode: 0644]
plugins/openvswitch-plugin/MANIFEST.in [new file with mode: 0644]
plugins/openvswitch-plugin/README [moved from quantum/plugins/openvswitch/README with 100% similarity]
plugins/openvswitch-plugin/etc/ovs_quantum_plugin.ini [moved from quantum/plugins/openvswitch/ovs_quantum_plugin.ini with 100% similarity]
plugins/openvswitch-plugin/lib/__init__.py [new file with mode: 0644]
plugins/openvswitch-plugin/lib/quantum/__init__.py [new file with mode: 0644]
plugins/openvswitch-plugin/lib/quantum/plugins/__init__.py [new file with mode: 0644]
plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/Makefile [moved from quantum/plugins/openvswitch/Makefile with 100% similarity]
plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/__init__.py [new file with mode: 0644]
plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/agent/ovs_quantum_agent.py [moved from quantum/plugins/openvswitch/agent/ovs_quantum_agent.py with 100% similarity]
plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/agent/xenserver_install.sh [moved from quantum/plugins/openvswitch/agent/xenserver_install.sh with 100% similarity]
plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/ovs_db.py [moved from quantum/plugins/openvswitch/ovs_db.py with 100% similarity]
plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/ovs_models.py [moved from quantum/plugins/openvswitch/ovs_models.py with 100% similarity]
plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/ovs_quantum_plugin.py [moved from quantum/plugins/openvswitch/ovs_quantum_plugin.py with 97% similarity]
plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/run_tests.py [moved from quantum/plugins/openvswitch/run_tests.py with 100% similarity]
plugins/openvswitch-plugin/lib/quantum/tests/__init__.py [new file with mode: 0644]
plugins/openvswitch-plugin/lib/quantum/tests/unit/__init__.py [new file with mode: 0644]
plugins/openvswitch-plugin/lib/quantum/tests/unit/test_vlan_map.py [moved from quantum/plugins/openvswitch/tests/test_vlan_map.py with 100% similarity]
plugins/openvswitch-plugin/setup.py [new file with mode: 0644]
plugins/sample-plugin/lib/__init__.py [new file with mode: 0644]
plugins/sample-plugin/lib/quantum/__init__.py [new file with mode: 0644]
plugins/sample-plugin/lib/quantum/plugins/SamplePlugin.py [moved from quantum/plugins/SamplePlugin.py with 100% similarity]
plugins/sample-plugin/lib/quantum/plugins/__init__.py [new file with mode: 0644]
plugins/sample-plugin/setup.py [new file with mode: 0644]
quantum/plugins/cisco/run_tests.py [deleted file]
quantum/setup.py [new file with mode: 0644]
quantum/utils.py [deleted file]
run_tests.py [changed mode: 0644->0755]
run_tests.sh
server/MANIFEST.in [new file with mode: 0644]
server/etc/init.d/quantum-server [new file with mode: 0755]
server/etc/plugins.ini [moved from quantum/plugins.ini with 100% similarity]
server/etc/quantum.conf [moved from etc/quantum.conf with 100% similarity]
server/etc/quantum.conf.sample [moved from etc/quantum.conf.sample with 100% similarity]
server/etc/quantum.conf.test [moved from etc/quantum.conf.test with 89% similarity]
server/lib/__init__.py [new file with mode: 0644]
server/lib/quantum/__init__.py [new file with mode: 0644]
server/lib/quantum/api/__init__.py [moved from quantum/api/__init__.py with 99% similarity]
server/lib/quantum/api/api_common.py [moved from quantum/api/api_common.py with 99% similarity]
server/lib/quantum/api/attachments.py [moved from quantum/api/attachments.py with 100% similarity]
server/lib/quantum/api/faults.py [moved from quantum/api/faults.py with 99% similarity]
server/lib/quantum/api/networks.py [moved from quantum/api/networks.py with 100% similarity]
server/lib/quantum/api/ports.py [moved from quantum/api/ports.py with 100% similarity]
server/lib/quantum/api/versions.py [moved from quantum/api/versions.py with 98% similarity]
server/lib/quantum/api/views/__init__.py [moved from quantum/api/views/__init__.py with 100% similarity]
server/lib/quantum/api/views/attachments.py [moved from quantum/api/views/attachments.py with 100% similarity]
server/lib/quantum/api/views/networks.py [moved from quantum/api/views/networks.py with 100% similarity]
server/lib/quantum/api/views/ports.py [moved from quantum/api/views/ports.py with 100% similarity]
server/lib/quantum/api/views/versions.py [moved from quantum/api/views/versions.py with 100% similarity]
server/lib/quantum/db/__init__.py [moved from quantum/db/__init__.py with 100% similarity]
server/lib/quantum/db/api.py [moved from quantum/db/api.py with 100% similarity]
server/lib/quantum/db/models.py [moved from quantum/db/models.py with 100% similarity]
server/lib/quantum/extensions/__init__.py [moved from extensions/__init__.py with 100% similarity]
server/lib/quantum/extensions/_credential_view.py [moved from extensions/_credential_view.py with 100% similarity]
server/lib/quantum/extensions/_novatenant_view.py [moved from extensions/_novatenant_view.py with 100% similarity]
server/lib/quantum/extensions/_pprofiles.py [moved from extensions/_pprofiles.py with 100% similarity]
server/lib/quantum/extensions/_qos_view.py [moved from extensions/_qos_view.py with 100% similarity]
server/lib/quantum/extensions/credential.py [moved from extensions/credential.py with 100% similarity]
server/lib/quantum/extensions/multiport.py [moved from extensions/multiport.py with 100% similarity]
server/lib/quantum/extensions/novatenant.py [moved from extensions/novatenant.py with 100% similarity]
server/lib/quantum/extensions/portprofile.py [moved from extensions/portprofile.py with 100% similarity]
server/lib/quantum/extensions/qos.py [moved from extensions/qos.py with 100% similarity]
server/lib/quantum/manager.py [moved from quantum/manager.py with 76% similarity]
server/lib/quantum/quantum_plugin_base.py [moved from quantum/quantum_plugin_base.py with 100% similarity]
server/lib/quantum/server.py [new file with mode: 0755]
server/lib/quantum/service.py [moved from quantum/service.py with 99% similarity]
server/lib/quantum/tests/__init__.py [moved from quantum/plugins/__init__.py with 88% similarity]
server/lib/quantum/tests/unit/__init__.py [new file with mode: 0644]
server/lib/quantum/tests/unit/client_tools/__init__.py [moved from tests/unit/client_tools/__init__.py with 100% similarity]
server/lib/quantum/tests/unit/client_tools/stubs.py [moved from tests/unit/client_tools/stubs.py with 97% similarity]
server/lib/quantum/tests/unit/database_stubs.py [moved from tests/unit/database_stubs.py with 100% similarity]
server/lib/quantum/tests/unit/extension_stubs.py [moved from tests/unit/extension_stubs.py with 98% similarity]
server/lib/quantum/tests/unit/extensions/__init__.py [moved from tests/unit/extensions/__init__.py with 100% similarity]
server/lib/quantum/tests/unit/extensions/foxinsocks.py [moved from tests/unit/extensions/foxinsocks.py with 99% similarity]
server/lib/quantum/tests/unit/test_api.py [moved from tests/unit/test_api.py with 99% similarity]
server/lib/quantum/tests/unit/test_cli.py [moved from tests/unit/test_cli.py with 99% similarity]
server/lib/quantum/tests/unit/test_database.py [moved from tests/unit/test_database.py with 98% similarity]
server/lib/quantum/tests/unit/test_extensions.py [moved from tests/unit/test_extensions.py with 98% similarity]
server/lib/quantum/tests/unit/testlib_api.py [moved from tests/unit/testlib_api.py with 99% similarity]
server/lib/quantum/wsgi.py [moved from quantum/common/wsgi.py with 99% similarity]
server/setup.py [new file with mode: 0644]
setup.py
tools/__init__.py [new file with mode: 0644]
tools/build_debs.sh [new file with mode: 0755]
tools/build_rpms.sh [new file with mode: 0755]
tools/clean.sh [new file with mode: 0755]
tools/install_venv.py
tools/source_environment.py [new file with mode: 0644]
tools/source_nonplugin_environment.py [new file with mode: 0644]
tools/with_venv.sh

diff --git a/README b/README
index 560e4054ce839a35574918659417e940dc35b4b4..e70b1f4d98ce3b1733cc1b5d84d499b824dc2cc3 100644 (file)
--- a/README
+++ b/README
    implementation and enables them to switch out a plug-in by simple editing a
    config file - plugins.ini
 
+# -- Layout
+
+  The Quantum project includes 3 core packages:
+
+    quantum-common (General utils for Quantum and its plugins)
+    quantum-server (The actual Quantum service itself)
+    quantum-client (The Quantum CLI and API Python library)
+
+  As well as some plugins.
+
 # -- Dependencies
 
  The following python packages are required to run quantum.  These can be
@@ -44,6 +54,24 @@ this)
 3) Install packages with pip:
    $ pip install <package name>
 
+# -- Running from the source code
+
+  bin/quantum-server      #Server
+  bin/quantum             #CLI
+  sh run_tests.sh         #Tests
+
+# -- Installing from the source code
+
+  You have 3 options:
+    a) sudo python setup.py install
+       # Installs to /usr/lib, /usr/bin, /etc, etc
+
+    b) python setup.py install --user
+       # Install into $HOME/.local/...
+
+    c) python setup.py install --venv
+       # Creates and installs into a virtual-env at ~/.quantum-venv
+
 # -- Configuring Quantum plug-in
 
 1) Identify your desired plug-in.  Choose a plugin from one of he options in
@@ -60,29 +88,30 @@ this)
 
 # -- Launching the Quantum Service
 
-1) Start quantum using the following command [on the quantum service host]:
-~/src/quantum$ PYTHONPATH=.:$PYTHONPATH python bin/quantum etc/quantum.conf
-
-# -- Making requests against the Quantum Service
+  # If you're running from the source
+  bin/quantum-server
 
-Please refer to sample Web Service client code in:
+  # If you installed Quantum
+  quantum-server
 
-../quantum/test_scripts/miniclient.py
+# -- Making requests against the Quantum Service
 
-# -- CLI tools to program the Quantum-managed Cloud networking fabric
+  Quantum comes with a programmatic CLI that is driven by the Quantum Web
+  Service.  You can use the CLI by issuing the following command:
 
-Quantum comes with a programmatic CLI that is driven by the Quantum Web
-Service.  You can use the CLI by issuing the following command:
+  # If you're running from the source
+  bin/quantum
 
-~/src/quantum$ PYTHONPATH=.:$PYTHONPATH python quantum/cli.py
+  # If you installed Quantum
+  quantum
 
-This will show help all of the available commands.
+  This will show help all of the available commands.
 
-An example session looks like this:
+  An example session looks like this:
 
-$ export TENANT=t1
-$ PYTHONPATH=. python quantum/cli.py -v create_net $TENANT network1
-Created a new Virtual Network with ID:e754e7c0-a8eb-40e5-861a-b182d30c3441
+  $ export TENANT=t1
+  $ quantum -v create_net $TENANT network1
+  Created a new Virtual Network with ID:e754e7c0-a8eb-40e5-861a-b182d30c3441
 
 # -- Authentication and Authorization
 
@@ -102,12 +131,12 @@ pipeline = authN authZ extensions quantumapiapp
 The final step concerns configuring access to Keystone. The following attributes
 must be specified in the [filter:authN] section of quantum.conf:
 
-auth_host                      IP address or host name of the server where Keystone is running
-auth_port                      Port where the Keystone Admin API is listening
-auth_protocol          Protocol used for communicating with Keystone (http/https)
-auth_version           Keystone API version (default: 2.0)
-auth_admin_token       Keystone token for administrative access
-auth_admin_user                Keystone user with administrative rights
+auth_host           IP address or host name of the server where Keystone is running
+auth_port           Port where the Keystone Admin API is listening
+auth_protocol       Protocol used for communicating with Keystone (http/https)
+auth_version        Keystone API version (default: 2.0)
+auth_admin_token    Keystone token for administrative access
+auth_admin_user     Keystone user with administrative rights
 auth_admin_password Password for the user specified with auth_admin_user
 
 NOTE: aut_admin_token and auth_admin_user/password are exclusive. 
@@ -200,3 +229,11 @@ There are a few requirements to writing your own plugin:
 
   The QuantumEchoPlugin lists foxinsox in its supported_extension_aliases 
   and implements the method from FoxInSocksPluginInterface.
+
+# -- Building packages
+
+  rpms:
+    python setup.py build rpm
+
+  debs:
+    python setup.py build deb
similarity index 81%
rename from quantum/common/__init__.py
rename to bin/__init__.py
index 7e695ff08d5a0255a09f05d18898bbd991a13f50..8e233bcf4234451fcab777204729d542c64b2d16 100644 (file)
@@ -1,5 +1,6 @@
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011 Nicira Networks, Inc.
+
+# Copyright 2011 Cisco Systems
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -13,4 +14,8 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
-# @author: Somik Behera, Nicira Networks, Inc.
+#    @author: Tyler Smith, Cisco Systems
+import os
+import sys
+
+sys.path.append(os.path.join(os.getcwd(), 'tools'))
index 48abd18ae90a8689bc78d5924a67a7e0023875f2..649047493c4e61ce4f5e99238f9881fdc84c26b9 100755 (executable)
 # If ../quantum/__init__.py exists, add ../ to Python search path, so that
 # it will override what happens to be installed in /usr/(local/)lib/python...
 
-import gettext
-import optparse
-import os
-import sys
+import __init__
+import source_environment
+from quantum.cli import main as cli
 
-
-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
-                                   os.pardir,
-                                   os.pardir))
-if os.path.exists(os.path.join(possible_topdir, 'quantum', '__init__.py')):
-    sys.path.insert(0, possible_topdir)
-
-gettext.install('quantum', unicode=1)
-
-from quantum import service
-from quantum.common import config
-
-
-def create_options(parser):
-    """
-    Sets up the CLI and config-file options that may be
-    parsed and program commands.
-    :param parser: The option parser
-    """
-    config.add_common_options(parser)
-    config.add_log_options(parser)
-
-
-if __name__ == '__main__':
-    oparser = optparse.OptionParser(version='%%prog VERSION')
-    create_options(oparser)
-    (options, args) = config.parse_options(oparser)
-
-    try:
-        service = service.serve_wsgi(service.QuantumApiService,
-                                     options=options,
-                                     args=args)
-        service.wait()
-    except RuntimeError, e:
-        sys.exit("ERROR: %s" % e)
+cli()
diff --git a/bin/quantum-server b/bin/quantum-server
new file mode 100755 (executable)
index 0000000..d6b9fbe
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nicira Neworks, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+# If ../quantum/__init__.py exists, add ../ to Python search path, so that
+# it will override what happens to be installed in /usr/(local/)lib/python...
+
+import __init__
+import source_environment
+from quantum.server import main as server
+
+server()
diff --git a/client/lib/quantum/__init__.py b/client/lib/quantum/__init__.py
new file mode 100644 (file)
index 0000000..d407605
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
similarity index 99%
rename from bin/cli
rename to client/lib/quantum/cli.py
index 2bc1cb3d6da5f03b50866a19cff3f5948aba5108..138d75d5e6eebb15fbfc5b1e78124b880983de6f 100755 (executable)
--- a/bin/cli
@@ -112,7 +112,7 @@ def build_args(cmd, cmdargs, arglist):
     return args
 
 
-if __name__ == "__main__":
+def main():
     usagestr = "Usage: %prog [OPTIONS] <command> [args]"
     parser = OptionParser(usage=usagestr)
     parser.add_option("-H", "--host", dest="host",
similarity index 99%
rename from quantum/client.py
rename to client/lib/quantum/client.py
index cf72f8a7ec8233049871bdb398b71f711201148f..afba7efb94b7d48eb8d049300cd2993d32726144 100644 (file)
@@ -22,7 +22,7 @@ import socket
 import urllib
 
 from quantum.common import exceptions
-from quantum.common.wsgi import Serializer
+from quantum.common.serializer import Serializer
 
 LOG = logging.getLogger('quantum.client')
 EXCEPTIONS = {
similarity index 85%
rename from quantum/plugins/cisco/tests/unit/__init__.py
rename to client/lib/quantum/tests/unit/__init__.py
index 5910e354941d9135614d8e84a7add54efcb8675b..726786924dae91b338d06c38fafd1925d489d7cf 100644 (file)
 
 # See http://code.google.com/p/python-nose/issues/detail?id=373
 # The code below enables nosetests to work with i18n _() blocks
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
+
 import __builtin__
 import unittest
 setattr(__builtin__, '_', lambda x: x)
similarity index 99%
rename from tests/unit/test_clientlib.py
rename to client/lib/quantum/tests/unit/test_clientlib.py
index ce3e7186b0ef5d99910ce92fbf0e8bdc2331d08d..4e2c920c765f8a93cc601ac26765d17c5e11fee6 100644 (file)
@@ -20,7 +20,7 @@ import logging
 import unittest
 import re
 
-from quantum.common.wsgi import Serializer
+from quantum.common.serializer import Serializer
 from quantum.client import Client
 
 LOG = logging.getLogger('quantum.tests.test_api')
diff --git a/client/setup.py b/client/setup.py
new file mode 100644 (file)
index 0000000..b0d4a30
--- /dev/null
@@ -0,0 +1,57 @@
+try:
+    from setuptools import setup, find_packages
+except ImportError:
+    from ez_setup import use_setuptools
+    use_setuptools()
+    from setuptools import setup, find_packages
+
+Name = 'quantum-client'
+Url = "https://launchpad.net/quantum"
+Version = '2012.1-dev'
+License = 'Apache License 2.0'
+# Change as required
+Author = 'Netstack'
+AuthorEmail = 'netstack@lists.launchpad.net'
+Maintainer = ''
+Summary = 'Client functionalities for Quantum'
+ShortDescription = Summary
+Description = Summary
+
+requires = [
+    'quantum-common'
+]
+
+EagerResources = [
+    'quantum',
+]
+
+ProjectScripts = [
+]
+
+PackageData = {
+}
+
+
+setup(
+    name=Name,
+    version=Version,
+    url=Url,
+    author=Author,
+    author_email=AuthorEmail,
+    description=ShortDescription,
+    long_description=Description,
+    license=License,
+    scripts=ProjectScripts,
+    install_requires=requires,
+    include_package_data=True,
+    packages=find_packages('lib'),
+    package_data=PackageData,
+    package_dir={'': 'lib'},
+    eager_resources=EagerResources,
+    namespace_packages=['quantum'],
+    entry_points={
+        'console_scripts': [
+            'quantum = quantum.cli:main'
+        ]
+    },
+)
diff --git a/common/README b/common/README
new file mode 100644 (file)
index 0000000..51b0f1e
--- /dev/null
@@ -0,0 +1,239 @@
+# -- Welcome!
+
+  You have come across a cloud computing network fabric controller.  It has
+  identified itself as "Quantum."  It aims to tame your (cloud) networking!
+
+# -- Basics:
+
+1) Quantum REST API: Quantum supports a REST-ful programmatic interface to
+   manage your cloud networking fabric.
+
+2) Quantum Plugins: Quantum sports a plug-able architecture that allows
+   Quantum's REST API to be backed by various entities that can create a
+   cloud-class virtual networking fabric.  The advantages of this plug-able
+   architecture is two-folds:
+
+   a) Allows for ANY open-source project or commercial vendor to write a
+   Quantum plug-in.
+
+   b) Allows Quantum users to not be tied down to a single Quantum
+   implementation and enables them to switch out a plug-in by simple editing a
+   config file - plugins.ini
+
+# -- Layout
+
+  The Quantum project includes 3 core packages:
+
+    quantum-common (General utils for Quantum and its plugins)
+    quantum-server (The actual Quantum service itself)
+    quantum-client (The Quantum CLI and API Python library)
+
+  As well as some plugins.
+
+# -- Dependencies
+
+ The following python packages are required to run quantum.  These can be
+ installed using pip:
+
+ eventlet>=0.9.12
+ nose
+ Paste
+ PasteDeploy
+ pep8==0.5.0
+ python-gflags
+ routes
+ simplejson
+ webob
+ webtest
+
+1) Install easy_install (there is probably a distribution specific package for
+this)
+
+2) Install pip:
+   $ easy_install pip==dev
+3) Install packages with pip:
+   $ pip install <package name>
+
+# -- Running from the source code
+
+  bin/quantum-server      #Server
+  bin/quantum             #CLI
+  python run_tests.py     #Tests
+
+# -- Installing from the source code
+
+  You have 3 options:
+    a) sudo python setup.py install
+       # Installs to /usr/lib, /usr/bin, /etc, etc
+
+    b) python setup.py install --user
+       # Install into $HOME/.local/...
+
+    c) python setup.py install --venv
+       # Creates and installs into a virtual-env at ~/.quantum-venv
+
+# -- Configuring Quantum plug-in
+
+1) Identify your desired plug-in.  Choose a plugin from one of he options in
+   the quantum/plugins directory.
+
+2) Update plug-in configuration by editing the quantum/plugins.ini file and
+   modify "provider" property to point to the location of the Quantum plug-in.
+   It should specify the class path to the plugin and the class name (i.e. for
+   a plugin class MyPlugin in quantum/plugins/myplugin/myplugin.py the
+   provider would be: quantum.plugins.myplugin.myplugin.MyPlugin)
+
+3) Read the plugin specific README, this is usually found in the same
+   directory as your Quantum plug-in, and follow configuration instructions.
+
+# -- Launching the Quantum Service
+
+  # If you're running from the source
+  bin/quantum-server
+
+  # If you installed Quantum
+  quantum-server
+
+# -- Making requests against the Quantum Service
+
+  Quantum comes with a programmatic CLI that is driven by the Quantum Web
+  Service.  You can use the CLI by issuing the following command:
+
+  # If you're running from the source
+  bin/quantum
+
+  # If you installed Quantum
+  quantum
+
+  This will show help all of the available commands.
+
+  An example session looks like this:
+
+  $ export TENANT=t1
+  $ quantum -v create_net $TENANT network1
+  Created a new Virtual Network with ID:e754e7c0-a8eb-40e5-861a-b182d30c3441
+
+# -- Authentication and Authorization
+
+Requests to Quantum API are authenticated with the Keystone identity service
+using a token-based authentication protocol. 
+
+1) Enabling Authentication and Authorization
+The Keystone identity service is a requirement. It must be installed, although
+not necessarily on the same machine where Quantum is running; both Keystone's
+admin API and service API should be running
+
+Authentication and Authorization middleware should be enabled in the Quantum
+pipeline. To this aim, uncomment the following line in /etc/quantum.conf:
+
+pipeline = authN authZ extensions quantumapiapp
+
+The final step concerns configuring access to Keystone. The following attributes
+must be specified in the [filter:authN] section of quantum.conf:
+
+auth_host           IP address or host name of the server where Keystone is running
+auth_port           Port where the Keystone Admin API is listening
+auth_protocol       Protocol used for communicating with Keystone (http/https)
+auth_version        Keystone API version (default: 2.0)
+auth_admin_token    Keystone token for administrative access
+auth_admin_user     Keystone user with administrative rights
+auth_admin_password Password for the user specified with auth_admin_user
+
+NOTE: aut_admin_token and auth_admin_user/password are exclusive. 
+If both are specified, auth_admin_token has priority.
+
+2) Authenticating and Authorizing request for Quantum API 
+
+A user should first authenticate with Keystone, supplying user credentials;
+the Keystone service will return an authentication token, together with
+informations concerning token expirations and endpoint where that token can
+be used. 
+
+The authentication token must be included in every request for the Quantum
+API, in the 'X_AUTH_TOKEN' header. Quantum will look for the authentication
+token in this header, and validate it with the Keystone service.
+
+In order to validate authentication tokens, Quantum uses Keystone's
+administrative API. It therefore requires credentials for an administrative
+user, which can be specified in Quantum's configuration file
+(etc/quantum.conf)
+Either username and password, or an authentication token for an administrative
+user can be specified in the configuration file: 
+
+- Credentials:
+
+auth_admin_user = admin
+auth_admin_password = secrete
+
+- Admin token:
+
+auth_admin_token = 9a82c95a-99e9-4c3a-b5ee-199f6ba7ff04
+
+As of the current release, any user for a tenant is allowed to perform
+every operation on the networks owned by the tenant itself, except for
+plugging interfaces. In order to perform such operation, the user must have
+the Quantum:NetworkAdmin roles. Roles can be configured in Keystone using 
+the administrative API.
+
+
+# -- Writing your own Quantum plug-in
+
+If you wish the write your own Quantum plugin, please refer to some concrete as
+well as sample plugins available in:
+
+../quantum/quantum/plugins/.. directory.
+
+There are a few requirements to writing your own plugin:
+
+1) Your plugin should implement all methods defined in the
+   quantum/quantum_plugin_base.QuantumPluginBase class
+
+2) Copy your Quantum plug-in over to the quantum/quantum/plugins/.. directory
+
+3) The next step is to edit the plugins.ini file in the same directory
+   as QuantumPluginBase class and specify the location of your custom plugin
+   as the "provider"
+
+4) Launch the Quantum Service, and your plug-in is configured and ready to
+   manage a Cloud Networking Fabric.
+
+# -- Extensions
+
+1) Creating Extensions:
+   a) Extension files should be placed under ./extensions folder. 
+   b) The extension file should have a class with the same name as the filename. 
+      This class should implement the contract required by the extension framework. 
+      See ExtensionDescriptor class in ./quantum/common/extensions.py for details
+   c) To stop a file in ./extensions folder from being loaded as an extension, 
+      the filename should start with an "_"
+   For an example of an extension file look at Foxinsocks class in 
+   ./tests/unit/extensions/foxinsocks.py
+   The unit tests in ./tests/unit/test_extensions.py document all the ways in 
+   which you can use extensions
+
+2) Associating plugins with extensions:
+   a) A Plugin can advertize all the extensions it supports through the 
+     'supported_extension_aliases' attribute. Eg:
+      class SomePlugin:
+        ...
+        supported_extension_aliases = ['extension1_alias', 
+                                     'extension2_alias',
+                                     'extension3_alias']
+      Any extension not in this list will not be loaded for the plugin
+
+  b) Extension Interfaces for plugins (optional)
+     The extension can mandate an interface that plugins have to support with the
+     'get_plugin_interface' method in the extension.
+     For an example see the FoxInSocksPluginInterface in foxinsocks.py.
+
+  The QuantumEchoPlugin lists foxinsox in its supported_extension_aliases 
+  and implements the method from FoxInSocksPluginInterface.
+
+# -- Building packages
+
+  rpms:
+    python setup.py build rpm
+
+  debs:
+    python setup.py build deb
diff --git a/common/lib/quantum/__init__.py b/common/lib/quantum/__init__.py
new file mode 100644 (file)
index 0000000..d407605
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
similarity index 90%
rename from quantum/common/config.py
rename to common/lib/quantum/common/config.py
index 320c3b2cf0a9b076d62dc00faf117e0a8aa823d7..6cf47779d4c37310c69d791ab250e3f0d7db6f77 100644 (file)
@@ -38,7 +38,7 @@ DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s"
 DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
 
 FLAGS = flags.FLAGS
-LOG = logging.getLogger('quantum.common.wsgi')
+LOG = logging.getLogger('quantum.wsgi')
 
 
 def parse_options(parser, cli_args=None):
@@ -179,14 +179,14 @@ def setup_logging(options, conf):
         root_logger.addHandler(handler)
 
 
-def find_config_file(options, args):
+def find_config_file(options, args, config_file='quantum.conf'):
     """
     Return the first config file found.
 
     We search for the paste config file in the following order:
     * If --config-file option is used, use that
     * If args[0] is a file, use that
-    * Search for quantum.conf in standard directories:
+    * Search for the configuration file in standard directories:
         * .
         * ~.quantum/
         * ~
@@ -204,16 +204,31 @@ def find_config_file(options, args):
         if os.path.exists(args[0]):
             return fix_path(args[0])
 
-    # Handle standard directory search for quantum.conf
-    config_file_dirs = [fix_path(os.getcwd()),
-                        fix_path(os.path.join('~', '.quantum')),
+    dir_to_common = os.path.dirname(os.path.abspath(__file__))
+    root = os.path.join(dir_to_common, '..', '..', '..', '..')
+    # Handle standard directory search for the config file
+    config_file_dirs = [fix_path(os.path.join(os.getcwd(), 'server', 'etc')),
+                        fix_path(os.path.join('~', '.quantum-venv', 'etc',
+                                 'quantum')),
                         fix_path('~'),
                         os.path.join(FLAGS.state_path, 'etc'),
                         os.path.join(FLAGS.state_path, 'etc', 'quantum'),
+                        os.path.join(root, 'server', 'etc'),
+                        fix_path(os.path.join('~', '.local',
+                                              'etc', 'quantum')),
+                        '/usr/etc/quantum',
+                        '/usr/local/etc/quantum',
                         '/etc/quantum/',
                         '/etc']
+
+    if os.path.exists(os.path.join(root, 'plugins')):
+        plugins = [fix_path(os.path.join(root, 'plugins', p, 'etc'))
+                  for p in os.listdir(os.path.join(root, 'plugins'))]
+        plugins = [p for p in plugins if os.path.isdir(p)]
+        config_file_dirs.extend(plugins)
+
     for cfg_dir in config_file_dirs:
-        cfg_file = os.path.join(cfg_dir, 'quantum.conf')
+        cfg_file = os.path.join(cfg_dir, config_file)
         if os.path.exists(cfg_file):
             return cfg_file
 
similarity index 99%
rename from quantum/common/extensions.py
rename to common/lib/quantum/common/extensions.py
index 380572c0c2f7c16c4f3bcfc5b9b70f475010c846..b77ce75b9597bda8c9510710b66eaae5813d6e0e 100644 (file)
@@ -27,7 +27,7 @@ from gettext import gettext as _
 from abc import ABCMeta
 from quantum.common import exceptions
 from quantum.manager import QuantumManager
-from quantum.common import wsgi
+from quantum import wsgi
 
 LOG = logging.getLogger('quantum.common.extensions')
 
diff --git a/common/lib/quantum/common/serializer.py b/common/lib/quantum/common/serializer.py
new file mode 100644 (file)
index 0000000..b596cf8
--- /dev/null
@@ -0,0 +1,153 @@
+from xml.dom import minidom
+import webob.exc
+
+from quantum.common import utils
+
+
+class Serializer(object):
+    """Serializes and deserializes dictionaries to certain MIME types."""
+
+    def __init__(self, metadata=None, default_xmlns=None):
+        """Create a serializer based on the given WSGI environment.
+
+        'metadata' is an optional dict mapping MIME types to information
+        needed to serialize a dictionary to that type.
+
+        """
+        self.metadata = metadata or {}
+        self.default_xmlns = default_xmlns
+
+    def _get_serialize_handler(self, content_type):
+        handlers = {
+            'application/json': self._to_json,
+            'application/xml': self._to_xml,
+        }
+
+        try:
+            return handlers[content_type]
+        except Exception:
+            raise exception.InvalidContentType(content_type=content_type)
+
+    def serialize(self, data, content_type):
+        """Serialize a dictionary into the specified content type."""
+        return self._get_serialize_handler(content_type)(data)
+
+    def deserialize(self, datastring, content_type):
+        """Deserialize a string to a dictionary.
+
+        The string must be in the format of a supported MIME type.
+
+        """
+        try:
+            return self.get_deserialize_handler(content_type)(datastring)
+        except Exception:
+            raise webob.exc.HTTPBadRequest("Could not deserialize data")
+
+    def get_deserialize_handler(self, content_type):
+        handlers = {
+            'application/json': self._from_json,
+            'application/xml': self._from_xml,
+        }
+
+        try:
+            return handlers[content_type]
+        except Exception:
+            raise exception.InvalidContentType(content_type=content_type)
+
+    def _from_json(self, datastring):
+        return utils.loads(datastring)
+
+    def _from_xml(self, datastring):
+        xmldata = self.metadata.get('application/xml', {})
+        plurals = set(xmldata.get('plurals', {}))
+        node = minidom.parseString(datastring).childNodes[0]
+        return {node.nodeName: self._from_xml_node(node, plurals)}
+
+    def _from_xml_node(self, node, listnames):
+        """Convert a minidom node to a simple Python type.
+
+        listnames is a collection of names of XML nodes whose subnodes should
+        be considered list items.
+
+        """
+        if len(node.childNodes) == 1 and node.childNodes[0].nodeType == 3:
+            return node.childNodes[0].nodeValue
+        elif node.nodeName in listnames:
+            return [self._from_xml_node(n, listnames)
+                    for n in node.childNodes if n.nodeType != node.TEXT_NODE]
+        else:
+            result = dict()
+            for attr in node.attributes.keys():
+                result[attr] = node.attributes[attr].nodeValue
+            for child in node.childNodes:
+                if child.nodeType != node.TEXT_NODE:
+                    result[child.nodeName] = self._from_xml_node(child,
+                                                                 listnames)
+            return result
+
+    def _to_json(self, data):
+        return utils.dumps(data)
+
+    def _to_xml(self, data):
+        metadata = self.metadata.get('application/xml', {})
+        # We expect data to contain a single key which is the XML root.
+        root_key = data.keys()[0]
+        doc = minidom.Document()
+        node = self._to_xml_node(doc, metadata, root_key, data[root_key])
+
+        xmlns = node.getAttribute('xmlns')
+        if not xmlns and self.default_xmlns:
+            node.setAttribute('xmlns', self.default_xmlns)
+
+        return node.toprettyxml(indent='', newl='')
+
+    def _to_xml_node(self, doc, metadata, nodename, data):
+        """Recursive method to convert data members to XML nodes."""
+        result = doc.createElement(nodename)
+
+        # Set the xml namespace if one is specified
+        # TODO(justinsb): We could also use prefixes on the keys
+        xmlns = metadata.get('xmlns', None)
+        if xmlns:
+            result.setAttribute('xmlns', xmlns)
+        if type(data) is list:
+            collections = metadata.get('list_collections', {})
+            if nodename in collections:
+                metadata = collections[nodename]
+                for item in data:
+                    node = doc.createElement(metadata['item_name'])
+                    node.setAttribute(metadata['item_key'], str(item))
+                    result.appendChild(node)
+                return result
+            singular = metadata.get('plurals', {}).get(nodename, None)
+            if singular is None:
+                if nodename.endswith('s'):
+                    singular = nodename[:-1]
+                else:
+                    singular = 'item'
+            for item in data:
+                node = self._to_xml_node(doc, metadata, singular, item)
+                result.appendChild(node)
+        elif type(data) is dict:
+            collections = metadata.get('dict_collections', {})
+            if nodename in collections:
+                metadata = collections[nodename]
+                for k, v in data.items():
+                    node = doc.createElement(metadata['item_name'])
+                    node.setAttribute(metadata['item_key'], str(k))
+                    text = doc.createTextNode(str(v))
+                    node.appendChild(text)
+                    result.appendChild(node)
+                return result
+            attrs = metadata.get('attributes', {}).get(nodename, {})
+            for k, v in data.items():
+                if k in attrs:
+                    result.setAttribute(k, str(v))
+                else:
+                    node = self._to_xml_node(doc, metadata, k, v)
+                    result.appendChild(node)
+        else:
+            # Type is atom.
+            node = doc.createTextNode(str(data))
+            result.appendChild(node)
+        return result
similarity index 76%
rename from quantum/common/utils.py
rename to common/lib/quantum/common/utils.py
index 5662e7465a35c181bfa6a92814bc9065642afc27..849337a3b7f4221daac2908de46cfb680aec1ba0 100644 (file)
@@ -1,7 +1,6 @@
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
-# Copyright 2011 Nicira Networks, Inc
-# All Rights Reserved.
+# Copyright 2011, Nicira Networks, Inc.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
+#
+# Borrowed from nova code base, more utilities will be added/borrowed as and
+# when needed.
+# @author: Somik Behera, Nicira Networks, Inc.
+
+"""Utilities and helper functions."""
 
-"""
-System-level utilities and helper functions.
-"""
 import ConfigParser
 import datetime
 import exceptions as exception
-import flags
 import inspect
 import logging
 import os
@@ -29,10 +30,72 @@ import random
 import subprocess
 import socket
 import sys
+import base64
+import functools
+import json
+import re
+import string
+import struct
+import time
+import types
+
+from quantum.common import flags
+from quantum.common import exceptions as exception
+from quantum.common.exceptions import ProcessExecutionError
+
+
+def import_class(import_str):
+    """Returns a class from a string including module and class."""
+    mod_str, _sep, class_str = import_str.rpartition('.')
+    try:
+        __import__(mod_str)
+        return getattr(sys.modules[mod_str], class_str)
+    except (ImportError, ValueError, AttributeError), exc:
+        print(('Inner Exception: %s'), exc)
+        raise exception.ClassNotFound(class_name=class_str)
+
+
+def import_object(import_str):
+    """Returns an object including a module or module and class."""
+    try:
+        __import__(import_str)
+        return sys.modules[import_str]
+    except ImportError:
+        cls = import_class(import_str)
+        return cls()
+
+
+def to_primitive(value):
+    if type(value) is type([]) or type(value) is type((None,)):
+        o = []
+        for v in value:
+            o.append(to_primitive(v))
+        return o
+    elif type(value) is type({}):
+        o = {}
+        for k, v in value.iteritems():
+            o[k] = to_primitive(v)
+        return o
+    elif isinstance(value, datetime.datetime):
+        return str(value)
+    elif hasattr(value, 'iteritems'):
+        return to_primitive(dict(value.iteritems()))
+    elif hasattr(value, '__iter__'):
+        return to_primitive(list(value))
+    else:
+        return value
+
 
+def dumps(value):
+    try:
+        return json.dumps(value)
+    except TypeError:
+        pass
+    return json.dumps(to_primitive(value))
 
-from exceptions import ProcessExecutionError
 
+def loads(s):
+    return json.loads(s)
 
 TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
 FLAGS = flags.FLAGS
@@ -78,7 +141,7 @@ def import_class(import_str):
         return getattr(sys.modules[mod_str], class_str)
     except (ImportError, ValueError, AttributeError) as e:
         print e
-        raise exception.NotFound('Class %s cannot be found' % class_str)
+        raise exception.ClassNotFound(class_name=class_str)
 
 
 def import_object(import_str):
diff --git a/common/lib/quantum/run_tests.py b/common/lib/quantum/run_tests.py
new file mode 100644 (file)
index 0000000..7043196
--- /dev/null
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 OpenStack, LLC
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+
+
+"""Unittest runner for quantum
+
+To run all test::
+    python run_tests.py
+
+To run all unit tests::
+    python run_tests.py unit
+
+To run all functional tests::
+    python run_tests.py functional
+
+To run a single unit test::
+    python run_tests.py unit.test_stores:TestSwiftBackend.test_get
+
+To run a single functional test::
+    python run_tests.py functional.test_service:TestController.test_create
+
+To run a single unit test module::
+    python run_tests.py unit.test_stores
+
+To run a single functional test module::
+    python run_tests.py functional.test_stores
+"""
+
+import gettext
+import os
+import unittest
+import sys
+
+from quantum.common.test_lib import run_tests
+from nose import config
+from nose import core
+
+import quantum.tests.unit
+
+
+def main():
+    c = config.Config(stream=sys.stdout,
+                      env=os.environ,
+                      verbosity=3,
+                      includeExe=True,
+                      traverseNamespace=True,
+                      plugins=core.DefaultPluginManager())
+    c.configureWhere(quantum.tests.unit.__path__)
+    sys.exit(run_tests(c))
+
+if __name__ == "__main__":
+    main()
diff --git a/common/setup.py b/common/setup.py
new file mode 100644 (file)
index 0000000..f5ffb68
--- /dev/null
@@ -0,0 +1,67 @@
+try:
+    from setuptools import setup, find_packages
+except ImportError:
+    from ez_setup import use_setuptools
+    use_setuptools()
+    from setuptools import setup, find_packages
+
+Name = 'quantum-common'
+Url = "https://launchpad.net/quantum"
+Version = '2012.1-dev'
+License = 'Apache License 2.0'
+# Change as required
+Author = 'Netstack'
+AuthorEmail = 'netstack@lists.launchpad.net'
+Maintainer = ''
+Summary = 'Common functionalities for Quantum'
+ShortDescription = Summary
+Description = Summary
+
+requires = [
+    'eventlet>=0.9.12',
+    'Routes>=1.12.3',
+    'nose',
+    'Paste',
+    'PasteDeploy',
+    'pep8>=0.6.1',
+    'python-gflags',
+    'simplejson',
+    'sqlalchemy',
+    'webob',
+    'webtest'
+]
+
+EagerResources = [
+    'quantum',
+]
+
+ProjectScripts = [
+]
+
+PackageData = {
+}
+
+
+setup(
+    name=Name,
+    version=Version,
+    url=Url,
+    author=Author,
+    author_email=AuthorEmail,
+    description=ShortDescription,
+    long_description=Description,
+    license=License,
+    scripts=ProjectScripts,
+    install_requires=requires,
+    include_package_data=True,
+    packages=find_packages('lib'),
+    package_data=PackageData,
+    package_dir={'': 'lib'},
+    eager_resources=EagerResources,
+    namespace_packages=['quantum'],
+    entry_points={
+        'console_scripts': [
+            'quantum-tests = quantum.run_tests:main'
+        ]
+    },
+)
diff --git a/plugins/cisco-plugin/MANIFEST.in b/plugins/cisco-plugin/MANIFEST.in
new file mode 100644 (file)
index 0000000..8f08290
--- /dev/null
@@ -0,0 +1 @@
+include etc/*
diff --git a/plugins/cisco-plugin/lib/quantum/__init__.py b/plugins/cisco-plugin/lib/quantum/__init__.py
new file mode 100644 (file)
index 0000000..d407605
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/plugins/cisco-plugin/lib/quantum/plugins/__init__.py b/plugins/cisco-plugin/lib/quantum/plugins/__init__.py
new file mode 100644 (file)
index 0000000..d407605
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
similarity index 91%
rename from quantum/plugins/cisco/common/cisco_credentials.py
rename to plugins/cisco-plugin/lib/quantum/plugins/cisco/common/cisco_credentials.py
index e3f395f988cdf3df8d087991c3ad137ff98d6aac..1a1bae9235d5f2afd30326f5634778938888a71e 100644 (file)
 """
 
 import os
+import logging as LOG
 
+from quantum.common.config import find_config_file
 from quantum.plugins.cisco.common import cisco_configparser as confp
 from quantum.plugins.cisco.common import cisco_constants as const
 from quantum.plugins.cisco.common import cisco_exceptions as cexc
 from quantum.plugins.cisco.db import l2network_db as cdb
 
-TENANT = const.NETWORK_ADMIN
+LOG.basicConfig(level=LOG.WARN)
+LOG.getLogger(const.LOGGER_COMPONENT_NAME)
 
-CREDENTIALS_FILE = "../conf/credentials.ini"
+CREDENTIALS_FILE = find_config_file({}, None, "credentials.ini")
+TENANT = const.NETWORK_ADMIN
 
-cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
-                             + "/" + CREDENTIALS_FILE)
+cp = confp.CiscoConfigParser(CREDENTIALS_FILE)
 _creds_dictionary = cp.walk(cp.dummy)
 
 
similarity index 81%
rename from quantum/plugins/cisco/l2network_plugin_configuration.py
rename to plugins/cisco-plugin/lib/quantum/plugins/cisco/l2network_plugin_configuration.py
index ec20fcceb0cee6a6c886d1e7c4fbc2e09a1f5303..b4abf32da3051d2a9f81dc8c07addee55bfe1436 100644 (file)
 """
 
 import os
-
+from quantum.common.config import find_config_file
 from quantum.plugins.cisco.common import cisco_configparser as confp
 
-CONF_FILE = "conf/l2network_plugin.ini"
-
-CONF_PARSER_OBJ = confp.\
-CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
-"/" + CONF_FILE)
+CONF_FILE = find_config_file({}, None, "l2network_plugin.ini")
+CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
 
 """
 Reading the conf for the l2network_plugin
@@ -49,25 +46,22 @@ MAX_NETWORKS = SECTION_CONF['max_networks']
 SECTION_CONF = CONF_PARSER_OBJ['MODEL']
 MODEL_CLASS = SECTION_CONF['model_class']
 
+CONF_FILE = find_config_file({}, None, "cisco_plugins.ini")
+
 SECTION_CONF = CONF_PARSER_OBJ['SEGMENTATION']
 MANAGER_CLASS = SECTION_CONF['manager_class']
 
-CONF_FILE = "conf/plugins.ini"
 
-CONF_PARSER_OBJ = confp.\
-CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
-"/" + CONF_FILE)
+CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
 
 """
 Reading the config for the device plugins
 """
 PLUGINS = CONF_PARSER_OBJ.walk(CONF_PARSER_OBJ.dummy)
 
-CONF_FILE = "conf/db_conn.ini"
+CONF_FILE = find_config_file({}, None, "db_conn.ini")
 
-CONF_PARSER_OBJ = confp.\
-CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
-"/" + CONF_FILE)
+CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
 
 """
 Reading DB config for the Quantum DB
diff --git a/plugins/cisco-plugin/lib/quantum/plugins/cisco/nova/__init__.py b/plugins/cisco-plugin/lib/quantum/plugins/cisco/nova/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
similarity index 78%
rename from quantum/plugins/cisco/ucs/cisco_ucs_configuration.py
rename to plugins/cisco-plugin/lib/quantum/plugins/cisco/ucs/cisco_ucs_configuration.py
index a4fbec42b1b819a6b2132e8770611b5b3a6b7d7c..55921bf23c0d43086d9df370ff34273a008d97dd 100644 (file)
 """
 
 import os
-
+from quantum.common.config import find_config_file
 from quantum.plugins.cisco.common import cisco_configparser as confp
 
-CONF_FILE = "../conf/ucs.ini"
-
-CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
-                             + "/" + CONF_FILE)
+CP = confp.CiscoConfigParser(find_config_file({}, [], 'ucs.ini'))
 
 SECTION = CP['UCSM']
 UCSM_IP_ADDRESS = SECTION['ip_address']
@@ -38,9 +35,7 @@ PROFILE_NAME_PREFIX = SECTION['profile_name_prefix']
 SECTION = CP['DRIVER']
 UCSM_DRIVER = SECTION['name']
 
-CONF_FILE = "../conf/ucs_inventory.ini"
-
-CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
-                             + "/" + CONF_FILE)
+CP = confp.CiscoConfigParser(find_config_file({}, [],
+                             'ucs_inventory.ini'))
 
 INVENTORY = CP.walk(CP.dummy)
similarity index 83%
rename from quantum/plugins/cisco/ucs/cisco_ucs_inventory_configuration.py
rename to plugins/cisco-plugin/lib/quantum/plugins/cisco/ucs/cisco_ucs_inventory_configuration.py
index 3183658c369b7a6aa54879d62bc77ac8f82c7dbb..721ee11f5c15fc0e8eeb99216d6e4e3efe9bde8a 100644 (file)
 """
 
 import os
-
+from quantum.common.config import find_config_file
 from quantum.plugins.cisco.common import cisco_configparser as confp
 
-CONF_FILE = "../conf/ucs_inventory.ini"
-
-CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
-                             + "/" + CONF_FILE)
+CP = confp.CiscoConfigParser(find_config_file({}, [],
+                             'plugins/cisco/ucs_inventory.ini'))
 
 INVENTORY = CP.walk(CP.dummy)
similarity index 81%
rename from quantum/plugins/cisco/tests/__init__.py
rename to plugins/cisco-plugin/lib/quantum/tests/__init__.py
index db695fb0afb5d6a63f051006fba6aae6297a7414..383dfaa982311565ee1ded684855f4d2598afe1e 100644 (file)
@@ -16,3 +16,8 @@
 #
 # @author: Sumit Naiksatam, Cisco Systems, Inc.
 #
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
similarity index 85%
rename from tests/unit/__init__.py
rename to plugins/cisco-plugin/lib/quantum/tests/unit/__init__.py
index 5910e354941d9135614d8e84a7add54efcb8675b..726786924dae91b338d06c38fafd1925d489d7cf 100644 (file)
 
 # See http://code.google.com/p/python-nose/issues/detail?id=373
 # The code below enables nosetests to work with i18n _() blocks
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
+
 import __builtin__
 import unittest
 setattr(__builtin__, '_', lambda x: x)
diff --git a/plugins/cisco-plugin/setup.py b/plugins/cisco-plugin/setup.py
new file mode 100644 (file)
index 0000000..8b47f63
--- /dev/null
@@ -0,0 +1,72 @@
+try:
+    from setuptools import setup, find_packages
+except ImportError:
+    from ez_setup import use_setuptools
+    use_setuptools()
+    from setuptools import setup, find_packages
+
+import sys
+
+Name = 'quantum-cisco-plugin'
+ProjecUrl = ""
+Version = '0.1'
+License = 'Apache License 2.0'
+# Change as required
+Author = 'Cisco Systems'
+AuthorEmail = ''
+Maintainer = ''
+Summary = 'Cisco plugin for Quantum'
+ShortDescription = Summary
+Description = Summary
+
+requires = [
+    'quantum-common',
+    'quantum-server',
+]
+
+EagerResources = [
+    'quantum',
+]
+
+ProjectScripts = [
+]
+
+PackageData = {
+}
+
+# If we're installing server-wide, use an aboslute path for config
+# if not, use a relative path
+config_path = '/etc/quantum/plugins/cisco'
+relative_locations = ['--user', '--virtualenv', '--venv']
+if [x for x in relative_locations if x in sys.argv]:
+    config_path = 'etc/quantum/plugins/cisco'
+
+DataFiles = [
+    (config_path,
+    ['etc/credentials.ini', 'etc/l2network_plugin.ini', 'etc/nexus.ini',
+    'etc/ucs.ini', 'etc/cisco_plugins.ini', 'etc/db_conn.ini'])
+]
+
+setup(
+    name=Name,
+    version=Version,
+    author=Author,
+    author_email=AuthorEmail,
+    description=ShortDescription,
+    long_description=Description,
+    license=License,
+    scripts=ProjectScripts,
+    install_requires=requires,
+    include_package_data=True,
+    packages=find_packages('lib'),
+    package_data=PackageData,
+    data_files=DataFiles,
+    package_dir={'': 'lib'},
+    eager_resources=EagerResources,
+    namespace_packages=['quantum'],
+    entry_points={
+        'console_scripts': [
+            'quantum-cisco-tests = quantum.plugins.cisco.run_tests:main'
+        ]
+    },
+)
diff --git a/plugins/openvswitch-plugin/MANIFEST.in b/plugins/openvswitch-plugin/MANIFEST.in
new file mode 100644 (file)
index 0000000..8f08290
--- /dev/null
@@ -0,0 +1 @@
+include etc/*
diff --git a/plugins/openvswitch-plugin/lib/__init__.py b/plugins/openvswitch-plugin/lib/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/plugins/openvswitch-plugin/lib/quantum/__init__.py b/plugins/openvswitch-plugin/lib/quantum/__init__.py
new file mode 100644 (file)
index 0000000..d407605
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/plugins/openvswitch-plugin/lib/quantum/plugins/__init__.py b/plugins/openvswitch-plugin/lib/quantum/plugins/__init__.py
new file mode 100644 (file)
index 0000000..d407605
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/__init__.py b/plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
similarity index 97%
rename from quantum/plugins/openvswitch/ovs_quantum_plugin.py
rename to plugins/openvswitch-plugin/lib/quantum/plugins/openvswitch/ovs_quantum_plugin.py
index f25893e7f032f9e98e4b0ef4777fb4563b3a0692..70e895f8a1d9aa0b14eea64a355778186d9b3a27 100644 (file)
@@ -24,24 +24,18 @@ import os
 import sys
 
 from quantum.common import exceptions as q_exc
+from quantum.common.config import find_config_file
 from quantum.quantum_plugin_base import QuantumPluginBase
 
 import quantum.db.api as db
 import ovs_db
 
-CONF_FILE = "ovs_quantum_plugin.ini"
+CONF_FILE = find_config_file({}, None, "ovs_quantum_plugin.ini")
 
 LOG.basicConfig(level=LOG.WARN)
 LOG.getLogger("ovs_quantum_plugin")
 
 
-def find_config(basepath):
-    for root, dirs, files in os.walk(basepath):
-        if CONF_FILE in files:
-            return os.path.join(root, CONF_FILE)
-    return None
-
-
 class VlanMap(object):
     vlans = {}
 
diff --git a/plugins/openvswitch-plugin/lib/quantum/tests/__init__.py b/plugins/openvswitch-plugin/lib/quantum/tests/__init__.py
new file mode 100644 (file)
index 0000000..d407605
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/plugins/openvswitch-plugin/lib/quantum/tests/unit/__init__.py b/plugins/openvswitch-plugin/lib/quantum/tests/unit/__init__.py
new file mode 100644 (file)
index 0000000..d407605
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/plugins/openvswitch-plugin/setup.py b/plugins/openvswitch-plugin/setup.py
new file mode 100644 (file)
index 0000000..b52b3f4
--- /dev/null
@@ -0,0 +1,66 @@
+try:
+    from setuptools import setup, find_packages
+except ImportError:
+    from ez_setup import use_setuptools
+    use_setuptools()
+    from setuptools import setup, find_packages
+
+import sys
+
+Name = 'quantum-openvswitch-plugin'
+ProjecUrl = ""
+Version = '0.1'
+License = 'Apache License 2.0'
+# Change as required
+Author = 'Open vSwitch Team'
+AuthorEmail = 'discuss@openvswitch.org'
+Maintainer = ''
+Summary = 'OpenVSwitch plugin for Quantum'
+ShortDescription = Summary
+Description = Summary
+
+requires = [
+    'quantum-common',
+    'quantum-server',
+]
+
+EagerResources = [
+    'quantum',
+]
+
+ProjectScripts = [
+]
+
+PackageData = {
+}
+
+# If we're installing server-wide, use an aboslute path for config
+# if not, use a relative path
+config_path = '/etc/quantum/plugins/openvswitch'
+relative_locations = ['--user', '--virtualenv', '--venv']
+if [x for x in relative_locations if x in sys.argv]:
+    config_path = 'etc/quantum/plugins/openvswitch'
+
+DataFiles = [
+    (config_path,
+    ['etc/ovs_quantum_plugin.ini'])
+]
+
+setup(
+    name=Name,
+    version=Version,
+    author=Author,
+    author_email=AuthorEmail,
+    description=ShortDescription,
+    long_description=Description,
+    license=License,
+    scripts=ProjectScripts,
+    install_requires=requires,
+    include_package_data=True,
+    packages=find_packages('lib'),
+    package_data=PackageData,
+    data_files=DataFiles,
+    package_dir={'': 'lib'},
+    eager_resources=EagerResources,
+    namespace_packages=['quantum'],
+)
diff --git a/plugins/sample-plugin/lib/__init__.py b/plugins/sample-plugin/lib/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/plugins/sample-plugin/lib/quantum/__init__.py b/plugins/sample-plugin/lib/quantum/__init__.py
new file mode 100644 (file)
index 0000000..d407605
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/plugins/sample-plugin/lib/quantum/plugins/__init__.py b/plugins/sample-plugin/lib/quantum/plugins/__init__.py
new file mode 100644 (file)
index 0000000..d407605
--- /dev/null
@@ -0,0 +1,5 @@
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
diff --git a/plugins/sample-plugin/setup.py b/plugins/sample-plugin/setup.py
new file mode 100644 (file)
index 0000000..6a8097a
--- /dev/null
@@ -0,0 +1,55 @@
+try:
+    from setuptools import setup, find_packages
+except ImportError:
+    from ez_setup import use_setuptools
+    use_setuptools()
+    from setuptools import setup, find_packages
+
+Name = 'quantum-sample-plugin'
+ProjecUrl = "https://launchpad.net/quantum"
+Version = '2012.1-dev'
+License = 'Apache License 2.0'
+# Change as required
+Author = 'Netstack'
+AuthorEmail = 'netstack@lists.launchpad.net'
+Maintainer = ''
+Summary = 'Sample functionalities for Quantum'
+ShortDescription = Summary
+Description = Summary
+
+requires = [
+    'quantum-common',
+    'quantum-server',
+]
+
+EagerResources = [
+    'quantum',
+]
+
+ProjectScripts = [
+]
+
+PackageData = {
+}
+
+DataFiles = [
+]
+
+setup(
+    name=Name,
+    version=Version,
+    author=Author,
+    author_email=AuthorEmail,
+    description=ShortDescription,
+    long_description=Description,
+    license=License,
+    scripts=ProjectScripts,
+    install_requires=requires,
+    include_package_data=True,
+    packages=find_packages('lib'),
+    package_data=PackageData,
+    data_files=DataFiles,
+    package_dir={'': 'lib'},
+    eager_resources=EagerResources,
+    namespace_packages=['quantum'],
+)
diff --git a/quantum/plugins/cisco/run_tests.py b/quantum/plugins/cisco/run_tests.py
deleted file mode 100644 (file)
index 690e61b..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack, LLC
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License");
-#    you may not use this file except in compliance with the License.
-#    You may obtain a copy of the License at
-#
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS,
-#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#    See the License for the specific language governing permissions and
-#    limitations under the License.
-
-
-"""Unittest runner for quantum Cisco plugin
-
-This file should be run from the top dir in the quantum directory
-
-To run all test::
-    python quantum/plugins/cisco/run_tests.py
-
-To run all unit tests::
-    python quantum/plugins/cisco/run_tests.py quantum.plugins.cisco.tests.unit
-
-To run all functional tests::
-    python quantum/plugins/cisco/run_tests.py functional
-
-To run a single unit test::
-    python  quantum/plugins/cisco/run_tests.py \
-        quantum.plugins.cisco.tests.unit.test_stores:TestSwiftBackend.test_get
-
-To run a single functional test::
-    python  quantum/plugins/cisco/run_tests.py \
-    quantum.plugins.cisco.tests.functional.test_service \
-    :TestController.test_create
-
-To run a single unit test module::
-    python quantum/plugins/cisco/run_tests.py unit.test_stores
-
-To run a single functional test module::
-    python quantum/plugins/cisco/run_tests.py functional.test_stores
-"""
-
-import gettext
-import logging
-import os
-import unittest
-import sys
-
-from nose import config
-
-sys.path.append(os.getcwd())
-
-from quantum.common.test_lib import run_tests, test_config
-
-if __name__ == '__main__':
-    exit_status = False
-
-    # if a single test case was specified,
-    # we should only invoked the tests once
-    invoke_once = len(sys.argv) > 1
-
-    cwd = os.getcwd()
-
-    working_dir = os.path.abspath("tests")
-    c = config.Config(stream=sys.stdout,
-                      env=os.environ,
-                      verbosity=3,
-                      workingDir=working_dir)
-    exit_status = run_tests(c)
-
-    if invoke_once:
-        sys.exit(0)
-
-    os.chdir(cwd)
-
-    working_dir = os.path.abspath("quantum/plugins/cisco/tests")
-    c = config.Config(stream=sys.stdout,
-                      env=os.environ,
-                      verbosity=3,
-                      workingDir=working_dir)
-    exit_status = exit_status or run_tests(c)
-
-    sys.exit(exit_status)
diff --git a/quantum/setup.py b/quantum/setup.py
new file mode 100644 (file)
index 0000000..3693883
--- /dev/null
@@ -0,0 +1,49 @@
+try:
+    from setuptools import setup, find_packages
+except ImportError:
+    from ez_setup import use_setuptools
+    use_setuptools()
+    from setuptools import setup, find_packages
+
+Name = 'quantum'
+Url = "https://launchpad.net/quantum"
+Version = '2012.1-dev'
+License = 'Apache License 2.0'
+Author = 'Netstack'
+AuthorEmail = 'netstack@lists.launchpad.net'
+Maintainer = ''
+Summary = 'Layer 2 network as a service for Openstack'
+ShortDescription = Summary
+Description = Summary
+
+requires = [
+    'quantum-common',
+    'quantum-client',
+    'quantum-server'
+]
+
+EagerResources = [
+    'quantum',
+]
+
+ProjectScripts = [
+]
+
+PackageData = {
+}
+
+
+setup(
+    name=Name,
+    version=Version,
+    url=Url,
+    author=Author,
+    author_email=AuthorEmail,
+    description=ShortDescription,
+    long_description=Description,
+    license=License,
+    scripts=ProjectScripts,
+    install_requires=requires,
+    include_package_data=True,
+    package_data=PackageData,
+)
diff --git a/quantum/utils.py b/quantum/utils.py
deleted file mode 100644 (file)
index 508debb..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011, Nicira Networks, Inc.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-#
-# Borrowed from nova code base, more utilities will be added/borrowed as and
-# when needed.
-# @author: Somik Behera, Nicira Networks, Inc.
-
-"""Utilities and helper functions."""
-
-import base64
-import datetime
-import functools
-import inspect
-import json
-import os
-import random
-import re
-import socket
-import string
-import struct
-import sys
-import time
-import types
-
-from common import exceptions as exception
-
-
-def import_class(import_str):
-    """Returns a class from a string including module and class."""
-    mod_str, _sep, class_str = import_str.rpartition('.')
-    try:
-        __import__(mod_str)
-        return getattr(sys.modules[mod_str], class_str)
-    except (ImportError, ValueError, AttributeError), exc:
-        print(('Inner Exception: %s'), exc)
-        raise exception.ClassNotFound(class_name=class_str)
-
-
-def import_object(import_str):
-    """Returns an object including a module or module and class."""
-    try:
-        __import__(import_str)
-        return sys.modules[import_str]
-    except ImportError:
-        cls = import_class(import_str)
-        return cls()
-
-
-def to_primitive(value):
-    if type(value) is type([]) or type(value) is type((None,)):
-        o = []
-        for v in value:
-            o.append(to_primitive(v))
-        return o
-    elif type(value) is type({}):
-        o = {}
-        for k, v in value.iteritems():
-            o[k] = to_primitive(v)
-        return o
-    elif isinstance(value, datetime.datetime):
-        return str(value)
-    elif hasattr(value, 'iteritems'):
-        return to_primitive(dict(value.iteritems()))
-    elif hasattr(value, '__iter__'):
-        return to_primitive(list(value))
-    else:
-        return value
-
-
-def dumps(value):
-    try:
-        return json.dumps(value)
-    except TypeError:
-        pass
-    return json.dumps(to_primitive(value))
-
-
-def loads(s):
-    return json.loads(s)
old mode 100644 (file)
new mode 100755 (executable)
index 34d56c5..847b686
@@ -1,61 +1,5 @@
 #!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
+import tools.source_nonplugin_environment
+from quantum.run_tests import main as tests
 
-# Copyright 2010 OpenStack, LLC
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License");
-#    you may not use this file except in compliance with the License.
-#    You may obtain a copy of the License at
-#
-#        http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS,
-#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#    See the License for the specific language governing permissions and
-#    limitations under the License.
-
-
-"""Unittest runner for quantum
-
-To run all test::
-    python run_tests.py
-
-To run all unit tests::
-    python run_tests.py unit
-
-To run all functional tests::
-    python run_tests.py functional
-
-To run a single unit test::
-    python run_tests.py unit.test_stores:TestSwiftBackend.test_get
-
-To run a single functional test::
-    python run_tests.py functional.test_service:TestController.test_create
-
-To run a single unit test module::
-    python run_tests.py unit.test_stores
-
-To run a single functional test module::
-    python run_tests.py functional.test_stores
-"""
-
-import gettext
-import os
-import unittest
-import sys
-
-from quantum.common.test_lib import run_tests
-from nose import config
-from nose import core
-
-
-if __name__ == '__main__':
-    working_dir = os.path.abspath("tests")
-    c = config.Config(stream=sys.stdout,
-                      env=os.environ,
-                      verbosity=3,
-                      workingDir=working_dir,
-                      plugins=core.DefaultPluginManager())
-    sys.exit(run_tests(c))
+tests()
index aee422a623ab610c1b27ace2f3d31635c4b420f8..9b0a92c3443a29f4b0b0eb87be05d93ce130112c 100755 (executable)
@@ -102,7 +102,7 @@ fi
 #
 PEP8_EXCLUDE=vcsversion.py
 PEP8_OPTIONS="--exclude=$PEP8_EXCLUDE --repeat --show-source"
-PEP8_INCLUDE="bin/* quantum tests tools run_tests.py"
+PEP8_INCLUDE="bin/* quantum server client common plugins tools run_tests.py setup.py"
 RV=0
 run_tests && pep8 $PEP8_OPTIONS $PEP8_INCLUDE || RV=1
 
diff --git a/server/MANIFEST.in b/server/MANIFEST.in
new file mode 100644 (file)
index 0000000..a42c1a7
--- /dev/null
@@ -0,0 +1,2 @@
+include etc/*
+include etc/init.d/*
diff --git a/server/etc/init.d/quantum-server b/server/etc/init.d/quantum-server
new file mode 100755 (executable)
index 0000000..f526868
--- /dev/null
@@ -0,0 +1,68 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides:          quantum-server
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: quantum-server
+# Description:       Provides the Quantum networking service
+### END INIT INFO
+
+set -e
+
+PIDFILE=/var/run/quantum/quantum-server.pid
+LOGFILE=/var/log/quantum/quantum-server.log
+
+DAEMON=/usr/bin/quantum-server
+DAEMON_ARGS="--log-file=$LOGFILE"
+DAEMON_DIR=/var/run
+
+ENABLED=true
+
+if test -f /etc/default/quantum-server; then
+  . /etc/default/quantum-server
+fi
+
+mkdir -p /var/run/quantum
+mkdir -p /var/log/quantum
+
+. /lib/lsb/init-functions
+
+export PATH="${PATH:+$PATH:}/usr/sbin:/sbin"
+export TMPDIR=/var/lib/quantum/tmp
+
+if [ ! -x ${DAEMON} ] ; then
+       exit 0
+fi
+
+case "$1" in
+  start)
+    test "$ENABLED" = "true" || exit 0
+    log_daemon_msg "Starting quantum server" "quantum-server"
+    start-stop-daemon -Sbmv --pidfile $PIDFILE --chdir $DAEMON_DIR --exec $DAEMON -- $DAEMON_ARGS
+    log_end_msg $?
+    ;;
+  stop)
+    test "$ENABLED" = "true" || exit 0
+    log_daemon_msg "Stopping quantum server" "quantum-server"
+    start-stop-daemon --stop --oknodo --pidfile ${PIDFILE}
+    log_end_msg $?
+    ;;
+  restart|force-reload)
+    test "$ENABLED" = "true" || exit 1
+    $0 stop
+    sleep 1
+    $0 start
+    ;;
+  status)
+    test "$ENABLED" = "true" || exit 0
+    status_of_proc -p $PIDFILE $DAEMON quantum-server && exit 0 || exit $?
+    ;;
+  *)
+    log_action_msg "Usage: /etc/init.d/quantum-server {start|stop|restart|force-reload|status}"
+    exit 1
+    ;;
+esac
+
+exit 0
similarity index 100%
rename from quantum/plugins.ini
rename to server/etc/plugins.ini
similarity index 100%
rename from etc/quantum.conf
rename to server/etc/quantum.conf
similarity index 89%
rename from etc/quantum.conf.test
rename to server/etc/quantum.conf.test
index a7134d2848f78c3262792bc5b0bb9a61a33c2fe4..6157d5b0284e9c88396e7a63e3b215590651d621 100644 (file)
@@ -21,4 +21,4 @@ pipeline = extensions extensions_test_app
 paste.filter_factory = quantum.common.extensions:plugin_aware_extension_middleware_factory
 
 [app:extensions_test_app]
-paste.app_factory = tests.unit.test_extensions:app_factory
+paste.app_factory = quantum.tests.unit.test_extensions:app_factory
diff --git a/server/lib/__init__.py b/server/lib/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/server/lib/quantum/__init__.py b/server/lib/quantum/__init__.py
new file mode 100644 (file)
index 0000000..5846cd9
--- /dev/null
@@ -0,0 +1,21 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright 2011 Nicira Networks, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+# @author: Somik Behera, Nicira Networks, Inc.
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
similarity index 99%
rename from quantum/api/__init__.py
rename to server/lib/quantum/api/__init__.py
index ea02d26779525e1d1ca13d2d900e840556409128..4de6bce8d6efd2ea3631043b29d23b77e98e7148 100644 (file)
@@ -30,7 +30,7 @@ from quantum.api import attachments
 from quantum.api import networks
 from quantum.api import ports
 from quantum.common import flags
-from quantum.common import wsgi
+from quantum import wsgi
 
 
 LOG = logging.getLogger('quantum.api')
similarity index 99%
rename from quantum/api/api_common.py
rename to server/lib/quantum/api/api_common.py
index 8201f38b31c9d19bcc882331211d5adb22bfbb3b..11d56fd079ab94c59f2afb9cccb9e61f8f72ff35 100644 (file)
@@ -20,7 +20,7 @@ import webob
 
 from webob import exc
 
-from quantum.common import wsgi
+from quantum import wsgi
 
 XML_NS_V01 = 'http://netstack.org/quantum/api/v0.1'
 XML_NS_V10 = 'http://netstack.org/quantum/api/v1.0'
similarity index 99%
rename from quantum/api/faults.py
rename to server/lib/quantum/api/faults.py
index ef4d50bc6b27c59279257afb22927ebdb64bbe17..51cc9974c074b40590ded9dbadbd5939b4b316ca 100644 (file)
@@ -20,7 +20,7 @@ import webob.dec
 import webob.exc
 
 from quantum.api import api_common as common
-from quantum.common import wsgi
+from quantum import wsgi
 
 
 class Fault(webob.exc.HTTPException):
similarity index 98%
rename from quantum/api/versions.py
rename to server/lib/quantum/api/versions.py
index 2fd6812e293db9afb9b15312d463a4fd59769165..6e730b5e38f64112b2b6d249454f67f6d7070095 100644 (file)
@@ -18,7 +18,7 @@
 import logging
 import webob.dec
 
-from quantum.common import wsgi
+from quantum import wsgi
 from quantum.api.views import versions as versions_view
 
 LOG = logging.getLogger('quantum.api.versions')
similarity index 76%
rename from quantum/manager.py
rename to server/lib/quantum/manager.py
index 782b71cee7a622620f78a9756a3d88f16d570aa2..eb3ffba84d7f8b9f21e29ad691852074d3e6c4fc 100644 (file)
@@ -29,7 +29,9 @@ import os
 
 gettext.install('quantum', unicode=1)
 
-from common import utils
+from quantum.common import utils
+from quantum.common.config import find_config_file
+from quantum.common.exceptions import ClassNotFound
 from quantum_plugin_base import QuantumPluginBase
 
 LOG = logging.getLogger('quantum.manager')
@@ -49,19 +51,28 @@ class QuantumManager(object):
     _instance = None
 
     def __init__(self, options=None, config_file=None):
-        if config_file == None:
-            self.configuration_file = find_config(
-                os.path.abspath(os.path.dirname(__file__)))
-        else:
-            self.configuration_file = config_file
         # If no options have been provided, create an empty dict
         if not options:
             options = {}
+
+        if config_file:
+            config_file = [config_file]
+
+        self.configuration_file = find_config_file(options, config_file,
+                                                   CONFIG_FILE)
         if not 'plugin_provider' in options:
             options['plugin_provider'] = \
                 utils.get_plugin_from_config(self.configuration_file)
         LOG.debug("Plugin location:%s", options['plugin_provider'])
-        plugin_klass = utils.import_class(options['plugin_provider'])
+
+        # If the plugin can't be found let them know gracefully
+        try:
+            plugin_klass = utils.import_class(options['plugin_provider'])
+        except ClassNotFound:
+            raise Exception("Plugin not found.  You can install a " \
+                            "plugin with: pip install <plugin-name>\n" \
+                            "Example: pip install quantum-sample-plugin")
+
         if not issubclass(plugin_klass, QuantumPluginBase):
             raise Exception("Configured Quantum plug-in " \
                             "didn't pass compatibility test")
diff --git a/server/lib/quantum/server.py b/server/lib/quantum/server.py
new file mode 100755 (executable)
index 0000000..709eeda
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nicira Neworks, Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+# If ../quantum/__init__.py exists, add ../ to Python search path, so that
+# it will override what happens to be installed in /usr/(local/)lib/python...
+
+import gettext
+import optparse
+import os
+import sys
+
+
+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
+                                   os.pardir,
+                                   os.pardir))
+if os.path.exists(os.path.join(possible_topdir, 'quantum', '__init__.py')):
+    sys.path.insert(0, possible_topdir)
+
+gettext.install('quantum', unicode=1)
+
+from quantum import service
+from quantum.common import config
+
+
+def create_options(parser):
+    """
+    Sets up the CLI and config-file options that may be
+    parsed and program commands.
+    :param parser: The option parser
+    """
+    config.add_common_options(parser)
+    config.add_log_options(parser)
+
+
+def main():
+    oparser = optparse.OptionParser(version='%%prog VERSION')
+    create_options(oparser)
+    (options, args) = config.parse_options(oparser)
+
+    try:
+        quantum_service = service.serve_wsgi(service.QuantumApiService,
+                                     options=options,
+                                     args=args)
+        quantum_service.wait()
+    except RuntimeError, e:
+        sys.exit("ERROR: %s" % e)
+
+if __name__ == "__main__":
+    main()
similarity index 99%
rename from quantum/service.py
rename to server/lib/quantum/service.py
index 0c27bcc5b733f062e1874f09b956ae34b2441c19..307c9900dd98854def43c0cd7891dccebc16afba 100644 (file)
@@ -17,7 +17,7 @@
 
 import logging
 from quantum.common import config
-from quantum.common import wsgi
+from quantum import wsgi
 from quantum.common import exceptions as exception
 
 
similarity index 88%
rename from quantum/plugins/__init__.py
rename to server/lib/quantum/tests/__init__.py
index 7e695ff08d5a0255a09f05d18898bbd991a13f50..9578283b2d65e9ea45d938f9f20f71a12cb7eef4 100644 (file)
@@ -1,5 +1,6 @@
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright 2011 Nicira Networks, Inc.
+
+# Copyright 2011 OpenStack LLC.
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -13,4 +14,6 @@
 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 #    License for the specific language governing permissions and limitations
 #    under the License.
-# @author: Somik Behera, Nicira Networks, Inc.
+
+import logging
+logging.basicConfig()
diff --git a/server/lib/quantum/tests/unit/__init__.py b/server/lib/quantum/tests/unit/__init__.py
new file mode 100644 (file)
index 0000000..7267869
--- /dev/null
@@ -0,0 +1,38 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 OpenStack LLC.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+# See http://code.google.com/p/python-nose/issues/detail?id=373
+# The code below enables nosetests to work with i18n _() blocks
+try:
+    __import__('pkg_resources').declare_namespace(__name__)
+except ImportError:
+    from pkgutil import extend_path
+    __path__ = extend_path(__path__, __name__)
+
+import __builtin__
+import unittest
+setattr(__builtin__, '_', lambda x: x)
+
+
+class BaseTest(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+
+def setUp():
+    pass
similarity index 97%
rename from tests/unit/client_tools/stubs.py
rename to server/lib/quantum/tests/unit/client_tools/stubs.py
index 7b66cac59224244f5c5a4bc4e302f7bf3d3cf93d..99f1410d69e6a5cdbef76ec17fa3b367f6290c0e 100644 (file)
@@ -17,7 +17,7 @@
 
 
 from quantum import api as server
-from tests.unit import testlib_api
+from quantum.tests.unit import testlib_api
 
 
 class FakeStdout:
similarity index 98%
rename from tests/unit/extension_stubs.py
rename to server/lib/quantum/tests/unit/extension_stubs.py
index c8a7385f607006a9dd408c3828961e14baee0bff..09af1da60d20788ce311148832cc435201cde7a9 100644 (file)
@@ -16,7 +16,7 @@
 from abc import  abstractmethod
 
 from quantum.common import extensions
-from quantum.common import wsgi
+from quantum import wsgi
 
 
 class StubExtension(object):
similarity index 99%
rename from tests/unit/extensions/foxinsocks.py
rename to server/lib/quantum/tests/unit/extensions/foxinsocks.py
index 4a1aa2377fba686e3e18c4c364d973e9f965fddb..581aeefbd7fcd225b76cc9180826f0b4ccb6f9a6 100644 (file)
@@ -17,7 +17,7 @@
 
 import json
 
-from quantum.common import wsgi
+from quantum import wsgi
 from quantum.common import extensions
 from abc import  abstractmethod
 
similarity index 99%
rename from tests/unit/test_api.py
rename to server/lib/quantum/tests/unit/test_api.py
index ed5bdcbd377bffed802c48c1ee62106e5f1a34bd..0f5e4967e45d6478c9387aaea6286129a7be73b7 100644 (file)
 import logging
 import unittest
 
-import tests.unit.testlib_api as testlib
+
+import quantum.tests.unit.testlib_api as testlib
 
 from quantum import api as server
-from quantum.db import api as db
+from quantum.common.serializer import Serializer
 from quantum.common.test_lib import test_config
-from quantum.common.wsgi import Serializer
+from quantum.db import api as db
 
 LOG = logging.getLogger('quantum.tests.test_api')
 
similarity index 99%
rename from tests/unit/test_cli.py
rename to server/lib/quantum/tests/unit/test_cli.py
index 4e98391caefbf1933102c185d54447a5dbde7800..001db667901d30be345d420d7a7b6cb6ecf55607 100644 (file)
@@ -30,7 +30,7 @@ from quantum import api as server
 from quantum import cli_lib as cli
 from quantum.client import Client
 from quantum.db import api as db
-from tests.unit.client_tools import stubs as client_stubs
+from quantum.tests.unit.client_tools import stubs as client_stubs
 
 LOG = logging.getLogger('quantum.tests.test_cli')
 FORMAT = 'json'
similarity index 98%
rename from tests/unit/test_database.py
rename to server/lib/quantum/tests/unit/test_database.py
index 3e56b652e84409cc7b81e72e93eaf8538c9317a4..dae4f24664413606ac571c5267058bed582c730d 100644 (file)
@@ -24,7 +24,7 @@ import unittest
 
 
 from quantum.db import api as db
-from tests.unit import database_stubs as db_stubs
+from quantum.tests.unit import database_stubs as db_stubs
 
 
 LOG = logging.getLogger('quantum.tests.test_database')
similarity index 98%
rename from tests/unit/test_extensions.py
rename to server/lib/quantum/tests/unit/test_extensions.py
index a33897e47e837e554f51bce0f48d2725b4e91894..5309c28ddbe8d7a783ee2a138f2941a482ae42af 100644 (file)
 #    License for the specific language governing permissions and limitations
 #    under the License.
 import json
-import os.path
+import logging
+import os
 import routes
 import unittest
-from tests.unit import BaseTest
+from quantum.tests.unit import BaseTest
 from webtest import TestApp
 
 
-from quantum.common import wsgi
+from quantum import wsgi
 from quantum.common import config
 from quantum.common import extensions
 from quantum.plugins.SamplePlugin import QuantumEchoPlugin
-from tests.unit.extension_stubs import (StubExtension, StubPlugin,
+from quantum.tests.unit.extension_stubs import (StubExtension, StubPlugin,
                                         StubPluginInterface,
                                         StubBaseAppController,
                                         ExtensionExpectingPluginInterface)
@@ -33,9 +34,9 @@ from quantum.common.extensions import (ExtensionManager,
                                        PluginAwareExtensionManager,
                                        ExtensionMiddleware)
 
+LOG = logging.getLogger('test_extensions')
 
-test_conf_file = os.path.join(os.path.dirname(__file__), os.pardir,
-                              os.pardir, 'etc', 'quantum.conf.test')
+test_conf_file = config.find_config_file({}, None, "quantum.conf.test")
 extensions_path = os.path.join(os.path.dirname(__file__), "extensions")
 
 
similarity index 99%
rename from tests/unit/testlib_api.py
rename to server/lib/quantum/tests/unit/testlib_api.py
index cd3cce0063b520eb5dd9844f64f2ba029ba5bb1c..1b7214531a72afef0c9c7d28409b529514499194 100644 (file)
@@ -1,6 +1,6 @@
 import webob
 
-from quantum.common.wsgi import Serializer
+from quantum.common.serializer import Serializer
 
 
 def create_request(path, body, content_type, method='GET'):
similarity index 99%
rename from quantum/common/wsgi.py
rename to server/lib/quantum/wsgi.py
index 11fdd68c1eaa0b51d64551084c5d536658321adb..2bee9705d1ae455536b07ec6931962957dec7770 100644 (file)
@@ -31,7 +31,7 @@ from xml.dom import minidom
 
 
 from quantum.common import exceptions as exception
-from quantum import utils
+from quantum.common import utils
 
 
 LOG = logging.getLogger('quantum.common.wsgi')
diff --git a/server/setup.py b/server/setup.py
new file mode 100644 (file)
index 0000000..618a5d1
--- /dev/null
@@ -0,0 +1,76 @@
+try:
+    from setuptools import setup, find_packages
+except ImportError:
+    from ez_setup import use_setuptools
+    use_setuptools()
+    from setuptools import setup, find_packages
+
+import os
+import sys
+
+Name = 'quantum-server'
+Url = "https://launchpad.net/quantum"
+Version = '2012.1-dev'
+License = 'Apache License 2.0'
+Author = 'Netstatck'
+AuthorEmail = 'netstack@lists.launchpad.net'
+Maintainer = ''
+Summary = 'Server functionalities for Quantum'
+ShortDescription = Summary
+Description = Summary
+
+requires = [
+    'quantum-common'
+]
+
+EagerResources = [
+    'quantum',
+]
+
+ProjectScripts = [
+]
+
+PackageData = {
+}
+
+# If we're installing server-wide, use an aboslute path for config
+# if not, use a relative path
+config_path = '/etc/quantum/'
+init_path = '/etc/init.d'
+
+relative_locations = ['--user', '--virtualenv', '--venv']
+if [x for x in relative_locations if x in sys.argv]:
+    config_path = 'etc/quantum/'
+    init_path = 'etc/init.d'
+
+DataFiles = [
+    (config_path,
+    ['etc/quantum.conf', 'etc/quantum.conf.sample',
+     'etc/quantum.conf.test', 'etc/plugins.ini']),
+    (init_path, ['etc/init.d/quantum-server'])
+]
+
+setup(
+    name=Name,
+    version=Version,
+    url=Url,
+    author=Author,
+    author_email=AuthorEmail,
+    description=ShortDescription,
+    long_description=Description,
+    license=License,
+    scripts=ProjectScripts,
+    install_requires=requires,
+    include_package_data=True,
+    packages=find_packages('lib'),
+    package_data=PackageData,
+    data_files=DataFiles,
+    package_dir={'': 'lib'},
+    eager_resources=EagerResources,
+    namespace_packages=['quantum'],
+    entry_points={
+        'console_scripts': [
+            'quantum-server = quantum.server:main'
+        ]
+    },
+)
index 8ddc6fccf2b6526231f4c336b36b7906659b5af5..cdb14e4abcb3a5b75819ddcd9a927fa6c4ffb05b 100644 (file)
--- a/setup.py
+++ b/setup.py
-import os
+from copy import deepcopy
+from optparse import OptionParser
+from os import path
+import re
 import sys
-from setuptools import setup, find_packages
-
-
-def read(fname):
-    return open(os.path.join(os.path.dirname(__file__), fname)).read()
-
-requirements = ['httplib2', 'eventlet', 'routes', 'webob']
-
-setup(
-    name='Quantum',
-    version='0.1',
-    description='Layer 2 network as a service for Openstack',
-    long_description=read('README'),
-    url='http://launchpad.net/quantum',
-    license='Apache',
-    author='Netstack',
-    author_email='netstack@launchpad.net',
-    packages=find_packages(exclude=['tests']),
-    classifiers=[
-        'Development Status :: 4 - Beta',
-        'Environment :: Console',
-        'Intended Audience :: Developers',
-        'Intended Audience :: Information Technology',
-        'License :: OSI Approved :: BSD License',
-        'Operating System :: OS Independent',
-        'Programming Language :: Python',
-    ],
-    namespace_packages=["quantum"],
-    install_requires=requirements,
-
-    tests_require=["nose"],
-    test_suite="nose.collector",
-)
+
+from tools import install_venv
+
+ROOT = path.abspath(path.dirname(__file__))
+CONFIG_PATH = path.abspath('/etc/quantum')
+BASE_PACKAGES = ['common', 'server', 'client']
+PLUGINS = ['plugins/sample-plugin', 'plugins/cisco-plugin',
+           'plugins/openvswitch-plugin']
+
+RELATIVE = False
+
+
+def clean_path(dirty):
+    """Makes sure path delimiters are OS compliant"""
+    return path.join(*dirty.split('/'))
+
+
+def script_dir():
+    script_dir = '/usr/sbin/'
+    if RELATIVE:
+        script_dir = 'usr/sbin/'
+    return script_dir
+
+
+def create_parser():
+    """Setup the option parser"""
+    usagestr = "Usage: %prog [OPTIONS] <command> [args]"
+    parser = OptionParser(usage=usagestr)
+    parser.add_option("-V", "--virtualenv", "--venv", dest="venv",
+        action="store_true", default=False, help="Install to a virtual-env")
+    parser.add_option("-U", "--user", dest="user", action="store_true",
+        default=False, help="Install to users's home")
+    options, args = parser.parse_args()
+
+    if args.__len__() is 0:
+        print usagestr
+        print "Commands:\ninstall\nuninstall\nbuild\nclean"
+        exit(0)
+
+    cmd = args[0]
+    args = args[1:]
+    return (options, cmd, args)
+
+
+def install_packages(options, args=None):
+    """Builds and installs packages"""
+    # Start building a command list
+    cmd = ['pip', 'install']
+
+    # If no options, just a regular install.  If venv, create, prepare and
+    # install in venv.  If --user install in user's local dir.  Usually
+    # ~/.local/
+    if options.venv:
+        if install_venv.VENV_EXISTS:
+            print "Virtual-env exists"
+        else:
+            install_venv.create_virtualenv(install_pip=False)
+        install_venv.install_dependencies()
+        cmd.extend(['-E', install_venv.VENV])
+    elif options.user:
+        cmd.append('--user')
+
+    # Install packages
+    # TODO(Tyler) allow users to pass in packages in cli
+    for package in BASE_PACKAGES + PLUGINS:
+        print "Installing %s" % package
+        # Each package needs its own command list, and it needs the path
+        # in the correct place (after "pip install")
+        pcmd = deepcopy(cmd)
+        pcmd.insert(2, path.join(ROOT, clean_path(package)))
+
+        if package is 'server':
+            pcmd.append("--install-option=--install-scripts=%s" %\
+                        script_dir())
+        print pcmd
+        install_venv.run_command(pcmd)
+        print "done."
+
+
+def uninstall_packages(options, args=None):
+    """Removes packages"""
+    cmd = ['pip', 'uninstall', '-y']
+
+    for package in ['quantum-' + x.split('/')[-1] \
+                    for x in BASE_PACKAGES + PLUGINS]:
+        print "Uninstalling %s" % package
+        # Each package needs its own command list, and it needs the path
+        # in the correct place (after "pip uninstall"
+        pcmd = deepcopy(cmd)
+        pcmd.insert(2, package)
+        print pcmd
+        install_venv.run_command(pcmd)
+        print "done."
+
+
+def build_packages(options, args=None):
+    """Build RPM and/or deb packages"""
+    if not args:
+        print "To build packages you must specifiy either 'rpm', " \
+              "'deb', or 'all'"
+        exit(0)
+    if args[0] not in ['rpm', 'deb', 'all']:
+        raise Exception("Packge type must be rpm, deb, or all")
+
+    if 'rpm' in args or 'all' in args:
+        # Since we need to cd to build rpms, we call this sh script
+        cmd = ['tools/build_rpms.sh']
+        for package in BASE_PACKAGES + PLUGINS:
+            print "Building %s rpm" % package
+            pcmd = deepcopy(cmd)
+            pcmd.append(package)
+            install_venv.run_command(pcmd)
+            print "done."
+
+    if 'deb' in args or 'all' in args:
+        cmd = ['tools/build_debs.sh']
+        for p in BASE_PACKAGES + PLUGINS:
+            print "Building %s deb" % p
+            pcmd = deepcopy(cmd)
+            pcmd.append(p)
+            install_venv.run_command(pcmd)
+        print "done."
+
+
+def clean_packages(options, args):
+    """Cleans build packages"""
+    cmd = ["tools/clean.sh"]
+    install_venv.run_command(cmd)
+
+
+def main():
+    """Main Build script for Quantum"""
+    options, cmd, args = create_parser()
+
+    if options.user:
+        RELATIVE = True
+
+    print "Checking for virtual-env and easy_install"
+    install_venv.check_dependencies()
+
+    # Execute command
+    try:
+        globals()["%s_packages" % cmd](options, args)
+    except KeyError as exc:
+        print "Command %s' not found" % exc.__str__().split('_')[0]
+
+if __name__ == "__main__":
+    main()
diff --git a/tools/__init__.py b/tools/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tools/build_debs.sh b/tools/build_debs.sh
new file mode 100755 (executable)
index 0000000..5578763
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/bash
+ALIEN=`which alien`
+if [ $? -ne 0 ]; then
+       echo "You must have alien installed to build debian packages"
+       exit 1
+fi
+FAKEROOT=""
+if [ `id -u` != 0 ]; then
+       FAKEROOT=`which fakeroot`
+       if [ $? -ne 0 ]; then
+               echo "You must be root or have fakeroot installed to build debian packages"
+               exit 1
+       fi
+fi
+
+ls $@/dist/*.rpm >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+       echo "You must build rpms before building debian packages"
+       exit 1
+fi
+
+cd $@
+if [ $? -ne 0 ]; then
+       echo "Directory $@ doesn't exist -- what do you want me to build?"
+       exit 1
+fi
+$FAKEROOT $ALIEN -c -v -d dist/*.noarch.rpm
diff --git a/tools/build_rpms.sh b/tools/build_rpms.sh
new file mode 100755 (executable)
index 0000000..7ae6ef7
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+cd $@ && python setup.py bdist_rpm
diff --git a/tools/clean.sh b/tools/clean.sh
new file mode 100755 (executable)
index 0000000..c1deb84
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+rm -rf ./*.deb ./*.tar.gz ./*.dsc ./*.changes
+rm -rf */*.deb
+rm -rf ./plugins/**/build/ ./plugins/**/dist
+rm -rf ./plugins/**/lib/quantum_*_plugin.egg-info ./plugins/quantum-*
index 5c3ef374b6b4615a7725ac376a022af17f458ac3..f6fb708f062bf2890395b024d382ade54adcd6e1 100644 (file)
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
 # Copyright 2010 United States Government as represented by the
@@ -28,7 +29,8 @@ import sys
 
 
 ROOT = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
-VENV = os.path.join(ROOT, '.quantum-venv')
+VENV = os.path.expanduser('~/.quantum-venv')
+VENV_EXISTS = bool(os.path.exists(VENV))
 PIP_REQUIRES = os.path.join(ROOT, 'tools', 'pip-requires')
 
 
@@ -46,11 +48,10 @@ def run_command(cmd, redirect_output=True, check_exit_code=True):
         stdout = subprocess.PIPE
     else:
         stdout = None
-
     proc = subprocess.Popen(cmd, cwd=ROOT, stdout=stdout)
     output = proc.communicate()[0]
     if check_exit_code and proc.returncode != 0:
-        die('Command "%s" failed.\n%s', ' '.join(cmd), output)
+        raise Exception('Command "%s" failed.\n%s' % (' '.join(cmd), output))
     return output
 
 
@@ -64,27 +65,24 @@ def check_dependencies():
     """Make sure virtualenv is in the path."""
 
     if not HAS_VIRTUALENV:
-        print 'not found.'
-        # Try installing it via easy_install...
-        if HAS_EASY_INSTALL:
-            print 'Installing virtualenv via easy_install...',
-            if not run_command(['which', 'easy_install']):
-                die('ERROR: virtualenv not found.\n\n'
-                    'Quantum requires virtualenv, please install'
-                    ' it using your favorite package management tool')
-            print 'done.'
+        raise Exception('Virtualenv not found. ' + \
+                         'Try installing python-virtualenv')
     print 'done.'
 
 
-def create_virtualenv(venv=VENV):
+def create_virtualenv(venv=VENV, install_pip=False):
     """Creates the virtual environment and installs PIP only into the
     virtual environment
     """
     print 'Creating venv...',
-    run_command(['virtualenv', '-q', '--no-site-packages', VENV])
+
+    install = ['virtualenv', '-q', venv]
+    run_command(install)
+
     print 'done.'
     print 'Installing pip in virtualenv...',
-    if not run_command(['tools/with_venv.sh', 'easy_install', 'pip']).strip():
+    if install_pip and \
+            not run_command(['tools/with_venv.sh', 'easy_install', 'pip']):
         die("Failed to install pip.")
     print 'done.'
 
@@ -94,9 +92,8 @@ def install_dependencies(venv=VENV):
 
     # Install greenlet by hand - just listing it in the requires file does not
     # get it in stalled in the right order
-    venv_tool = 'tools/with_venv.sh'
-    run_command([venv_tool, 'pip', 'install', '-E', venv, '-r', PIP_REQUIRES],
-                redirect_output=False)
+    run_command(['tools/with_venv.sh', 'pip', 'install', '-E', venv,
+        '-r', PIP_REQUIRES], redirect_output=False)
 
     # Tell the virtual env how to "import quantum"
     pthfile = os.path.join(venv, "lib", "python2.6", "site-packages",
diff --git a/tools/source_environment.py b/tools/source_environment.py
new file mode 100644 (file)
index 0000000..960225c
--- /dev/null
@@ -0,0 +1,28 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Cisco Systems
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+#    @author: Tyler Smith, Cisco Systems
+import os
+import sys
+
+# To run from the source code, we need to add the various packages
+# to our path so we can find all of the modules correctly
+packages = ['common', 'server', 'client']
+plugins = ["plugins/%s" % p for p in
+              os.listdir(os.path.join(os.getcwd(), 'plugins'))]
+
+for project in packages + plugins:
+    sys.path.insert(0, os.path.join(os.getcwd(), project, 'lib'))
diff --git a/tools/source_nonplugin_environment.py b/tools/source_nonplugin_environment.py
new file mode 100644 (file)
index 0000000..0891c2f
--- /dev/null
@@ -0,0 +1,26 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Cisco Systems
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+#    @author: Tyler Smith, Cisco Systems
+import os
+import sys
+
+# To run from the source code, we need to add the various packages
+# to our path so we can find all of the modules correctly
+packages = ['common', 'server', 'client']
+
+for project in packages + ["plugins/sample-plugin"]:
+    sys.path.insert(0, os.path.join(os.getcwd(), project, 'lib'))
index 83149462c1aa06520a7ea6ea4e49c48bee2a231b..88444a24030c2fadefbaae25d1290268a1253b7a 100755 (executable)
@@ -17,5 +17,5 @@
 #    under the License.
 
 TOOLS=`dirname $0`
-VENV=$TOOLS/../.quantum-venv
+VENV=~/.quantum-venv
 source $VENV/bin/activate && $@