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
|
||||
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,28 +88,29 @@ 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
|
||||
# If you're running from the source
|
||||
bin/quantum-server
|
||||
|
||||
# If you installed Quantum
|
||||
quantum-server
|
||||
|
||||
# -- 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
|
||||
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.
|
||||
|
||||
An example session looks like this:
|
||||
|
||||
$ 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
|
||||
|
||||
# -- 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
|
||||
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
|
||||
# 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'))
|
43
bin/quantum
43
bin/quantum
@ -19,43 +19,8 @@
|
||||
# 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()
|
||||
|
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
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
def main():
|
||||
usagestr = "Usage: %prog [OPTIONS] <command> [args]"
|
||||
parser = OptionParser(usage=usagestr)
|
||||
parser.add_option("-H", "--host", dest="host",
|
@ -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 = {
|
@ -17,6 +17,12 @@
|
||||
|
||||
# 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)
|
@ -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')
|
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"
|
||||
|
||||
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
|
||||
|
@ -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')
|
||||
|
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
|
||||
|
||||
# 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
|
||||
@ -14,14 +13,16 @@
|
||||
# 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,11 +30,73 @@ 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
|
||||
|
||||
|
||||
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"
|
||||
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):
|
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 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
|
||||
|
||||
LOG.basicConfig(level=LOG.WARN)
|
||||
LOG.getLogger(const.LOGGER_COMPONENT_NAME)
|
||||
|
||||
CREDENTIALS_FILE = find_config_file({}, None, "credentials.ini")
|
||||
TENANT = const.NETWORK_ADMIN
|
||||
|
||||
CREDENTIALS_FILE = "../conf/credentials.ini"
|
||||
|
||||
cp = confp.CiscoConfigParser(os.path.dirname(os.path.realpath(__file__)) \
|
||||
+ "/" + CREDENTIALS_FILE)
|
||||
cp = confp.CiscoConfigParser(CREDENTIALS_FILE)
|
||||
_creds_dictionary = cp.walk(cp.dummy)
|
||||
|
||||
|
@ -20,14 +20,11 @@
|
||||
"""
|
||||
|
||||
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
|
@ -20,13 +20,10 @@
|
||||
"""
|
||||
|
||||
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)
|
@ -20,12 +20,10 @@
|
||||
"""
|
||||
|
||||
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)
|
@ -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__)
|
@ -17,6 +17,12 @@
|
||||
|
||||
# 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)
|
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