blueprint quantum-packaging
Change-Id: Ica19170540b06ecddb0fbb6d340ee7a6819c1708
This commit is contained in:
parent
e767b8f463
commit
24b0207cbe
57
README
57
README
@ -20,6 +20,16 @@
|
|||||||
implementation and enables them to switch out a plug-in by simple editing a
|
implementation and enables them to switch out a plug-in by simple editing a
|
||||||
config file - plugins.ini
|
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
|
# -- Dependencies
|
||||||
|
|
||||||
The following python packages are required to run quantum. These can be
|
The following python packages are required to run quantum. These can be
|
||||||
@ -44,6 +54,24 @@ this)
|
|||||||
3) Install packages with pip:
|
3) Install packages with pip:
|
||||||
$ pip install <package name>
|
$ 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
|
# -- Configuring Quantum plug-in
|
||||||
|
|
||||||
1) Identify your desired plug-in. Choose a plugin from one of he options in
|
1) Identify your desired plug-in. Choose a plugin from one of he options in
|
||||||
@ -60,28 +88,29 @@ this)
|
|||||||
|
|
||||||
# -- Launching the Quantum Service
|
# -- Launching the Quantum Service
|
||||||
|
|
||||||
1) Start quantum using the following command [on the quantum service host]:
|
# If you're running from the source
|
||||||
~/src/quantum$ PYTHONPATH=.:$PYTHONPATH python bin/quantum etc/quantum.conf
|
bin/quantum-server
|
||||||
|
|
||||||
|
# If you installed Quantum
|
||||||
|
quantum-server
|
||||||
|
|
||||||
# -- Making requests against the Quantum Service
|
# -- Making requests against the Quantum Service
|
||||||
|
|
||||||
Please refer to sample Web Service client code in:
|
|
||||||
|
|
||||||
../quantum/test_scripts/miniclient.py
|
|
||||||
|
|
||||||
# -- CLI tools to program the Quantum-managed Cloud networking fabric
|
|
||||||
|
|
||||||
Quantum comes with a programmatic CLI that is driven by the Quantum Web
|
Quantum comes with a programmatic CLI that is driven by the Quantum Web
|
||||||
Service. You can use the CLI by issuing the following command:
|
Service. You can use the CLI by issuing the following command:
|
||||||
|
|
||||||
~/src/quantum$ PYTHONPATH=.:$PYTHONPATH python quantum/cli.py
|
# If you're running from the source
|
||||||
|
bin/quantum
|
||||||
|
|
||||||
|
# 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
|
$ export TENANT=t1
|
||||||
$ PYTHONPATH=. python quantum/cli.py -v create_net $TENANT network1
|
$ quantum -v create_net $TENANT network1
|
||||||
Created a new Virtual Network with ID:e754e7c0-a8eb-40e5-861a-b182d30c3441
|
Created a new Virtual Network with ID:e754e7c0-a8eb-40e5-861a-b182d30c3441
|
||||||
|
|
||||||
# -- Authentication and Authorization
|
# -- Authentication and Authorization
|
||||||
@ -200,3 +229,11 @@ There are a few requirements to writing your own plugin:
|
|||||||
|
|
||||||
The QuantumEchoPlugin lists foxinsox in its supported_extension_aliases
|
The QuantumEchoPlugin lists foxinsox in its supported_extension_aliases
|
||||||
and implements the method from FoxInSocksPluginInterface.
|
and implements the method from FoxInSocksPluginInterface.
|
||||||
|
|
||||||
|
# -- Building packages
|
||||||
|
|
||||||
|
rpms:
|
||||||
|
python setup.py build rpm
|
||||||
|
|
||||||
|
debs:
|
||||||
|
python setup.py build deb
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
# Copyright 2011 Nicira Networks, Inc.
|
|
||||||
|
# Copyright 2011 Cisco Systems
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# 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'))
|
43
bin/quantum
43
bin/quantum
@ -19,43 +19,8 @@
|
|||||||
# If ../quantum/__init__.py exists, add ../ to Python search path, so that
|
# 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...
|
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||||
|
|
||||||
import gettext
|
import __init__
|
||||||
import optparse
|
import source_environment
|
||||||
import os
|
from quantum.cli import main as cli
|
||||||
import sys
|
|
||||||
|
|
||||||
|
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)
|
|
||||||
|
26
bin/quantum-server
Executable file
26
bin/quantum-server
Executable file
@ -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()
|
5
client/lib/quantum/__init__.py
Normal file
5
client/lib/quantum/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
try:
|
||||||
|
__import__('pkg_resources').declare_namespace(__name__)
|
||||||
|
except ImportError:
|
||||||
|
from pkgutil import extend_path
|
||||||
|
__path__ = extend_path(__path__, __name__)
|
@ -112,7 +112,7 @@ def build_args(cmd, cmdargs, arglist):
|
|||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def main():
|
||||||
usagestr = "Usage: %prog [OPTIONS] <command> [args]"
|
usagestr = "Usage: %prog [OPTIONS] <command> [args]"
|
||||||
parser = OptionParser(usage=usagestr)
|
parser = OptionParser(usage=usagestr)
|
||||||
parser.add_option("-H", "--host", dest="host",
|
parser.add_option("-H", "--host", dest="host",
|
@ -22,7 +22,7 @@ import socket
|
|||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
from quantum.common import exceptions
|
from quantum.common import exceptions
|
||||||
from quantum.common.wsgi import Serializer
|
from quantum.common.serializer import Serializer
|
||||||
|
|
||||||
LOG = logging.getLogger('quantum.client')
|
LOG = logging.getLogger('quantum.client')
|
||||||
EXCEPTIONS = {
|
EXCEPTIONS = {
|
@ -17,6 +17,12 @@
|
|||||||
|
|
||||||
# See http://code.google.com/p/python-nose/issues/detail?id=373
|
# See http://code.google.com/p/python-nose/issues/detail?id=373
|
||||||
# The code below enables nosetests to work with i18n _() blocks
|
# 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 __builtin__
|
||||||
import unittest
|
import unittest
|
||||||
setattr(__builtin__, '_', lambda x: x)
|
setattr(__builtin__, '_', lambda x: x)
|
@ -20,7 +20,7 @@ import logging
|
|||||||
import unittest
|
import unittest
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from quantum.common.wsgi import Serializer
|
from quantum.common.serializer import Serializer
|
||||||
from quantum.client import Client
|
from quantum.client import Client
|
||||||
|
|
||||||
LOG = logging.getLogger('quantum.tests.test_api')
|
LOG = logging.getLogger('quantum.tests.test_api')
|
57
client/setup.py
Normal file
57
client/setup.py
Normal file
@ -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'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
239
common/README
Normal file
239
common/README
Normal file
@ -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
|
5
common/lib/quantum/__init__.py
Normal file
5
common/lib/quantum/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
try:
|
||||||
|
__import__('pkg_resources').declare_namespace(__name__)
|
||||||
|
except ImportError:
|
||||||
|
from pkgutil import extend_path
|
||||||
|
__path__ = extend_path(__path__, __name__)
|
@ -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"
|
DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
LOG = logging.getLogger('quantum.common.wsgi')
|
LOG = logging.getLogger('quantum.wsgi')
|
||||||
|
|
||||||
|
|
||||||
def parse_options(parser, cli_args=None):
|
def parse_options(parser, cli_args=None):
|
||||||
@ -179,14 +179,14 @@ def setup_logging(options, conf):
|
|||||||
root_logger.addHandler(handler)
|
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.
|
Return the first config file found.
|
||||||
|
|
||||||
We search for the paste config file in the following order:
|
We search for the paste config file in the following order:
|
||||||
* If --config-file option is used, use that
|
* If --config-file option is used, use that
|
||||||
* If args[0] is a file, 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/
|
* ~.quantum/
|
||||||
* ~
|
* ~
|
||||||
@ -204,16 +204,31 @@ def find_config_file(options, args):
|
|||||||
if os.path.exists(args[0]):
|
if os.path.exists(args[0]):
|
||||||
return fix_path(args[0])
|
return fix_path(args[0])
|
||||||
|
|
||||||
# Handle standard directory search for quantum.conf
|
dir_to_common = os.path.dirname(os.path.abspath(__file__))
|
||||||
config_file_dirs = [fix_path(os.getcwd()),
|
root = os.path.join(dir_to_common, '..', '..', '..', '..')
|
||||||
fix_path(os.path.join('~', '.quantum')),
|
# 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('~'),
|
fix_path('~'),
|
||||||
os.path.join(FLAGS.state_path, 'etc'),
|
os.path.join(FLAGS.state_path, 'etc'),
|
||||||
os.path.join(FLAGS.state_path, 'etc', 'quantum'),
|
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/quantum/',
|
||||||
'/etc']
|
'/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:
|
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):
|
if os.path.exists(cfg_file):
|
||||||
return cfg_file
|
return cfg_file
|
||||||
|
|
@ -27,7 +27,7 @@ from gettext import gettext as _
|
|||||||
from abc import ABCMeta
|
from abc import ABCMeta
|
||||||
from quantum.common import exceptions
|
from quantum.common import exceptions
|
||||||
from quantum.manager import QuantumManager
|
from quantum.manager import QuantumManager
|
||||||
from quantum.common import wsgi
|
from quantum import wsgi
|
||||||
|
|
||||||
LOG = logging.getLogger('quantum.common.extensions')
|
LOG = logging.getLogger('quantum.common.extensions')
|
||||||
|
|
153
common/lib/quantum/common/serializer.py
Normal file
153
common/lib/quantum/common/serializer.py
Normal file
@ -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
|
@ -1,7 +1,6 @@
|
|||||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
# Copyright 2011 Nicira Networks, Inc
|
# Copyright 2011, Nicira Networks, Inc.
|
||||||
# All Rights Reserved.
|
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
@ -14,14 +13,16 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# 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 ConfigParser
|
||||||
import datetime
|
import datetime
|
||||||
import exceptions as exception
|
import exceptions as exception
|
||||||
import flags
|
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
@ -29,11 +30,73 @@ import random
|
|||||||
import subprocess
|
import subprocess
|
||||||
import socket
|
import socket
|
||||||
import sys
|
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
|
||||||
|
|
||||||
|
|
||||||
from 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))
|
||||||
|
|
||||||
|
|
||||||
|
def loads(s):
|
||||||
|
return json.loads(s)
|
||||||
|
|
||||||
TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
||||||
FLAGS = flags.FLAGS
|
FLAGS = flags.FLAGS
|
||||||
|
|
||||||
@ -78,7 +141,7 @@ def import_class(import_str):
|
|||||||
return getattr(sys.modules[mod_str], class_str)
|
return getattr(sys.modules[mod_str], class_str)
|
||||||
except (ImportError, ValueError, AttributeError) as e:
|
except (ImportError, ValueError, AttributeError) as e:
|
||||||
print 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):
|
def import_object(import_str):
|
67
common/lib/quantum/run_tests.py
Normal file
67
common/lib/quantum/run_tests.py
Normal file
@ -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()
|
67
common/setup.py
Normal file
67
common/setup.py
Normal file
@ -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'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
1
plugins/cisco-plugin/MANIFEST.in
Normal file
1
plugins/cisco-plugin/MANIFEST.in
Normal file
@ -0,0 +1 @@
|
|||||||
|
include etc/*
|
5
plugins/cisco-plugin/lib/quantum/__init__.py
Normal file
5
plugins/cisco-plugin/lib/quantum/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
try:
|
||||||
|
__import__('pkg_resources').declare_namespace(__name__)
|
||||||
|
except ImportError:
|
||||||
|
from pkgutil import extend_path
|
||||||
|
__path__ = extend_path(__path__, __name__)
|
5
plugins/cisco-plugin/lib/quantum/plugins/__init__.py
Normal file
5
plugins/cisco-plugin/lib/quantum/plugins/__init__.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
try:
|
||||||
|
__import__('pkg_resources').declare_namespace(__name__)
|
||||||
|
except ImportError:
|
||||||
|
from pkgutil import extend_path
|
||||||
|
__path__ = extend_path(__path__, __name__)
|
@ -20,18 +20,21 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
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_configparser as confp
|
||||||
from quantum.plugins.cisco.common import cisco_constants as const
|
from quantum.plugins.cisco.common import cisco_constants as const
|
||||||
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
from quantum.plugins.cisco.common import cisco_exceptions as cexc
|
||||||
from quantum.plugins.cisco.db import l2network_db as cdb
|
from quantum.plugins.cisco.db import l2network_db as cdb
|
||||||
|
|
||||||
|
LOG.basicConfig(level=LOG.WARN)
|
||||||
|
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||||
|
|
||||||
|
CREDENTIALS_FILE = find_config_file({}, None, "credentials.ini")
|
||||||
TENANT = const.NETWORK_ADMIN
|
TENANT = const.NETWORK_ADMIN
|
||||||
|
|
||||||
CREDENTIALS_FILE = "../conf/credentials.ini"
|
cp = confp.CiscoConfigParser(CREDENTIALS_FILE)
|
||||||
|
|
||||||
cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
|
||||||
+ "/" + CREDENTIALS_FILE)
|
|
||||||
_creds_dictionary = cp.walk(cp.dummy)
|
_creds_dictionary = cp.walk(cp.dummy)
|
||||||
|
|
||||||
|
|
@ -20,14 +20,11 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
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_configparser as confp
|
||||||
|
|
||||||
CONF_FILE = "conf/l2network_plugin.ini"
|
CONF_FILE = find_config_file({}, None, "l2network_plugin.ini")
|
||||||
|
CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
|
||||||
CONF_PARSER_OBJ = confp.\
|
|
||||||
CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
|
|
||||||
"/" + CONF_FILE)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Reading the conf for the l2network_plugin
|
Reading the conf for the l2network_plugin
|
||||||
@ -49,25 +46,22 @@ MAX_NETWORKS = SECTION_CONF['max_networks']
|
|||||||
SECTION_CONF = CONF_PARSER_OBJ['MODEL']
|
SECTION_CONF = CONF_PARSER_OBJ['MODEL']
|
||||||
MODEL_CLASS = SECTION_CONF['model_class']
|
MODEL_CLASS = SECTION_CONF['model_class']
|
||||||
|
|
||||||
|
CONF_FILE = find_config_file({}, None, "cisco_plugins.ini")
|
||||||
|
|
||||||
SECTION_CONF = CONF_PARSER_OBJ['SEGMENTATION']
|
SECTION_CONF = CONF_PARSER_OBJ['SEGMENTATION']
|
||||||
MANAGER_CLASS = SECTION_CONF['manager_class']
|
MANAGER_CLASS = SECTION_CONF['manager_class']
|
||||||
|
|
||||||
CONF_FILE = "conf/plugins.ini"
|
|
||||||
|
|
||||||
CONF_PARSER_OBJ = confp.\
|
CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
|
||||||
CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
|
|
||||||
"/" + CONF_FILE)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Reading the config for the device plugins
|
Reading the config for the device plugins
|
||||||
"""
|
"""
|
||||||
PLUGINS = CONF_PARSER_OBJ.walk(CONF_PARSER_OBJ.dummy)
|
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.\
|
CONF_PARSER_OBJ = confp.CiscoConfigParser(CONF_FILE)
|
||||||
CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) + \
|
|
||||||
"/" + CONF_FILE)
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Reading DB config for the Quantum DB
|
Reading DB config for the Quantum DB
|
@ -20,13 +20,10 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
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_configparser as confp
|
||||||
|
|
||||||
CONF_FILE = "../conf/ucs.ini"
|
CP = confp.CiscoConfigParser(find_config_file({}, [], 'ucs.ini'))
|
||||||
|
|
||||||
CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
|
||||||
+ "/" + CONF_FILE)
|
|
||||||
|
|
||||||
SECTION = CP['UCSM']
|
SECTION = CP['UCSM']
|
||||||
UCSM_IP_ADDRESS = SECTION['ip_address']
|
UCSM_IP_ADDRESS = SECTION['ip_address']
|
||||||
@ -38,9 +35,7 @@ PROFILE_NAME_PREFIX = SECTION['profile_name_prefix']
|
|||||||
SECTION = CP['DRIVER']
|
SECTION = CP['DRIVER']
|
||||||
UCSM_DRIVER = SECTION['name']
|
UCSM_DRIVER = SECTION['name']
|
||||||
|
|
||||||
CONF_FILE = "../conf/ucs_inventory.ini"
|
CP = confp.CiscoConfigParser(find_config_file({}, [],
|
||||||
|
'ucs_inventory.ini'))
|
||||||
CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
|
||||||
+ "/" + CONF_FILE)
|
|
||||||
|
|
||||||
INVENTORY = CP.walk(CP.dummy)
|
INVENTORY = CP.walk(CP.dummy)
|
@ -20,12 +20,10 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
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_configparser as confp
|
||||||
|
|
||||||
CONF_FILE = "../conf/ucs_inventory.ini"
|
CP = confp.CiscoConfigParser(find_config_file({}, [],
|
||||||
|
'plugins/cisco/ucs_inventory.ini'))
|
||||||
CP = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
|
||||||
+ "/" + CONF_FILE)
|
|
||||||
|
|
||||||
INVENTORY = CP.walk(CP.dummy)
|
INVENTORY = CP.walk(CP.dummy)
|
@ -16,3 +16,8 @@
|
|||||||
#
|
#
|
||||||
# @author: Sumit Naiksatam, Cisco Systems, Inc.
|
# @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__)
|
@ -17,6 +17,12 @@
|
|||||||
|
|
||||||
# See http://code.google.com/p/python-nose/issues/detail?id=373
|
# See http://code.google.com/p/python-nose/issues/detail?id=373
|
||||||
# The code below enables nosetests to work with i18n _() blocks
|
# 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 __builtin__
|
||||||
import unittest
|
import unittest
|
||||||
setattr(__builtin__, '_', lambda x: x)
|
setattr(__builtin__, '_', lambda x: x)
|
72
plugins/cisco-plugin/setup.py
Normal file
72
plugins/cisco-plugin/setup.py
Normal file
@ -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'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
1
plugins/openvswitch-plugin/MANIFEST.in
Normal file
1
plugins/openvswitch-plugin/MANIFEST.in
Normal file
@ -0,0 +1 @@
|
|||||||
|
include etc/*
|
0
plugins/openvswitch-plugin/lib/__init__.py
Normal file
0
plugins/openvswitch-plugin/lib/__init__.py
Normal file
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user