aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/openstack/neutron
diff options
context:
space:
mode:
authorAshlee Young <ashlee@onosfw.com>2015-10-30 09:20:45 -0700
committerAshlee Young <ashlee@onosfw.com>2015-10-30 09:20:45 -0700
commit89a574196783f93e32d81244f37f726be11bbf30 (patch)
tree408c721579d29d49eebf50c78b7f4a8da7a6489e /framework/src/openstack/neutron
parent62bb467ca10e4fd0ca23499953bc7f7f413dee16 (diff)
New ML2/L3 plugin to support SFC
Change-Id: Ie778a2b2e09a29972e28d70c8eedee407b1d8eb6 Signed-off-by: Ashlee Young <ashlee@onosfw.com>
Diffstat (limited to 'framework/src/openstack/neutron')
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.mailmap4
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.pylintrc130
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.testr.conf8
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/CONTRIBUTING.rst16
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/HACKING.rst33
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/LICENSE176
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/MANIFEST.in9
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/README.rst20
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/TESTING.rst160
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/babel.cfg2
-rwxr-xr-xframework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/conf.py75
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/contributing.rst4
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/index.rst25
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/installation.rst12
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/readme.rst1
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/usage.rst7
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/etc/conf_onos.ini11
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/__init__.py19
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/config.py31
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/utils.py44
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/README29
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/driver.py126
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/floating_ip.py40
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/router.py74
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/README33
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/driver.py140
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/test_driver.py230
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/__init__.py0
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/test_driver.py237
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/openstack-common.conf5
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/requirements.txt9
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/setup.cfg56
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/setup.py29
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/test-requirements.txt15
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_bash.sh31
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_i18n.py153
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_i18n_test_case.txt67
-rwxr-xr-xframework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/clean.sh5
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/i18n_cfg.py97
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/install_venv.py72
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/install_venv_common.py172
-rwxr-xr-xframework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/pretty_tox.sh6
-rwxr-xr-xframework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/subunit-trace.py307
-rwxr-xr-xframework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/with_venv.sh19
-rw-r--r--framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tox.ini41
53 files changed, 2780 insertions, 0 deletions
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.mailmap b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.mailmap
new file mode 100644
index 00000000..7b5fe1b3
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.mailmap
@@ -0,0 +1,4 @@
+# Format is:
+# <preferred e-mail> <other e-mail 1>
+# <preferred e-mail> <other e-mail 2>
+Vikram Choudhary <vikram.choudhary@huawei.com> <vikschw@gmail.com> \ No newline at end of file
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.pylintrc b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.pylintrc
new file mode 100644
index 00000000..d343d72a
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.pylintrc
@@ -0,0 +1,130 @@
+# The format of this file isn't really documented; just use --generate-rcfile
+[MASTER]
+# Add <file or directory> to the black list. It should be a base name, not a
+# path. You may set this option multiple times.
+#
+# Note the 'openstack' below is intended to match only
+# neutron.openstack.common. If we ever have another 'openstack'
+# dirname, then we'll need to expand the ignore features in pylint :/
+ignore=.git,tests,openstack
+
+[MESSAGES CONTROL]
+# NOTE(gus): This is a long list. A number of these are important and
+# should be re-enabled once the offending code is fixed (or marked
+# with a local disable)
+disable=
+# "F" Fatal errors that prevent further processing
+ import-error,
+# "I" Informational noise
+ locally-disabled,
+# "E" Error for important programming issues (likely bugs)
+ access-member-before-definition,
+ bad-super-call,
+ maybe-no-member,
+ no-member,
+ no-method-argument,
+ no-self-argument,
+ not-callable,
+ no-value-for-parameter,
+ super-on-old-class,
+ too-few-format-args,
+# "W" Warnings for stylistic problems or minor programming issues
+ abstract-method,
+ anomalous-backslash-in-string,
+ anomalous-unicode-escape-in-string,
+ arguments-differ,
+ attribute-defined-outside-init,
+ bad-builtin,
+ bad-indentation,
+ broad-except,
+ dangerous-default-value,
+ deprecated-lambda,
+ duplicate-key,
+ expression-not-assigned,
+ fixme,
+ global-statement,
+ global-variable-not-assigned,
+ logging-not-lazy,
+ no-init,
+ non-parent-init-called,
+ protected-access,
+ redefined-builtin,
+ redefined-outer-name,
+ redefine-in-handler,
+ signature-differs,
+ star-args,
+ super-init-not-called,
+ unnecessary-lambda,
+ unnecessary-pass,
+ unpacking-non-sequence,
+ unreachable,
+ unused-argument,
+ unused-import,
+ unused-variable,
+# "C" Coding convention violations
+ bad-continuation,
+ invalid-name,
+ missing-docstring,
+ old-style-class,
+ superfluous-parens,
+# "R" Refactor recommendations
+ abstract-class-little-used,
+ abstract-class-not-used,
+ duplicate-code,
+ interface-not-implemented,
+ no-self-use,
+ too-few-public-methods,
+ too-many-ancestors,
+ too-many-arguments,
+ too-many-branches,
+ too-many-instance-attributes,
+ too-many-lines,
+ too-many-locals,
+ too-many-public-methods,
+ too-many-return-statements,
+ too-many-statements
+
+[BASIC]
+# Variable names can be 1 to 31 characters long, with lowercase and underscores
+variable-rgx=[a-z_][a-z0-9_]{0,30}$
+
+# Argument names can be 2 to 31 characters long, with lowercase and underscores
+argument-rgx=[a-z_][a-z0-9_]{1,30}$
+
+# Method names should be at least 3 characters long
+# and be lowecased with underscores
+method-rgx=([a-z_][a-z0-9_]{2,}|setUp|tearDown)$
+
+# Module names matching neutron-* are ok (files in bin/)
+module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)|(neutron-[a-z0-9_-]+))$
+
+# Don't require docstrings on tests.
+no-docstring-rgx=((__.*__)|([tT]est.*)|setUp|tearDown)$
+
+[FORMAT]
+# Maximum number of characters on a single line.
+max-line-length=79
+
+[VARIABLES]
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid to define new builtins when possible.
+# _ is used by our localization
+additional-builtins=_
+
+[CLASSES]
+# List of interface methods to ignore, separated by a comma.
+ignore-iface-methods=
+
+[IMPORTS]
+# Deprecated modules which should not be used, separated by a comma
+deprecated-modules=
+# should use openstack.common.jsonutils
+ json
+
+[TYPECHECK]
+# List of module names for which member attributes should not be checked
+ignored-modules=six.moves,_MovedItems
+
+[REPORTS]
+# Tells whether to display a full report or only the messages
+reports=no
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.testr.conf b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.testr.conf
new file mode 100644
index 00000000..4b24f61e
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/.testr.conf
@@ -0,0 +1,8 @@
+[DEFAULT]
+test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
+ OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
+ OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
+ OS_LOG_CAPTURE=1 \
+ ${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
+test_id_option=--load-list $IDFILE
+test_list_option=--list
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/CONTRIBUTING.rst b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/CONTRIBUTING.rst
new file mode 100644
index 00000000..44cb395d
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/CONTRIBUTING.rst
@@ -0,0 +1,16 @@
+If you would like to contribute to the development of OpenStack,
+you must follow the steps documented at:
+
+ http://docs.openstack.org/infra/manual/developers.html#development-workflow
+
+Once those steps have been completed, changes to OpenStack
+should be submitted for review via the Gerrit tool, following
+the workflow documented at:
+
+ http://docs.openstack.org/infra/manual/developers.html#development-workflow
+
+Pull requests submitted through GitHub will be ignored.
+
+Bugs should be filed on Launchpad, not GitHub:
+
+ https://bugs.launchpad.net/networking-onos
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/HACKING.rst b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/HACKING.rst
new file mode 100644
index 00000000..06d3f2c1
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/HACKING.rst
@@ -0,0 +1,33 @@
+Neutron Style Commandments
+==========================
+
+- Step 1: Read the OpenStack Style Commandments
+ http://docs.openstack.org/developer/hacking/
+- Step 2: Read on
+
+Neutron Specific Commandments
+--------------------------
+
+- [N319] Validate that debug level logs are not translated
+- [N320] Validate that LOG messages, except debug ones, have translations
+- [N321] Validate that jsonutils module is used instead of json
+- [N322] We do not use @authors tags in source files. We have git to track
+ authorship.
+- [N323] Detect common errors with assert_called_once_with
+
+Creating Unit Tests
+-------------------
+For every new feature, unit tests should be created that both test and
+(implicitly) document the usage of said feature. If submitting a patch for a
+bug that had no unit test, a new passing unit test should be added. If a
+submitted bug fix does have a unit test, be sure to add a new one that fails
+without the patch and passes with the patch.
+
+All unittest classes must ultimately inherit from testtools.TestCase. In the
+Neutron test suite, this should be done by inheriting from
+neutron.tests.base.BaseTestCase.
+
+All setUp and tearDown methods must upcall using the super() method.
+tearDown methods should be avoided and addCleanup calls should be preferred.
+Never manually create tempfiles. Always use the tempfile fixtures from
+the fixture library to ensure that they are cleaned up.
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/LICENSE b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/LICENSE
new file mode 100644
index 00000000..68c771a0
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/LICENSE
@@ -0,0 +1,176 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/MANIFEST.in b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/MANIFEST.in
new file mode 100644
index 00000000..f1c38fb2
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/MANIFEST.in
@@ -0,0 +1,9 @@
+include AUTHORS
+include README.rst
+include ChangeLog
+include LICENSE
+
+exclude .gitignore
+exclude .gitreview
+
+global-exclude *.pyc
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/README.rst b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/README.rst
new file mode 100644
index 00000000..2a9d3291
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/README.rst
@@ -0,0 +1,20 @@
+Word about ONOS
+===============
+
+Open Networking Operating System (ONOS) is a new carrier-grade SDN network
+operating system designed for high availability, performance and scale-out with
+a mission "to produce the Open Source Network Operating System that will enable
+service providers to build real Software Defined Network".
+
+Word about networking-onos
+==========================
+The "networking-onos" repository contains code which makes the interaction
+between ONOS and OpenStack Neutron possible. For more information about ONOS
+you can visit "http://onosproject.org/" and
+"https://launchpad.net/neutron" for OpenStack Neutron.
+
+Important Pointers
+==================
+* You can visit the launchpad page "https://launchpad.net/networking-onos" to get latest project status.
+* For any issues or new requirement raise a bug at “https://bugs.launchpad.net/networking-onos”. We will get back.
+* Any contribution is appreciated. Let's start contributing. \ No newline at end of file
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/TESTING.rst b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/TESTING.rst
new file mode 100644
index 00000000..657fb412
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/TESTING.rst
@@ -0,0 +1,160 @@
+Testing Neutron
+===============
+
+Overview
+--------
+
+The unit tests (neutron/test/unit/) are meant to cover as much code as
+possible and should be executed without the service running. They are
+designed to test the various pieces of the neutron tree to make sure
+any new changes don't break existing functionality.
+
+The functional tests (neutron/tests/functional/) are intended to
+validate actual system interaction. Mocks should be used sparingly,
+if at all. Care should be taken to ensure that existing system
+resources are not modified and that resources created in tests are
+properly cleaned up.
+
+Development process
+-------------------
+
+It is expected that any new changes that are proposed for merge
+come with tests for that feature or code area. Ideally any bugs
+fixes that are submitted also have tests to prove that they stay
+fixed! In addition, before proposing for merge, all of the
+current tests should be passing.
+
+Virtual environments
+~~~~~~~~~~~~~~~~~~~~
+
+Testing OpenStack projects, including Neutron, is made easier with `DevStack <https://git.openstack.org/cgit/openstack-dev/devstack>`_.
+
+Create a machine (such as a VM or Vagrant box) running a distribution supported
+by DevStack and install DevStack there. For example, there is a Vagrant script
+for DevStack at https://github.com/bcwaldon/vagrant_devstack.
+
+ .. note::
+
+ If you prefer not to use DevStack, you can still check out source code on your local
+ machine and develop from there.
+
+
+Running unit tests
+------------------
+
+There are two mechanisms for running tests: tox, and nose. Before submitting
+a patch for review you should always ensure all test pass; a tox run is
+triggered by the jenkins gate executed on gerrit for each patch pushed for
+review.
+
+With these mechanisms you can either run the tests in the standard
+environment or create a virtual environment to run them in.
+
+By default after running all of the tests, any pep8 errors
+found in the tree will be reported.
+
+
+With `nose`
+~~~~~~~~~~~
+
+You can use `nose`_ to run individual tests, as well as use for debugging
+portions of your code::
+
+ source .venv/bin/activate
+ pip install nose
+ nosetests
+
+There are disadvantages to running Nose - the tests are run sequentially, so
+race condition bugs will not be triggered, and the full test suite will
+take significantly longer than tox & testr. The upside is that testr has
+some rough edges when it comes to diagnosing errors and failures, and there is
+no easy way to set a breakpoint in the Neutron code, and enter an
+interactive debugging session while using testr.
+
+.. _nose: https://nose.readthedocs.org/en/latest/index.html
+
+With `tox`
+~~~~~~~~~~
+
+Neutron, like other OpenStack projects, uses `tox`_ for managing the virtual
+environments for running test cases. It uses `Testr`_ for managing the running
+of the test cases.
+
+Tox handles the creation of a series of `virtualenvs`_ that target specific
+versions of Python (2.6, 2.7, 3.3, etc).
+
+Testr handles the parallel execution of series of test cases as well as
+the tracking of long-running tests and other things.
+
+Running unit tests is as easy as executing this in the root directory of the
+Neutron source code::
+
+ tox
+
+For more information on the standard Tox-based test infrastructure used by
+OpenStack and how to do some common test/debugging procedures with Testr,
+see this wiki page:
+
+ https://wiki.openstack.org/wiki/Testr
+
+.. _Testr: https://wiki.openstack.org/wiki/Testr
+.. _tox: http://tox.readthedocs.org/en/latest/
+.. _virtualenvs: https://pypi.python.org/pypi/virtualenv
+
+
+Running individual tests
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+For running individual test modules or cases, you just need to pass
+the dot-separated path to the module you want as an argument to it.
+
+For executing a specific test case, specify the name of the test case
+class separating it from the module path with a colon.
+
+For example, the following would run only the JSONV2TestCase tests from
+neutron/tests/unit/test_api_v2.py::
+
+ $ tox -e py27 neutron.tests.unit.test_api_v2.JSONV2TestCase
+
+Adding more tests
+~~~~~~~~~~~~~~~~~
+
+Neutron has a fast growing code base and there is plenty of areas that
+need to be covered by unit and functional tests.
+
+To get a grasp of the areas where tests are needed, you can check
+current coverage by running::
+
+ $ tox -ecover
+
+Debugging
+---------
+
+It's possible to debug tests in a tox environment::
+
+ $ tox -e venv -- python -m testtools.run [test module path]
+
+Tox-created virtual environments (venv's) can also be activated
+after a tox run and reused for debugging::
+
+ $ tox -e venv
+ $ . .tox/venv/bin/activate
+ $ python -m testtools.run [test module path]
+
+Tox packages and installs the neutron source tree in a given venv
+on every invocation, but if modifications need to be made between
+invocation (e.g. adding more pdb statements), it is recommended
+that the source tree be installed in the venv in editable mode::
+
+ # run this only after activating the venv
+ $ pip install --editable .
+
+Editable mode ensures that changes made to the source tree are
+automatically reflected in the venv, and that such changes are not
+overwritten during the next tox run.
+
+References
+==========
+
+.. [#pudb] PUDB debugger:
+ https://pypi.python.org/pypi/pudb
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/babel.cfg b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/babel.cfg
new file mode 100644
index 00000000..15cd6cb7
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/babel.cfg
@@ -0,0 +1,2 @@
+[python: **.py]
+
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/conf.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/conf.py
new file mode 100755
index 00000000..8519f06d
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/conf.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+# 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.
+
+import os
+import sys
+
+sys.path.insert(0, os.path.abspath('../..'))
+# -- General configuration ----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+ #'sphinx.ext.intersphinx',
+ 'oslosphinx'
+]
+
+# autodoc generation is a bit aggressive and a nuisance when doing heavy
+# text edit cycles.
+# execute "export SPHINX_DEBUG=1" in your terminal to disable
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'networking-onos'
+copyright = u'2013, OpenStack Foundation'
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+add_module_names = True
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# -- Options for HTML output --------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+# html_theme_path = ["."]
+# html_theme = '_theme'
+# html_static_path = ['static']
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = '%sdoc' % project
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass
+# [howto/manual]).
+latex_documents = [
+ ('index',
+ '%s.tex' % project,
+ u'%s Documentation' % project,
+ u'OpenStack Foundation', 'manual'),
+]
+
+# Example configuration for intersphinx: refer to the Python standard library.
+#intersphinx_mapping = {'http://docs.python.org/': None}
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/contributing.rst b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/contributing.rst
new file mode 100644
index 00000000..1728a61c
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/contributing.rst
@@ -0,0 +1,4 @@
+============
+Contributing
+============
+.. include:: ../../CONTRIBUTING.rst
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/index.rst b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/index.rst
new file mode 100644
index 00000000..8b8ac262
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/index.rst
@@ -0,0 +1,25 @@
+.. networking-onos documentation master file, created by
+ sphinx-quickstart on Tue Jul 9 22:26:36 2013.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to networking-onos's documentation!
+========================================================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ readme
+ installation
+ usage
+ contributing
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/installation.rst b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/installation.rst
new file mode 100644
index 00000000..2228fde0
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/installation.rst
@@ -0,0 +1,12 @@
+============
+Installation
+============
+
+At the command line::
+
+ $ pip install networking-onos
+
+Or, if you have virtualenvwrapper installed::
+
+ $ mkvirtualenv networking-onos
+ $ pip install networking-onos
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/readme.rst b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/readme.rst
new file mode 100644
index 00000000..a6210d3d
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/readme.rst
@@ -0,0 +1 @@
+.. include:: ../../README.rst
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/usage.rst b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/usage.rst
new file mode 100644
index 00000000..fdc232a2
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/doc/source/usage.rst
@@ -0,0 +1,7 @@
+========
+Usage
+========
+
+To use networking-onos in a project::
+
+ import networking-onos
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/etc/conf_onos.ini b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/etc/conf_onos.ini
new file mode 100644
index 00000000..45ad6ac8
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/etc/conf_onos.ini
@@ -0,0 +1,11 @@
+#Configuration options for ONOS driver
+
+[onos]
+# (StrOpt) ONOS ReST interface URL. This is a mandatory field.
+# url_path =
+
+# (StrOpt) Username for authentication. This is a mandatory field.
+# username =
+
+# (StrOpt) Password for authentication. This is a mandatory field.
+# password =
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/__init__.py
new file mode 100644
index 00000000..d0b36107
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/__init__.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+
+# 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.
+
+import pbr.version
+
+
+__version__ = pbr.version.VersionInfo(
+ 'networking-onos').version_string()
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/config.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/config.py
new file mode 100644
index 00000000..8dc72286
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/config.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2015 Huawei Technologies India Pvt Ltd
+# 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.
+
+from oslo_config import cfg
+
+ONOS_DRIVER_OPTS = [
+ cfg.StrOpt('url_path',
+ default='',
+ help=_('ONOS ReST interface URL')),
+ cfg.StrOpt('username',
+ default='',
+ help=_('Username for authentication.')),
+ cfg.StrOpt('password',
+ default='',
+ secret=True, # do not expose value in the logs
+ help=_('Password for authentication.'))
+]
+
+cfg.CONF.register_opts(ONOS_DRIVER_OPTS, "onos")
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/utils.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/utils.py
new file mode 100644
index 00000000..49477149
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/common/utils.py
@@ -0,0 +1,44 @@
+# Copyright (c) 2015 Huawei Technologies India Pvt Ltd
+# 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.
+
+from oslo_log import log as logging
+from oslo_serialization import jsonutils
+import requests
+
+
+LOG = logging.getLogger(__name__)
+
+
+def send_msg(onos_path, onos_auth, msg_type, entity_path, entity=None):
+ """Send message to the ONOS controller."""
+
+ path = '/'.join([onos_path, entity_path])
+ hdr = {'Content-Type': 'application/json'}
+ body = jsonutils.dumps(entity, indent=2) if entity else None
+ LOG.debug("Sending MSG_TYPE (%(msg)s) URL (%(path)s) "
+ "OBJECT (%(entity)s) BODY (%(body)s)",
+ {'msg': msg_type, 'path': path,
+ 'entity': entity, 'body': body})
+ req = requests.request(method=msg_type, url=path,
+ headers=hdr, data=body,
+ auth=onos_auth)
+ # Let's raise voice for an error
+ req.raise_for_status()
+
+
+def safe_delete_from_dict(dict, keys):
+ """Ignore key errors when deleting from a dictionary."""
+ for key in keys:
+ dict.pop(key, None)
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/README b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/README
new file mode 100644
index 00000000..04ca224b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/README
@@ -0,0 +1,29 @@
+Open Networking Operating System (ONOS) L3 Plugin
+=================================================
+ONOS is a carrier grade SDN open operating system designed for
+High Availability, scale-out and better performance.
+
+ http://www.onosproject.org/
+
+Mode of Working:
+================
+networking-onos.plugins.l3 define onos plug-in for supporting neutron's router
+functionality. This shim layer makes the communication between ONOS and
+Openstack neutron possible via ReST call.
+The driver code can be downloaded from:
+
+ https://git.openstack.org/cgit/openstack/networking-onos
+
+Using ONOS L3 Plugin
+====================
+To use ONOS L3 Plugin one should
+1. Make sure networking-onos code is downloaded and installed. If doing
+ mannually then download the code, go inside networking_onos folder
+ and finally run "sudo python setup.py install" otherwise download the
+ required package version from "https://pypi.python.org/pypi/networking-onos/"
+ and install using pip.
+
+2. Configure ONOS credentials in networking_onos/etc/conf_onos.ini.
+
+3. Start neutron server mentioning networking_onos/etc/conf_onos.ini as
+ one of the config-file with ONOS L3 Plugin support.
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/driver.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/driver.py
new file mode 100644
index 00000000..2db3ad35
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/driver.py
@@ -0,0 +1,126 @@
+# Copyright (C) 2015 Huawei Technologies India Pvt Ltd.
+# 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.
+#
+
+from oslo_config import cfg
+
+from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api
+from neutron.api.rpc.handlers import l3_rpc
+from neutron.common import constants as q_const
+from neutron.common import rpc as n_rpc
+from neutron.common import topics
+from neutron.db import db_base_plugin_v2
+from neutron.db import extraroute_db
+from neutron.db import l3_agentschedulers_db
+from neutron.db import l3_gwmode_db
+from neutron.plugins.common import constants
+
+from networking_onos.common import config # noqa
+from networking_onos.plugins.l3 import floating_ip as onos_fip
+from networking_onos.plugins.l3 import router as onos_router
+
+
+class ONOSL3Plugin(db_base_plugin_v2.NeutronDbPluginV2,
+ extraroute_db.ExtraRoute_db_mixin,
+ l3_gwmode_db.L3_NAT_db_mixin,
+ l3_agentschedulers_db.L3AgentSchedulerDbMixin,
+ onos_router.ONOSRouter,
+ onos_fip.ONOSFloatingIP):
+
+ """Implementation of the ONOS L3 Router Service Plugin.
+
+ This class implements a L3 service plugin that provides
+ router and floatingip resources and manages associated
+ request/response.
+ """
+ supported_extension_aliases = ["router", "ext-gw-mode", "extraroute"]
+
+ def __init__(self):
+ self.setup_rpc()
+ self.onos_path = cfg.CONF.onos.url_path
+ self.onos_auth = (cfg.CONF.onos.username, cfg.CONF.onos.password)
+
+ def setup_rpc(self):
+ self.topic = topics.L3PLUGIN
+ self.conn = n_rpc.create_connection(new=True)
+ self.agent_notifiers.update(
+ {q_const.AGENT_TYPE_L3: l3_rpc_agent_api.L3AgentNotifyAPI()})
+ self.endpoints = [l3_rpc.L3RpcCallback()]
+ self.conn.create_consumer(self.topic, self.endpoints, fanout=False)
+ self.conn.consume_in_threads()
+
+ def get_plugin_type(self):
+ return constants.L3_ROUTER_NAT
+
+ def get_plugin_description(self):
+ """returns plug-in description"""
+ return ("L3 Router Service Plug-in for basic L3 forwarding using ONOS")
+
+ def create_router(self, context, router):
+ router_dict = super(ONOSL3Plugin, self).create_router(context, router)
+ self.handle_create_router(router_dict)
+ return router_dict
+
+ def update_router(self, context, id, router):
+ router_dict = super(ONOSL3Plugin, self).update_router(context, id,
+ router)
+ self.handle_update_router(router_dict, id)
+ return router_dict
+
+ def delete_router(self, context, id):
+ super(ONOSL3Plugin, self).delete_router(context, id)
+ self.handle_delete_router(id)
+
+ def create_floatingip(self, context, floatingip,
+ initial_status=q_const.FLOATINGIP_STATUS_ACTIVE):
+ fip_dict = super(ONOSL3Plugin, self).create_floatingip(context,
+ floatingip,
+ initial_status)
+ self.handle_create_floatingip(fip_dict)
+ return fip_dict
+
+ def update_floatingip(self, context, id, floatingip):
+ fip_dict = super(ONOSL3Plugin, self).update_floatingip(context, id,
+ floatingip)
+ self.handle_update_floatingip(id, fip_dict)
+ return fip_dict
+
+ def delete_floatingip(self, context, id):
+ super(ONOSL3Plugin, self).delete_floatingip(context, id)
+ self.handle_delete_floatingip(id)
+
+ def add_router_interface(self, context, router_id, interface_info):
+ router = super(ONOSL3Plugin, self).add_router_interface(context,
+ router_id,
+ interface_info)
+ intf_add_type = self._get_intf_add_type(router, interface_info)
+ self.handle_add_router_interface(router, router_id,
+ interface_info, intf_add_type)
+ return router
+
+ def remove_router_interface(self, context, router_id, interface_info):
+ router = super(ONOSL3Plugin, self).remove_router_interface(
+ context, router_id, interface_info)
+ intf_add_type = self._get_intf_add_type(router, interface_info)
+ self.handle_remove_router_interface(router, router_id,
+ interface_info, intf_add_type)
+ return router
+
+ def _get_intf_add_type(self, router_info, intf_info):
+ add_by_port, add_by_sub = self._validate_interface_info(intf_info)
+ if add_by_sub:
+ return onos_router.ADD_INTF_BY_SUBNET
+
+ return onos_router.ADD_INTF_BY_PORT
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/floating_ip.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/floating_ip.py
new file mode 100644
index 00000000..0748724e
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/floating_ip.py
@@ -0,0 +1,40 @@
+# Copyright (C) 2015 Huawei Technologies India Pvt Ltd.
+#
+# 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.
+#
+
+from networking_onos.common import utils as onos_utils
+
+
+class ONOSFloatingIP(object):
+
+ """Implementation of ONOS L3 Floating IP Service.
+
+ This class sends Neutron's L3 Floating IP messages to ONOS.
+ """
+ def send_floatingip_msg(self, msg_type, entity_path, entity):
+ onos_utils.send_msg(self.onos_path, self.onos_auth,
+ msg_type, entity_path, entity)
+
+ def handle_create_floatingip(self, fip_dict):
+ self.send_floatingip_msg('post', 'floatingips',
+ {'floatingip': fip_dict})
+
+ def handle_update_floatingip(self, id, fip_dict):
+ url_path = 'floatingips' + '/' + id
+ self.send_floatingip_msg('put', url_path,
+ {'floatingip': fip_dict})
+
+ def handle_delete_floatingip(self, id):
+ url_path = 'floatingips' + '/' + id
+ self.send_floatingip_msg('delete', url_path, None)
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/router.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/router.py
new file mode 100644
index 00000000..495dacd6
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/l3/router.py
@@ -0,0 +1,74 @@
+# Copyright (C) 2015 Huawei Technologies India Pvt Ltd.
+#
+# 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.
+#
+
+from networking_onos.common import utils as onos_utils
+
+ADD_INTF_BY_PORT = 1
+ADD_INTF_BY_SUBNET = 2
+
+
+class ONOSRouter(object):
+
+ """Implementation of ONOS L3 Router Service.
+
+ This class sends Neutron's L3 router messages to ONOS.
+ """
+ def send_router_msg(self, msg_type, entity_path, entity):
+ onos_utils.send_msg(self.onos_path, self.onos_auth,
+ msg_type, entity_path, entity)
+
+ def handle_create_router(self, router_dict):
+ self.send_router_msg('post', 'routers',
+ {'router': router_dict})
+
+ def handle_update_router(self, router_dict, id):
+ url_path = 'routers' + '/' + id
+ resource = router_dict.copy()
+ onos_utils.safe_delete_from_dict(resource,
+ ['id', 'tenant_id', 'status'])
+ self.send_router_msg('put', url_path, {'router': resource})
+
+ def handle_delete_router(self, id):
+ url_path = 'routers' + '/' + id
+ self.send_router_msg('delete', url_path, None)
+
+ def handle_add_router_interface(self, new_router, router_id,
+ interface_info, intf_add_type):
+ url_path = 'routers' + '/' + router_id + '/add_router_interface'
+ router_dict = self._prepare_router_dict(router_id, interface_info,
+ new_router, intf_add_type)
+ self.send_router_msg('put', url_path, router_dict)
+
+ def handle_remove_router_interface(self, new_router, router_id,
+ interface_info, intf_add_type):
+ url_path = 'routers' + '/' + router_id + '/remove_router_interface'
+ router_dict = self._prepare_router_dict(router_id, interface_info,
+ new_router, intf_add_type)
+ self.send_router_msg('put', url_path, router_dict)
+
+ def _prepare_router_dict(self, router_id, interface_info,
+ new_router, add_type):
+ if add_type == ADD_INTF_BY_SUBNET:
+ _port_id = new_router['port_id']
+ _subnet_id = interface_info['subnet_id']
+ else:
+ _port_id = interface_info['port_id']
+ _subnet_id = new_router['subnet_id']
+
+ router_dict = {'subnet_id': _subnet_id,
+ 'port_id': _port_id,
+ 'id': router_id,
+ 'tenant_id': new_router['tenant_id']}
+ return router_dict
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/README b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/README
new file mode 100644
index 00000000..c3c722c8
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/README
@@ -0,0 +1,33 @@
+Open Networking Operating System (ONOS) ML2 MechanismDriver
+==========================================================
+ONOS is a carrier grade SDN open operating system designed for
+High Availability, scale-out and better performance.
+
+ http://www.onosproject.org/
+
+Mode of Working:
+================
+The networking-onos project provides a thin layer which makes the
+communication between ONOS and OpenStack neutron possible via ReST
+call. The driver code can be downloaded from:
+
+ https://git.openstack.org/cgit/openstack/networking-onos
+
+Using ONOS ML2 MechanismDriver
+==============================
+To use ONOS ML2 MechanismDriver one should
+1. Make sure networking-onos code is downloaded and installed. If doing
+ mannually then download the code, go inside networking_onos folder
+ and finally run "sudo python setup.py install" otherwise download the
+ required package version from "https://pypi.python.org/pypi/networking-onos/"
+ and install using pip.
+
+2. Configure ONOS as the required ML2 "mechanism_drivers" in
+ neutron/plugins/ml2/ml2_conf.ini:
+
+ mechanism_drivers=onos_ml2
+
+3. Configure ONOS credentials in networking_onos/etc/conf_onos.ini.
+
+4. Start neutron server mentioning networking_onos/etc/conf_onos.ini as
+ one of the config-file.
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/driver.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/driver.py
new file mode 100644
index 00000000..b78775f4
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/plugins/ml2/driver.py
@@ -0,0 +1,140 @@
+# Copyright (c) 2015 Huawei Technologies India Pvt Ltd
+# 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.
+
+from oslo_config import cfg
+from oslo_log import helpers as log_helpers
+from oslo_log import log as logging
+
+from neutron.common import constants as n_const
+from neutron.extensions import portbindings
+from neutron.plugins.common import constants
+from neutron.plugins.ml2 import driver_api as api
+
+from networking_onos.common import config # noqa
+from networking_onos.common import utils as onos_utils
+
+LOG = logging.getLogger(__name__)
+
+
+class ONOSMechanismDriver(api.MechanismDriver):
+
+ """Open Networking Operating System ML2 Driver for Neutron.
+
+ Code which makes communication between ONOS and OpenStack Neutron
+ possible.
+ """
+ def __init__(self):
+ self.onos_path = cfg.CONF.onos.url_path
+ self.onos_auth = (cfg.CONF.onos.username, cfg.CONF.onos.password)
+ self.vif_type = portbindings.VIF_TYPE_OVS
+ self.vif_details = {portbindings.CAP_PORT_FILTER: True}
+
+ def initialize(self):
+ # No action required as of now. Can be extended in
+ # the future if required.
+ pass
+
+ @log_helpers.log_method_call
+ def create_network_postcommit(self, context):
+ entity_path = 'networks'
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'post',
+ entity_path, {'network': resource})
+
+ @log_helpers.log_method_call
+ def update_network_postcommit(self, context):
+ entity_path = 'networks/' + context.current['id']
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'put',
+ entity_path, {'network': resource})
+
+ @log_helpers.log_method_call
+ def delete_network_postcommit(self, context):
+ entity_path = 'networks/' + context.current['id']
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'delete',
+ entity_path)
+
+ @log_helpers.log_method_call
+ def create_subnet_postcommit(self, context):
+ entity_path = 'subnets'
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'post',
+ entity_path, {'subnet': resource})
+
+ @log_helpers.log_method_call
+ def update_subnet_postcommit(self, context):
+ entity_path = 'subnets/' + context.current['id']
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'put',
+ entity_path, {'subnet': resource})
+
+ @log_helpers.log_method_call
+ def delete_subnet_postcommit(self, context):
+ entity_path = 'subnets/' + context.current['id']
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'delete',
+ entity_path)
+
+ @log_helpers.log_method_call
+ def create_port_postcommit(self, context):
+ entity_path = 'ports'
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'post',
+ entity_path, {'port': resource})
+
+ @log_helpers.log_method_call
+ def update_port_postcommit(self, context):
+ entity_path = 'ports/' + context.current['id']
+ resource = context.current.copy()
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'put',
+ entity_path, {'port': resource})
+
+ @log_helpers.log_method_call
+ def delete_port_postcommit(self, context):
+ entity_path = 'ports/' + context.current['id']
+ onos_utils.send_msg(self.onos_path, self.onos_auth, 'delete',
+ entity_path)
+
+ @log_helpers.log_method_call
+ def bind_port(self, context):
+ """Set port binding data for use with nova."""
+ LOG.debug("Attempting to bind port %(port)s on network %(network)s",
+ {'port': context.current['id'],
+ 'network': context.network.current['id']})
+ # Prepared porting binding data
+ for segment in context.segments_to_bind:
+ if self.check_segment(segment):
+ context.set_binding(segment[api.ID],
+ self.vif_type,
+ self.vif_details,
+ status=n_const.PORT_STATUS_ACTIVE)
+ LOG.debug("Port bound successful for segment: %s", segment)
+ return
+ else:
+ LOG.debug("Port bound un-successfult for segment ID %(id)s, "
+ "segment %(seg)s, phys net %(physnet)s, and "
+ "network type %(nettype)s",
+ {'id': segment[api.ID],
+ 'seg': segment[api.SEGMENTATION_ID],
+ 'physnet': segment[api.PHYSICAL_NETWORK],
+ 'nettype': segment[api.NETWORK_TYPE]})
+
+ @log_helpers.log_method_call
+ def check_segment(self, segment):
+ """Check whether segment is valid for the ONOS MechanismDriver."""
+
+ return segment[api.NETWORK_TYPE] in [constants.TYPE_LOCAL,
+ constants.TYPE_GRE,
+ constants.TYPE_VXLAN,
+ constants.TYPE_VLAN]
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/test_driver.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/test_driver.py
new file mode 100644
index 00000000..c0bba85a
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/l3/test_driver.py
@@ -0,0 +1,230 @@
+# Copyright (C) 2015 Huawei Technologies India Pvt Ltd.
+# 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.
+#
+
+import copy
+import mock
+
+from oslotest import base
+
+from neutron.extensions import l3
+from neutron.tests.unit.api.v2 import test_base
+from neutron.tests.unit.extensions import base as test_neutron_extensions
+from webob import exc
+
+import networking_onos.plugins.l3.driver as onos_driver
+
+fake_tenant_id = '048aa98a3ec345dc8b14427c81e276cf'
+
+fake_router_uuid = '292f7967-c5e7-47d8-8265-dc2160678b75'
+fake_router_object = {'router': {'name': 'router_abc',
+ 'external_gateway_info': None,
+ 'admin_state_up': True,
+ 'tenant_id': fake_tenant_id}}
+
+fake_network_id = '7464aaf0-27ea-448a-97df-51732f9e0e27'
+fake_router_external_info = {'external_gateway_info':
+ {'network_id': fake_network_id,
+ 'enable_snat': False}}
+
+fake_floating_ip_id = '7464aaf0-27ea-448a-97df-51732f9e0e25'
+fake_floating_ip = {'floatingip':
+ {'fixed_ip_address': '10.1.1.1',
+ 'id': fake_floating_ip_id,
+ 'router_id': fake_router_uuid,
+ 'port_id': None,
+ 'status': None,
+ 'tenant_id': fake_tenant_id}}
+
+fake_port_id = '7db560e9-76d4-4bf9-9c28-43efa7afa45d'
+fake_subnet_id = 'dc2b8071-c24c-4a8e-b471-dbf3fbe55830'
+fake_port = {'id': fake_port_id,
+ 'network_id': fake_network_id,
+ 'fixed_ips': [{'ip_address': '21.41.4.5',
+ 'prefixlen': 28,
+ 'subnet_id': fake_subnet_id}],
+ 'subnets': [{'id': fake_subnet_id,
+ 'cidr': '21.41.4.0/28',
+ 'gateway_ip': '21.41.4.1'}]}
+
+fake_floating_ip_update_info = {'floating_network_id': fake_network_id,
+ 'tenant_id': fake_tenant_id,
+ 'fixed_ip_address': '20.1.1.11',
+ 'subnet_id': fake_port['subnets'][0]['id'],
+ 'port_id': fake_port_id,
+ 'floating_ip_address': '198.1.2.3'}
+
+fake_interface_add = {'subnet_id': fake_subnet_id}
+
+fake_interface_remove = {'subnet_id': fake_subnet_id,
+ 'port_id': fake_port_id}
+
+
+class ONOSL3PluginTestCase(base.BaseTestCase,
+ test_neutron_extensions.ExtensionTestCase,
+ onos_driver.ONOSL3Plugin):
+
+ def setUp(self):
+ super(ONOSL3PluginTestCase, self).setUp()
+ self._setUpExtension(
+ 'neutron.extensions.l3.RouterPluginBase', None,
+ l3.RESOURCE_ATTRIBUTE_MAP, l3.L3, None,
+ allow_pagination=True, allow_sorting=True,
+ supported_extension_aliases=['router'],
+ use_quota=True)
+ self.instance = self.plugin.return_value
+
+ def _mock_req_res(self, status_code):
+ response = mock.Mock(status_code=status_code)
+ response.raise_for_status = mock.Mock()
+ return response
+
+ def _test_send_msg(self, dict_info, oper_type, url):
+ if oper_type == 'post':
+ resp = self.api.post(url, self.serialize(dict_info))
+ elif oper_type == 'put':
+ resp = self.api.put(url, self.serialize(dict_info))
+ else:
+ resp = self.api.delete(url)
+ return resp
+
+ def test_create_router(self):
+ router_info = copy.deepcopy(fake_router_object['router'])
+ router_info.update({'status': 'ACTIVE', 'id': fake_router_uuid})
+ self.instance.create_router.return_value = router_info
+ self.instance.get_routers_count.return_value = 0
+ url = test_base._get_path('routers', fmt=self.fmt)
+ resp = self._test_send_msg(fake_router_object, 'post', url)
+ self.instance.create_router.\
+ assert_called_once_with(mock.ANY, router=fake_router_object)
+ self._verify_resp(resp, exc.HTTPCreated.code,
+ 'router', fake_router_uuid)
+
+ def test_update_router(self):
+ router_info = copy.deepcopy(fake_router_object['router'])
+ router_info.update(fake_router_external_info)
+ router_info.update({'status': 'ACTIVE', 'id': fake_router_uuid})
+ self.instance.update_router.return_value = router_info
+ router_request = {'router': fake_router_external_info}
+ url = test_base._get_path('routers', id=fake_router_uuid, fmt=self.fmt)
+ resp = self._test_send_msg(router_request, 'put', url)
+ self.instance.update_router.\
+ assert_called_once_with(mock.ANY, fake_router_uuid,
+ router=router_request)
+ self._verify_resp(resp, exc.HTTPOk.code, 'router', fake_router_uuid)
+
+ def test_delete_router(self):
+ url = test_base._get_path('routers', id=fake_router_uuid, fmt=self.fmt)
+ resp = self._test_send_msg(None, 'delete', url)
+ self.instance.delete_router.assert_called_once_with(mock.ANY,
+ fake_router_uuid)
+ self.assertEqual(resp.status_int, exc.HTTPNoContent.code)
+
+ def test_create_floating_ip(self):
+ floatingip_info = copy.deepcopy(fake_floating_ip['floatingip'])
+ floatingip_info.update(fake_floating_ip_update_info)
+ floatingip_info.update({'status': 'ACTIVE', 'fixed_ip_address': None})
+
+ self.instance.create_floatingip.return_value = floatingip_info
+ self.instance.get_floatingips_count.return_value = 0
+ self.instance.get_port = mock.Mock(return_value=fake_port)
+
+ floating_ip_request = {'floatingip': fake_floating_ip_update_info}
+ url = test_base._get_path('floatingips', fmt=self.fmt)
+ resp = self._test_send_msg(floating_ip_request, 'post', url)
+ self.instance.create_floatingip.\
+ assert_called_once_with(mock.ANY,
+ floatingip=floating_ip_request)
+ self._verify_resp(resp, exc.HTTPCreated.code,
+ 'floatingip', fake_floating_ip_id)
+
+ def test_update_floating_ip(self):
+ fake_floating_ip_update_info = {'port_id': None}
+ floatingip_info = copy.deepcopy(fake_floating_ip['floatingip'])
+ floatingip_info.update(fake_floating_ip_update_info)
+ floatingip_info.update({'status': 'ACTIVE',
+ 'tenant_id': fake_tenant_id,
+ 'floating_network_id': fake_network_id,
+ 'fixed_ip_address': None,
+ 'floating_ip_address': '172.24.4.228'})
+
+ self.instance.update_floatingip.return_value = floatingip_info
+ self.instance.get_port = mock.Mock(return_value=fake_port)
+ floating_ip_request = {'floatingip': fake_floating_ip_update_info}
+ url = test_base._get_path('floatingips',
+ id=fake_floating_ip_id, fmt=self.fmt)
+ resp = self._test_send_msg(floating_ip_request, 'put', url)
+ self.instance.update_floatingip.\
+ assert_called_once_with(mock.ANY,
+ fake_floating_ip_id,
+ floatingip=floating_ip_request)
+ self._verify_resp(resp, exc.HTTPOk.code,
+ 'floatingip', fake_floating_ip_id)
+
+ def test_delete_floating_ip(self):
+ self.instance.get_port = mock.Mock(return_value=fake_port)
+ url = test_base._get_path('floatingips', id=fake_floating_ip_id)
+ resp = self._test_send_msg(None, 'delete', url)
+ self.instance.delete_floatingip.\
+ assert_called_once_with(mock.ANY, fake_floating_ip_id)
+ self.assertEqual(resp.status_int, exc.HTTPNoContent.code)
+
+ def test_add_router_interface(self):
+ interface_info = {'tenant_id': fake_tenant_id,
+ 'port_id': fake_port_id,
+ 'id': fake_router_uuid}
+ interface_info.update(fake_interface_add)
+ self.instance.add_router_interface.return_value = interface_info
+ url = test_base._get_path('routers', id=fake_router_uuid,
+ action='add_router_interface',
+ fmt=self.fmt)
+ resp = self._test_send_msg(fake_interface_add, 'put', url)
+ self.instance.add_router_interface.\
+ assert_called_once_with(mock.ANY, fake_router_uuid,
+ fake_interface_add)
+ self._verify_resp(resp, exc.HTTPOk.code, None, fake_router_uuid)
+
+ def test_remove_router_interface(self):
+ interface_info = {'tenant_id': fake_tenant_id,
+ 'id': fake_router_uuid}
+ interface_info.update(fake_interface_remove)
+ self.instance.remove_router_interface.return_value = interface_info
+ url = test_base._get_path('routers', id=fake_router_uuid,
+ action='remove_router_interface',
+ fmt=self.fmt)
+ resp = self._test_send_msg(fake_interface_remove, 'put', url)
+ self.instance.remove_router_interface.\
+ assert_called_once_with(mock.ANY, fake_router_uuid,
+ fake_interface_remove)
+ self._verify_resp(resp, exc.HTTPOk.code, None, fake_router_uuid)
+
+ def _verify_resp(self, resp, return_code, context, id):
+ self.assertEqual(resp.status_int, return_code)
+ resp = self.deserialize(resp)
+
+ if context is None:
+ self.assertEqual(resp['id'], id)
+ self.assertEqual(resp['subnet_id'], fake_subnet_id)
+ return
+
+ self.assertIn(context, resp)
+ resource = resp[context]
+ self.assertEqual(resource['id'], id)
+ if context == 'router':
+ self.assertEqual(resource['status'], 'ACTIVE')
+ self.assertEqual(resource['admin_state_up'], True)
+ elif context == 'floatingip':
+ self.assertEqual(resource['status'], 'ACTIVE')
+ self.assertEqual(resource['fixed_ip_address'], None)
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/__init__.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/__init__.py
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/test_driver.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/test_driver.py
new file mode 100644
index 00000000..89969239
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/networking_onos/tests/unit/plugins/ml2/test_driver.py
@@ -0,0 +1,237 @@
+# Copyright (c) 2015 Huawei Technologies India Pvt Ltd
+# 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.
+
+import mock
+import requests
+
+from oslo_config import cfg
+from oslo_serialization import jsonutils
+from oslotest import base
+
+from neutron.common import constants as n_const
+from neutron.plugins.common import constants
+from neutron.plugins.ml2 import driver_api as api
+from neutron.plugins.ml2 import driver_context as ctx
+
+import networking_onos.plugins.ml2.driver as onos_ml2_driver
+
+
+fake_network_uuid = 'd897e21a-dfd6-4331-a5dd-7524fa421c3e'
+fake_network_object = {'status': 'ACTIVE',
+ 'subnets': [],
+ 'name': 'net1',
+ 'provider:physical_network': None,
+ 'admin_state_up': True,
+ 'tenant_id': 'test-tenant',
+ 'provider:network_type': 'local',
+ 'router:external': False,
+ 'shared': False,
+ 'id': fake_network_uuid,
+ 'provider:segmentation_id': None}
+
+fake_subnet_uuid = 'd897e21a-dfd6-4331-a5dd-7524fa421c3e'
+fake_subnet_object = {'ipv6_ra_mode': None,
+ 'allocation_pools': [{'start': '10.0.0.2',
+ 'end': '10.0.1.254'}],
+ 'host_routes': [],
+ 'ipv6_address_mode': None,
+ 'cidr': '10.0.0.0/23',
+ 'id': fake_subnet_uuid,
+ 'name': '',
+ 'enable_dhcp': True,
+ 'network_id': fake_network_uuid,
+ 'tenant_id': 'test-tenant',
+ 'dns_nameservers': [],
+ 'gateway_ip': '10.0.0.1',
+ 'ip_version': 4,
+ 'shared': False}
+
+fake_port_uuid = '72c56c48-e9b8-4dcf-b3a7-0813bb3bd839'
+fake_port_object = {'status': 'DOWN',
+ 'binding:host_id': '',
+ 'allowed_address_pairs': [],
+ 'device_owner': 'fake_owner',
+ 'binding:profile': {},
+ 'fixed_ips': [],
+ 'id': fake_port_uuid,
+ 'security_groups':
+ ['2f9244b4-9bee-4e81-bc4a-3f3c2045b3d7'],
+ 'device_id': 'fake_device',
+ 'name': '',
+ 'admin_state_up': True,
+ 'network_id': fake_network_uuid,
+ 'tenant_id': 'test-tenant',
+ 'binding:vif_details': {},
+ 'binding:vnic_type': 'normal',
+ 'binding:vif_type': 'unbound',
+ 'mac_address': '12:34:56 :78:21:b6'}
+
+
+class ONOSMechanismDriverTestCase(base.BaseTestCase,
+ onos_ml2_driver.ONOSMechanismDriver):
+
+ def setUp(self):
+ super(ONOSMechanismDriverTestCase, self).setUp()
+ self.set_test_config()
+
+ def set_test_config(self):
+ cfg.CONF.set_override('url_path', 'http://127.0.0.1:1111', 'onos')
+ cfg.CONF.set_override('username', 'onos_user', 'onos')
+ cfg.CONF.set_override('password', 'awesome', 'onos')
+ self.onos_path = cfg.CONF.onos.url_path
+ self.onos_auth = (cfg.CONF.onos.username,
+ cfg.CONF.onos.password)
+
+ def _mock_req_resp(self, status_code):
+ response = mock.Mock(status_code=status_code)
+ response.raise_for_status = mock.Mock()
+ return response
+
+ def _test_response(self, context, oper_type, obj_type, mock_method):
+ body = None
+ if oper_type is not 'delete':
+ entity = {obj_type: context.current.copy()}
+ body = jsonutils.dumps(entity, indent=2)
+ if oper_type == 'post':
+ url = '%s/%s' % (self.onos_path, obj_type + 's')
+ else:
+ url = '%s/%s/%s' % (self.onos_path, obj_type + 's',
+ context.current['id'])
+ kwargs = {'url': url, 'data': body}
+ mock_method.assert_called_once_with(
+ method=oper_type,
+ headers={'Content-Type': 'application/json'},
+ auth=self.onos_auth, **kwargs)
+
+ def test_create_network_postcommit(self):
+ context = mock.Mock(current=fake_network_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.create_network_postcommit(context)
+ self._test_response(context, 'post', 'network', mock_method)
+
+ def test_update_network_postcommit(self):
+ context = mock.Mock(current=fake_network_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.update_network_postcommit(context)
+ self._test_response(context, 'put', 'network', mock_method)
+
+ def test_delete_network_postcommit(self):
+ context = mock.Mock(current={'id': fake_network_uuid})
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.delete_network_postcommit(context)
+ self._test_response(context, 'delete', 'network', mock_method)
+
+ def test_create_subnet_postcommit(self):
+ context = mock.Mock(current=fake_subnet_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.create_subnet_postcommit(context)
+ self._test_response(context, 'post', 'subnet', mock_method)
+
+ def test_update_subnet_postcommit(self):
+ context = mock.Mock(current=fake_subnet_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.update_subnet_postcommit(context)
+ self._test_response(context, 'put', 'subnet', mock_method)
+
+ def test_delete_subnet_postcommit(self):
+ context = mock.Mock(current={'id': fake_subnet_uuid})
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.delete_subnet_postcommit(context)
+ self._test_response(context, 'delete', 'subnet', mock_method)
+
+ def test_create_port_postcommit(self):
+ context = mock.Mock(current=fake_port_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.create_port_postcommit(context)
+ self._test_response(context, 'post', 'port', mock_method)
+
+ def test_update_port_postcommit(self):
+ context = mock.Mock(current=fake_port_object)
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.update_port_postcommit(context)
+ self._test_response(context, 'put', 'port', mock_method)
+
+ def test_delete_port_postcommit(self):
+ context = mock.Mock(current={'id': fake_port_uuid})
+ resp = self._mock_req_resp(requests.codes.created)
+ with mock.patch('requests.request',
+ return_value=resp) as mock_method:
+ self.delete_port_postcommit(context)
+ self._test_response(context, 'delete', 'port', mock_method)
+
+ # given valid and invalid segments
+ valid_segment = {
+ api.ID: 'API_ID',
+ api.NETWORK_TYPE: constants.TYPE_LOCAL,
+ api.SEGMENTATION_ID: 'API_SEGMENTATION_ID',
+ api.PHYSICAL_NETWORK: 'API_PHYSICAL_NETWORK'}
+
+ invalid_segment = {
+ api.ID: 'API_ID',
+ api.NETWORK_TYPE: constants.TYPE_NONE,
+ api.SEGMENTATION_ID: 'API_SEGMENTATION_ID',
+ api.PHYSICAL_NETWORK: 'API_PHYSICAL_NETWORK'}
+
+ def test_check_segment(self):
+ """Validate the check_segment method."""
+
+ # given driver and all network types
+ all_network_types = [constants.TYPE_FLAT, constants.TYPE_GRE,
+ constants.TYPE_LOCAL, constants.TYPE_VXLAN,
+ constants.TYPE_VLAN, constants.TYPE_NONE]
+
+ # when checking segments network type
+ valid_types = {network_type
+ for network_type in all_network_types
+ if self.check_segment({api.NETWORK_TYPE: network_type})}
+
+ # then true is returned only for valid network types
+ self.assertEqual({constants.TYPE_LOCAL, constants.TYPE_GRE,
+ constants.TYPE_VXLAN, constants.TYPE_VLAN},
+ valid_types)
+
+ def test_bind_port(self):
+ self.vif_type = "MY_VIF_TYPE"
+ self.vif_details = "MY_VIF_DETAILS"
+ network = mock.MagicMock(spec=api.NetworkContext)
+ port_context = mock.MagicMock(
+ spec=ctx.PortContext, current={'id': 'CURRENT_CONTEXT_ID'},
+ segments_to_bind=[self.valid_segment, self.invalid_segment],
+ network=network)
+
+ # when port is bound
+ self.bind_port(port_context)
+
+ # then context binding is setup with returned vif_type and valid
+ # segment api ID
+ port_context.set_binding.assert_called_once_with(
+ self.valid_segment[api.ID], self.vif_type,
+ self.vif_details, status=n_const.PORT_STATUS_ACTIVE)
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/openstack-common.conf b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/openstack-common.conf
new file mode 100644
index 00000000..7caa758d
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/openstack-common.conf
@@ -0,0 +1,5 @@
+[DEFAULT]
+# The list of modules to copy from oslo-incubator.git
+
+# The base module to hold the copy of openstack.common
+base=networking_onos
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/requirements.txt b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/requirements.txt
new file mode 100644
index 00000000..26bb9244
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/requirements.txt
@@ -0,0 +1,9 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
+
+pbr>=1.6
+Babel>=1.3
+-e git://git.openstack.org/openstack/neutron.git#egg=neutron
+
+
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/setup.cfg b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/setup.cfg
new file mode 100644
index 00000000..d7fd5b1d
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/setup.cfg
@@ -0,0 +1,56 @@
+[metadata]
+name = networking-onos
+summary = OpenStack Networking
+description-file =
+ README.rst
+author = OpenStack
+author-email = openstack-dev@lists.openstack.org
+home-page = http://www.openstack.org/
+classifier =
+ Environment :: OpenStack
+ Intended Audience :: Information Technology
+ Intended Audience :: System Administrators
+ License :: OSI Approved :: Apache Software License
+ Operating System :: POSIX :: Linux
+ Programming Language :: Python
+ Programming Language :: Python :: 2
+ Programming Language :: Python :: 2.7
+
+[files]
+packages =
+ networking_onos
+data_files =
+ etc/neutron/plugins/ml2 =
+ etc/conf_onos.ini
+
+[global]
+setup-hooks =
+ pbr.hooks.setup_hook
+
+[entry_points]
+neutron.ml2.mechanism_drivers =
+ onos_ml2 = networking_onos.plugins.ml2.driver:ONOSMechanismDriver
+neutron.service_plugins =
+ onos_router = networking_onos.plugins.l3.driver:ONOSL3Plugin
+
+[build_sphinx]
+all_files = 1
+build-dir = doc/build
+source-dir = doc/source
+
+[extract_messages]
+keywords = _ gettext ngettext l_ lazy_gettext
+mapping_file = babel.cfg
+output_file = networking_onos/locale/networking-onos.pot
+
+[compile_catalog]
+directory = networking_onos/locale
+domain = networking-onos
+
+[update_catalog]
+domain = networking-onos
+output_dir = networking_onos/locale
+input_file = networking_onos/locale/networking-onos.pot
+
+[wheel]
+universal = 1
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/setup.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/setup.py
new file mode 100644
index 00000000..782bb21f
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/setup.py
@@ -0,0 +1,29 @@
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
+#
+# 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.
+
+# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
+import setuptools
+
+# In python < 2.7.4, a lazy loading of package `pbr` will break
+# setuptools if some other modules registered functions in `atexit`.
+# solution from: http://bugs.python.org/issue15881#msg170215
+try:
+ import multiprocessing # noqa
+except ImportError:
+ pass
+
+setuptools.setup(
+ setup_requires=['pbr>=1.8'],
+ pbr=True)
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/test-requirements.txt b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/test-requirements.txt
new file mode 100644
index 00000000..2bf64e0b
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/test-requirements.txt
@@ -0,0 +1,15 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
+
+hacking<0.11,>=0.10.0
+
+coverage>=3.6
+python-subunit>=0.0.18
+sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
+oslosphinx>=2.5.0 # Apache-2.0
+oslotest>=1.10.0 # Apache-2.0
+testrepository>=0.0.18
+testscenarios>=0.4
+WebTest>=2.0
+testtools>=1.4.0
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_bash.sh b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_bash.sh
new file mode 100644
index 00000000..e9d178ee
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_bash.sh
@@ -0,0 +1,31 @@
+#! /bin/sh
+
+# Copyright (C) 2014 VA Linux Systems Japan K.K.
+# Copyright (C) 2014 YAMAMOTO Takashi <yamamoto at valinux co jp>
+# 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.
+
+# The purpose of this script is to avoid casual introduction of more
+# bash dependency. Please consider alternatives before commiting code
+# which uses bash specific features.
+
+# Ignore comments, but include shebangs
+OBSERVED=$(grep -E '^([^#]|#!).*bash' tox.ini tools/* | wc -l)
+EXPECTED=5
+if [ ${EXPECTED} -ne ${OBSERVED} ]; then
+ echo Unexpected number of bash usages are detected.
+ echo Please read the comment in $0
+ exit 1
+fi
+exit 0
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_i18n.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_i18n.py
new file mode 100644
index 00000000..697ad180
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_i18n.py
@@ -0,0 +1,153 @@
+# Copyright 2012 OpenStack Foundation
+#
+# 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.
+from __future__ import print_function
+
+import compiler
+import imp
+import os.path
+import sys
+
+
+def is_localized(node):
+ """Check message wrapped by _()"""
+ if isinstance(node.parent, compiler.ast.CallFunc):
+ if isinstance(node.parent.node, compiler.ast.Name):
+ if node.parent.node.name == '_':
+ return True
+ return False
+
+
+class ASTWalker(compiler.visitor.ASTVisitor):
+
+ def default(self, node, *args):
+ for child in node.getChildNodes():
+ child.parent = node
+ compiler.visitor.ASTVisitor.default(self, node, *args)
+
+
+class Visitor(object):
+
+ def __init__(self, filename, i18n_msg_predicates,
+ msg_format_checkers, debug):
+ self.filename = filename
+ self.debug = debug
+ self.error = 0
+ self.i18n_msg_predicates = i18n_msg_predicates
+ self.msg_format_checkers = msg_format_checkers
+ with open(filename) as f:
+ self.lines = f.readlines()
+
+ def visitConst(self, node):
+ if not isinstance(node.value, str):
+ return
+
+ if is_localized(node):
+ for (checker, msg) in self.msg_format_checkers:
+ if checker(node):
+ print('%s:%d %s: %s Error: %s' %
+ (self.filename, node.lineno,
+ self.lines[node.lineno - 1][:-1],
+ checker.__name__, msg),
+ file=sys.stderr)
+ self.error = 1
+ return
+ if debug:
+ print('%s:%d %s: %s' %
+ (self.filename, node.lineno,
+ self.lines[node.lineno - 1][:-1],
+ "Pass"))
+ else:
+ for (predicate, action, msg) in self.i18n_msg_predicates:
+ if predicate(node):
+ if action == 'skip':
+ if debug:
+ print('%s:%d %s: %s' %
+ (self.filename, node.lineno,
+ self.lines[node.lineno - 1][:-1],
+ "Pass"))
+ return
+ elif action == 'error':
+ print('%s:%d %s: %s Error: %s' %
+ (self.filename, node.lineno,
+ self.lines[node.lineno - 1][:-1],
+ predicate.__name__, msg),
+ file=sys.stderr)
+ self.error = 1
+ return
+ elif action == 'warn':
+ print('%s:%d %s: %s' %
+ (self.filename, node.lineno,
+ self.lines[node.lineno - 1][:-1],
+ "Warn: %s" % msg))
+ return
+ print('Predicate with wrong action!', file=sys.stderr)
+
+
+def is_file_in_black_list(black_list, f):
+ for f in black_list:
+ if os.path.abspath(input_file).startswith(
+ os.path.abspath(f)):
+ return True
+ return False
+
+
+def check_i18n(input_file, i18n_msg_predicates, msg_format_checkers, debug):
+ input_mod = compiler.parseFile(input_file)
+ v = compiler.visitor.walk(input_mod,
+ Visitor(input_file,
+ i18n_msg_predicates,
+ msg_format_checkers,
+ debug),
+ ASTWalker())
+ return v.error
+
+
+if __name__ == '__main__':
+ input_path = sys.argv[1]
+ cfg_path = sys.argv[2]
+ try:
+ cfg_mod = imp.load_source('', cfg_path)
+ except Exception:
+ print("Load cfg module failed", file=sys.stderr)
+ sys.exit(1)
+
+ i18n_msg_predicates = cfg_mod.i18n_msg_predicates
+ msg_format_checkers = cfg_mod.msg_format_checkers
+ black_list = cfg_mod.file_black_list
+
+ debug = False
+ if len(sys.argv) > 3:
+ if sys.argv[3] == '-d':
+ debug = True
+
+ if os.path.isfile(input_path):
+ sys.exit(check_i18n(input_path,
+ i18n_msg_predicates,
+ msg_format_checkers,
+ debug))
+
+ error = 0
+ for dirpath, dirs, files in os.walk(input_path):
+ for f in files:
+ if not f.endswith('.py'):
+ continue
+ input_file = os.path.join(dirpath, f)
+ if is_file_in_black_list(black_list, input_file):
+ continue
+ if check_i18n(input_file,
+ i18n_msg_predicates,
+ msg_format_checkers,
+ debug):
+ error = 1
+ sys.exit(error)
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_i18n_test_case.txt b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_i18n_test_case.txt
new file mode 100644
index 00000000..3d1391d9
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/check_i18n_test_case.txt
@@ -0,0 +1,67 @@
+# test-case for check_i18n.py
+# python check_i18n.py check_i18n.txt -d
+
+# message format checking
+# capital checking
+msg = _("hello world, error")
+msg = _("hello world_var, error")
+msg = _('file_list xyz, pass')
+msg = _("Hello world, pass")
+
+# format specifier checking
+msg = _("Hello %s world %d, error")
+msg = _("Hello %s world, pass")
+msg = _("Hello %(var1)s world %(var2)s, pass")
+
+# message has been localized
+# is_localized
+msg = _("Hello world, pass")
+msg = _("Hello world, pass") % var
+LOG.debug(_('Hello world, pass'))
+LOG.info(_('Hello world, pass'))
+raise x.y.Exception(_('Hello world, pass'))
+raise Exception(_('Hello world, pass'))
+
+# message need be localized
+# is_log_callfunc
+LOG.debug('hello world, error')
+LOG.debug('hello world, error' % xyz)
+sys.append('hello world, warn')
+
+# is_log_i18n_msg_with_mod
+LOG.debug(_('Hello world, error') % xyz)
+
+# default warn
+msg = 'hello world, warn'
+msg = 'hello world, warn' % var
+
+# message needn't be localized
+# skip only one word
+msg = ''
+msg = "hello,pass"
+
+# skip dict
+msg = {'hello world, pass': 1}
+
+# skip list
+msg = ["hello world, pass"]
+
+# skip subscript
+msg['hello world, pass']
+
+# skip xml marker
+msg = "<test><t></t></test>, pass"
+
+# skip sql statement
+msg = "SELECT * FROM xyz WHERE hello=1, pass"
+msg = "select * from xyz, pass"
+
+# skip add statement
+msg = 'hello world' + e + 'world hello, pass'
+
+# skip doc string
+"""
+Hello world, pass
+"""
+class Msg:
+ pass
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/clean.sh b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/clean.sh
new file mode 100755
index 00000000..27bc219f
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/clean.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+rm -rf ./*.deb ./*.tar.gz ./*.dsc ./*.changes
+rm -rf */*.deb
+rm -rf ./plugins/**/build/ ./plugins/**/dist
+rm -rf ./plugins/**/lib/neutron_*_plugin.egg-info ./plugins/neutron-*
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/i18n_cfg.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/i18n_cfg.py
new file mode 100644
index 00000000..5ad1a514
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/i18n_cfg.py
@@ -0,0 +1,97 @@
+import compiler
+import re
+
+
+def is_log_callfunc(n):
+ """LOG.xxx('hello %s' % xyz) and LOG('hello')"""
+ if isinstance(n.parent, compiler.ast.Mod):
+ n = n.parent
+ if isinstance(n.parent, compiler.ast.CallFunc):
+ if isinstance(n.parent.node, compiler.ast.Getattr):
+ if isinstance(n.parent.node.getChildNodes()[0],
+ compiler.ast.Name):
+ if n.parent.node.getChildNodes()[0].name == 'LOG':
+ return True
+ return False
+
+
+def is_log_i18n_msg_with_mod(n):
+ """LOG.xxx("Hello %s" % xyz) should be LOG.xxx("Hello %s", xyz)"""
+ if not isinstance(n.parent.parent, compiler.ast.Mod):
+ return False
+ n = n.parent.parent
+ if isinstance(n.parent, compiler.ast.CallFunc):
+ if isinstance(n.parent.node, compiler.ast.Getattr):
+ if isinstance(n.parent.node.getChildNodes()[0],
+ compiler.ast.Name):
+ if n.parent.node.getChildNodes()[0].name == 'LOG':
+ return True
+ return False
+
+
+def is_wrong_i18n_format(n):
+ """Check _('hello %s' % xyz)"""
+ if isinstance(n.parent, compiler.ast.Mod):
+ n = n.parent
+ if isinstance(n.parent, compiler.ast.CallFunc):
+ if isinstance(n.parent.node, compiler.ast.Name):
+ if n.parent.node.name == '_':
+ return True
+ return False
+
+
+"""
+Used for check message need be localized or not.
+(predicate_func, action, message)
+"""
+i18n_msg_predicates = [
+ # Skip ['hello world', 1]
+ (lambda n: isinstance(n.parent, compiler.ast.List), 'skip', ''),
+ # Skip {'hellow world', 1}
+ (lambda n: isinstance(n.parent, compiler.ast.Dict), 'skip', ''),
+ # Skip msg['hello world']
+ (lambda n: isinstance(n.parent, compiler.ast.Subscript), 'skip', ''),
+ # Skip doc string
+ (lambda n: isinstance(n.parent, compiler.ast.Discard), 'skip', ''),
+ # Skip msg = "hello", in normal, message should more than one word
+ (lambda n: len(n.value.strip().split(' ')) <= 1, 'skip', ''),
+ # Skip msg = 'hello world' + vars + 'world hello'
+ (lambda n: isinstance(n.parent, compiler.ast.Add), 'skip', ''),
+ # Skip xml markers msg = "<test></test>"
+ (lambda n: len(re.compile("</.*>").findall(n.value)) > 0, 'skip', ''),
+ # Skip sql statement
+ (lambda n: len(
+ re.compile("^SELECT.*FROM", flags=re.I).findall(n.value)) > 0,
+ 'skip', ''),
+ # LOG.xxx()
+ (is_log_callfunc, 'error', 'Message must be localized'),
+ # _('hello %s' % xyz) should be _('hello %s') % xyz
+ (is_wrong_i18n_format, 'error',
+ ("Message format was wrong, _('hello %s' % xyz) "
+ "should be _('hello %s') % xyz")),
+ # default
+ (lambda n: True, 'warn', 'Message might need localized')
+]
+
+
+"""
+Used for checking message format. (checker_func, message)
+"""
+msg_format_checkers = [
+ # If message contain more than on format specifier, it should use
+ # mapping key
+ (lambda n: len(re.compile("%[bcdeEfFgGnosxX]").findall(n.value)) > 1,
+ "The message shouldn't contain more than one format specifier"),
+ # Check capital
+ (lambda n: n.value.split(' ')[0].count('_') == 0 and
+ n.value[0].isalpha() and
+ n.value[0].islower(),
+ "First letter must be capital"),
+ (is_log_i18n_msg_with_mod,
+ 'LOG.xxx("Hello %s" % xyz) should be LOG.xxx("Hello %s", xyz)')
+]
+
+
+file_black_list = ["./neutron/tests/unit",
+ "./neutron/openstack",
+ "./neutron/plugins/bigswitch/tests"]
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/install_venv.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/install_venv.py
new file mode 100644
index 00000000..f8fb8fa2
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/install_venv.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2010 OpenStack Foundation.
+# Copyright 2013 IBM Corp.
+#
+# 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.
+
+"""
+Installation script for Neutron's development virtualenv
+"""
+from __future__ import print_function
+
+import os
+import sys
+
+import install_venv_common as install_venv
+
+
+def print_help():
+ help = """
+ Neutron development environment setup is complete.
+
+ Neutron development uses virtualenv to track and manage Python dependencies
+ while in development and testing.
+
+ To activate the Neutron virtualenv for the extent of your current shell
+ session you can run:
+
+ $ source .venv/bin/activate
+
+ Or, if you prefer, you can run commands in the virtualenv on a case by case
+ basis by running:
+
+ $ tools/with_venv.sh <your command>
+
+ Also, make test will automatically use the virtualenv.
+ """
+ print(help)
+
+
+def main(argv):
+ root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
+ venv = os.path.join(root, '.venv')
+ pip_requires = os.path.join(root, 'requirements.txt')
+ test_requires = os.path.join(root, 'test-requirements.txt')
+ py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
+ project = 'Neutron'
+ install = install_venv.InstallVenv(root, venv, pip_requires, test_requires,
+ py_version, project)
+ options = install.parse_args(argv)
+ install.check_python_version()
+ install.check_dependencies()
+ install.create_virtualenv(no_site_packages=options.no_site_packages)
+ install.install_dependencies()
+ print_help()
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/install_venv_common.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/install_venv_common.py
new file mode 100644
index 00000000..e279159a
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/install_venv_common.py
@@ -0,0 +1,172 @@
+# Copyright 2013 OpenStack Foundation
+# Copyright 2013 IBM Corp.
+#
+# 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.
+
+"""Provides methods needed by installation script for OpenStack development
+virtual environments.
+
+Since this script is used to bootstrap a virtualenv from the system's Python
+environment, it should be kept strictly compatible with Python 2.6.
+
+Synced in from openstack-common
+"""
+
+from __future__ import print_function
+
+import optparse
+import os
+import subprocess
+import sys
+
+
+class InstallVenv(object):
+
+ def __init__(self, root, venv, requirements,
+ test_requirements, py_version,
+ project):
+ self.root = root
+ self.venv = venv
+ self.requirements = requirements
+ self.test_requirements = test_requirements
+ self.py_version = py_version
+ self.project = project
+
+ def die(self, message, *args):
+ print(message % args, file=sys.stderr)
+ sys.exit(1)
+
+ def check_python_version(self):
+ if sys.version_info < (2, 6):
+ self.die("Need Python Version >= 2.6")
+
+ def run_command_with_code(self, cmd, redirect_output=True,
+ check_exit_code=True):
+ """Runs a command in an out-of-process shell.
+
+ Returns the output of that command. Working directory is self.root.
+ """
+ if redirect_output:
+ stdout = subprocess.PIPE
+ else:
+ stdout = None
+
+ proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout)
+ output = proc.communicate()[0]
+ if check_exit_code and proc.returncode != 0:
+ self.die('Command "%s" failed.\n%s', ' '.join(cmd), output)
+ return (output, proc.returncode)
+
+ def run_command(self, cmd, redirect_output=True, check_exit_code=True):
+ return self.run_command_with_code(cmd, redirect_output,
+ check_exit_code)[0]
+
+ def get_distro(self):
+ if (os.path.exists('/etc/fedora-release') or
+ os.path.exists('/etc/redhat-release')):
+ return Fedora(
+ self.root, self.venv, self.requirements,
+ self.test_requirements, self.py_version, self.project)
+ else:
+ return Distro(
+ self.root, self.venv, self.requirements,
+ self.test_requirements, self.py_version, self.project)
+
+ def check_dependencies(self):
+ self.get_distro().install_virtualenv()
+
+ def create_virtualenv(self, no_site_packages=True):
+ """Creates the virtual environment and installs PIP.
+
+ Creates the virtual environment and installs PIP only into the
+ virtual environment.
+ """
+ if not os.path.isdir(self.venv):
+ print('Creating venv...', end=' ')
+ if no_site_packages:
+ self.run_command(['virtualenv', '-q', '--no-site-packages',
+ self.venv])
+ else:
+ self.run_command(['virtualenv', '-q', self.venv])
+ print('done.')
+ else:
+ print("venv already exists...")
+ pass
+
+ def pip_install(self, *args):
+ self.run_command(['tools/with_venv.sh',
+ 'pip', 'install', '--upgrade'] + list(args),
+ redirect_output=False)
+
+ def install_dependencies(self):
+ print('Installing dependencies with pip (this can take a while)...')
+
+ # First things first, make sure our venv has the latest pip and
+ # setuptools and pbr
+ self.pip_install('pip>=1.4')
+ self.pip_install('setuptools')
+ self.pip_install('pbr')
+
+ self.pip_install('-r', self.requirements, '-r', self.test_requirements)
+
+ def parse_args(self, argv):
+ """Parses command-line arguments."""
+ parser = optparse.OptionParser()
+ parser.add_option('-n', '--no-site-packages',
+ action='store_true',
+ help="Do not inherit packages from global Python "
+ "install.")
+ return parser.parse_args(argv[1:])[0]
+
+
+class Distro(InstallVenv):
+
+ def check_cmd(self, cmd):
+ return bool(self.run_command(['which', cmd],
+ check_exit_code=False).strip())
+
+ def install_virtualenv(self):
+ if self.check_cmd('virtualenv'):
+ return
+
+ if self.check_cmd('easy_install'):
+ print('Installing virtualenv via easy_install...', end=' ')
+ if self.run_command(['easy_install', 'virtualenv']):
+ print('Succeeded')
+ return
+ else:
+ print('Failed')
+
+ self.die('ERROR: virtualenv not found.\n\n%s development'
+ ' requires virtualenv, please install it using your'
+ ' favorite package management tool' % self.project)
+
+
+class Fedora(Distro):
+ """This covers all Fedora-based distributions.
+
+ Includes: Fedora, RHEL, CentOS, Scientific Linux
+ """
+
+ def check_pkg(self, pkg):
+ return self.run_command_with_code(['rpm', '-q', pkg],
+ check_exit_code=False)[1] == 0
+
+ def install_virtualenv(self):
+ if self.check_cmd('virtualenv'):
+ return
+
+ if not self.check_pkg('python-virtualenv'):
+ self.die("Please install 'python-virtualenv'.")
+
+ super(Fedora, self).install_virtualenv()
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/pretty_tox.sh b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/pretty_tox.sh
new file mode 100755
index 00000000..a40f2482
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/pretty_tox.sh
@@ -0,0 +1,6 @@
+#! /bin/sh
+
+TESTRARGS=$1
+
+exec 3>&1
+status=$(exec 4>&1 >&3; ( python setup.py testr --slowest --testr-args="--subunit $TESTRARGS"; echo $? >&4 ) | $(dirname $0)/subunit-trace.py -f) && exit $status
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/subunit-trace.py b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/subunit-trace.py
new file mode 100755
index 00000000..73f2f105
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/subunit-trace.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python
+
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
+# Copyright 2014 Samsung Electronics
+# 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.
+
+"""Trace a subunit stream in reasonable detail and high accuracy."""
+
+import argparse
+import functools
+import os
+import re
+import sys
+
+import mimeparse
+import subunit
+import testtools
+
+DAY_SECONDS = 60 * 60 * 24
+FAILS = []
+RESULTS = {}
+
+
+class Starts(testtools.StreamResult):
+
+ def __init__(self, output):
+ super(Starts, self).__init__()
+ self._output = output
+
+ def startTestRun(self):
+ self._neednewline = False
+ self._emitted = set()
+
+ def status(self, test_id=None, test_status=None, test_tags=None,
+ runnable=True, file_name=None, file_bytes=None, eof=False,
+ mime_type=None, route_code=None, timestamp=None):
+ super(Starts, self).status(
+ test_id, test_status,
+ test_tags=test_tags, runnable=runnable, file_name=file_name,
+ file_bytes=file_bytes, eof=eof, mime_type=mime_type,
+ route_code=route_code, timestamp=timestamp)
+ if not test_id:
+ if not file_bytes:
+ return
+ if not mime_type or mime_type == 'test/plain;charset=utf8':
+ mime_type = 'text/plain; charset=utf-8'
+ primary, sub, parameters = mimeparse.parse_mime_type(mime_type)
+ content_type = testtools.content_type.ContentType(
+ primary, sub, parameters)
+ content = testtools.content.Content(
+ content_type, lambda: [file_bytes])
+ text = content.as_text()
+ if text and text[-1] not in '\r\n':
+ self._neednewline = True
+ self._output.write(text)
+ elif test_status == 'inprogress' and test_id not in self._emitted:
+ if self._neednewline:
+ self._neednewline = False
+ self._output.write('\n')
+ worker = ''
+ for tag in test_tags or ():
+ if tag.startswith('worker-'):
+ worker = '(' + tag[7:] + ') '
+ if timestamp:
+ timestr = timestamp.isoformat()
+ else:
+ timestr = ''
+ self._output.write('%s: %s%s [start]\n' %
+ (timestr, worker, test_id))
+ self._emitted.add(test_id)
+
+
+def cleanup_test_name(name, strip_tags=True, strip_scenarios=False):
+ """Clean up the test name for display.
+
+ By default we strip out the tags in the test because they don't help us
+ in identifying the test that is run to it's result.
+
+ Make it possible to strip out the testscenarios information (not to
+ be confused with tempest scenarios) however that's often needed to
+ indentify generated negative tests.
+ """
+ if strip_tags:
+ tags_start = name.find('[')
+ tags_end = name.find(']')
+ if tags_start > 0 and tags_end > tags_start:
+ newname = name[:tags_start]
+ newname += name[tags_end + 1:]
+ name = newname
+
+ if strip_scenarios:
+ tags_start = name.find('(')
+ tags_end = name.find(')')
+ if tags_start > 0 and tags_end > tags_start:
+ newname = name[:tags_start]
+ newname += name[tags_end + 1:]
+ name = newname
+
+ return name
+
+
+def get_duration(timestamps):
+ start, end = timestamps
+ if not start or not end:
+ duration = ''
+ else:
+ delta = end - start
+ duration = '%d.%06ds' % (
+ delta.days * DAY_SECONDS + delta.seconds, delta.microseconds)
+ return duration
+
+
+def find_worker(test):
+ for tag in test['tags']:
+ if tag.startswith('worker-'):
+ return int(tag[7:])
+ return 'NaN'
+
+
+# Print out stdout/stderr if it exists, always
+def print_attachments(stream, test, all_channels=False):
+ """Print out subunit attachments.
+
+ Print out subunit attachments that contain content. This
+ runs in 2 modes, one for successes where we print out just stdout
+ and stderr, and an override that dumps all the attachments.
+ """
+ channels = ('stdout', 'stderr')
+ for name, detail in test['details'].items():
+ # NOTE(sdague): the subunit names are a little crazy, and actually
+ # are in the form pythonlogging:'' (with the colon and quotes)
+ name = name.split(':')[0]
+ if detail.content_type.type == 'test':
+ detail.content_type.type = 'text'
+ if (all_channels or name in channels) and detail.as_text():
+ title = "Captured %s:" % name
+ stream.write("\n%s\n%s\n" % (title, ('~' * len(title))))
+ # indent attachment lines 4 spaces to make them visually
+ # offset
+ for line in detail.as_text().split('\n'):
+ stream.write(" %s\n" % line)
+
+
+def show_outcome(stream, test, print_failures=False, failonly=False):
+ global RESULTS
+ status = test['status']
+ # TODO(sdague): ask lifeless why on this?
+ if status == 'exists':
+ return
+
+ worker = find_worker(test)
+ name = cleanup_test_name(test['id'])
+ duration = get_duration(test['timestamps'])
+
+ if worker not in RESULTS:
+ RESULTS[worker] = []
+ RESULTS[worker].append(test)
+
+ # don't count the end of the return code as a fail
+ if name == 'process-returncode':
+ return
+
+ if status == 'fail':
+ FAILS.append(test)
+ stream.write('{%s} %s [%s] ... FAILED\n' % (
+ worker, name, duration))
+ if not print_failures:
+ print_attachments(stream, test, all_channels=True)
+ elif not failonly:
+ if status == 'success':
+ stream.write('{%s} %s [%s] ... ok\n' % (
+ worker, name, duration))
+ print_attachments(stream, test)
+ elif status == 'skip':
+ stream.write('{%s} %s ... SKIPPED: %s\n' % (
+ worker, name, test['details']['reason'].as_text()))
+ else:
+ stream.write('{%s} %s [%s] ... %s\n' % (
+ worker, name, duration, test['status']))
+ if not print_failures:
+ print_attachments(stream, test, all_channels=True)
+
+ stream.flush()
+
+
+def print_fails(stream):
+ """Print summary failure report.
+
+ Currently unused, however there remains debate on inline vs. at end
+ reporting, so leave the utility function for later use.
+ """
+ if not FAILS:
+ return
+ stream.write("\n==============================\n")
+ stream.write("Failed %s tests - output below:" % len(FAILS))
+ stream.write("\n==============================\n")
+ for f in FAILS:
+ stream.write("\n%s\n" % f['id'])
+ stream.write("%s\n" % ('-' * len(f['id'])))
+ print_attachments(stream, f, all_channels=True)
+ stream.write('\n')
+
+
+def count_tests(key, value):
+ count = 0
+ for k, v in RESULTS.items():
+ for item in v:
+ if key in item:
+ if re.search(value, item[key]):
+ count += 1
+ return count
+
+
+def run_time():
+ runtime = 0.0
+ for k, v in RESULTS.items():
+ for test in v:
+ runtime += float(get_duration(test['timestamps']).strip('s'))
+ return runtime
+
+
+def worker_stats(worker):
+ tests = RESULTS[worker]
+ num_tests = len(tests)
+ delta = tests[-1]['timestamps'][1] - tests[0]['timestamps'][0]
+ return num_tests, delta
+
+
+def print_summary(stream):
+ stream.write("\n======\nTotals\n======\n")
+ stream.write("Run: %s in %s sec.\n" % (count_tests('status', '.*'),
+ run_time()))
+ stream.write(" - Passed: %s\n" % count_tests('status', 'success'))
+ stream.write(" - Skipped: %s\n" % count_tests('status', 'skip'))
+ stream.write(" - Failed: %s\n" % count_tests('status', 'fail'))
+
+ # we could have no results, especially as we filter out the process-codes
+ if RESULTS:
+ stream.write("\n==============\nWorker Balance\n==============\n")
+
+ for w in range(max(RESULTS.keys()) + 1):
+ if w not in RESULTS:
+ stream.write(
+ " - WARNING: missing Worker %s! "
+ "Race in testr accounting.\n" % w)
+ else:
+ num, time = worker_stats(w)
+ stream.write(" - Worker %s (%s tests) => %ss\n" %
+ (w, num, time))
+
+
+def parse_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--no-failure-debug', '-n', action='store_true',
+ dest='print_failures', help='Disable printing failure '
+ 'debug information in realtime')
+ parser.add_argument('--fails', '-f', action='store_true',
+ dest='post_fails', help='Print failure debug '
+ 'information after the stream is proccesed')
+ parser.add_argument('--failonly', action='store_true',
+ dest='failonly', help="Don't print success items",
+ default=(
+ os.environ.get('TRACE_FAILONLY', False)
+ is not False))
+ return parser.parse_args()
+
+
+def main():
+ args = parse_args()
+ stream = subunit.ByteStreamToStreamResult(
+ sys.stdin, non_subunit_name='stdout')
+ starts = Starts(sys.stdout)
+ outcomes = testtools.StreamToDict(
+ functools.partial(show_outcome, sys.stdout,
+ print_failures=args.print_failures,
+ failonly=args.failonly
+ ))
+ summary = testtools.StreamSummary()
+ result = testtools.CopyStreamResult([starts, outcomes, summary])
+ result.startTestRun()
+ try:
+ stream.run(result)
+ finally:
+ result.stopTestRun()
+ if count_tests('status', '.*') == 0:
+ print("The test run didn't actually run any tests")
+ return 1
+ if args.post_fails:
+ print_fails(sys.stdout)
+ print_summary(sys.stdout)
+ return (0 if summary.wasSuccessful() else 1)
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/with_venv.sh b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/with_venv.sh
new file mode 100755
index 00000000..dea5c5fc
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tools/with_venv.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright 2011 OpenStack Foundation.
+# 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.
+
+TOOLS=`dirname $0`
+VENV=$TOOLS/../.venv
+source $VENV/bin/activate && "$@"
diff --git a/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tox.ini b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tox.ini
new file mode 100644
index 00000000..41b875ed
--- /dev/null
+++ b/framework/src/openstack/neutron/plugin/networking-onos/networking-onos/tox.ini
@@ -0,0 +1,41 @@
+[tox]
+envlist = py27,pep8
+minversion = 1.6
+skipsdist = True
+
+[testenv]
+setenv = VIRTUAL_ENV={envdir}
+usedevelop = True
+install_command = pip install -r requirements.txt -U {opts} {packages}
+deps = -r{toxinidir}/test-requirements.txt
+whitelist_externals = bash
+commands = bash tools/pretty_tox.sh '{posargs}'
+
+[testenv:pep8]
+commands = flake8
+
+[testenv:i18n]
+commands = python ./tools/check_i18n.py ./networking_onos ./tools/i18n_cfg.py
+
+[testenv:venv]
+commands = {posargs}
+
+[testenv:cover]
+commands = python setup.py testr --coverage --testr-args='{posargs}'
+
+[testenv:docs]
+commands = python setup.py build_sphinx
+
+[hacking]
+import_exceptions = neutron.i18n
+local-check-factory = neutron.hacking.checks.factory
+show-source = True
+ignore = E123,E124,E125,H803
+
+[flake8]
+# H803 skipped on purpose per list discussion.
+# E123, E125 skipped as they are invalid PEP-8.
+show-source = True
+ignore = E123,E125,H803
+builtins = _
+exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,tools