Retire Packaging Deb project repos

This commit is part of a series to retire the Packaging Deb
project. Step 2 is to remove all content from the project
repos, replacing it with a README notification where to find
ongoing work, and how to recover the repo if needed at some
future point (as in
https://docs.openstack.org/infra/manual/drivers.html#retiring-a-project).

Change-Id: I76a161b00d94c91e065703ec3c2687329c36f453
This commit is contained in:
Tony Breeds 2017-09-12 16:10:16 -06:00
parent b9101294a9
commit 67ee2140b0
240 changed files with 14 additions and 29945 deletions

View File

@ -1,7 +0,0 @@
[run]
branch = True
source = neutronclient
omit = neutronclient/tests/*
[report]
ignore_errors = True

22
.gitignore vendored
View File

@ -1,22 +0,0 @@
*.pyc
*.DS_Store
*.egg
*.sw?
AUTHORS
ChangeLog
build/*
build-stamp
cover/*
doc/build/
doc/source/api/
releasenotes/build/
python_neutronclient.egg-info/*
neutron/vcsversion.py
neutronclient/versioninfo
run_tests.err.log
run_tests.log
.autogenerated
.coverage
.testrepository/
.tox/
.venv/

View File

@ -1,4 +0,0 @@
[gerrit]
host=review.openstack.org
port=29418
project=openstack/python-neutronclient.git

View File

@ -1,42 +0,0 @@
# 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.
ignore=test
[Messages Control]
# NOTE(justinsb): We might want to have a 2nd strict pylintrc in future
# C0111: Don't require docstrings on every method
# W0511: TODOs in code comments are fine.
# W0142: *args and **kwargs are fine.
# W0622: Redefining id is fine.
disable=C0111,W0511,W0142,W0622
[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,50}|setUp|tearDown)$
# Module names matching quantum-* are ok (files in bin/)
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)|(quantum-[a-z0-9_-]+))$
# Don't require docstrings on tests.
no-docstring-rgx=((__.*__)|([tT]est.*)|setUp|tearDown)$
[Design]
max-public-methods=100
min-public-methods=0
max-args=6
[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=_

View File

@ -1,4 +0,0 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./neutronclient/tests/unit} $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -1,16 +0,0 @@
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/python-neutronclient

View File

@ -1,26 +0,0 @@
Neutron Style Commandments
================================
- Step 1: Read the OpenStack Style Commandments
http://docs.openstack.org/developer/hacking/
- Step 2: Read on
Running Tests
-------------
The testing system is based on a combination of tox and testr. The canonical
approach to running tests is to simply run the command `tox`. This will
create virtual environments, populate them with depenedencies and run all of
the tests that OpenStack CI systems run. Behind the scenes, tox is running
`testr run --parallel`, but is set up such that you can supply any additional
testr arguments that are needed to tox. For example, you can run:
`tox -- --analyze-isolation` to cause tox to tell testr to add
--analyze-isolation to its argument list.
It is also possible to run the tests inside of a virtual environment
you have created, or it is possible that you have all of the dependencies
installed locally already. In this case, you can interact with the testr
command directly. Running `testr run` will run the entire test suite. `testr
run --parallel` will run it in parallel (this is the default incantation tox
uses.) More information about testr can be found at:
http://wiki.openstack.org/testr

176
LICENSE
View File

@ -1,176 +0,0 @@
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.

View File

@ -1,6 +0,0 @@
include tox.ini
include LICENSE README.rst HACKING.rst
include AUTHORS
include ChangeLog
include tools/*
recursive-include tests *

14
README Normal file
View File

@ -0,0 +1,14 @@
This project is no longer maintained.
The contents of this repository are still available in the Git
source code management system. To see the contents of this
repository before it reached its end of life, please check out the
previous commit with "git checkout HEAD^1".
For ongoing work on maintaining OpenStack packages in the Debian
distribution, please see the Debian OpenStack packaging team at
https://wiki.debian.org/OpenStack/.
For any further questions, please email
openstack-dev@lists.openstack.org or join #openstack-dev on
Freenode.

View File

@ -1,31 +0,0 @@
Python bindings to the Neutron API
==================================
.. image:: https://img.shields.io/pypi/v/python-neutronclient.svg
:target: https://pypi.python.org/pypi/python-neutronclient/
:alt: Latest Version
.. image:: https://img.shields.io/pypi/dm/python-neutronclient.svg
:target: https://pypi.python.org/pypi/python-neutronclient/
:alt: Downloads
This is a client library for Neutron built on the Neutron API. It
provides a Python API (the ``neutronclient`` module) and a command-line tool
(``neutron``).
* License: Apache License, Version 2.0
* `PyPi`_ - package installation
* `Online Documentation`_
* `Launchpad project`_ - release management
* `Blueprints`_ - feature specifications
* `Bugs`_ - issue tracking
* `Source`_
* `Developer's Guide`_
.. _PyPi: https://pypi.python.org/pypi/python-neutronclient
.. _Online Documentation: http://docs.openstack.org/developer/python-neutronclient
.. _Launchpad project: https://launchpad.net/python-neutronclient
.. _Blueprints: https://blueprints.launchpad.net/python-neutronclient
.. _Bugs: https://bugs.launchpad.net/python-neutronclient
.. _Source: https://git.openstack.org/cgit/openstack/python-neutronclient
.. _Developer's Guide: http://docs.openstack.org/infra/manual/developers.html

View File

@ -1,2 +0,0 @@
[python: **.py]

View File

@ -1,55 +0,0 @@
# -*- coding: utf-8 -*-
#
project = 'python-neutronclient'
# -- 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',
'oslosphinx',
'reno.sphinxext',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
copyright = u'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 = 'nature'
# 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'),
]

View File

@ -1,263 +0,0 @@
..
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.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
CLI Option Guideline
====================
This document describes the conventions of neutron CLI options.
General conventions
-------------------
#. Option names should be delimited by a hyphen instead of a underscore.
This is the common guidelines across all OpenStack CLIs.
* Good: ``--ip-version``
* Not Good: ``--ip_version``
#. Use at least one required option for ``*-create`` command. If all options
are optional, we typically use ``name`` field as a required option.
#. When you need to specify an ID of a resource, it is better to provide
another way to specify the resource like ``name`` or other reasonable field.
#. If an attribute name in API is ``foo_id``, the corresponding option
should be ``--foo`` instead of ``--foo-id``.
* It is because we usually support ID and ``name`` to specify a resource.
#. Do not use ``nargs='?'`` without a special reason.
* The behavior of ``nargs='?'`` option for python argparse is
bit tricky and may lead to unexpected option parsing different
from the help message. The detail is described in the
:ref:`Background section <background-nargs>` below.
#. (option) Avoid using positional options as much as possible.
* Positional arguments should be limited to attributes which will
be required in the long future.
#. We honor existing options and should keep compatibilities when adding or
changing options.
Options for boolean value
-------------------------
Use the form of ``--option-name {True|False}``.
* For a new option, it is recommended.
* It is suggested to use ``common.utils.add_boolean_argument`` in an
implementation. It allows ``true``/``false`` in addition to ``True``/``False``.
* For existing options, migration to the recommended form is not necessarily
required. All backward-compatibility should be kept without reasonable
reasons.
Options for dict value
----------------------
Some API attributes take a dictionary.
``--foo key1=val1,key2=val2`` is usually used.
This means ``{"key1": "val1", "key2": "val2"}`` is passed in the API layer.
Examples:
* ``--host-route destination=CIDR,nexthop=IP_ADDR`` for a subnet
* ``--fixed-ip subnet_id=SUBNET,ip_address=IP_ADDR`` for a port.
Options for list value
----------------------
Some attributes take a list.
In this case, we usually use:
* Define an option per element (Use a singular form as an option name)
* Allow to specify the option multiple times
For Example, **port-create** has ``--security-group`` option.
``--security-group SG1 --security-group SG2`` generates
``{"security_groups: ["SG1", "SG2"]}`` in the API layer.
This convention applies to a case of a list of dict.
``--allocation-pool`` and ``--host-route`` for a subnet are examples.
Compatibility with extra arguments
----------------------------------
*extra arguments* supports various types of option specifications.
At least the following patterns needs to be considered when defining
a new option. For more detail, see :ref:`cli_extra_arguments`.
* Normal options with value
* Boolean options : ``--foo True``, ``--bar=False``
* List options : ``--bars list=true val1 val2``, ``--bars val1 val2``
* Dict options : ``--foo type=dict key1=va1,key2=val2``
* List of Dict options : ``--bars list=true type=dict key1=val1,key2=val2 key3=val3,key4=val4``
* ``action=clear``
For normal options with value, there are four patterns to specify an option
as extra arguments.
* ``--admin-state-up True`` (a space between option name and value)
* ``--admin-state-up=True`` (= between option name and value)
* ``--admin_state_up True`` (underscore is used as delimiter)
* ``--admin_state_up=True`` (underscore is used as delimiter)
.. _background:
Background
----------
There are a lot of opinions on which form of options are better or not.
This section tries to capture the reason of the current choice.
Use at least one required option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As a convention, **neutron** CLI requires one required argument.
If all options are optional in the API level and we have ``name`` field,
we usually use ``name`` as a required parameter.
Requiring at least one argument has the following benefits:
* If we run ``neutron *-create`` without a required argument, we will have a
brief help message without detail option help. It is convenient.
* We can avoid miss operation by just hitting ``neutron *-create``.
Requiring at least one parameter is a good balance.
Even though we can change this convention to allow to create a resource
without ``name`` field, it will bring confusions to existing users.
There may be opinion that it is inconsistent with API level requirement
or Horizon behavior, but even if neutron CLI requires ``name`` field
there is no bad impact on regular users. Considering possible confusion
if we change it, it looks better to keep it as-is.
Options for Boolean value
~~~~~~~~~~~~~~~~~~~~~~~~~
* ``--enable-foo``/``--disable-foo`` or similar patterns (including
``--admin-state-down``) is not suggested because we need two exclusive
options for one attribute in REST API. It is meaningless.
* It is not recommended to have an option only to specify non-default value.
For example, we have ``--shared`` or ``--admin-state-down`` options for
net-create. This form only works for ``*-create`` and does not work for
``*-update``. It leads to having different options for ``*-create`` and
``*-update``.
* A flag option like ``--enable-dhcp`` (without value) also has a problem when
considering the compatibility with *extra argument*. We can specify
``-enable-dhcp True/False`` or ``--enable-dhcp=True/False`` in the *extra
argument* mechanism. If we introduce ``--enable-dhcp`` (without value),
the form of ``-enable-dhcp True/False`` cannot be used now.
This is another reason we don't use a flag style option for a boolean parameter.
.. _background-nargs:
Avoid using nargs in positional or optional arguments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The behavior of ``nargs='?'`` option for python argparse is bit tricky.
When we use ``nargs='?'`` and if the order of command-line options is
changed then the command-line parser may fail to parse the arguments
correctly. Two examples of such failures are provided below.
Example 1:
This example shows how the actual behavior can differ from the provided
help message. In the below block, help message at ``[5]`` says ``--bb CC``
is a valid format but the argument parsing for the same format fails at ``[7]``.
.. code-block:: console
In [1]: import argparse
In [2]: parser = argparse.ArgumentParser()
In [3]: parser.add_argument('--bb', nargs='?')
In [4]: parser.add_argument('cc')
In [5]: parser.print_help()
usage: ipython [-h] [--bb [BB]] cc
positional arguments:
cc
optional arguments:
-h, --help show this help message and exit
--bb [BB]
In [6]: parser.parse_args('--bb 1 X'.split())
Out[6]: Namespace(bb='1', cc='X')
In [7]: parser.parse_args('--bb X'.split())
usage: ipython [-h] [--bb [BB]] cc
ipython: error: too few arguments
An exception has occurred, use %tb to see the full traceback.
SystemExit: 2
Example 2:
This example shows how fragile ``nargs='?'`` can be when user specifies
options in different order from the help message.
.. code-block:: console
In [1]: import argparse
In [2]: parser = argparse.ArgumentParser()
In [3]: parser.add_argument('--a', help='option a')
In [4]: parser.add_argument('--b', help='option b')
In [5]: parser.add_argument('x', help='positional arg X')
In [6]: parser.add_argument('y', nargs='?', help='positional arg Y')
In [7]: parser.print_help()
usage: ipython [-h] [--a A] [--b B] x [y]
positional arguments:
x positional arg X
y positional arg Y
optional arguments:
-h, --help show this help message and exit
--a A option a
--b B option b
In [8]: parser.parse_args('--a 1 --b 2 X Y'.split())
Out[8]: Namespace(a='1', b='2', x='X', y='Y')
In [9]: parser.parse_args('X Y --a 1 --b 2'.split())
Out[9]: Namespace(a='1', b='2', x='X', y='Y')
In [10]: parser.parse_args('X --a 1 --b 2 Y'.split())
usage: ipython [-h] [--a A] [--b B] x [y]
ipython: error: unrecognized arguments: Y
An exception has occurred, use %tb to see the full traceback.
SystemExit: 2
To exit: use 'exit', 'quit', or Ctrl-D.
To exit: use 'exit', 'quit', or Ctrl-D.
Note: Most CLI users don't care about the order of the command-line
options. Hence, such fragile behavior should be avoided.

View File

@ -1,97 +0,0 @@
..
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.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
Client command extension support
=================================
The client command extension adds support for extending the neutron client while
considering ease of creation.
Extensions strongly conform to preexisting neutron commands (/neutron/v2_0/).
A sample extension can be seen at:
neutronclient/neutron/v2_0/contrib/_fox_sockets.py
Minimum requirements from an extension
--------------------------------------
* NeutronClientExtension subclasses must have a shell_command class variable
if the command is to be available to the CLI (shell.py)
Example: neutronclient.neutron.v2_0.contrib._fox_sockets.FoxInSocketsList
Minimum requirements to use canonical neutron CRUD commands framework
----------------------------------------------------------------------
Neutron commands are cliff commands, commands in extension can use their
own way to finish their tasks. But if they want to make use of the canonical
neutron CRUD commands framework, the extension should:
* have a class that subclasses NeutronClientExtension to provide the
requisite resource name, version support, and resource collection and
object paths for a resource the commands will process.
Example: neutronclient.neutron.v2_0.contrib._fox_sockets.FoxInSocket
* have a class that subclasses from the ClientExtensionList to provide
resource object list function. This is because most commands
need the list function to get object ID via
neutronclient.neutron.v2_0.__init__.find_resource_by_id.
Example: neutronclient.neutron.v2_0.contrib._fox_sockets.FoxInSocketsList
* if needed, subclass ClientExtensionUpdate to implement update of the resource
object.
Example: neutronclient.neutron.v2_0.contrib._fox_sockets.FoxInSocketsUpdate
* if needed, subclass ClientExtensionDelete to implement deletion of the resource
object.
Example: neutronclient.neutron.v2_0.contrib._fox_sockets.FoxInSocketsDelete
* if needed, subclass ClientExtensionShow to get the detail of the resource
object.
Example: neutronclient.neutron.v2_0.contrib._fox_sockets.FoxInSocketsShow
Precedence of command loading
------------------------------
* hard coded commands are loaded first
* external commands (installed in the environment) are loaded then
Commands that have the same name will be overwritten by commands that are
loaded later. To change the execution of a command for your particular
extension you only need to override the execute method.
Currently this extension support is limited to top-level resources.
Parent/child relationships may be added if desired.
neutronclient.extension entry_point
-----------------------------------
To activate the commands in a specific extension module, add an entry in
setup.cfg under neutronclient.extension. For example::
[entry_points]
neutronclient.extension =
fox_sockets = neutronclient.neutron.v2_0.contrib._fox_sockets

View File

@ -1,228 +0,0 @@
..
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.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
Transition to OpenStack Client
==============================
This document details the transition roadmap for moving the neutron client's
OpenStack Networking API support, both the Python library and the ``neutron``
command-line interface (CLI), to the
`OpenStack Client (OSC) <https://github.com/openstack/python-openstackclient>`_
and the `OpenStack Python SDK <https://github.com/openstack/python-openstacksdk>`_.
This transition is being guided by the
`Deprecate individual CLIs in favour of OSC <https://review.openstack.org/#/c/243348/>`_
OpenStack spec. See the `Neutron RFE <https://bugs.launchpad.net/neutron/+bug/1521291>`_,
`OSC neutron support etherpad <https://etherpad.openstack.org/p/osc-neutron-support>`_ and
details below for the overall progress of this transition.
Overview
--------
This transition will result in the neutron client's ``neutron`` CLI being
deprecated and then eventually removed. The ``neutron`` CLI will be replaced
by OSC's networking support available via the ``openstack`` CLI. This is
similar to the deprecation and removal process for the
`keystone client's <https://github.com/openstack/python-keystoneclient>`_
``keystone`` CLI. The neutron client's Python library won't be deprecated.
It will be available along side the networking support provided by the
OpenStack Python SDK.
Users of the neutron client's command extensions will need to transition to the
`OSC plugin system <http://docs.openstack.org/developer/python-openstackclient/plugins.html>`_
before the ``neutron`` CLI is removed. Such users will maintain their OSC plugin
commands within their own project and will be responsible for deprecating and
removing their ``neutron`` CLI extension.
Transition Steps
----------------
1. **Done:** OSC adds OpenStack Python SDK as a dependency. See the following
patch set: https://review.openstack.org/#/c/138745/
2. **Done:** OSC switches its networking support for the
`network <http://docs.openstack.org/developer/python-openstackclient/command-objects/network.html>`_
command object to use the OpenStack Python SDK instead of the neutron
client's Python library. See the following patch set:
https://review.openstack.org/#/c/253348/
3. **Done:** OSC removes its python-neutronclient dependency.
See the following patch set: https://review.openstack.org/#/c/255545/
4. **In Progress:** OpenStack Python SDK releases version 1.0 to guarantee
backwards compatibility of its networking support and OSC updates
its dependencies to include OpenStack Python SDK version 1.0 or later.
5. **Done:** OSC switches its networking support for the
`ip floating <http://docs.openstack.org/developer/python-openstackclient/command-objects/ip-floating.html>`_,
`ip floating pool <http://docs.openstack.org/developer/python-openstackclient/command-objects/ip-floating-pool.html>`_,
`ip fixed <http://docs.openstack.org/developer/python-openstackclient/command-objects/ip-fixed.html>`_,
`security group <http://docs.openstack.org/developer/python-openstackclient/command-objects/security-group.html>`_, and
`security group rule <http://docs.openstack.org/developer/python-openstackclient/command-objects/security-group-rule.html>`_
command objects to use the OpenStack Python SDK instead of the nova
client's Python library when neutron is enabled. When nova network
is enabled, then the nova client's Python library will continue to
be used. See the following OSC bugs:
* **Done** `Floating IP CRUD <https://bugs.launchpad.net/python-openstackclient/+bug/1519502>`_
* **Done** `Port CRUD <https://bugs.launchpad.net/python-openstackclient/+bug/1519909>`_
* **Done** `Security Group CRUD <https://bugs.launchpad.net/python-openstackclient/+bug/1519511>`_
* **Done** `Security Group Rule CRUD <https://bugs.launchpad.net/python-openstackclient/+bug/1519512>`_
6. **In Progress:** OSC continues enhancing its networking support.
At this point and when applicable, enhancements to the ``neutron``
CLI must also be made to the ``openstack`` CLI and the OpenStack Python SDK.
Enhancements to the networking support in the OpenStack Python SDK will be
handled via bugs. Users of the neutron client's command extensions should
start their transition to the OSC plugin system.
See the developer guide section below for more information on this step.
7. **Not Started:** Deprecate the ``neutron`` CLI once the criteria below have
been meet. Running the CLI after it has been deprecated will issue a warning
messages such as the following:
``DeprecationWarning: The neutron CLI is deprecated in favor of python-openstackclient.``
In addition, only security fixes will be made to the CLI after it has been
deprecated.
* The networking support provide by the ``openstack`` CLI is functionally
equivalent to the ``neutron`` CLI and it contains sufficient functional
and unit test coverage.
* `Neutron Stadium <http://docs.openstack.org/developer/neutron/stadium/sub_projects.html>`_
projects, Neutron documentation and `DevStack <http://docs.openstack.org/developer/devstack/>`_
use ``openstack`` CLI instead of ``neutron`` CLI.
* Most users of the neutron client's command extensions have transitioned
to the OSC plugin system and use the ``openstack`` CLI instead of the
``neutron`` CLI.
8. **Not Started:** Remove the ``neutron`` CLI after two deprecation cycles.
Developer Guide
---------------
The ``neutron`` CLI version 4.x, without extensions, supports over 200
commands while the ``openstack`` CLI version 2.6.0 supports over 50
networking commands. Of the 50 commands, some do not have all of the options
or arguments of their ``neutron`` CLI equivalent. With this large functional
gap, a couple critical questions for developers during this transition are "Which
CLI do I change?" and "Where does my CLI belong?" The answer depends on the
state of a command and the state of the overall transition. Details are
outlined in the tables below. Early stages of the transition will require dual
maintenance. Eventually, dual maintenance will be reduced to critical bug fixes
only with feature requests only being made to the ``openstack`` CLI.
**Which CLI do I change?**
+----------------------+------------------------+-------------------------------------------------+
| ``neutron`` Command | ``openstack`` Command | CLI to Change |
+======================+========================+=================================================+
| Exists | Doesn't Exist | ``neutron`` |
+----------------------+------------------------+-------------------------------------------------+
| Exists | In Progress | ``neutron`` and ``openstack`` |
| | | (update related blueprint or bug) |
+----------------------+------------------------+-------------------------------------------------+
| Exists | Exists | ``openstack`` |
| | | (assumes command parity resulting in |
| | | ``neutron`` being deprecated) |
+----------------------+------------------------+-------------------------------------------------+
| Doesn't Exist | Doesn't Exist | ``openstack`` |
+----------------------+------------------------+-------------------------------------------------+
**Where does my CLI belong?**
+---------------------------+-------------------+-------------------------------------------------+
| Networking Commands | OSC Plugin | OpenStack Project for ``openstack`` Commands |
+===========================+===================+=================================================+
| Core | No | python-openstackclient |
+---------------------------+-------------------+-------------------------------------------------+
| Dynamic Routing | Yes | python-neutronclient |
| | | (``neutronclient/osc/v2/dynamic_routing``) |
+---------------------------+-------------------+-------------------------------------------------+
| FWaaS v1 | N/A | None (deprecated) |
+---------------------------+-------------------+-------------------------------------------------+
| FWaaS v2 | Yes | python-neutronclient |
| | | (``neutronclient/osc/v2/fwaas``) |
+---------------------------+-------------------+-------------------------------------------------+
| LBaaS v1 | N/A | None (deprecated) |
+---------------------------+-------------------+-------------------------------------------------+
| LBaaS v2 | Yes | python-neutronclient |
| | | (``neutronclient/osc/v2/lbaas``) |
+---------------------------+-------------------+-------------------------------------------------+
| Other | Yes | Applicable project owning networking resource |
+---------------------------+-------------------+-------------------------------------------------+
| VPNaaS | Yes | python-neutronclient |
| | | (``neutronclient/osc/v2/vpnaas``) |
+---------------------------+-------------------+-------------------------------------------------+
**Important:** The actual name of the command object and/or action in OSC may differ
from those used by neutron in order to follow the OSC command structure and to avoid
name conflicts. Developers should get new command objects and actions approved by
the OSC team before proceeding with the implementation.
The "Core" group includes network resources that provide ``neutron`` project features
(i.e. not advanced service or other features). Examples in the "Core" group include:
network, subnet, port, etc.
When adding or updating an ``openstack`` networking command to
python-openstackclient, changes may first be required to the
OpenStack Python SDK to support the underlying networking resource object,
properties and/or actions. Once the OpenStack Python SDK changes are merged,
the related OSC changes can be merged. The OSC changes may require an update
to the OSC openstacksdk version in the
`requirements.txt <https://github.com/openstack/python-openstackclient/blob/master/requirements.txt>`_
file. ``openstack`` networking commands outside python-openstackclient
are encouraged but not required to use the OpenStack Python SDK.
When adding an ``openstack`` networking command to python-openstackclient,
you can optionally propose an
`OSC command spec <https://github.com/openstack/python-openstackclient/blob/master/doc/source/specs/commands.rst>`_
which documents the new command interface before proceeding with the implementation.
Users of the neutron client's command extensions must adopt the
`OSC plugin <https://github.com/openstack/python-openstackclient/blob/master/doc/source/plugins.rst>`_
system for this transition. Such users will maintain their OSC plugin within their
own project and should follow the guidance in the table above to determine
which command to change.
Developer References
--------------------
* See `OSC neutron support etherpad <https://etherpad.openstack.org/p/osc-neutron-support>`_
to determine if an ``openstack`` command is in progress.
* See `OSC command list <https://github.com/openstack/python-openstackclient/tree/master/doc/source/command-objects>`_
to determine if an ``openstack`` command exists.
* See `OSC command spec list <https://github.com/openstack/python-openstackclient/tree/master/doc/source/specs/command-objects>`_
to determine if an ``openstack`` command spec exists.
* See `OSC plugin command list <http://docs.openstack.org/developer/python-openstackclient/plugin-commands.html>`_
to determine if an ``openstack`` plugin command exists.
* See `OSC command structure <https://github.com/openstack/python-openstackclient/blob/master/doc/source/commands.rst>`_
to determine the current ``openstack`` command objects, plugin objects and actions.
* See `OSC human interface guide <https://github.com/openstack/python-openstackclient/blob/master/doc/source/humaninterfaceguide.rst>`_
for guidance on creating new OSC command interfaces.
* See `OSC plugin <https://github.com/openstack/python-openstackclient/blob/master/doc/source/plugins.rst>`_
for information on the OSC plugin system to be used for ``neutron`` CLI extensions.
* Create an OSC blueprint: https://blueprints.launchpad.net/python-openstackclient/
* Report an OSC bug: https://bugs.launchpad.net/python-openstackclient/+filebug
* Report an OpenStack Python SDK bug: https://bugs.launchpad.net/python-openstacksdk/+filebug

View File

@ -1,58 +0,0 @@
..
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.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
Python bindings to the OpenStack Networking API
===============================================
This is a client for OpenStack Networking API. There is a :doc:`Python API
<usage/library>` (the neutronclient module), and a :doc:`command-line script
<usage/cli>` (installed as **neutron**). Each implements the entire OpenStack
Networking API.
Using neutronclient
-------------------
.. toctree::
:maxdepth: 2
usage/cli
usage/library
usage/osc_cli_plugins
Developer Guide
---------------
In the Developer Guide, you will find information on Neutrons client
lower level programming details or APIs as well as the transition to
OpenStack client.
.. toctree::
:maxdepth: 2
devref/client_command_extensions
devref/cli_option_guideline
devref/transition_to_osc
History
-------
Release notes is available at
http://docs.openstack.org/releasenotes/python-neutronclient/.

View File

@ -1,390 +0,0 @@
..
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.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
Command-line Interface
======================
The **neutron** shell utility interacts with OpenStack Networking API from the
command-line. It supports the entire features of OpenStack Networking API.
Basic Usage
-----------
In order to use the CLI, you must provide your OpenStack username, password,
tenant, and auth endpoint. Use the corresponding configuration options
(``--os-username``, ``--os-password``, ``--os-tenant-name``, and
``--os-auth-url``), but it is easier to set them in environment variables.
.. code-block:: shell
export OS_USERNAME=user
export OS_PASSWORD=pass
export OS_TENANT_NAME=tenant
export OS_AUTH_URL=http://auth.example.com:5000/v2.0
Once you've configured your authentication parameters, you can run **neutron**
commands. All commands take the form of:
.. code-block:: none
neutron <command> [arguments...]
Run **neutron help** to get a full list of all possible commands, and run
**neutron help <command>** to get detailed help for that command.
Using with os-client-config
~~~~~~~~~~~~~~~~~~~~~~~~~~~
`os-client-config <http://docs.openstack.org/developer/os-client-config/>`_
provides more convenient way to manage a collection of client configurations
and you can easily switch multiple OpenStack-based configurations.
To use os-client-config, you first need to prepare
``~/.config/openstack/clouds.yaml`` like the following.
.. code-block:: yaml
clouds:
devstack:
auth:
auth_url: http://auth.example.com:5000
password: your-secret
project_domain_id: default
project_name: demo
user_domain_id: default
username: demo
identity_api_version: '3'
region_name: RegionOne
devstack-admin:
auth:
auth_url: http://auth.example.com:35357
password: another-secret
project_domain_id: default
project_name: admin
user_domain_id: default
username: admin
identity_api_version: '3'
region_name: RegionOne
Then, you need to specify a configuration name defined in the above clouds.yaml.
.. code-block:: shell
export OS_CLOUD=devstack
For more detail information, see the
`os-client-config <http://docs.openstack.org/developer/os-client-config/>`_
documentation.
Using with keystone token
~~~~~~~~~~~~~~~~~~~~~~~~~
The command-line tool will attempt to re-authenticate using your provided
credentials for every request. You can override this behavior by manually
supplying an auth token using ``--os-url`` and ``--os-auth-token``. You can
alternatively set these environment variables.
.. code-block:: shell
export OS_URL=http://neutron.example.org:9696/
export OS_TOKEN=3bcc3d3a03f44e3d8377f9247b0ad155
Using noauth mode
~~~~~~~~~~~~~~~~~
If neutron server does not require authentication, besides these two arguments
or environment variables (We can use any value as token.), we need manually
supply ``--os-auth-strategy`` or set the environment variable.
.. code-block:: shell
export OS_AUTH_STRATEGY=noauth
Display options
---------------
Filtering
~~~~~~~~~
Neutron API supports filtering in the listing operation.
**neutron** CLI supports this feature too.
To specify a filter in ``*-list`` command, you need to pass a pair of an
attribute name and an expected value with the format of ``--<attribute> <value>``.
The example below retrieves ports owned by compute instances.
.. code-block:: console
$ neutron port-list --device_owner network:dhcp
+--------------------------------------+------+-------------------+-------------------------------------------------------------------------------------------------------------+
| id | name | mac_address | fixed_ips |
+--------------------------------------+------+-------------------+-------------------------------------------------------------------------------------------------------------+
| 8953d683-29ad-4be3-b73f-060727c7849b | | fa:16:3e:4b:9e:0a | {"subnet_id": "6b832dfe-f271-443c-abad-629961414a73", "ip_address": "10.0.0.2"} |
| | | | {"subnet_id": "cdcc616b-0cff-482f-96f5-06fc63d21247", "ip_address": "fd12:877c:1d66:0:f816:3eff:fe4b:9e0a"} |
+--------------------------------------+------+-------------------+-------------------------------------------------------------------------------------------------------------+
You can also specify multiple filters.
The example below retrieves security group rules applied to IPv4 traffic
which belongs to a security group bfa493f9-2b03-46d2-8399-b9b038a53bc1.
.. code-block:: console
$ neutron security-group-rule-list --security-group-id bfa493f9-2b03-46d2-8399-b9b038a53bc1 --ethertype IPv4
+--------------------------------------+----------------+-----------+-----------+---------------+-----------------+
| id | security_group | direction | ethertype | protocol/port | remote |
+--------------------------------------+----------------+-----------+-----------+---------------+-----------------+
| 65489805-0400-4bce-9bd9-16a81952263c | default | egress | IPv4 | any | any |
| 9429f336-4947-4643-bbd9-24528cc65648 | default | ingress | IPv4 | any | default (group) |
+--------------------------------------+----------------+-----------+-----------+---------------+-----------------+
.. note::
Looking up UUID from name is not supported when specifying a filter.
You need to use UUID to specify a specific resource.
.. note::
Filtering for dictionary or list attributes is not supported.
Changing displayed columns
~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want displayed columns in a list operation, ``-c`` option can be used.
``-c`` can be specified multiple times and the column order will be same as
the order of ``-c`` options.
.. code-block:: console
$ neutron port-list -c id -c device_owner -c fixed_ips
+--------------------------------------+--------------------------+-------------------------------------------------------------------------------------------------------------+
| id | device_owner | fixed_ips |
+--------------------------------------+--------------------------+-------------------------------------------------------------------------------------------------------------+
| 41ca1b9b-4bbd-4aa8-bcaa-31d3d5704205 | network:router_interface | {"subnet_id": "6b832dfe-f271-443c-abad-629961414a73", "ip_address": "10.0.0.1"} |
| 8953d683-29ad-4be3-b73f-060727c7849b | network:dhcp | {"subnet_id": "6b832dfe-f271-443c-abad-629961414a73", "ip_address": "10.0.0.2"} |
| | | {"subnet_id": "cdcc616b-0cff-482f-96f5-06fc63d21247", "ip_address": "fd12:877c:1d66:0:f816:3eff:fe4b:9e0a"} |
| a9da29f8-4504-4526-a5ce-cd3624fbd173 | neutron:LOADBALANCER | {"subnet_id": "6b832dfe-f271-443c-abad-629961414a73", "ip_address": "10.0.0.3"} |
| | | {"subnet_id": "cdcc616b-0cff-482f-96f5-06fc63d21247", "ip_address": "fd12:877c:1d66:0:f816:3eff:feb1:ab71"} |
| d6a1ff96-0a99-416f-a4d6-65d9614cf64e | compute:nova | {"subnet_id": "6b832dfe-f271-443c-abad-629961414a73", "ip_address": "10.0.0.4"} |
| | | {"subnet_id": "cdcc616b-0cff-482f-96f5-06fc63d21247", "ip_address": "fd12:877c:1d66:0:f816:3eff:fe2c:348e"} |
| f4789225-26d0-409f-8047-82d2c7a87a95 | network:router_interface | {"subnet_id": "cdcc616b-0cff-482f-96f5-06fc63d21247", "ip_address": "fd12:877c:1d66::1"} |
+--------------------------------------+--------------------------+-------------------------------------------------------------------------------------------------------------+
.. _cli_extra_arguments:
Extra arguments for create/update operation
-------------------------------------------
**neutron** CLI has a mechanism called the *extra arguments* for ``*-create``
and ``*-update`` commands. It allows users to specify a set of *unknown
options* which are not defined as options and not shown in the help text.
**Unknown options MUST be placed at the end of the command line.**
*unknown options* will be directly passed to the API layer. By this mechanism,
you can pass an attribute which is not defined in the upstream **neutron**
CLI. For example, when you are developing a new feature which add a new
attribute to an existing resource, it is useful because we can test your
feature without changing the existing neutron CLI.
For example, if you run the following command::
neutron resource-update <ID> --key1 value1 --key2 value2
where ``resource`` is some resource name and ``--key1`` and ``--key2`` are
unknown options, then the following JSON will be sent to the neutron API::
PUT /v2.0/resources/<ID>
{
"resource": {
"key2": "value2",
"key1": "value1"
}
}
Key interpretation
~~~~~~~~~~~~~~~~~~
This means an option name (``--key1`` in this case) must be one of valid
resources of a corresponding resource. An option name ``--foo_bar`` is
recognized as an attribute name ``foo_bar``. ``--foo-bar`` is also interpreted
as an attribute name ``foo_bar``.
Value interpretation
~~~~~~~~~~~~~~~~~~~~
By default, if the number of values is 1, the option value is interpreted as a
string and is passed to the API layer as specified in a command-line.
If the number of values is greater than 1, the option value is interpreted as a
list and the result in the API layer will be same as when specifying a list as
described below.
neutron resource-update <ID> --key1 val1 val2 val3 --key2 val4
In the above example, a value of ``key1`` is interpreted as
``["val1", "val2", "val3"]`` and a value of ``key2`` is interpreted
as ``val4``.
The extra argument mechanism supports more complex value like a list or a dict.
Specify a list value
++++++++++++++++++++
A command-line::
neutron resource-update <ID> --key list=true val1 val2 val3
will send the following in the API layer::
{
"key": [
"val1",
"val2",
"val3"
]
}
.. note::
If you want to specify a list value, it is recommended to specify
``list=true``. When ``list=true`` is specified, specified values are
interpreted as a list even regardless of the number of values.
If ``list=true`` is not specified, specified values are interpreted
depends on the number of values how. If the number of values is more than 2,
the specified values are interpreted as a list. If 1, the value
is interpreted as a string.
Specify a dict value
++++++++++++++++++++
A command-line::
neutron resource-update <ID> --key type=dict key1=val1,key2=val2,key3=val3
will send the following in the API layer::
{
"key": {
"key1": "val1",
"key2": "val2",
"key3": "val3"
}
}
.. note::
``type=bool True/False`` and ``type=int 10`` are also supported.
Specify a list of dicts
+++++++++++++++++++++++
A command-line::
neutron resource-update <ID> --key type=dict list=true key1=val1 key2=val2 key3=val3
will send the following in the API layer::
{
"key": [
{"key1": "val1"},
{"key2": "val2"},
{"key3": "val3"}
]
}
Passing None as a value
~~~~~~~~~~~~~~~~~~~~~~~
There is a case where we would like to pass ``None`` (``null`` in JSON)
in the API layer. To do this::
neutron resource-update <ID> --key action=clear
The following body will be in the API layer::
{"key": null}
.. note::
If ``action=clear`` is specified, ``list=true`` or ``type=dict`` is ignored.
It means when ``action=clear`` is specified ``None`` is always sent.
Debugging
---------
Display API-level communication
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``-v`` (or ``--verbose``, ``--debug``) option displays a detail interaction
with your neutron server. It is useful to debug what happens in the API level.
Here is an sample output of ``net-show`` command.
The first line show what parameters are recognized by neutronclient.
It is sometimes useful to check if command-line parameters you specify are recognized properly.
.. code-block:: console
$ neutron -v net-show mynetwork
DEBUG: neutronclient.neutron.v2_0.network.ShowNetwork get_data(Namespace(columns=[], fields=[], formatter='table', id=u'mynetwork', max_width=0, noindent=False, prefix='', request_format='json', show_details=False, variables=[]))
Next, neutronclient sends an authentication request to keystone to get a token
which is used in further operations.
.. code-block:: console
DEBUG: keystoneauth.session REQ: curl -g -i -X GET http://172.16.18.47:5000 -H "Accept: application/json" -H "User-Agent: keystoneauth1"
DEBUG: keystoneauth.session RESP: [300] Content-Length: 593 Vary: X-Auth-Token Keep-Alive: timeout=5, max=100 Server: Apache/2.4.7 (Ubuntu) Connection: Keep-Alive Date: Fri, 27 Nov 2015 20:10:54 GMT Content-Type: application/json
RESP BODY: {"versions": {"values": [{"status": "stable", "updated": "2015-03-30T00:00:00Z", "media-types": [{"base": "application/json", "type": "application/vnd.openstack.identity-v3+json"}], "id": "v3.4", "links": [{"href": "http://172.16.18.47:5000/v3/", "rel": "self"}]}, {"status": "stable", "updated": "2014-04-17T00:00:00Z", "media-types": [{"base": "application/json", "type": "application/vnd.openstack.identity-v2.0+json"}], "id": "v2.0", "links": [{"href": "http://172.16.18.47:5000/v2.0/", "rel": "self"}, {"href": "http://docs.openstack.org/", "type": "text/html", "rel": "describedby"}]}]}}
DEBUG: keystoneauth.identity.v3.base Making authentication request to http://172.16.18.47:5000/v3/auth/tokens
Neutronclient looks up a network ID corresponding to a given network name.
.. code-block:: console
DEBUG: keystoneauth.session REQ: curl -g -i -X GET http://172.16.18.47:9696/v2.0/networks.json?fields=id&name=mynetwork -H "User-Agent: python-neutronclient" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}39300e7398d53a02afd183f13cb6afaef95ec4e5"
DEBUG: keystoneauth.session RESP: [200] Date: Fri, 27 Nov 2015 20:10:55 GMT Connection: keep-alive Content-Type: application/json; charset=UTF-8 Content-Length: 62 X-Openstack-Request-Id: req-ccebf6e4-4f52-4874-a1ab-5499abcba378
RESP BODY: {"networks": [{"id": "3698d3c7-d581-443e-bf86-53c4e3a738f7"}]}
Finally, neutronclient retrieves a detail of a given network using the resolved ID.
.. code-block:: console
DEBUG: keystoneauth.session REQ: curl -g -i -X GET http://172.16.18.47:9696/v2.0/networks/3698d3c7-d581-443e-bf86-53c4e3a738f7.json -H "User-Agent: python-neutronclient" -H "Accept: application/json" -H "X-Auth-Token: {SHA1}39300e7398d53a02afd183f13cb6afaef95ec4e5"
DEBUG: keystoneauth.session RESP: [200] Date: Fri, 27 Nov 2015 20:10:55 GMT Connection: keep-alive Content-Type: application/json; charset=UTF-8 Content-Length: 272 X-Openstack-Request-Id: req-261add00-d6d3-4ea7-becc-105b60ac7369
RESP BODY: {"network": {"status": "ACTIVE", "subnets": [], "name": "mynetwork", "admin_state_up": true, "tenant_id": "8f0ebf767043483a987736c8c684178d", "mtu": 0, "router:external": false, "shared": false, "port_security_enabled": true, "id": "3698d3c7-d581-443e-bf86-53c4e3a738f7"}}
+-----------------------+--------------------------------------+
| Field | Value |
+-----------------------+--------------------------------------+
| admin_state_up | True |
| id | 3698d3c7-d581-443e-bf86-53c4e3a738f7 |
| mtu | 0 |
| name | mynetwork |
| port_security_enabled | True |
| router:external | False |
| shared | False |
| status | ACTIVE |
| subnets | |
| tenant_id | 8f0ebf767043483a987736c8c684178d |
+-----------------------+--------------------------------------+

View File

@ -1,71 +0,0 @@
..
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.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
neutronclient Python API
========================
Basic Usage
-----------
First create a client instance.
.. code-block:: python
>>> from neutronclient.v2_0 import client
>>> username='adminUser'
>>> password='secretword'
>>> project_name='openstackDemo'
>>> auth_url='http://192.168.206.130:5000/v2.0'
>>> neutron = client.Client(username=username,
... password=password,
... project_name=project_name,
... auth_url=auth_url)
Now you can call various methods on the client instance.
.. code-block:: python
>>> network = {'name': 'mynetwork', 'admin_state_up': True}
>>> neutron.create_network({'network':network})
>>> networks = neutron.list_networks(name='mynetwork')
>>> print networks
>>> network_id = networks['networks'][0]['id']
>>> neutron.delete_network(network_id)
Alternatively, you can create a client instance using an auth token
and a service endpoint URL directly.
.. code-block:: python
>>> from neutronclient.v2_0 import client
>>> neutron = client.Client(endpoint_url='http://192.168.206.130:9696/',
... token='d3f9226f27774f338019aa2611112ef6')
You can get ``X-Openstack-Request-Id`` as ``request_ids`` from the result.
.. code-block:: python
>>> network = {'name': 'mynetwork', 'admin_state_up': True}
>>> neutron.create_network({'network':network})
>>> networks = neutron.list_networks(name='mynetwork')
>>> print networks.request_ids
['req-978a0160-7ab0-44f0-8a93-08e9a4e785fa']

View File

@ -1,171 +0,0 @@
=============
network trunk
=============
A **network trunk** is a container to group logical ports from different
networks and provide a single trunked vNIC for servers. It consists of
one parent port which is a regular VIF and multiple subports which allow
the server to connect to more networks.
Network v2
network subport list
--------------------
List all subports for a given network trunk
.. program:: network subport list
.. code:: bash
os network subport list
--trunk <trunk>
.. option:: --trunk <trunk>
List subports belonging to this trunk (name or ID) (required)
network trunk create
--------------------
Create a network trunk for a given project
.. program:: network trunk create
.. code:: bash
os network trunk create
--parent-port <parent-port>
[--subport <port=,segmentation-type=,segmentation-id=>]
[--enable | --disable]
[--project <project> [--project-domain <project-domain>]]
<name>
.. option:: --parent-port <parent-port>
Parent port belonging to this trunk (name or ID) (required)
.. option:: --subport <port=,segmentation-type=,segmentation-id=>
Subport to add. Subport is of form 'port=<name or ID>,segmentation-type=,segmentation-ID='
(--subport) option can be repeated
.. option:: --enable
Enable trunk (default)
.. option:: --disable
Disable trunk
.. option:: --project <project>
Owner's project (name or ID)
.. option:: --project-domain <project-domain>
Domain the project belongs to (name or ID).
This can be used in case collisions between project names exist.
network trunk delete
--------------------
Delete a given network trunk
.. program:: network trunk delete
.. code:: bash
os network trunk delete
<trunk> [<trunk> ...]
.. _network_trunk_delete-trunk:
.. describe:: <trunk>
Trunk(s) to delete (name or ID)
network trunk list
------------------
List all network trunks
.. program:: network trunk list
.. code:: bash
os network trunk list
[--long]
.. option:: --long
List additional fields in output
network trunk set
-----------------
Set network trunk properties
.. program:: network trunk set
.. code:: bash
os network trunk set
[--name <name>]
[--subport <port=,segmentation-type=,segmentation-id=>]
[--enable | --disable]
<trunk>
.. option:: --name <name>
Set trunk name
.. option:: --subport <port=,segmentation-type=,segmentation-id=>
Subport to add. Subport is of form 'port=<name or ID>,segmentation-type=,segmentation-ID='
(--subport) option can be repeated
.. option:: --enable
Enable trunk
.. option:: --disable
Disable trunk
.. _network_trunk_set-trunk:
.. describe:: <trunk>
Trunk to modify (name or ID)
network trunk show
------------------
Show information of a given network trunk
.. program:: network trunk show
.. code:: bash
os network trunk show
<trunk>
.. _network_trunk_show-trunk:
.. describe:: <trunk>
Trunk to display (name or ID)
network trunk unset
-------------------
Unset subports from a given network trunk
.. program:: network trunk unset
.. code:: bash
os network trunk unset
--subport <subport>
<trunk>
.. option:: --subport <subport>
Subport to delete (name or ID of the port) (required)
(--subport) option can be repeated
.. _network_trunk_unset-trunk:
.. describe:: <trunk>
Unset subports from this trunk (name or ID)

View File

@ -1,33 +0,0 @@
..
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.
Convention for heading levels in Neutron devref:
======= Heading 0 (reserved for the title in a document)
------- Heading 1
~~~~~~~ Heading 2
+++++++ Heading 3
''''''' Heading 4
(Avoid deeper levels because they do not render well.)
Using Network CLI extensions to OpenStack Client
================================================
List of released CLI commands available in openstack client. These commands
can be referenced by doing ``openstack help network``.
.. toctree::
:glob:
:maxdepth: 2
osc/v2/*

View File

@ -1,165 +0,0 @@
#!/bin/bash
set -x
function die() {
local exitcode=$?
set +o xtrace
echo $@
cleanup
exit $exitcode
}
net_name=mynet1
subnet_name=mysubnet1
port_name=myport1
function cleanup() {
echo Removing test port, subnet and net...
neutron port-delete $port_name
neutron subnet-delete $subnet_name
neutron net-delete $net_name
}
noauth_tenant_id=me
if [ "$1" == "noauth" ]; then
NOAUTH="--tenant_id $noauth_tenant_id"
else
NOAUTH=
fi
echo "NOTE: User should be admin in order to perform all operations."
sleep 3
# test the CRUD of network
network=$net_name
neutron net-create $NOAUTH $network || die "fail to create network $network"
temp=`neutron net-list -- --name $network --fields id | wc -l`
echo $temp
if [ $temp -ne 5 ]; then
die "networks with name $network is not unique or found"
fi
network_id=`neutron net-list -- --name $network --fields id | tail -n 2 | head -n 1 | cut -d' ' -f 2`
echo "ID of network with name $network is $network_id"
neutron net-show $network || die "fail to show network $network"
neutron net-show $network_id || die "fail to show network $network_id"
neutron net-update $network --admin_state_up False || die "fail to update network $network"
neutron net-update $network_id --admin_state_up True || die "fail to update network $network_id"
neutron net-list -c id -- --id fakeid || die "fail to list networks with column selection on empty list"
# test the CRUD of subnet
subnet=$subnet_name
cidr=10.0.1.0/24
neutron subnet-create $NOAUTH $network $cidr --name $subnet || die "fail to create subnet $subnet"
tempsubnet=`neutron subnet-list -- --name $subnet --fields id | wc -l`
echo $tempsubnet
if [ $tempsubnet -ne 5 ]; then
die "subnets with name $subnet is not unique or found"
fi
subnet_id=`neutron subnet-list -- --name $subnet --fields id | tail -n 2 | head -n 1 | cut -d' ' -f 2`
echo "ID of subnet with name $subnet is $subnet_id"
neutron subnet-show $subnet || die "fail to show subnet $subnet"
neutron subnet-show $subnet_id || die "fail to show subnet $subnet_id"
neutron subnet-update $subnet --dns_nameservers list=true 1.1.1.11 1.1.1.12 || die "fail to update subnet $subnet"
neutron subnet-update $subnet_id --dns_nameservers list=true 2.2.2.21 2.2.2.22 || die "fail to update subnet $subnet_id"
# test the crud of ports
port=$port_name
neutron port-create $NOAUTH $network --name $port || die "fail to create port $port"
tempport=`neutron port-list -- --name $port --fields id | wc -l`
echo $tempport
if [ $tempport -ne 5 ]; then
die "ports with name $port is not unique or found"
fi
port_id=`neutron port-list -- --name $port --fields id | tail -n 2 | head -n 1 | cut -d' ' -f 2`
echo "ID of port with name $port is $port_id"
neutron port-show $port || die "fail to show port $port"
neutron port-show $port_id || die "fail to show port $port_id"
neutron port-update $port --device_id deviceid1 || die "fail to update port $port"
neutron port-update $port_id --device_id deviceid2 || die "fail to update port $port_id"
neutron port-update $port_id --allowed-address-pair ip_address=1.1.1.11,mac_address=10:00:00:00:00:00 --allowed-address-pair ip_address=1.1.1.12,mac_address=10:00:00:00:00:01 || die "fail to update port $port_id --allowed-address-pair"
neutron port-show $port || die "fail to show port $port"
neutron port-show $port_id || die "fail to show port $port_id"
neutron port-update $port_id --no-allowed-address-pairs || die "fail to update port $port_id --no-allowed-address-pairs"
neutron port-show $port || die "fail to show port $port"
neutron port-show $port_id || die "fail to show port $port_id"
neutron port-delete $port_id
# test the create port with allowed-address-pairs
port=$port_name
neutron port-create $NOAUTH $network --name $port -- --allowed-address-pairs type=dict list=true ip_address=1.1.1.11,mac_address=10:00:00:00:00:00 ip_address=1.1.1.12,mac_address=10:00:00:00:00:01 || die "fail to create port $port"
tempport=`neutron port-list -- --name $port --fields id | wc -l`
echo $tempport
if [ $tempport -ne 5 ]; then
die "ports with name $port is not unique or found"
fi
port_id=`neutron port-list -- --name $port --fields id | tail -n 2 | head -n 1 | cut -d' ' -f 2`
echo "ID of port with name $port is $port_id"
neutron port-show $port || die "fail to show port $port"
neutron port-show $port_id || die "fail to show port $port_id"
neutron port-update $port_id --no-allowed-address-pairs || die "fail to update port $port_id --no-allowed-address-pairs"
neutron port-show $port_id
# test quota commands RUD
DEFAULT_NETWORKS=10
DEFAULT_PORTS=50
tenant_id=tenant_a
tenant_id_b=tenant_b
neutron quota-update --tenant_id $tenant_id --network 30 || die "fail to update quota for tenant $tenant_id"
neutron quota-update --tenant_id $tenant_id_b --network 20 || die "fail to update quota for tenant $tenant_id"
networks=`neutron quota-list -c network -c tenant_id | grep $tenant_id | awk '{print $2}'`
if [ $networks -ne 30 ]; then
die "networks quota should be 30"
fi
networks=`neutron quota-list -c network -c tenant_id | grep $tenant_id_b | awk '{print $2}'`
if [ $networks -ne 20 ]; then
die "networks quota should be 20"
fi
networks=`neutron quota-show --tenant_id $tenant_id | grep network | awk -F'|' '{print $3}'`
if [ $networks -ne 30 ]; then
die "networks quota should be 30"
fi
neutron quota-delete --tenant_id $tenant_id || die "fail to delete quota for tenant $tenant_id"
networks=`neutron quota-show --tenant_id $tenant_id | grep network | awk -F'|' '{print $3}'`
if [ $networks -ne $DEFAULT_NETWORKS ]; then
die "networks quota should be $DEFAULT_NETWORKS"
fi
# update self
if [ "t$NOAUTH" = "t" ]; then
# with auth
neutron quota-update --port 99 || die "fail to update quota for self"
ports=`neutron quota-show | grep port | awk -F'|' '{print $3}'`
if [ $ports -ne 99 ]; then
die "ports quota should be 99"
fi
ports=`neutron quota-list -c port | grep 99 | awk '{print $2}'`
if [ $ports -ne 99 ]; then
die "ports quota should be 99"
fi
neutron quota-delete || die "fail to delete quota for tenant self"
ports=`neutron quota-show | grep port | awk -F'|' '{print $3}'`
if [ $ports -ne $DEFAULT_PORTS ]; then
die "ports quota should be $DEFAULT_PORTS"
fi
else
# without auth
neutron quota-update --port 100
if [ $? -eq 0 ]; then
die "without valid context on server, quota update command should fail."
fi
neutron quota-show
if [ $? -eq 0 ]; then
die "without valid context on server, quota show command should fail."
fi
neutron quota-delete
if [ $? -eq 0 ]; then
die "without valid context on server, quota delete command should fail."
fi
neutron quota-list || die "fail to update quota for self"
fi
cleanup
echo "Success! :)"

View File

@ -1,41 +0,0 @@
# 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 oslo_i18n
DOMAIN = 'neutronclient'
_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN)
# The primary translation function using the well-known name "_"
_ = _translators.primary
# The contextual translation function using the name "_C"
_C = _translators.contextual_form
# The plural translation function using the name "_P"
_P = _translators.plural_form
# Translators for log levels.
#
# The abbreviated names are meant to reflect the usual use of a short
# name like '_'. The "L" is for "log" and the other letter comes from
# the level.
_LI = _translators.log_info
_LW = _translators.log_warning
_LE = _translators.log_error
_LC = _translators.log_critical
def get_available_languages():
return oslo_i18n.get_available_languages(DOMAIN)

View File

@ -1,400 +0,0 @@
# Copyright 2012 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.
#
try:
import json
except ImportError:
import simplejson as json
import logging
import os
import debtcollector.renames
from keystoneauth1 import access
from keystoneauth1 import adapter
import requests
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
_logger = logging.getLogger(__name__)
if os.environ.get('NEUTRONCLIENT_DEBUG'):
ch = logging.StreamHandler()
_logger.setLevel(logging.DEBUG)
_logger.addHandler(ch)
_requests_log_level = logging.DEBUG
else:
_requests_log_level = logging.WARNING
logging.getLogger("requests").setLevel(_requests_log_level)
MAX_URI_LEN = 8192
USER_AGENT = 'python-neutronclient'
class HTTPClient(object):
"""Handles the REST calls and responses, include authn."""
CONTENT_TYPE = 'application/json'
@debtcollector.renames.renamed_kwarg(
'tenant_id', 'project_id', replace=True)
@debtcollector.renames.renamed_kwarg(
'tenant_name', 'project_name', replace=True)
def __init__(self, username=None, user_id=None,
project_name=None, project_id=None,
password=None, auth_url=None,
token=None, region_name=None, timeout=None,
endpoint_url=None, insecure=False,
endpoint_type='publicURL',
auth_strategy='keystone', ca_cert=None, log_credentials=False,
service_type='network',
**kwargs):
self.username = username
self.user_id = user_id
self.project_name = project_name
self.project_id = project_id
self.password = password
self.auth_url = auth_url.rstrip('/') if auth_url else None
self.service_type = service_type
self.endpoint_type = endpoint_type
self.region_name = region_name
self.timeout = timeout
self.auth_token = token
self.auth_tenant_id = None
self.auth_user_id = None
self.endpoint_url = endpoint_url
self.auth_strategy = auth_strategy
self.log_credentials = log_credentials
if insecure:
self.verify_cert = False
else:
self.verify_cert = ca_cert if ca_cert else True
def _cs_request(self, *args, **kwargs):
kargs = {}
kargs.setdefault('headers', kwargs.get('headers', {}))
kargs['headers']['User-Agent'] = USER_AGENT
if 'body' in kwargs:
kargs['body'] = kwargs['body']
if self.log_credentials:
log_kargs = kargs
else:
log_kargs = self._strip_credentials(kargs)
utils.http_log_req(_logger, args, log_kargs)
try:
resp, body = self.request(*args, **kargs)
except requests.exceptions.SSLError as e:
raise exceptions.SslCertificateValidationError(reason=e)
except Exception as e:
# Wrap the low-level connection error (socket timeout, redirect
# limit, decompression error, etc) into our custom high-level
# connection exception (it is excepted in the upper layers of code)
_logger.debug("throwing ConnectionFailed : %s", e)
raise exceptions.ConnectionFailed(reason=e)
utils.http_log_resp(_logger, resp, body)
if resp.status_code == 401:
raise exceptions.Unauthorized(message=body)
return resp, body
def _strip_credentials(self, kwargs):
if kwargs.get('body') and self.password:
log_kwargs = kwargs.copy()
log_kwargs['body'] = kwargs['body'].replace(self.password,
'REDACTED')
return log_kwargs
else:
return kwargs
def authenticate_and_fetch_endpoint_url(self):
if not self.auth_token:
self.authenticate()
elif not self.endpoint_url:
self.endpoint_url = self._get_endpoint_url()
def request(self, url, method, body=None, headers=None, **kwargs):
"""Request without authentication."""
content_type = kwargs.pop('content_type', None) or 'application/json'
headers = headers or {}
headers.setdefault('Accept', content_type)
if body:
headers.setdefault('Content-Type', content_type)
headers['User-Agent'] = USER_AGENT
resp = requests.request(
method,
url,
data=body,
headers=headers,
verify=self.verify_cert,
timeout=self.timeout,
**kwargs)
return resp, resp.text
def _check_uri_length(self, action):
uri_len = len(self.endpoint_url) + len(action)
if uri_len > MAX_URI_LEN:
raise exceptions.RequestURITooLong(
excess=uri_len - MAX_URI_LEN)
def do_request(self, url, method, **kwargs):
# Ensure client always has correct uri - do not guesstimate anything
self.authenticate_and_fetch_endpoint_url()
self._check_uri_length(url)
# Perform the request once. If we get a 401 back then it
# might be because the auth token expired, so try to
# re-authenticate and try again. If it still fails, bail.
try:
kwargs.setdefault('headers', {})
if self.auth_token is None:
self.auth_token = ""
kwargs['headers']['X-Auth-Token'] = self.auth_token
resp, body = self._cs_request(self.endpoint_url + url, method,
**kwargs)
return resp, body
except exceptions.Unauthorized:
self.authenticate()
kwargs.setdefault('headers', {})
kwargs['headers']['X-Auth-Token'] = self.auth_token
resp, body = self._cs_request(
self.endpoint_url + url, method, **kwargs)
return resp, body
def _extract_service_catalog(self, body):
"""Set the client's service catalog from the response data."""
self.auth_ref = access.create(body=body)
self.service_catalog = self.auth_ref.service_catalog
self.auth_token = self.auth_ref.auth_token
self.auth_tenant_id = self.auth_ref.tenant_id
self.auth_user_id = self.auth_ref.user_id
if not self.endpoint_url:
self.endpoint_url = self.service_catalog.url_for(
region_name=self.region_name,
service_type=self.service_type,
interface=self.endpoint_type)
def _authenticate_keystone(self):
if self.user_id:
creds = {'userId': self.user_id,
'password': self.password}
else:
creds = {'username': self.username,
'password': self.password}
if self.project_id:
body = {'auth': {'passwordCredentials': creds,
'tenantId': self.project_id, }, }
else:
body = {'auth': {'passwordCredentials': creds,
'tenantName': self.project_name, }, }
if self.auth_url is None:
raise exceptions.NoAuthURLProvided()
token_url = self.auth_url + "/tokens"
resp, resp_body = self._cs_request(token_url, "POST",
body=json.dumps(body),
content_type="application/json",
allow_redirects=True)
if resp.status_code != 200:
raise exceptions.Unauthorized(message=resp_body)
if resp_body:
try:
resp_body = json.loads(resp_body)
except ValueError:
pass
else:
resp_body = None
self._extract_service_catalog(resp_body)
def _authenticate_noauth(self):
if not self.endpoint_url:
message = _('For "noauth" authentication strategy, the endpoint '
'must be specified either in the constructor or '
'using --os-url')
raise exceptions.Unauthorized(message=message)
def authenticate(self):
if self.auth_strategy == 'keystone':
self._authenticate_keystone()
elif self.auth_strategy == 'noauth':
self._authenticate_noauth()
else:
err_msg = _('Unknown auth strategy: %s') % self.auth_strategy
raise exceptions.Unauthorized(message=err_msg)
def _get_endpoint_url(self):
if self.auth_url is None:
raise exceptions.NoAuthURLProvided()
url = self.auth_url + '/tokens/%s/endpoints' % self.auth_token
try:
resp, body = self._cs_request(url, "GET")
except exceptions.Unauthorized:
# rollback to authenticate() to handle case when neutron client
# is initialized just before the token is expired
self.authenticate()
return self.endpoint_url
body = json.loads(body)
for endpoint in body.get('endpoints', []):
if (endpoint['type'] == 'network' and
endpoint.get('region') == self.region_name):
if self.endpoint_type not in endpoint:
raise exceptions.EndpointTypeNotFound(
type_=self.endpoint_type)
return endpoint[self.endpoint_type]
raise exceptions.EndpointNotFound()
def get_auth_info(self):
return {'auth_token': self.auth_token,
'auth_tenant_id': self.auth_tenant_id,
'auth_user_id': self.auth_user_id,
'endpoint_url': self.endpoint_url}
class SessionClient(adapter.Adapter):
def request(self, *args, **kwargs):
kwargs.setdefault('authenticated', False)
kwargs.setdefault('raise_exc', False)
content_type = kwargs.pop('content_type', None) or 'application/json'
headers = kwargs.setdefault('headers', {})
headers.setdefault('Accept', content_type)
try:
kwargs.setdefault('data', kwargs.pop('body'))
except KeyError:
pass
if kwargs.get('data'):
headers.setdefault('Content-Type', content_type)
resp = super(SessionClient, self).request(*args, **kwargs)
return resp, resp.text
def _check_uri_length(self, url):
uri_len = len(self.endpoint_url) + len(url)
if uri_len > MAX_URI_LEN:
raise exceptions.RequestURITooLong(
excess=uri_len - MAX_URI_LEN)
def do_request(self, url, method, **kwargs):
kwargs.setdefault('authenticated', True)
self._check_uri_length(url)
return self.request(url, method, **kwargs)
@property
def endpoint_url(self):
# NOTE(jamielennox): This is used purely by the CLI and should be
# removed when the CLI gets smarter.
return self.get_endpoint()
@property
def auth_token(self):
# NOTE(jamielennox): This is used purely by the CLI and should be
# removed when the CLI gets smarter.
return self.get_token()
def authenticate(self):
# NOTE(jamielennox): This is used purely by the CLI and should be
# removed when the CLI gets smarter.
self.get_token()
def get_auth_info(self):
auth_info = {'auth_token': self.auth_token,
'endpoint_url': self.endpoint_url}
# NOTE(jamielennox): This is the best we can do here. It will work
# with identity plugins which is the primary case but we should
# deprecate it's usage as much as possible.
try:
get_access = (self.auth or self.session.auth).get_access
except AttributeError:
pass
else:
auth_ref = get_access(self.session)
auth_info['auth_tenant_id'] = auth_ref.project_id
auth_info['auth_user_id'] = auth_ref.user_id
return auth_info
# FIXME(bklei): Should refactor this to use kwargs and only
# explicitly list arguments that are not None.
@debtcollector.renames.renamed_kwarg('tenant_id', 'project_id', replace=True)
@debtcollector.renames.renamed_kwarg(
'tenant_name', 'project_name', replace=True)
def construct_http_client(username=None,
user_id=None,
project_name=None,
project_id=None,
password=None,
auth_url=None,
token=None,
region_name=None,
timeout=None,
endpoint_url=None,
insecure=False,
endpoint_type='public',
log_credentials=None,
auth_strategy='keystone',
ca_cert=None,
service_type='network',
session=None,
**kwargs):
if session:
kwargs.setdefault('user_agent', USER_AGENT)
kwargs.setdefault('interface', endpoint_type)
return SessionClient(session=session,
service_type=service_type,
region_name=region_name,
**kwargs)
else:
# FIXME(bklei): username and password are now optional. Need
# to test that they were provided in this mode. Should also
# refactor to use kwargs.
return HTTPClient(username=username,
password=password,
project_id=project_id,
project_name=project_name,
user_id=user_id,
auth_url=auth_url,
token=token,
endpoint_url=endpoint_url,
insecure=insecure,
timeout=timeout,
region_name=region_name,
endpoint_type=endpoint_type,
service_type=service_type,
ca_cert=ca_cert,
log_credentials=log_credentials,
auth_strategy=auth_strategy)

View File

@ -1,125 +0,0 @@
# Copyright 2012 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.
#
"""Manage access to the clients, including authenticating when needed.
"""
import logging
import debtcollector.renames
from neutronclient import client
from neutronclient.neutron import client as neutron_client
LOG = logging.getLogger(__name__)
class ClientCache(object):
"""Descriptor class for caching created client handles."""
def __init__(self, factory):
self.factory = factory
self._handle = None
def __get__(self, instance, owner):
# Tell the ClientManager to login to keystone
if self._handle is None:
self._handle = self.factory(instance)
return self._handle
class ClientManager(object):
"""Manages access to API clients, including authentication."""
neutron = ClientCache(neutron_client.make_client)
# Provide support for old quantum commands (for example
# in stable versions)
quantum = neutron
@debtcollector.renames.renamed_kwarg(
'tenant_id', 'project_id', replace=True)
@debtcollector.renames.renamed_kwarg(
'tenant_name', 'project_name', replace=True)
def __init__(self, token=None, url=None,
auth_url=None,
endpoint_type=None,
project_name=None,
project_id=None,
username=None,
user_id=None,
password=None,
region_name=None,
api_version=None,
auth_strategy=None,
insecure=False,
ca_cert=None,
log_credentials=False,
service_type=None,
service_name=None,
timeout=None,
retries=0,
raise_errors=True,
session=None,
auth=None,
):
self._token = token
self._url = url
self._auth_url = auth_url
self._service_type = service_type
self._service_name = service_name
self._endpoint_type = endpoint_type
self._project_name = project_name
self._project_id = project_id
self._username = username
self._user_id = user_id
self._password = password
self._region_name = region_name
self._api_version = api_version
self._service_catalog = None
self._auth_strategy = auth_strategy
self._insecure = insecure
self._ca_cert = ca_cert
self._log_credentials = log_credentials
self._timeout = timeout
self._retries = retries
self._raise_errors = raise_errors
self._session = session
self._auth = auth
return
def initialize(self):
if not self._url:
httpclient = client.construct_http_client(
username=self._username,
user_id=self._user_id,
project_name=self._project_name,
project_id=self._project_id,
password=self._password,
region_name=self._region_name,
auth_url=self._auth_url,
service_type=self._service_type,
service_name=self._service_name,
endpoint_type=self._endpoint_type,
insecure=self._insecure,
ca_cert=self._ca_cert,
timeout=self._timeout,
session=self._session,
auth=self._auth,
log_credentials=self._log_credentials)
httpclient.authenticate()
# Populate other password flow attributes
self._token = httpclient.auth_token
self._url = httpclient.endpoint_url

View File

@ -1,32 +0,0 @@
# Copyright (c) 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.
TYPE_BOOL = "bool"
TYPE_INT = "int"
TYPE_LONG = "long"
TYPE_FLOAT = "float"
TYPE_LIST = "list"
TYPE_DICT = "dict"
PLURALS = {'networks': 'network',
'ports': 'port',
'subnets': 'subnet',
'subnetpools': 'subnetpool',
'dns_nameservers': 'dns_nameserver',
'host_routes': 'host_route',
'allocation_pools': 'allocation_pool',
'fixed_ips': 'fixed_ip',
'extensions': 'extension'}

View File

@ -1,246 +0,0 @@
# Copyright 2011 VMware, Inc
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from neutronclient._i18n import _
"""
Neutron base exception handling.
Exceptions are classified into three categories:
* Exceptions corresponding to exceptions from neutron server:
This type of exceptions should inherit one of exceptions
in HTTP_EXCEPTION_MAP.
* Exceptions from client library:
This type of exceptions should inherit NeutronClientException.
* Exceptions from CLI code:
This type of exceptions should inherit NeutronCLIError.
"""
class NeutronException(Exception):
"""Base Neutron Exception.
To correctly use this class, inherit from it and define
a 'message' property. That message will get printf'd
with the keyword arguments provided to the constructor.
"""
message = _("An unknown exception occurred.")
def __init__(self, message=None, **kwargs):
if message:
self.message = message
try:
self._error_string = self.message % kwargs
except Exception:
# at least get the core message out if something happened
self._error_string = self.message
def __str__(self):
return self._error_string
class NeutronClientException(NeutronException):
"""Base exception which exceptions from Neutron are mapped into.
NOTE: on the client side, we use different exception types in order
to allow client library users to handle server exceptions in try...except
blocks. The actual error message is the one generated on the server side.
"""
status_code = 0
req_ids_msg = _("Neutron server returns request_ids: %s")
request_ids = []
def __init__(self, message=None, **kwargs):
self.request_ids = kwargs.get('request_ids')
if 'status_code' in kwargs:
self.status_code = kwargs['status_code']
if self.request_ids:
req_ids_msg = self.req_ids_msg % self.request_ids
if message:
message = _('%(msg)s\n%(id)s') % {'msg': message,
'id': req_ids_msg}
else:
message = req_ids_msg
super(NeutronClientException, self).__init__(message, **kwargs)
# Base exceptions from Neutron
class BadRequest(NeutronClientException):
status_code = 400
class Unauthorized(NeutronClientException):
status_code = 401
message = _("Unauthorized: bad credentials.")
class Forbidden(NeutronClientException):
status_code = 403
message = _("Forbidden: your credentials don't give you access to this "
"resource.")
class NotFound(NeutronClientException):
status_code = 404
class Conflict(NeutronClientException):
status_code = 409
class InternalServerError(NeutronClientException):
status_code = 500
class ServiceUnavailable(NeutronClientException):
status_code = 503
HTTP_EXCEPTION_MAP = {
400: BadRequest,
401: Unauthorized,
403: Forbidden,
404: NotFound,
409: Conflict,
500: InternalServerError,
503: ServiceUnavailable,
}
# Exceptions mapped to Neutron server exceptions
# These are defined if a user of client library needs specific exception.
# Exception name should be <Neutron Exception Name> + 'Client'
# e.g., NetworkNotFound -> NetworkNotFoundClient
class NetworkNotFoundClient(NotFound):
pass
class PortNotFoundClient(NotFound):
pass
class StateInvalidClient(BadRequest):
pass
class NetworkInUseClient(Conflict):
pass
class PortInUseClient(Conflict):
pass
class IpAddressInUseClient(Conflict):
pass
class InvalidIpForNetworkClient(BadRequest):
pass
class InvalidIpForSubnetClient(BadRequest):
pass
class OverQuotaClient(Conflict):
pass
class IpAddressGenerationFailureClient(Conflict):
pass
class MacAddressInUseClient(Conflict):
pass
class HostNotCompatibleWithFixedIpsClient(Conflict):
pass
class ExternalIpAddressExhaustedClient(BadRequest):
pass
# Exceptions from client library
class NoAuthURLProvided(Unauthorized):
message = _("auth_url was not provided to the Neutron client")
class EndpointNotFound(NeutronClientException):
message = _("Could not find Service or Region in Service Catalog.")
class EndpointTypeNotFound(NeutronClientException):
message = _("Could not find endpoint type %(type_)s in Service Catalog.")
class AmbiguousEndpoints(NeutronClientException):
message = _("Found more than one matching endpoint in Service Catalog: "
"%(matching_endpoints)")
class RequestURITooLong(NeutronClientException):
"""Raised when a request fails with HTTP error 414."""
def __init__(self, **kwargs):
self.excess = kwargs.get('excess', 0)
super(RequestURITooLong, self).__init__(**kwargs)
class ConnectionFailed(NeutronClientException):
message = _("Connection to neutron failed: %(reason)s")
class SslCertificateValidationError(NeutronClientException):
message = _("SSL certificate validation has failed: %(reason)s")
class MalformedResponseBody(NeutronClientException):
message = _("Malformed response body: %(reason)s")
class InvalidContentType(NeutronClientException):
message = _("Invalid content type %(content_type)s.")
# Command line exceptions
class NeutronCLIError(NeutronException):
"""Exception raised when command line parsing fails."""
pass
class CommandError(NeutronCLIError):
pass
class UnsupportedVersion(NeutronCLIError):
"""Indicates usage of an unsupported API version
Indicates that the user is trying to use an unsupported version of
the API.
"""
pass
class NeutronClientNoUniqueMatch(NeutronCLIError):
message = _("Multiple %(resource)s matches found for name '%(name)s',"
" use an ID to be more specific.")

View File

@ -1,86 +0,0 @@
# Copyright 2015 Rackspace Hosting Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from stevedore import extension
from neutronclient.neutron import v2_0 as neutronV20
def _discover_via_entry_points():
emgr = extension.ExtensionManager('neutronclient.extension',
invoke_on_load=False)
return ((ext.name, ext.plugin) for ext in emgr)
class NeutronClientExtension(neutronV20.NeutronCommand):
pagination_support = False
_formatters = {}
sorting_support = False
class ClientExtensionShow(NeutronClientExtension, neutronV20.ShowCommand):
def take_action(self, parsed_args):
# NOTE(mdietz): Calls 'execute' to provide a consistent pattern
# for any implementers adding extensions with
# regard to any other extension verb.
return self.execute(parsed_args)
def execute(self, parsed_args):
return super(ClientExtensionShow, self).take_action(parsed_args)
class ClientExtensionList(NeutronClientExtension, neutronV20.ListCommand):
def take_action(self, parsed_args):
# NOTE(mdietz): Calls 'execute' to provide a consistent pattern
# for any implementers adding extensions with
# regard to any other extension verb.
return self.execute(parsed_args)
def execute(self, parsed_args):
return super(ClientExtensionList, self).take_action(parsed_args)
class ClientExtensionDelete(NeutronClientExtension, neutronV20.DeleteCommand):
def take_action(self, parsed_args):
# NOTE(mdietz): Calls 'execute' to provide a consistent pattern
# for any implementers adding extensions with
# regard to any other extension verb.
return self.execute(parsed_args)
def execute(self, parsed_args):
return super(ClientExtensionDelete, self).take_action(parsed_args)
class ClientExtensionCreate(NeutronClientExtension, neutronV20.CreateCommand):
def take_action(self, parsed_args):
# NOTE(mdietz): Calls 'execute' to provide a consistent pattern
# for any implementers adding extensions with
# regard to any other extension verb.
return self.execute(parsed_args)
def execute(self, parsed_args):
return super(ClientExtensionCreate, self).take_action(parsed_args)
class ClientExtensionUpdate(NeutronClientExtension, neutronV20.UpdateCommand):
def take_action(self, parsed_args):
# NOTE(mdietz): Calls 'execute' to provide a consistent pattern
# for any implementers adding extensions with
# regard to any other extension verb.
return self.execute(parsed_args)
def execute(self, parsed_args):
return super(ClientExtensionUpdate, self).take_action(parsed_args)

View File

@ -1,128 +0,0 @@
# Copyright 2013 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.
import logging
from oslo_serialization import jsonutils
import six
from neutronclient._i18n import _
from neutronclient.common import exceptions as exception
LOG = logging.getLogger(__name__)
if six.PY3:
long = int
class ActionDispatcher(object):
"""Maps method name to local methods through action name."""
def dispatch(self, *args, **kwargs):
"""Find and call local method."""
action = kwargs.pop('action', 'default')
action_method = getattr(self, str(action), self.default)
return action_method(*args, **kwargs)
def default(self, data):
raise NotImplementedError()
class DictSerializer(ActionDispatcher):
"""Default request body serialization."""
def serialize(self, data, action='default'):
return self.dispatch(data, action=action)
def default(self, data):
return ""
class JSONDictSerializer(DictSerializer):
"""Default JSON request body serialization."""
def default(self, data):
def sanitizer(obj):
return six.text_type(obj)
return jsonutils.dumps(data, default=sanitizer)
class TextDeserializer(ActionDispatcher):
"""Default request body deserialization."""
def deserialize(self, datastring, action='default'):
return self.dispatch(datastring, action=action)
def default(self, datastring):
return {}
class JSONDeserializer(TextDeserializer):
def _from_json(self, datastring):
try:
return jsonutils.loads(datastring)
except ValueError:
msg = _("Cannot understand JSON")
raise exception.MalformedResponseBody(reason=msg)
def default(self, datastring):
return {'body': self._from_json(datastring)}
# NOTE(maru): this class is duplicated from neutron.wsgi
class Serializer(object):
"""Serializes and deserializes dictionaries to certain MIME types."""
def __init__(self, metadata=None):
"""Create a serializer based on the given WSGI environment.
'metadata' is an optional dict mapping MIME types to information
needed to serialize a dictionary to that type.
"""
self.metadata = metadata or {}
def _get_serialize_handler(self, content_type):
handlers = {
'application/json': JSONDictSerializer(),
}
try:
return handlers[content_type]
except Exception:
raise exception.InvalidContentType(content_type=content_type)
def serialize(self, data):
"""Serialize a dictionary into the specified content type."""
return self._get_serialize_handler("application/json").serialize(data)
def deserialize(self, datastring):
"""Deserialize a string to a dictionary.
The string must be in the format of a supported MIME type.
"""
return self.get_deserialize_handler("application/json").deserialize(
datastring)
def get_deserialize_handler(self, content_type):
handlers = {
'application/json': JSONDeserializer(),
}
try:
return handlers[content_type]
except Exception:
raise exception.InvalidContentType(content_type=content_type)

View File

@ -1,236 +0,0 @@
# Copyright 2011, VMware, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# Borrowed from nova code base, more utilities will be added/borrowed as and
# when needed.
"""Utilities and helper functions."""
import argparse
import functools
import hashlib
import logging
import netaddr
import os
from oslo_utils import encodeutils
from oslo_utils import importutils
import six
from neutronclient._i18n import _
from neutronclient.common import exceptions
SENSITIVE_HEADERS = ('X-Auth-Token',)
def env(*vars, **kwargs):
"""Returns the first environment variable set.
If none are non-empty, defaults to '' or keyword arg default.
"""
for v in vars:
value = os.environ.get(v)
if value:
return value
return kwargs.get('default', '')
def convert_to_uppercase(string):
return string.upper()
def convert_to_lowercase(string):
return string.lower()
def get_client_class(api_name, version, version_map):
"""Returns the client class for the requested API version.
:param api_name: the name of the API, e.g. 'compute', 'image', etc
:param version: the requested API version
:param version_map: a dict of client classes keyed by version
:rtype: a client class for the requested API version
"""
try:
client_path = version_map[str(version)]
except (KeyError, ValueError):
msg = _("Invalid %(api_name)s client version '%(version)s'. must be "
"one of: %(map_keys)s")
msg = msg % {'api_name': api_name, 'version': version,
'map_keys': ', '.join(version_map.keys())}
raise exceptions.UnsupportedVersion(msg)
return importutils.import_class(client_path)
def get_item_properties(item, fields, mixed_case_fields=(), formatters=None):
"""Return a tuple containing the item properties.
:param item: a single item resource (e.g. Server, Tenant, etc)
:param fields: tuple of strings with the desired field names
:param mixed_case_fields: tuple of field names to preserve case
:param formatters: dictionary mapping field names to callables
to format the values
"""
if formatters is None:
formatters = {}
row = []
for field in fields:
if field in formatters:
row.append(formatters[field](item))
else:
if field in mixed_case_fields:
field_name = field.replace(' ', '_')
else:
field_name = field.lower().replace(' ', '_')
if not hasattr(item, field_name) and isinstance(item, dict):
data = item[field_name]
else:
data = getattr(item, field_name, '')
if data is None:
data = ''
row.append(data)
return tuple(row)
def str2bool(strbool):
if strbool is None:
return None
return strbool.lower() == 'true'
def str2dict(strdict, required_keys=None, optional_keys=None):
"""Convert key1=value1,key2=value2,... string into dictionary.
:param strdict: string in the form of key1=value1,key2=value2
:param required_keys: list of required keys. All keys in this list must be
specified. Otherwise ArgumentTypeError will be raised.
If this parameter is unspecified, no required key check
will be done.
:param optional_keys: list of optional keys.
This parameter is used for valid key check.
When at least one of required_keys and optional_keys,
a key must be a member of either of required_keys or
optional_keys. Otherwise, ArgumentTypeError will be
raised. When both required_keys and optional_keys are
unspecified, no valid key check will be done.
"""
result = {}
if strdict:
for kv in strdict.split(','):
key, sep, value = kv.partition('=')
if not sep:
msg = _("invalid key-value '%s', expected format: key=value")
raise argparse.ArgumentTypeError(msg % kv)
result[key] = value
valid_keys = set(required_keys or []) | set(optional_keys or [])
if valid_keys:
invalid_keys = [k for k in result if k not in valid_keys]
if invalid_keys:
msg = _("Invalid key(s) '%(invalid_keys)s' specified. "
"Valid key(s): '%(valid_keys)s'.")
raise argparse.ArgumentTypeError(
msg % {'invalid_keys': ', '.join(sorted(invalid_keys)),
'valid_keys': ', '.join(sorted(valid_keys))})
if required_keys:
not_found_keys = [k for k in required_keys if k not in result]
if not_found_keys:
msg = _("Required key(s) '%s' not specified.")
raise argparse.ArgumentTypeError(msg % ', '.join(not_found_keys))
return result
def str2dict_type(optional_keys=None, required_keys=None):
return functools.partial(str2dict,
optional_keys=optional_keys,
required_keys=required_keys)
def http_log_req(_logger, args, kwargs):
if not _logger.isEnabledFor(logging.DEBUG):
return
string_parts = ['curl -i']
for element in args:
if element in ('GET', 'POST', 'DELETE', 'PUT'):
string_parts.append(' -X %s' % element)
else:
string_parts.append(' %s' % element)
for (key, value) in six.iteritems(kwargs['headers']):
if key in SENSITIVE_HEADERS:
v = value.encode('utf-8')
h = hashlib.sha1(v)
d = h.hexdigest()
value = "{SHA1}%s" % d
header = ' -H "%s: %s"' % (key, value)
string_parts.append(header)
if 'body' in kwargs and kwargs['body']:
string_parts.append(" -d '%s'" % (kwargs['body']))
req = encodeutils.safe_encode("".join(string_parts))
_logger.debug("REQ: %s", req)
def http_log_resp(_logger, resp, body):
if not _logger.isEnabledFor(logging.DEBUG):
return
_logger.debug("RESP: %(code)s %(headers)s %(body)s",
{'code': resp.status_code,
'headers': resp.headers,
'body': body})
def _safe_encode_without_obj(data):
if isinstance(data, six.string_types):
return encodeutils.safe_encode(data)
return data
def safe_encode_list(data):
return list(map(_safe_encode_without_obj, data))
def safe_encode_dict(data):
def _encode_item(item):
k, v = item
if isinstance(v, list):
return (k, safe_encode_list(v))
elif isinstance(v, dict):
return (k, safe_encode_dict(v))
return (k, _safe_encode_without_obj(v))
return dict(list(map(_encode_item, data.items())))
def add_boolean_argument(parser, name, **kwargs):
for keyword in ('metavar', 'choices'):
kwargs.pop(keyword, None)
default = kwargs.pop('default', argparse.SUPPRESS)
parser.add_argument(
name,
metavar='{True,False}',
choices=['True', 'true', 'False', 'false'],
default=default,
**kwargs)
def is_valid_cidr(cidr):
try:
netaddr.IPNetwork(cidr)
return True
except Exception:
return False

View File

@ -1,69 +0,0 @@
# Copyright 2014 NEC Corporation
# 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 netaddr
from neutronclient._i18n import _
from neutronclient.common import exceptions
def validate_int_range(parsed_args, attr_name, min_value=None, max_value=None):
val = getattr(parsed_args, attr_name, None)
if val is None:
return
try:
if not isinstance(val, int):
int_val = int(val, 0)
else:
int_val = val
if ((min_value is None or min_value <= int_val) and
(max_value is None or int_val <= max_value)):
return
except (ValueError, TypeError):
pass
if min_value is not None and max_value is not None:
msg = (_('%(attr_name)s "%(val)s" should be an integer '
'[%(min)i:%(max)i].') %
{'attr_name': attr_name.replace('_', '-'),
'val': val, 'min': min_value, 'max': max_value})
elif min_value is not None:
msg = (_('%(attr_name)s "%(val)s" should be an integer '
'greater than or equal to %(min)i.') %
{'attr_name': attr_name.replace('_', '-'),
'val': val, 'min': min_value})
elif max_value is not None:
msg = (_('%(attr_name)s "%(val)s" should be an integer '
'smaller than or equal to %(max)i.') %
{'attr_name': attr_name.replace('_', '-'),
'val': val, 'max': max_value})
else:
msg = (_('%(attr_name)s "%(val)s" should be an integer.') %
{'attr_name': attr_name.replace('_', '-'),
'val': val})
raise exceptions.CommandError(msg)
def validate_ip_subnet(parsed_args, attr_name):
val = getattr(parsed_args, attr_name)
if not val:
return
try:
netaddr.IPNetwork(val)
except (netaddr.AddrFormatError, ValueError):
raise exceptions.CommandError(
(_('%(attr_name)s "%(val)s" is not a valid CIDR.') %
{'attr_name': attr_name.replace('_', '-'), 'val': val}))

View File

@ -1,27 +0,0 @@
# 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.
# TODO(amotoki): Remove this file at the beginning of Nxx cycle.
from debtcollector import moves
from neutronclient import _i18n
message = ("moved to neutronclient._i18n; please migrate to local "
"oslo_i18n usage, as defined at "
"http://docs.openstack.org/developer/oslo.i18n/usage.html")
_ = moves.moved_function(_i18n._, '_', __name__, message=message)
_LC = moves.moved_function(_i18n._LC, '_LC', __name__, message=message)
_LE = moves.moved_function(_i18n._LE, '_LE', __name__, message=message)
_LW = moves.moved_function(_i18n._LW, '_LW', __name__, message=message)
_LI = moves.moved_function(_i18n._LI, '_LI', __name__, message=message)

View File

@ -1,65 +0,0 @@
# Copyright 2012 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.
#
from neutronclient.common import utils
API_NAME = 'network'
API_VERSIONS = {
'2.0': 'neutronclient.v2_0.client.Client',
'2': 'neutronclient.v2_0.client.Client',
}
def make_client(instance):
"""Returns an neutron client."""
neutron_client = utils.get_client_class(
API_NAME,
instance._api_version[API_NAME],
API_VERSIONS,
)
instance.initialize()
url = instance._url
url = url.rstrip("/")
client = neutron_client(username=instance._username,
project_name=instance._project_name,
password=instance._password,
region_name=instance._region_name,
auth_url=instance._auth_url,
endpoint_url=url,
endpoint_type=instance._endpoint_type,
token=instance._token,
auth_strategy=instance._auth_strategy,
insecure=instance._insecure,
ca_cert=instance._ca_cert,
retries=instance._retries,
raise_errors=instance._raise_errors,
session=instance._session,
auth=instance._auth)
return client
def Client(api_version, *args, **kwargs):
"""Return an neutron client.
@param api_version: only 2.0 is supported now
"""
neutron_client = utils.get_client_class(
API_NAME,
api_version,
API_VERSIONS,
)
return neutron_client(*args, **kwargs)

View File

@ -1,782 +0,0 @@
# Copyright 2012 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.
#
from __future__ import print_function
import abc
import argparse
import functools
import logging
from cliff import command
from cliff import lister
from cliff import show
from oslo_serialization import jsonutils
import six
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
HYPHEN_OPTS = ['tags_any', 'not_tags', 'not_tags_any']
def find_resource_by_id(client, resource, resource_id, cmd_resource=None,
parent_id=None, fields=None):
return client.find_resource_by_id(resource, resource_id, cmd_resource,
parent_id, fields)
def find_resourceid_by_id(client, resource, resource_id, cmd_resource=None,
parent_id=None):
return find_resource_by_id(client, resource, resource_id, cmd_resource,
parent_id, fields='id')['id']
def find_resource_by_name_or_id(client, resource, name_or_id,
project_id=None, cmd_resource=None,
parent_id=None, fields=None):
return client.find_resource(resource, name_or_id, project_id,
cmd_resource, parent_id, fields)
def find_resourceid_by_name_or_id(client, resource, name_or_id,
project_id=None, cmd_resource=None,
parent_id=None):
return find_resource_by_name_or_id(client, resource, name_or_id,
project_id, cmd_resource,
parent_id, fields='id')['id']
def add_show_list_common_argument(parser):
parser.add_argument(
'-D', '--show-details',
help=_('Show detailed information.'),
action='store_true',
default=False, )
parser.add_argument(
'--show_details',
action='store_true',
help=argparse.SUPPRESS)
parser.add_argument(
'--fields',
help=argparse.SUPPRESS,
action='append',
default=[])
parser.add_argument(
'-F', '--field',
dest='fields', metavar='FIELD',
help=_('Specify the field(s) to be returned by server. You can '
'repeat this option.'),
action='append',
default=[])
def add_pagination_argument(parser):
parser.add_argument(
'-P', '--page-size',
dest='page_size', metavar='SIZE', type=int,
help=_("Specify retrieve unit of each request, then split one request "
"to several requests."),
default=None)
def add_sorting_argument(parser):
parser.add_argument(
'--sort-key',
dest='sort_key', metavar='FIELD',
action='append',
help=_("Sorts the list by the specified fields in the specified "
"directions. You can repeat this option, but you must "
"specify an equal number of sort_dir and sort_key values. "
"Extra sort_dir options are ignored. Missing sort_dir options "
"use the default asc value."),
default=[])
parser.add_argument(
'--sort-dir',
dest='sort_dir', metavar='{asc,desc}',
help=_("Sorts the list in the specified direction. You can repeat "
"this option."),
action='append',
default=[],
choices=['asc', 'desc'])
def is_number(s):
try:
float(s) # for int, long and float
except ValueError:
try:
complex(s) # for complex
except ValueError:
return False
return True
def _process_previous_argument(current_arg, _value_number, current_type_str,
_list_flag, _values_specs, _clear_flag,
values_specs):
if current_arg is not None:
if _value_number == 0 and (current_type_str or _list_flag):
# This kind of argument should have value
raise exceptions.CommandError(
_("Invalid values_specs %s") % ' '.join(values_specs))
if _value_number > 1 or _list_flag or current_type_str == 'list':
current_arg.update({'nargs': '+'})
elif _value_number == 0:
if _clear_flag:
# if we have action=clear, we use argument's default
# value None for argument
_values_specs.pop()
else:
# We assume non value argument as bool one
current_arg.update({'action': 'store_true'})
def parse_args_to_dict(values_specs):
"""It is used to analyze the extra command options to command.
Besides known options and arguments, our commands also support user to
put more options to the end of command line. For example,
list_nets -- --tag x y --key1 value1, where '-- --tag x y --key1 value1'
is extra options to our list_nets. This feature can support V2.0 API's
fields selection and filters. For example, to list networks which has name
'test4', we can have list_nets -- --name=test4.
value spec is: --key type=int|bool|... value. Type is one of Python
built-in types. By default, type is string. The key without value is
a bool option. Key with two values will be a list option.
"""
# values_specs for example: '-- --tag x y --key1 type=int value1'
# -- is a pseudo argument
values_specs_copy = values_specs[:]
if values_specs_copy and values_specs_copy[0] == '--':
del values_specs_copy[0]
# converted ArgumentParser arguments for each of the options
_options = {}
# the argument part for current option in _options
current_arg = None
# the string after remove meta info in values_specs
# for example, '--tag x y --key1 value1'
_values_specs = []
# record the count of values for an option
# for example: for '--tag x y', it is 2, while for '--key1 value1', it is 1
_value_number = 0
# list=true
_list_flag = False
# action=clear
_clear_flag = False
# the current item in values_specs
current_item = None
# the str after 'type='
current_type_str = None
for _item in values_specs_copy:
if _item.startswith('--'):
# Deal with previous argument if any
_process_previous_argument(
current_arg, _value_number, current_type_str,
_list_flag, _values_specs, _clear_flag, values_specs)
# Init variables for current argument
current_item = _item
_list_flag = False
_clear_flag = False
current_type_str = None
if "=" in _item:
_value_number = 1
_item = _item.split('=')[0]
else:
_value_number = 0
if _item in _options:
raise exceptions.CommandError(
_("Duplicated options %s") % ' '.join(values_specs))
else:
_options.update({_item: {}})
current_arg = _options[_item]
_item = current_item
elif _item.startswith('type='):
if current_arg is None:
raise exceptions.CommandError(
_("Invalid values_specs %s") % ' '.join(values_specs))
if 'type' not in current_arg:
current_type_str = _item.split('=', 2)[1]
current_arg.update({'type': eval(current_type_str)})
if current_type_str == 'bool':
current_arg.update({'type': utils.str2bool})
elif current_type_str == 'dict':
current_arg.update({'type': utils.str2dict})
continue
elif _item == 'list=true':
_list_flag = True
continue
elif _item == 'action=clear':
_clear_flag = True
continue
if not _item.startswith('--'):
# All others are value items
# Make sure '--' occurs first and allow minus value
if (not current_item or '=' in current_item or
_item.startswith('-') and not is_number(_item)):
raise exceptions.CommandError(
_("Invalid values_specs %s") % ' '.join(values_specs))
_value_number += 1
if _item.startswith('---'):
raise exceptions.CommandError(
_("Invalid values_specs %s") % ' '.join(values_specs))
_values_specs.append(_item)
# Deal with last one argument
_process_previous_argument(
current_arg, _value_number, current_type_str,
_list_flag, _values_specs, _clear_flag, values_specs)
# Populate the parser with arguments
_parser = argparse.ArgumentParser(add_help=False)
for opt, optspec in six.iteritems(_options):
_parser.add_argument(opt, **optspec)
_args = _parser.parse_args(_values_specs)
result_dict = {}
for opt in six.iterkeys(_options):
_opt = opt.split('--', 2)[1]
_opt = _opt.replace('-', '_')
_value = getattr(_args, _opt)
result_dict.update({_opt: _value})
return result_dict
def _merge_args(qCmd, parsed_args, _extra_values, value_specs):
"""Merge arguments from _extra_values into parsed_args.
If an argument value are provided in both and it is a list,
the values in _extra_values will be merged into parsed_args.
@param parsed_args: the parsed args from known options
@param _extra_values: the other parsed arguments in unknown parts
@param values_specs: the unparsed unknown parts
"""
temp_values = _extra_values.copy()
for key, value in six.iteritems(temp_values):
if hasattr(parsed_args, key):
arg_value = getattr(parsed_args, key)
if arg_value is not None and value is not None:
if isinstance(arg_value, list):
if value and isinstance(value, list):
if (not arg_value or
isinstance(arg_value[0], type(value[0]))):
arg_value.extend(value)
_extra_values.pop(key)
def update_dict(obj, dict, attributes):
"""Update dict with fields from obj.attributes.
:param obj: the object updated into dict
:param dict: the result dictionary
:param attributes: a list of attributes belonging to obj
"""
for attribute in attributes:
if hasattr(obj, attribute) and getattr(obj, attribute) is not None:
dict[attribute] = getattr(obj, attribute)
# cliff.command.Command is abstract class so that metaclass of
# subclass must be subclass of metaclass of all its base.
# otherwise metaclass conflict exception is raised.
class NeutronCommandMeta(abc.ABCMeta):
def __new__(cls, name, bases, cls_dict):
if 'log' not in cls_dict:
cls_dict['log'] = logging.getLogger(
cls_dict['__module__'] + '.' + name)
return super(NeutronCommandMeta, cls).__new__(cls,
name, bases, cls_dict)
@six.add_metaclass(NeutronCommandMeta)
class NeutronCommand(command.Command):
values_specs = []
json_indent = None
resource = None
shadow_resource = None
parent_id = None
def run(self, parsed_args):
self.log.debug('run(%s)', parsed_args)
return super(NeutronCommand, self).run(parsed_args)
@property
def cmd_resource(self):
if self.shadow_resource:
return self.shadow_resource
return self.resource
def get_client(self):
return self.app.client_manager.neutron
def get_parser(self, prog_name):
parser = super(NeutronCommand, self).get_parser(prog_name)
parser.add_argument(
'--request-format',
help=_('DEPRECATED! Only JSON request format is supported.'),
default='json',
choices=['json', ], )
parser.add_argument(
'--request_format',
choices=['json', ],
help=argparse.SUPPRESS)
return parser
def cleanup_output_data(self, data):
pass
def format_output_data(self, data):
self.cleanup_output_data(data)
# Modify data to make it more readable
if self.resource in data:
for k, v in six.iteritems(data[self.resource]):
if isinstance(v, list):
value = '\n'.join(jsonutils.dumps(
i, indent=self.json_indent) if isinstance(i, dict)
else str(i) for i in v)
data[self.resource][k] = value
elif isinstance(v, dict):
value = jsonutils.dumps(v, indent=self.json_indent)
data[self.resource][k] = value
elif v is None:
data[self.resource][k] = ''
def add_known_arguments(self, parser):
pass
def set_extra_attrs(self, parsed_args):
pass
def args2body(self, parsed_args):
return {}
class CreateCommand(NeutronCommand, show.ShowOne):
"""Create a resource for a given tenant."""
log = None
def get_parser(self, prog_name):
parser = super(CreateCommand, self).get_parser(prog_name)
parser.add_argument(
'--tenant-id', metavar='TENANT_ID',
help=_('The owner tenant ID.'), )
parser.add_argument(
'--tenant_id',
help=argparse.SUPPRESS)
self.add_known_arguments(parser)
return parser
def take_action(self, parsed_args):
self.set_extra_attrs(parsed_args)
neutron_client = self.get_client()
_extra_values = parse_args_to_dict(self.values_specs)
_merge_args(self, parsed_args, _extra_values,
self.values_specs)
body = self.args2body(parsed_args)
body[self.resource].update(_extra_values)
obj_creator = getattr(neutron_client,
"create_%s" % self.cmd_resource)
if self.parent_id:
data = obj_creator(self.parent_id, body)
else:
data = obj_creator(body)
self.format_output_data(data)
info = self.resource in data and data[self.resource] or None
if info:
if parsed_args.formatter == 'table':
print(_('Created a new %s:') % self.resource,
file=self.app.stdout)
else:
info = {'': ''}
return zip(*sorted(six.iteritems(info)))
class UpdateCommand(NeutronCommand):
"""Update resource's information."""
log = None
allow_names = True
help_resource = None
def get_parser(self, prog_name):
parser = super(UpdateCommand, self).get_parser(prog_name)
if self.allow_names:
help_str = _('ID or name of %s to update.')
else:
help_str = _('ID of %s to update.')
if not self.help_resource:
self.help_resource = self.resource
parser.add_argument(
'id', metavar=self.resource.upper(),
help=help_str % self.help_resource)
self.add_known_arguments(parser)
return parser
def take_action(self, parsed_args):
self.set_extra_attrs(parsed_args)
neutron_client = self.get_client()
_extra_values = parse_args_to_dict(self.values_specs)
_merge_args(self, parsed_args, _extra_values,
self.values_specs)
body = self.args2body(parsed_args)
if self.resource in body:
body[self.resource].update(_extra_values)
else:
body[self.resource] = _extra_values
if not body[self.resource]:
raise exceptions.CommandError(
_("Must specify new values to update %s") %
self.cmd_resource)
if self.allow_names:
_id = find_resourceid_by_name_or_id(
neutron_client, self.resource, parsed_args.id,
cmd_resource=self.cmd_resource, parent_id=self.parent_id)
else:
_id = find_resourceid_by_id(
neutron_client, self.resource, parsed_args.id,
self.cmd_resource, self.parent_id)
obj_updater = getattr(neutron_client,
"update_%s" % self.cmd_resource)
if self.parent_id:
obj_updater(_id, self.parent_id, body)
else:
obj_updater(_id, body)
print((_('Updated %(resource)s: %(id)s') %
{'id': parsed_args.id, 'resource': self.resource}),
file=self.app.stdout)
return
class DeleteCommand(NeutronCommand):
"""Delete a given resource."""
log = None
allow_names = True
help_resource = None
bulk_delete = True
def get_parser(self, prog_name):
parser = super(DeleteCommand, self).get_parser(prog_name)
if not self.help_resource:
self.help_resource = self.resource
if self.allow_names:
help_str = _('ID(s) or name(s) of %s to delete.')
else:
help_str = _('ID(s) of %s to delete.')
parser.add_argument(
'id', metavar=self.resource.upper(),
nargs='+' if self.bulk_delete else 1,
help=help_str % self.help_resource)
self.add_known_arguments(parser)
return parser
def take_action(self, parsed_args):
self.set_extra_attrs(parsed_args)
neutron_client = self.get_client()
obj_deleter = getattr(neutron_client,
"delete_%s" % self.cmd_resource)
if self.bulk_delete:
self._bulk_delete(obj_deleter, neutron_client, parsed_args.id)
else:
self.delete_item(obj_deleter, neutron_client, parsed_args.id)
print((_('Deleted %(resource)s: %(id)s')
% {'id': parsed_args.id,
'resource': self.resource}),
file=self.app.stdout)
return
def _bulk_delete(self, obj_deleter, neutron_client, parsed_args_ids):
successful_delete = []
non_existent = []
multiple_ids = []
for item_id in parsed_args_ids:
try:
self.delete_item(obj_deleter, neutron_client, item_id)
successful_delete.append(item_id)
except exceptions.NotFound:
non_existent.append(item_id)
except exceptions.NeutronClientNoUniqueMatch:
multiple_ids.append(item_id)
if successful_delete:
print((_('Deleted %(resource)s(s): %(id)s'))
% {'id': ", ".join(successful_delete),
'resource': self.cmd_resource},
file=self.app.stdout)
if non_existent:
print((_("Unable to find %(resource)s(s) with id(s) "
"'%(id)s'") %
{'resource': self.cmd_resource,
'id': ", ".join(non_existent)}),
file=self.app.stdout)
if multiple_ids:
print((_("Multiple %(resource)s(s) matches found for name(s)"
" '%(id)s'. Please use an ID to be more specific.")) %
{'resource': self.cmd_resource,
'id': ", ".join(multiple_ids)},
file=self.app.stdout)
def delete_item(self, obj_deleter, neutron_client, item_id):
if self.allow_names:
params = {'cmd_resource': self.cmd_resource,
'parent_id': self.parent_id}
_id = find_resourceid_by_name_or_id(neutron_client,
self.resource,
item_id,
**params)
else:
_id = item_id
if self.parent_id:
obj_deleter(_id, self.parent_id)
else:
obj_deleter(_id)
return
class ListCommand(NeutronCommand, lister.Lister):
"""List resources that belong to a given tenant."""
log = None
_formatters = {}
list_columns = []
unknown_parts_flag = True
pagination_support = False
sorting_support = False
resource_plural = None
# A list to define arguments for filtering by attribute value
# CLI arguments are shown in the order of this list.
# Each element must be either of a string of an attribute name
# or a dict of a full attribute definitions whose format is:
# {'name': attribute name, (mandatory)
# 'help': help message for CLI (mandatory)
# 'boolean': boolean parameter or not. (Default: False) (optional)
# 'argparse_kwargs': a dict of parameters passed to
# argparse add_argument()
# (Default: {}) (optional)
# }
# For more details, see ListNetworks.filter_attrs.
filter_attrs = []
default_attr_defs = {
'name': {
'help': _("Filter %s according to their name."),
'boolean': False,
},
'tenant_id': {
'help': _('Filter %s belonging to the given tenant.'),
'boolean': False,
},
'admin_state_up': {
'help': _('Filter and list the %s whose administrative '
'state is active'),
'boolean': True,
},
}
def get_parser(self, prog_name):
parser = super(ListCommand, self).get_parser(prog_name)
add_show_list_common_argument(parser)
if self.pagination_support:
add_pagination_argument(parser)
if self.sorting_support:
add_sorting_argument(parser)
self.add_known_arguments(parser)
self.add_filtering_arguments(parser)
return parser
def add_filtering_arguments(self, parser):
if not self.filter_attrs:
return
group_parser = parser.add_argument_group('filtering arguments')
collection = self.resource_plural or '%ss' % self.resource
for attr in self.filter_attrs:
if isinstance(attr, str):
# Use detail defined in default_attr_defs
attr_name = attr
attr_defs = self.default_attr_defs[attr]
else:
attr_name = attr['name']
attr_defs = attr
option_name = '--%s' % attr_name.replace('_', '-')
params = attr_defs.get('argparse_kwargs', {})
try:
help_msg = attr_defs['help'] % collection
except TypeError:
help_msg = attr_defs['help']
if attr_defs.get('boolean', False):
add_arg_func = functools.partial(utils.add_boolean_argument,
group_parser)
else:
add_arg_func = group_parser.add_argument
add_arg_func(option_name, help=help_msg, **params)
def args2search_opts(self, parsed_args):
search_opts = {}
fields = parsed_args.fields
if parsed_args.fields:
search_opts.update({'fields': fields})
if parsed_args.show_details:
search_opts.update({'verbose': 'True'})
filter_attrs = [field if isinstance(field, str) else field['name']
for field in self.filter_attrs]
for attr in filter_attrs:
val = getattr(parsed_args, attr, None)
if attr in HYPHEN_OPTS:
attr = attr.replace('_', '-')
if val:
search_opts[attr] = val
return search_opts
def call_server(self, neutron_client, search_opts, parsed_args):
resource_plural = neutron_client.get_resource_plural(self.cmd_resource)
obj_lister = getattr(neutron_client, "list_%s" % resource_plural)
if self.parent_id:
data = obj_lister(self.parent_id, **search_opts)
else:
data = obj_lister(**search_opts)
return data
def retrieve_list(self, parsed_args):
"""Retrieve a list of resources from Neutron server."""
neutron_client = self.get_client()
_extra_values = parse_args_to_dict(self.values_specs)
_merge_args(self, parsed_args, _extra_values,
self.values_specs)
search_opts = self.args2search_opts(parsed_args)
search_opts.update(_extra_values)
if self.pagination_support:
page_size = parsed_args.page_size
if page_size:
search_opts.update({'limit': page_size})
if self.sorting_support:
keys = parsed_args.sort_key
if keys:
search_opts.update({'sort_key': keys})
dirs = parsed_args.sort_dir
len_diff = len(keys) - len(dirs)
if len_diff > 0:
dirs += ['asc'] * len_diff
elif len_diff < 0:
dirs = dirs[:len(keys)]
if dirs:
search_opts.update({'sort_dir': dirs})
data = self.call_server(neutron_client, search_opts, parsed_args)
collection = neutron_client.get_resource_plural(self.resource)
return data.get(collection, [])
def extend_list(self, data, parsed_args):
"""Update a retrieved list.
This method provides a way to modify an original list returned from
the neutron server. For example, you can add subnet cidr information
to a network list.
"""
pass
def setup_columns(self, info, parsed_args):
_columns = len(info) > 0 and sorted(info[0].keys()) or []
if not _columns:
# clean the parsed_args.columns so that cliff will not break
parsed_args.columns = []
elif parsed_args.columns:
_columns = [x for x in parsed_args.columns if x in _columns]
elif self.list_columns:
# if no -c(s) by user and list_columns, we use columns in
# both list_columns and returned resource.
# Also Keep their order the same as in list_columns
_columns = [x for x in self.list_columns if x in _columns]
formatters = self._formatters
if hasattr(self, '_formatters_csv') and parsed_args.formatter == 'csv':
formatters = self._formatters_csv
return (_columns, (utils.get_item_properties(
s, _columns, formatters=formatters, )
for s in info), )
def take_action(self, parsed_args):
self.set_extra_attrs(parsed_args)
data = self.retrieve_list(parsed_args)
self.extend_list(data, parsed_args)
return self.setup_columns(data, parsed_args)
class ShowCommand(NeutronCommand, show.ShowOne):
"""Show information of a given resource."""
log = None
allow_names = True
help_resource = None
def get_parser(self, prog_name):
parser = super(ShowCommand, self).get_parser(prog_name)
add_show_list_common_argument(parser)
if self.allow_names:
help_str = _('ID or name of %s to look up.')
else:
help_str = _('ID of %s to look up.')
if not self.help_resource:
self.help_resource = self.resource
parser.add_argument(
'id', metavar=self.resource.upper(),
help=help_str % self.help_resource)
self.add_known_arguments(parser)
return parser
def take_action(self, parsed_args):
self.set_extra_attrs(parsed_args)
neutron_client = self.get_client()
params = {}
if parsed_args.show_details:
params = {'verbose': 'True'}
if parsed_args.fields:
params = {'fields': parsed_args.fields}
if self.allow_names:
_id = find_resourceid_by_name_or_id(neutron_client,
self.resource,
parsed_args.id,
cmd_resource=self.cmd_resource,
parent_id=self.parent_id)
else:
_id = parsed_args.id
obj_shower = getattr(neutron_client, "show_%s" % self.cmd_resource)
if self.parent_id:
data = obj_shower(_id, self.parent_id, **params)
else:
data = obj_shower(_id, **params)
self.format_output_data(data)
resource = data[self.resource]
if self.resource in data:
return zip(*sorted(six.iteritems(resource)))
else:
return None

View File

@ -1,84 +0,0 @@
# Copyright 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 neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
class ListAddressScope(neutronV20.ListCommand):
"""List address scopes that belong to a given tenant."""
resource = 'address_scope'
list_columns = ['id', 'name', 'ip_version']
pagination_support = True
sorting_support = True
class ShowAddressScope(neutronV20.ShowCommand):
"""Show information about an address scope."""
resource = 'address_scope'
class CreateAddressScope(neutronV20.CreateCommand):
"""Create an address scope for a given tenant."""
resource = 'address_scope'
def add_known_arguments(self, parser):
parser.add_argument(
'--shared',
action='store_true',
help=_('Set the address scope as shared.'))
parser.add_argument(
'name',
metavar='NAME',
help=_('Specify the name of the address scope.'))
parser.add_argument(
'ip_version',
metavar='IP_VERSION',
type=int,
choices=[4, 6],
help=_('Specify the address family of the address scope.'))
def args2body(self, parsed_args):
body = {'name': parsed_args.name,
'ip_version': parsed_args.ip_version}
if parsed_args.shared:
body['shared'] = True
neutronV20.update_dict(parsed_args, body, ['tenant_id'])
return {self.resource: body}
class DeleteAddressScope(neutronV20.DeleteCommand):
"""Delete an address scope."""
resource = 'address_scope'
class UpdateAddressScope(neutronV20.UpdateCommand):
"""Update an address scope."""
resource = 'address_scope'
def add_known_arguments(self, parser):
parser.add_argument('--name',
help=_('Updated name of the address scope.'))
def args2body(self, parsed_args):
body = {}
neutronV20.update_dict(parsed_args, body, ['name'])
return {self.resource: body}

View File

@ -1,78 +0,0 @@
# Copyright 2013 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.
#
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
def _format_timestamp(component):
try:
return component['heartbeat_timestamp'].split(".", 2)[0]
except (TypeError, KeyError):
return ''
class ListAgent(neutronV20.ListCommand):
"""List agents."""
resource = 'agent'
list_columns = ['id', 'agent_type', 'host', 'availability_zone', 'alive',
'admin_state_up', 'binary']
_formatters = {'heartbeat_timestamp': _format_timestamp}
sorting_support = True
def extend_list(self, data, parsed_args):
for agent in data:
if 'alive' in agent:
agent['alive'] = ":-)" if agent['alive'] else 'xxx'
class ShowAgent(neutronV20.ShowCommand):
"""Show information of a given agent."""
resource = 'agent'
allow_names = False
json_indent = 5
class DeleteAgent(neutronV20.DeleteCommand):
"""Delete a given agent."""
resource = 'agent'
allow_names = False
class UpdateAgent(neutronV20.UpdateCommand):
"""Updates the admin status and description for a specified agent."""
resource = 'agent'
allow_names = False
def add_known_arguments(self, parser):
parser.add_argument(
'--admin-state-down',
dest='admin_state',
action='store_false',
help=_('Set admin state up of the agent to false.'))
parser.add_argument(
'--description',
help=_('Description for the agent.'))
def args2body(self, parsed_args):
body = {'admin_state_up': parsed_args.admin_state}
neutronV20.update_dict(parsed_args, body,
['description'])
return {self.resource: body}

View File

@ -1,343 +0,0 @@
# Copyright 2013 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.
#
from __future__ import print_function
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.neutron.v2_0 import network
from neutronclient.neutron.v2_0 import router
PERFECT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
class AddNetworkToDhcpAgent(neutronV20.NeutronCommand):
"""Add a network to a DHCP agent."""
def get_parser(self, prog_name):
parser = super(AddNetworkToDhcpAgent, self).get_parser(prog_name)
parser.add_argument(
'dhcp_agent',
metavar='DHCP_AGENT',
help=_('ID of the DHCP agent.'))
parser.add_argument(
'network',
metavar='NETWORK',
help=_('Network to add.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_net_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'network', parsed_args.network)
neutron_client.add_network_to_dhcp_agent(parsed_args.dhcp_agent,
{'network_id': _net_id})
print(_('Added network %s to DHCP agent') % parsed_args.network,
file=self.app.stdout)
class RemoveNetworkFromDhcpAgent(neutronV20.NeutronCommand):
"""Remove a network from a DHCP agent."""
def get_parser(self, prog_name):
parser = super(RemoveNetworkFromDhcpAgent, self).get_parser(prog_name)
parser.add_argument(
'dhcp_agent',
metavar='DHCP_AGENT',
help=_('ID of the DHCP agent.'))
parser.add_argument(
'network',
metavar='NETWORK',
help=_('Network to remove.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_net_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'network', parsed_args.network)
neutron_client.remove_network_from_dhcp_agent(
parsed_args.dhcp_agent, _net_id)
print(_('Removed network %s from DHCP agent') % parsed_args.network,
file=self.app.stdout)
class ListNetworksOnDhcpAgent(network.ListNetwork):
"""List the networks on a DHCP agent."""
unknown_parts_flag = False
def get_parser(self, prog_name):
parser = super(ListNetworksOnDhcpAgent,
self).get_parser(prog_name)
parser.add_argument(
'dhcp_agent',
metavar='DHCP_AGENT',
help=_('ID of the DHCP agent.'))
return parser
def call_server(self, neutron_client, search_opts, parsed_args):
data = neutron_client.list_networks_on_dhcp_agent(
parsed_args.dhcp_agent, **search_opts)
return data
class ListDhcpAgentsHostingNetwork(neutronV20.ListCommand):
"""List DHCP agents hosting a network."""
resource = 'agent'
_formatters = {}
list_columns = ['id', 'host', 'admin_state_up', 'alive']
unknown_parts_flag = False
def get_parser(self, prog_name):
parser = super(ListDhcpAgentsHostingNetwork,
self).get_parser(prog_name)
parser.add_argument(
'network',
metavar='NETWORK',
help=_('Network to query.'))
return parser
def extend_list(self, data, parsed_args):
for agent in data:
agent['alive'] = ":-)" if agent['alive'] else 'xxx'
def call_server(self, neutron_client, search_opts, parsed_args):
_id = neutronV20.find_resourceid_by_name_or_id(neutron_client,
'network',
parsed_args.network)
search_opts['network'] = _id
data = neutron_client.list_dhcp_agent_hosting_networks(**search_opts)
return data
class AddRouterToL3Agent(neutronV20.NeutronCommand):
"""Add a router to a L3 agent."""
def get_parser(self, prog_name):
parser = super(AddRouterToL3Agent, self).get_parser(prog_name)
parser.add_argument(
'l3_agent',
metavar='L3_AGENT',
help=_('ID of the L3 agent.'))
parser.add_argument(
'router',
metavar='ROUTER',
help=_('Router to add.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'router', parsed_args.router)
neutron_client.add_router_to_l3_agent(parsed_args.l3_agent,
{'router_id': _id})
print(_('Added router %s to L3 agent') % parsed_args.router,
file=self.app.stdout)
class RemoveRouterFromL3Agent(neutronV20.NeutronCommand):
"""Remove a router from a L3 agent."""
def get_parser(self, prog_name):
parser = super(RemoveRouterFromL3Agent, self).get_parser(prog_name)
parser.add_argument(
'l3_agent',
metavar='L3_AGENT',
help=_('ID of the L3 agent.'))
parser.add_argument(
'router',
metavar='ROUTER',
help=_('Router to remove.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'router', parsed_args.router)
neutron_client.remove_router_from_l3_agent(
parsed_args.l3_agent, _id)
print(_('Removed router %s from L3 agent') % parsed_args.router,
file=self.app.stdout)
class ListRoutersOnL3Agent(neutronV20.ListCommand):
"""List the routers on a L3 agent."""
_formatters = {'external_gateway_info':
router._format_external_gateway_info}
list_columns = ['id', 'name', 'external_gateway_info']
resource = 'router'
unknown_parts_flag = False
def get_parser(self, prog_name):
parser = super(ListRoutersOnL3Agent,
self).get_parser(prog_name)
parser.add_argument(
'l3_agent',
metavar='L3_AGENT',
help=_('ID of the L3 agent to query.'))
return parser
def call_server(self, neutron_client, search_opts, parsed_args):
data = neutron_client.list_routers_on_l3_agent(
parsed_args.l3_agent, **search_opts)
return data
class ListL3AgentsHostingRouter(neutronV20.ListCommand):
"""List L3 agents hosting a router."""
resource = 'agent'
_formatters = {}
list_columns = ['id', 'host', 'admin_state_up', 'alive']
unknown_parts_flag = False
def get_parser(self, prog_name):
parser = super(ListL3AgentsHostingRouter,
self).get_parser(prog_name)
parser.add_argument('router',
metavar='ROUTER',
help=_('Router to query.'))
return parser
def extend_list(self, data, parsed_args):
# Show the ha_state column only if the server responds with it,
# as some plugins do not support HA routers.
if any('ha_state' in agent for agent in data):
if 'ha_state' not in self.list_columns:
self.list_columns.append('ha_state')
for agent in data:
agent['alive'] = ":-)" if agent['alive'] else 'xxx'
def call_server(self, neutron_client, search_opts, parsed_args):
_id = neutronV20.find_resourceid_by_name_or_id(neutron_client,
'router',
parsed_args.router)
search_opts['router'] = _id
data = neutron_client.list_l3_agent_hosting_routers(**search_opts)
return data
class ListPoolsOnLbaasAgent(neutronV20.ListCommand):
"""List the pools on a loadbalancer agent."""
list_columns = ['id', 'name', 'lb_method', 'protocol',
'admin_state_up', 'status']
resource = 'pool'
unknown_parts_flag = False
def get_parser(self, prog_name):
parser = super(ListPoolsOnLbaasAgent, self).get_parser(prog_name)
parser.add_argument(
'lbaas_agent',
metavar='LBAAS_AGENT',
help=_('ID of the loadbalancer agent to query.'))
return parser
def call_server(self, neutron_client, search_opts, parsed_args):
data = neutron_client.list_pools_on_lbaas_agent(
parsed_args.lbaas_agent, **search_opts)
return data
class GetLbaasAgentHostingPool(neutronV20.ListCommand):
"""Get loadbalancer agent hosting a pool.
Deriving from ListCommand though server will return only one agent
to keep common output format for all agent schedulers
"""
resource = 'agent'
list_columns = ['id', 'host', 'admin_state_up', 'alive']
unknown_parts_flag = False
def get_parser(self, prog_name):
parser = super(GetLbaasAgentHostingPool,
self).get_parser(prog_name)
parser.add_argument('pool',
metavar='POOL',
help=_('Pool to query.'))
return parser
def extend_list(self, data, parsed_args):
for agent in data:
agent['alive'] = ":-)" if agent['alive'] else 'xxx'
def call_server(self, neutron_client, search_opts, parsed_args):
_id = neutronV20.find_resourceid_by_name_or_id(neutron_client,
'pool',
parsed_args.pool)
search_opts['pool'] = _id
agent = neutron_client.get_lbaas_agent_hosting_pool(**search_opts)
data = {'agents': [agent['agent']]}
return data
class ListLoadBalancersOnLbaasAgent(neutronV20.ListCommand):
"""List the loadbalancers on a loadbalancer v2 agent."""
list_columns = ['id', 'name', 'admin_state_up', 'provisioning_status']
resource = 'loadbalancer'
unknown_parts_flag = False
def get_parser(self, prog_name):
parser = super(ListLoadBalancersOnLbaasAgent, self).get_parser(
prog_name)
parser.add_argument(
'lbaas_agent',
metavar='LBAAS_AGENT',
help=_('ID of the loadbalancer agent to query.'))
return parser
def call_server(self, neutron_client, search_opts, parsed_args):
data = neutron_client.list_loadbalancers_on_lbaas_agent(
parsed_args.lbaas_agent, **search_opts)
return data
class GetLbaasAgentHostingLoadBalancer(neutronV20.ListCommand):
"""Get lbaas v2 agent hosting a loadbalancer.
Deriving from ListCommand though server will return only one agent
to keep common output format for all agent schedulers
"""
resource = 'agent'
list_columns = ['id', 'host', 'admin_state_up', 'alive']
unknown_parts_flag = False
def get_parser(self, prog_name):
parser = super(GetLbaasAgentHostingLoadBalancer,
self).get_parser(prog_name)
parser.add_argument('loadbalancer',
metavar='LOADBALANCER',
help=_('LoadBalancer to query.'))
return parser
def extend_list(self, data, parsed_args):
for agent in data:
agent['alive'] = ":-)" if agent['alive'] else 'xxx'
def call_server(self, neutron_client, search_opts, parsed_args):
_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'loadbalancer', parsed_args.loadbalancer)
search_opts['loadbalancer'] = _id
agent = neutron_client.get_lbaas_agent_hosting_loadbalancer(
**search_opts)
data = {'agents': [agent['agent']]}
return data

View File

@ -1,81 +0,0 @@
# Copyright 2016 IBM
# 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 argparse
from cliff import show
from oslo_serialization import jsonutils
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.neutron import v2_0
class ShowAutoAllocatedTopology(v2_0.NeutronCommand, show.ShowOne):
"""Show the auto-allocated topology of a given tenant."""
resource = 'auto_allocated_topology'
def get_parser(self, prog_name):
parser = super(ShowAutoAllocatedTopology, self).get_parser(prog_name)
parser.add_argument(
'--dry-run',
help=_('Validate the requirements for auto-allocated-topology. '
'(Does not return a topology.)'),
action='store_true')
parser.add_argument(
'--tenant-id', metavar='tenant-id',
help=_('The owner tenant ID.'))
# Allow people to do
# neutron auto-allocated-topology-show <tenant-id>
# (Only useful to users who can look at other tenants' topologies.)
# We use a different name for this arg because the default will
# override whatever is in the named arg otherwise.
parser.add_argument(
'pos_tenant_id',
help=argparse.SUPPRESS, nargs='?')
return parser
def take_action(self, parsed_args):
client = self.get_client()
extra_values = v2_0.parse_args_to_dict(self.values_specs)
if extra_values:
raise exceptions.CommandError(
_("Invalid argument(s): --%s") % ', --'.join(extra_values))
tenant_id = parsed_args.tenant_id or parsed_args.pos_tenant_id
if parsed_args.dry_run:
data = client.validate_auto_allocated_topology_requirements(
tenant_id)
else:
data = client.get_auto_allocated_topology(tenant_id)
if self.resource in data:
for k, v in data[self.resource].items():
if isinstance(v, list):
value = ""
for _item in v:
if value:
value += "\n"
if isinstance(_item, dict):
value += jsonutils.dumps(_item)
else:
value += str(_item)
data[self.resource][k] = value
elif v == "dry-run=pass":
return ("dry-run",), ("pass",)
elif v is None:
data[self.resource][k] = ''
return zip(*sorted(data[self.resource].items()))
else:
return None

View File

@ -1,38 +0,0 @@
# 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 neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronv20
def add_az_hint_argument(parser, resource):
parser.add_argument(
'--availability-zone-hint', metavar='AVAILABILITY_ZONE',
action='append', dest='availability_zone_hints',
help=_('Availability Zone for the %s '
'(requires availability zone extension, '
'this option can be repeated).') % resource)
def args2body_az_hint(parsed_args, resource):
if parsed_args.availability_zone_hints:
resource['availability_zone_hints'] = (
parsed_args.availability_zone_hints)
class ListAvailabilityZone(neutronv20.ListCommand):
"""List availability zones."""
resource = 'availability_zone'
list_columns = ['name', 'resource', 'state']
pagination_support = True
sorting_support = True

View File

@ -1,117 +0,0 @@
# Copyright 2016 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 __future__ import print_function
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.neutron.v2_0.bgp import speaker as bgp_speaker
def add_common_args(parser):
parser.add_argument('dragent_id',
metavar='BGP_DRAGENT_ID',
help=_('ID of the Dynamic Routing agent.'))
parser.add_argument('bgp_speaker',
metavar='BGP_SPEAKER',
help=_('ID or name of the BGP speaker.'))
class AddBGPSpeakerToDRAgent(neutronV20.NeutronCommand):
"""Add a BGP speaker to a Dynamic Routing agent."""
def get_parser(self, prog_name):
parser = super(AddBGPSpeakerToDRAgent, self).get_parser(prog_name)
add_common_args(parser)
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_speaker_id = bgp_speaker.get_bgp_speaker_id(neutron_client,
parsed_args.bgp_speaker)
neutron_client.add_bgp_speaker_to_dragent(
parsed_args.dragent_id, {'bgp_speaker_id': _speaker_id})
print(_('Associated BGP speaker %s to the Dynamic Routing agent.')
% parsed_args.bgp_speaker, file=self.app.stdout)
class RemoveBGPSpeakerFromDRAgent(neutronV20.NeutronCommand):
"""Removes a BGP speaker from a Dynamic Routing agent."""
def get_parser(self, prog_name):
parser = super(RemoveBGPSpeakerFromDRAgent, self).get_parser(
prog_name)
add_common_args(parser)
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_speaker_id = bgp_speaker.get_bgp_speaker_id(neutron_client,
parsed_args.bgp_speaker)
neutron_client.remove_bgp_speaker_from_dragent(parsed_args.dragent_id,
_speaker_id)
print(_('Disassociated BGP speaker %s from the '
'Dynamic Routing agent.')
% parsed_args.bgp_speaker, file=self.app.stdout)
class ListBGPSpeakersOnDRAgent(neutronV20.ListCommand):
"""List BGP speakers hosted by a Dynamic Routing agent."""
list_columns = ['id', 'name', 'local_as', 'ip_version']
resource = 'bgp_speaker'
def get_parser(self, prog_name):
parser = super(ListBGPSpeakersOnDRAgent,
self).get_parser(prog_name)
parser.add_argument(
'dragent_id',
metavar='BGP_DRAGENT_ID',
help=_('ID of the Dynamic Routing agent.'))
return parser
def call_server(self, neutron_client, search_opts, parsed_args):
data = neutron_client.list_bgp_speaker_on_dragent(
parsed_args.dragent_id, **search_opts)
return data
class ListDRAgentsHostingBGPSpeaker(neutronV20.ListCommand):
"""List Dynamic Routing agents hosting a BGP speaker."""
resource = 'agent'
_formatters = {}
list_columns = ['id', 'host', 'admin_state_up', 'alive']
unknown_parts_flag = False
def get_parser(self, prog_name):
parser = super(ListDRAgentsHostingBGPSpeaker,
self).get_parser(prog_name)
parser.add_argument('bgp_speaker',
metavar='BGP_SPEAKER',
help=_('ID or name of the BGP speaker.'))
return parser
def extend_list(self, data, parsed_args):
for agent in data:
agent['alive'] = ":-)" if agent['alive'] else 'xxx'
def call_server(self, neutron_client, search_opts, parsed_args):
_speaker_id = bgp_speaker.get_bgp_speaker_id(neutron_client,
parsed_args.bgp_speaker)
search_opts['bgp_speaker'] = _speaker_id
data = neutron_client.list_dragents_hosting_bgp_speaker(**search_opts)
return data

View File

@ -1,127 +0,0 @@
# Copyright 2016 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 neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.common import validators
from neutronclient.neutron import v2_0 as neutronv20
def get_bgp_peer_id(client, id_or_name):
return neutronv20.find_resourceid_by_name_or_id(client,
'bgp_peer',
id_or_name)
def validate_peer_attributes(parsed_args):
# Validate AS number
validators.validate_int_range(parsed_args, 'remote_as',
neutronv20.bgp.speaker.MIN_AS_NUM,
neutronv20.bgp.speaker.MAX_AS_NUM)
# Validate password
if parsed_args.auth_type != 'none' and parsed_args.password is None:
raise exceptions.CommandError(_('Must provide password if auth-type '
'is specified.'))
if parsed_args.auth_type == 'none' and parsed_args.password:
raise exceptions.CommandError(_('Must provide auth-type if password '
'is specified.'))
class ListPeers(neutronv20.ListCommand):
"""List BGP peers."""
resource = 'bgp_peer'
list_columns = ['id', 'name', 'peer_ip', 'remote_as']
pagination_support = True
sorting_support = True
class ShowPeer(neutronv20.ShowCommand):
"""Show information of a given BGP peer."""
resource = 'bgp_peer'
class CreatePeer(neutronv20.CreateCommand):
"""Create a BGP Peer."""
resource = 'bgp_peer'
def add_known_arguments(self, parser):
parser.add_argument(
'name',
metavar='NAME',
help=_('Name of the BGP peer to create.'))
parser.add_argument(
'--peer-ip',
metavar='PEER_IP_ADDRESS',
required=True,
help=_('Peer IP address.'))
parser.add_argument(
'--remote-as',
required=True,
metavar='PEER_REMOTE_AS',
help=_('Peer AS number. (Integer in [%(min_val)s, %(max_val)s] '
'is allowed.)') %
{'min_val': neutronv20.bgp.speaker.MIN_AS_NUM,
'max_val': neutronv20.bgp.speaker.MAX_AS_NUM})
parser.add_argument(
'--auth-type',
metavar='PEER_AUTH_TYPE',
choices=['none', 'md5'],
default='none',
type=utils.convert_to_lowercase,
help=_('Authentication algorithm. Supported algorithms: '
'none(default), md5'))
parser.add_argument(
'--password',
metavar='AUTH_PASSWORD',
help=_('Authentication password.'))
def args2body(self, parsed_args):
body = {}
validate_peer_attributes(parsed_args)
neutronv20.update_dict(parsed_args, body,
['name', 'peer_ip',
'remote_as', 'auth_type', 'password'])
return {self.resource: body}
class UpdatePeer(neutronv20.UpdateCommand):
"""Update BGP Peer's information."""
resource = 'bgp_peer'
def add_known_arguments(self, parser):
parser.add_argument(
'--name',
help=_('Updated name of the BGP peer.'))
parser.add_argument(
'--password',
metavar='AUTH_PASSWORD',
help=_('Updated authentication password.'))
def args2body(self, parsed_args):
body = {}
neutronv20.update_dict(parsed_args, body, ['name', 'password'])
return {self.resource: body}
class DeletePeer(neutronv20.DeleteCommand):
"""Delete a BGP peer."""
resource = 'bgp_peer'

View File

@ -1,277 +0,0 @@
# Copyright 2016 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 __future__ import print_function
from neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.common import validators
from neutronclient.neutron import v2_0 as neutronv20
from neutronclient.neutron.v2_0.bgp import peer as bgp_peer
# Allowed BGP Autonomous number range
MIN_AS_NUM = 1
MAX_AS_NUM = 65535
def get_network_id(client, id_or_name):
return neutronv20.find_resourceid_by_name_or_id(client,
'network',
id_or_name)
def get_bgp_speaker_id(client, id_or_name):
return neutronv20.find_resourceid_by_name_or_id(client,
'bgp_speaker',
id_or_name)
def validate_speaker_attributes(parsed_args):
# Validate AS number
validators.validate_int_range(parsed_args, 'local_as',
MIN_AS_NUM, MAX_AS_NUM)
def add_common_arguments(parser):
utils.add_boolean_argument(
parser, '--advertise-floating-ip-host-routes',
help=_('Whether to enable or disable the advertisement '
'of floating-ip host routes by the BGP speaker. '
'By default floating ip host routes will be '
'advertised by the BGP speaker.'))
utils.add_boolean_argument(
parser, '--advertise-tenant-networks',
help=_('Whether to enable or disable the advertisement '
'of tenant network routes by the BGP speaker. '
'By default tenant network routes will be '
'advertised by the BGP speaker.'))
def args2body_common_arguments(body, parsed_args):
neutronv20.update_dict(parsed_args, body,
['name',
'advertise_floating_ip_host_routes',
'advertise_tenant_networks'])
class ListSpeakers(neutronv20.ListCommand):
"""List BGP speakers."""
resource = 'bgp_speaker'
list_columns = ['id', 'name', 'local_as', 'ip_version']
pagination_support = True
sorting_support = True
class ShowSpeaker(neutronv20.ShowCommand):
"""Show information of a given BGP speaker."""
resource = 'bgp_speaker'
class CreateSpeaker(neutronv20.CreateCommand):
"""Create a BGP Speaker."""
resource = 'bgp_speaker'
def add_known_arguments(self, parser):
parser.add_argument(
'name',
metavar='NAME',
help=_('Name of the BGP speaker to create.'))
parser.add_argument(
'--local-as',
metavar='LOCAL_AS',
required=True,
help=_('Local AS number. (Integer in [%(min_val)s, %(max_val)s] '
'is allowed.)') % {'min_val': MIN_AS_NUM,
'max_val': MAX_AS_NUM})
parser.add_argument(
'--ip-version',
type=int, choices=[4, 6],
default=4,
help=_('IP version for the BGP speaker (default is 4).'))
add_common_arguments(parser)
def args2body(self, parsed_args):
body = {}
validate_speaker_attributes(parsed_args)
body['local_as'] = parsed_args.local_as
body['ip_version'] = parsed_args.ip_version
args2body_common_arguments(body, parsed_args)
return {self.resource: body}
class UpdateSpeaker(neutronv20.UpdateCommand):
"""Update BGP Speaker's information."""
resource = 'bgp_speaker'
def add_known_arguments(self, parser):
parser.add_argument(
'--name',
help=_('Name of the BGP speaker to update.'))
add_common_arguments(parser)
def args2body(self, parsed_args):
body = {}
args2body_common_arguments(body, parsed_args)
return {self.resource: body}
class DeleteSpeaker(neutronv20.DeleteCommand):
"""Delete a BGP speaker."""
resource = 'bgp_speaker'
class AddPeerToSpeaker(neutronv20.NeutronCommand):
"""Add a peer to the BGP speaker."""
def get_parser(self, prog_name):
parser = super(AddPeerToSpeaker, self).get_parser(prog_name)
parser.add_argument(
'bgp_speaker',
metavar='BGP_SPEAKER',
help=_('ID or name of the BGP speaker.'))
parser.add_argument(
'bgp_peer',
metavar='BGP_PEER',
help=_('ID or name of the BGP peer to add.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_speaker_id = get_bgp_speaker_id(neutron_client,
parsed_args.bgp_speaker)
_peer_id = bgp_peer.get_bgp_peer_id(neutron_client,
parsed_args.bgp_peer)
neutron_client.add_peer_to_bgp_speaker(_speaker_id,
{'bgp_peer_id': _peer_id})
print(_('Added BGP peer %(peer)s to BGP speaker %(speaker)s.') %
{'peer': parsed_args.bgp_peer,
'speaker': parsed_args.bgp_speaker},
file=self.app.stdout)
class RemovePeerFromSpeaker(neutronv20.NeutronCommand):
"""Remove a peer from the BGP speaker."""
def get_parser(self, prog_name):
parser = super(RemovePeerFromSpeaker, self).get_parser(prog_name)
parser.add_argument(
'bgp_speaker',
metavar='BGP_SPEAKER',
help=_('ID or name of the BGP speaker.'))
parser.add_argument(
'bgp_peer',
metavar='BGP_PEER',
help=_('ID or name of the BGP peer to remove.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_speaker_id = get_bgp_speaker_id(neutron_client,
parsed_args.bgp_speaker)
_peer_id = bgp_peer.get_bgp_peer_id(neutron_client,
parsed_args.bgp_peer)
neutron_client.remove_peer_from_bgp_speaker(_speaker_id,
{'bgp_peer_id': _peer_id})
print(_('Removed BGP peer %(peer)s from BGP speaker %(speaker)s.') %
{'peer': parsed_args.bgp_peer,
'speaker': parsed_args.bgp_speaker},
file=self.app.stdout)
class AddNetworkToSpeaker(neutronv20.NeutronCommand):
"""Add a network to the BGP speaker."""
def get_parser(self, prog_name):
parser = super(AddNetworkToSpeaker, self).get_parser(prog_name)
parser.add_argument(
'bgp_speaker',
metavar='BGP_SPEAKER',
help=_('ID or name of the BGP speaker.'))
parser.add_argument(
'network',
metavar='NETWORK',
help=_('ID or name of the network to add.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_speaker_id = get_bgp_speaker_id(neutron_client,
parsed_args.bgp_speaker)
_net_id = get_network_id(neutron_client,
parsed_args.network)
neutron_client.add_network_to_bgp_speaker(_speaker_id,
{'network_id': _net_id})
print(_('Added network %(net)s to BGP speaker %(speaker)s.') %
{'net': parsed_args.network, 'speaker': parsed_args.bgp_speaker},
file=self.app.stdout)
class RemoveNetworkFromSpeaker(neutronv20.NeutronCommand):
"""Remove a network from the BGP speaker."""
def get_parser(self, prog_name):
parser = super(RemoveNetworkFromSpeaker, self).get_parser(prog_name)
parser.add_argument(
'bgp_speaker',
metavar='BGP_SPEAKER',
help=_('ID or name of the BGP speaker.'))
parser.add_argument(
'network',
metavar='NETWORK',
help=_('ID or name of the network to remove.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_speaker_id = get_bgp_speaker_id(neutron_client,
parsed_args.bgp_speaker)
_net_id = get_network_id(neutron_client,
parsed_args.network)
neutron_client.remove_network_from_bgp_speaker(_speaker_id,
{'network_id': _net_id})
print(_('Removed network %(net)s from BGP speaker %(speaker)s.') %
{'net': parsed_args.network, 'speaker': parsed_args.bgp_speaker},
file=self.app.stdout)
class ListRoutesAdvertisedBySpeaker(neutronv20.ListCommand):
"""List routes advertised by a given BGP speaker."""
list_columns = ['id', 'destination', 'next_hop']
resource = 'advertised_route'
pagination_support = True
sorting_support = True
def get_parser(self, prog_name):
parser = super(ListRoutesAdvertisedBySpeaker,
self).get_parser(prog_name)
parser.add_argument(
'bgp_speaker',
metavar='BGP_SPEAKER',
help=_('ID or name of the BGP speaker.'))
return parser
def call_server(self, neutron_client, search_opts, parsed_args):
_speaker_id = get_bgp_speaker_id(neutron_client,
parsed_args.bgp_speaker)
data = neutron_client.list_route_advertised_from_bgp_speaker(
_speaker_id, **search_opts)
return data

View File

@ -1,93 +0,0 @@
# Copyright 2015 Rackspace Hosting Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from neutronclient._i18n import _
from neutronclient.common import extension
def _add_updatable_args(parser):
parser.add_argument(
'name',
help=_('Name of this fox socket.'))
def _updatable_args2body(parsed_args, body, client):
if parsed_args.name:
body['name'] = parsed_args.name
class FoxInSocket(extension.NeutronClientExtension):
"""Define required variables for resource operations."""
resource = 'fox_socket'
resource_plural = '%ss' % resource
object_path = '/%s' % resource_plural
resource_path = '/%s/%%s' % resource_plural
versions = ['2.0']
class FoxInSocketsList(extension.ClientExtensionList, FoxInSocket):
"""List fox sockets."""
shell_command = 'fox-sockets-list'
list_columns = ['id', 'name']
pagination_support = True
sorting_support = True
class FoxInSocketsCreate(extension.ClientExtensionCreate, FoxInSocket):
"""Create a fox socket."""
shell_command = 'fox-sockets-create'
list_columns = ['id', 'name']
def add_known_arguments(self, parser):
_add_updatable_args(parser)
def args2body(self, parsed_args):
body = {}
client = self.get_client()
_updatable_args2body(parsed_args, body, client)
return {'fox_socket': body}
class FoxInSocketsUpdate(extension.ClientExtensionUpdate, FoxInSocket):
"""Update a fox socket."""
shell_command = 'fox-sockets-update'
list_columns = ['id', 'name']
def add_known_arguments(self, parser):
# _add_updatable_args(parser)
parser.add_argument(
'--name',
help=_('Name of this fox socket.'))
def args2body(self, parsed_args):
body = {'name': parsed_args.name}
return {'fox_socket': body}
class FoxInSocketsDelete(extension.ClientExtensionDelete, FoxInSocket):
"""Delete a fox socket."""
shell_command = 'fox-sockets-delete'
class FoxInSocketsShow(extension.ClientExtensionShow, FoxInSocket):
"""Show a fox socket."""
shell_command = 'fox-sockets-show'

View File

@ -1,67 +0,0 @@
# Copyright (c) 2016 IBM
# 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 neutronclient._i18n import _
def add_dns_argument_create(parser, resource, attribute):
# Add dns_name and dns_domain support to network, port and floatingip
# create
argument = '--dns-%s' % attribute
parser.add_argument(
argument,
help=_('Assign DNS %(attribute)s to the %(resource)s '
'(requires DNS integration '
'extension)') % {'attribute': attribute, 'resource': resource})
def args2body_dns_create(parsed_args, resource, attribute):
# Add dns_name and dns_domain support to network, port and floatingip
# create
destination = 'dns_%s' % attribute
argument = getattr(parsed_args, destination)
if argument:
resource[destination] = argument
def add_dns_argument_update(parser, resource, attribute):
# Add dns_name and dns_domain support to network, port and floatingip
# update
argument = '--dns-%s' % attribute
no_argument = '--no-dns-%s' % attribute
dns_args = parser.add_mutually_exclusive_group()
dns_args.add_argument(
argument,
help=_('Assign DNS %(attribute)s to the %(resource)s '
'(requires DNS integration '
'extension.)') % {'attribute': attribute, 'resource': resource})
dns_args.add_argument(
no_argument, action='store_true',
help=_('Unassign DNS %(attribute)s from the %(resource)s '
'(requires DNS integration '
'extension.)') % {'attribute': attribute, 'resource': resource})
def args2body_dns_update(parsed_args, resource, attribute):
# Add dns_name and dns_domain support to network, port and floatingip
# update
destination = 'dns_%s' % attribute
no_destination = 'no_dns_%s' % attribute
argument = getattr(parsed_args, destination)
no_argument = getattr(parsed_args, no_destination)
if argument:
resource[destination] = argument
if no_argument:
resource[destination] = ""

View File

@ -1,31 +0,0 @@
# Copyright 2012 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.
#
from neutronclient.neutron import v2_0 as cmd_base
class ListExt(cmd_base.ListCommand):
"""List all extensions."""
resource = 'extension'
list_columns = ['alias', 'name']
class ShowExt(cmd_base.ShowCommand):
"""Show information of a given resource."""
resource = "extension"
allow_names = False

View File

@ -1,165 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# 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 __future__ import print_function
import argparse
from neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
class ListFlavor(neutronV20.ListCommand):
"""List Neutron service flavors."""
resource = 'flavor'
list_columns = ['id', 'name', 'service_type', 'enabled']
pagination_support = True
sorting_support = True
class ShowFlavor(neutronV20.ShowCommand):
"""Show information about a given Neutron service flavor."""
resource = 'flavor'
class CreateFlavor(neutronV20.CreateCommand):
"""Create a Neutron service flavor."""
resource = 'flavor'
def add_known_arguments(self, parser):
parser.add_argument(
'name',
metavar='NAME',
help=_('Name for the flavor.'))
parser.add_argument(
'service_type',
metavar='SERVICE_TYPE',
help=_('Service type to which the flavor applies to: e.g. VPN. '
'(See service-provider-list for loaded examples.)'))
parser.add_argument(
'--description',
help=_('Description for the flavor.'))
utils.add_boolean_argument(
parser,
'--enabled',
default=argparse.SUPPRESS,
help=_('Sets enabled flag.'))
def args2body(self, parsed_args):
body = {}
neutronV20.update_dict(parsed_args, body,
['name', 'description', 'service_type',
'enabled'])
return {self.resource: body}
class DeleteFlavor(neutronV20.DeleteCommand):
"""Delete a given Neutron service flavor."""
resource = 'flavor'
class UpdateFlavor(neutronV20.UpdateCommand):
"""Update a Neutron service flavor."""
resource = 'flavor'
def add_known_arguments(self, parser):
parser.add_argument(
'--name',
help=_('Name for the flavor.'))
parser.add_argument(
'--description',
help=_('Description for the flavor.'))
utils.add_boolean_argument(
parser,
'--enabled',
default=argparse.SUPPRESS,
help=_('Sets enabled flag.'))
def args2body(self, parsed_args):
body = {}
neutronV20.update_dict(parsed_args, body,
['name', 'description', 'enabled'])
return {self.resource: body}
class AssociateFlavor(neutronV20.NeutronCommand):
"""Associate a Neutron service flavor with a flavor profile."""
resource = 'flavor'
def get_parser(self, prog_name):
parser = super(AssociateFlavor, self).get_parser(prog_name)
parser.add_argument(
'flavor',
metavar='FLAVOR',
help=_('ID or name of the flavor to associate.'))
parser.add_argument(
'flavor_profile',
metavar='FLAVOR_PROFILE',
help=_('ID of the flavor profile to be associated with the '
'flavor.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
flavor_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'flavor', parsed_args.flavor)
service_profile_id = neutronV20.find_resourceid_by_id(
neutron_client, 'service_profile', parsed_args.flavor_profile)
body = {'service_profile': {'id': service_profile_id}}
neutron_client.associate_flavor(flavor_id, body)
print((_('Associated flavor %(flavor)s with '
'flavor_profile %(profile)s') %
{'flavor': parsed_args.flavor,
'profile': parsed_args.flavor_profile}),
file=self.app.stdout)
class DisassociateFlavor(neutronV20.NeutronCommand):
"""Disassociate a Neutron service flavor from a flavor profile."""
resource = 'flavor'
def get_parser(self, prog_name):
parser = super(DisassociateFlavor, self).get_parser(prog_name)
parser.add_argument(
'flavor',
metavar='FLAVOR',
help=_('ID or name of the flavor to be disassociated.'))
parser.add_argument(
'flavor_profile',
metavar='FLAVOR_PROFILE',
help=_('ID of the flavor profile to be disassociated from the '
'flavor.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
flavor_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'flavor', parsed_args.flavor)
service_profile_id = neutronV20.find_resourceid_by_id(
neutron_client, 'service_profile', parsed_args.flavor_profile)
neutron_client.disassociate_flavor(flavor_id, service_profile_id)
print((_('Disassociated flavor %(flavor)s from '
'flavor_profile %(profile)s') %
{'flavor': parsed_args.flavor,
'profile': parsed_args.flavor_profile}),
file=self.app.stdout)

View File

@ -1,99 +0,0 @@
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# 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 argparse
from neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
class ListFlavorProfile(neutronV20.ListCommand):
"""List Neutron service flavor profiles."""
resource = 'service_profile'
list_columns = ['id', 'description', 'enabled', 'metainfo']
pagination_support = True
sorting_support = True
class ShowFlavorProfile(neutronV20.ShowCommand):
"""Show information about a given Neutron service flavor profile."""
resource = 'service_profile'
class CreateFlavorProfile(neutronV20.CreateCommand):
"""Create a Neutron service flavor profile."""
resource = 'service_profile'
def add_known_arguments(self, parser):
parser.add_argument(
'--description',
help=_('Description for the flavor profile.'))
parser.add_argument(
'--driver',
help=_('Python module path to driver.'))
parser.add_argument(
'--metainfo',
help=_('Metainfo for the flavor profile.'))
utils.add_boolean_argument(
parser,
'--enabled',
default=argparse.SUPPRESS,
help=_('Sets enabled flag.'))
def args2body(self, parsed_args):
body = {}
neutronV20.update_dict(parsed_args, body,
['description', 'driver', 'enabled',
'metainfo'])
return {self.resource: body}
class DeleteFlavorProfile(neutronV20.DeleteCommand):
"""Delete a given Neutron service flavor profile."""
resource = 'service_profile'
class UpdateFlavorProfile(neutronV20.UpdateCommand):
"""Update a given Neutron service flavor profile."""
resource = 'service_profile'
def add_known_arguments(self, parser):
parser.add_argument(
'--description',
help=_('Description for the flavor profile.'))
parser.add_argument(
'--driver',
help=_('Python module path to driver.'))
parser.add_argument(
'--metainfo',
help=_('Metainfo for the flavor profile.'))
utils.add_boolean_argument(
parser,
'--enabled',
default=argparse.SUPPRESS,
help=_('Sets enabled flag.'))
def args2body(self, parsed_args):
body = {}
neutronV20.update_dict(parsed_args, body,
['description', 'driver', 'enabled',
'metainfo'])
return {self.resource: body}

View File

@ -1,150 +0,0 @@
# Copyright 2012 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.
#
from __future__ import print_function
import argparse
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.neutron.v2_0 import dns
class ListFloatingIP(neutronV20.ListCommand):
"""List floating IPs that belong to a given tenant."""
resource = 'floatingip'
list_columns = ['id', 'fixed_ip_address', 'floating_ip_address',
'port_id']
pagination_support = True
sorting_support = True
class ShowFloatingIP(neutronV20.ShowCommand):
"""Show information of a given floating IP."""
resource = 'floatingip'
allow_names = False
class CreateFloatingIP(neutronV20.CreateCommand):
"""Create a floating IP for a given tenant."""
resource = 'floatingip'
def add_known_arguments(self, parser):
parser.add_argument(
'floating_network_id', metavar='FLOATING_NETWORK',
help=_('ID or name of the network from which '
'the floating IP is allocated.'))
parser.add_argument(
'--description',
help=_('Description of the floating IP.'))
parser.add_argument(
'--port-id',
help=_('ID of the port to be associated with the floating IP.'))
parser.add_argument(
'--port_id',
help=argparse.SUPPRESS)
parser.add_argument(
'--fixed-ip-address',
help=_('IP address on the port (only required if port has '
'multiple IPs).'))
parser.add_argument(
'--fixed_ip_address',
help=argparse.SUPPRESS)
parser.add_argument(
'--floating-ip-address',
help=_('IP address of the floating IP'))
parser.add_argument(
'--subnet',
dest='subnet_id',
help=_('Subnet ID on which you want to create the floating IP.'))
dns.add_dns_argument_create(parser, self.resource, 'domain')
dns.add_dns_argument_create(parser, self.resource, 'name')
def args2body(self, parsed_args):
_network_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'network', parsed_args.floating_network_id)
body = {'floating_network_id': _network_id}
neutronV20.update_dict(parsed_args, body,
['port_id', 'tenant_id',
'fixed_ip_address', 'description',
'floating_ip_address', 'subnet_id'])
dns.args2body_dns_create(parsed_args, body, 'domain')
dns.args2body_dns_create(parsed_args, body, 'name')
return {self.resource: body}
class DeleteFloatingIP(neutronV20.DeleteCommand):
"""Delete a given floating IP."""
resource = 'floatingip'
allow_names = False
class AssociateFloatingIP(neutronV20.NeutronCommand):
"""Create a mapping between a floating IP and a fixed IP."""
resource = 'floatingip'
def get_parser(self, prog_name):
parser = super(AssociateFloatingIP, self).get_parser(prog_name)
parser.add_argument(
'floatingip_id', metavar='FLOATINGIP_ID',
help=_('ID of the floating IP to associate.'))
parser.add_argument(
'port_id', metavar='PORT',
help=_('ID or name of the port to be associated with the '
'floating IP.'))
parser.add_argument(
'--fixed-ip-address',
help=_('IP address on the port (only required if port has '
'multiple IPs).'))
parser.add_argument(
'--fixed_ip_address',
help=argparse.SUPPRESS)
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
update_dict = {}
neutronV20.update_dict(parsed_args, update_dict,
['port_id', 'fixed_ip_address'])
neutron_client.update_floatingip(parsed_args.floatingip_id,
{'floatingip': update_dict})
print(_('Associated floating IP %s') % parsed_args.floatingip_id,
file=self.app.stdout)
class DisassociateFloatingIP(neutronV20.NeutronCommand):
"""Remove a mapping from a floating IP to a fixed IP."""
resource = 'floatingip'
def get_parser(self, prog_name):
parser = super(DisassociateFloatingIP, self).get_parser(prog_name)
parser.add_argument(
'floatingip_id', metavar='FLOATINGIP_ID',
help=_('ID of the floating IP to disassociate.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
neutron_client.update_floatingip(parsed_args.floatingip_id,
{'floatingip': {'port_id': None}})
print(_('Disassociated floating IP %s') % parsed_args.floatingip_id,
file=self.app.stdout)

View File

@ -1,128 +0,0 @@
# Copyright 2013 Big Switch Networks
# 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 neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronv20
def add_common_args(parser):
parser.add_argument(
'--name',
help=_('Name for the firewall.'))
parser.add_argument(
'--description',
help=_('Description for the firewall.'))
router = parser.add_mutually_exclusive_group()
router.add_argument(
'--router',
dest='routers',
metavar='ROUTER',
action='append',
help=_('ID or name of the router associated with the firewall '
'(requires FWaaS router insertion extension to be enabled). '
'This option can be repeated.'))
router.add_argument(
'--no-routers',
action='store_true',
help=_('Associate no routers with the firewall (requires FWaaS '
'router insertion extension).'))
def parse_common_args(client, parsed_args):
body = {}
if parsed_args.policy:
body['firewall_policy_id'] = neutronv20.find_resourceid_by_name_or_id(
client, 'firewall_policy',
parsed_args.policy)
if parsed_args.routers:
body['router_ids'] = [
neutronv20.find_resourceid_by_name_or_id(client, 'router', r)
for r in parsed_args.routers]
elif parsed_args.no_routers:
body['router_ids'] = []
neutronv20.update_dict(parsed_args, body,
['name', 'description'])
return body
class ListFirewall(neutronv20.ListCommand):
"""List firewalls that belong to a given tenant."""
resource = 'firewall'
list_columns = ['id', 'name', 'firewall_policy_id']
_formatters = {}
pagination_support = True
sorting_support = True
class ShowFirewall(neutronv20.ShowCommand):
"""Show information of a given firewall."""
resource = 'firewall'
class CreateFirewall(neutronv20.CreateCommand):
"""Create a firewall."""
resource = 'firewall'
def add_known_arguments(self, parser):
add_common_args(parser)
parser.add_argument(
'policy', metavar='POLICY',
help=_('ID or name of the firewall policy '
'associated to this firewall.'))
parser.add_argument(
'--admin-state-down',
dest='admin_state',
action='store_false',
help=_('Set admin state up to false.'))
def args2body(self, parsed_args):
body = parse_common_args(self.get_client(), parsed_args)
neutronv20.update_dict(parsed_args, body, ['tenant_id'])
body['admin_state_up'] = parsed_args.admin_state
return {self.resource: body}
class UpdateFirewall(neutronv20.UpdateCommand):
"""Update a given firewall."""
resource = 'firewall'
def add_known_arguments(self, parser):
add_common_args(parser)
parser.add_argument(
'--policy', metavar='POLICY',
help=_('ID or name of the firewall policy '
'associated to this firewall.'))
utils.add_boolean_argument(
parser, '--admin-state-up', dest='admin_state_up',
help=_('Update the admin state for the firewall '
'(True means UP).'))
def args2body(self, parsed_args):
body = parse_common_args(self.get_client(), parsed_args)
neutronv20.update_dict(parsed_args, body, ['admin_state_up'])
return {self.resource: body}
class DeleteFirewall(neutronv20.DeleteCommand):
"""Delete a given firewall."""
resource = 'firewall'

View File

@ -1,229 +0,0 @@
# Copyright 2013 Big Switch Networks
# 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 __future__ import print_function
import argparse
from neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronv20
def _format_firewall_rules(firewall_policy):
try:
output = '[' + ',\n '.join([rule for rule in
firewall_policy['firewall_rules']]) + ']'
return output
except (TypeError, KeyError):
return ''
def add_common_args(parser):
parser.add_argument(
'--description',
help=_('Description for the firewall policy.'))
parser.add_argument(
'--firewall-rules', type=lambda x: x.split(),
help=_('Ordered list of whitespace-delimited firewall rule '
'names or IDs; e.g., --firewall-rules \"rule1 rule2\"'))
def parse_common_args(client, parsed_args):
if parsed_args.firewall_rules:
_firewall_rules = []
for f in parsed_args.firewall_rules:
_firewall_rules.append(
neutronv20.find_resourceid_by_name_or_id(
client, 'firewall_rule', f))
body = {'firewall_rules': _firewall_rules}
else:
body = {}
neutronv20.update_dict(parsed_args, body,
['name', 'description', 'shared',
'audited', 'tenant_id'])
return {'firewall_policy': body}
class ListFirewallPolicy(neutronv20.ListCommand):
"""List firewall policies that belong to a given tenant."""
resource = 'firewall_policy'
list_columns = ['id', 'name', 'firewall_rules']
_formatters = {'firewall_rules': _format_firewall_rules,
}
pagination_support = True
sorting_support = True
class ShowFirewallPolicy(neutronv20.ShowCommand):
"""Show information of a given firewall policy."""
resource = 'firewall_policy'
class CreateFirewallPolicy(neutronv20.CreateCommand):
"""Create a firewall policy."""
resource = 'firewall_policy'
def add_known_arguments(self, parser):
parser.add_argument(
'name',
metavar='NAME',
help=_('Name for the firewall policy.'))
parser.add_argument(
'--shared',
action='store_true',
help=_('Create a shared policy.'),
default=argparse.SUPPRESS)
parser.add_argument(
'--audited',
action='store_true',
help=_('Sets audited to True.'),
default=argparse.SUPPRESS)
add_common_args(parser)
def args2body(self, parsed_args):
return parse_common_args(self.get_client(), parsed_args)
class UpdateFirewallPolicy(neutronv20.UpdateCommand):
"""Update a given firewall policy."""
resource = 'firewall_policy'
def add_known_arguments(self, parser):
add_common_args(parser)
parser.add_argument(
'--name',
help=_('Name for the firewall policy.'))
utils.add_boolean_argument(
parser, '--shared',
help=_('Update the sharing status of the policy. '
'(True means shared).'))
utils.add_boolean_argument(
parser, '--audited',
help=_('Update the audit status of the policy. '
'(True means auditing is enabled).'))
def args2body(self, parsed_args):
return parse_common_args(self.get_client(), parsed_args)
class DeleteFirewallPolicy(neutronv20.DeleteCommand):
"""Delete a given firewall policy."""
resource = 'firewall_policy'
class FirewallPolicyInsertRule(neutronv20.UpdateCommand):
"""Insert a rule into a given firewall policy."""
resource = 'firewall_policy'
def call_api(self, neutron_client, firewall_policy_id, body):
return neutron_client.firewall_policy_insert_rule(firewall_policy_id,
body)
def args2body(self, parsed_args):
_rule = ''
if parsed_args.firewall_rule_id:
_rule = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'firewall_rule',
parsed_args.firewall_rule_id)
_insert_before = ''
if 'insert_before' in parsed_args:
if parsed_args.insert_before:
_insert_before = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'firewall_rule',
parsed_args.insert_before)
_insert_after = ''
if 'insert_after' in parsed_args:
if parsed_args.insert_after:
_insert_after = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'firewall_rule',
parsed_args.insert_after)
body = {'firewall_rule_id': _rule,
'insert_before': _insert_before,
'insert_after': _insert_after}
return body
def get_parser(self, prog_name):
parser = super(FirewallPolicyInsertRule, self).get_parser(prog_name)
parser.add_argument(
'--insert-before',
metavar='FIREWALL_RULE',
help=_('Insert before this rule.'))
parser.add_argument(
'--insert-after',
metavar='FIREWALL_RULE',
help=_('Insert after this rule.'))
parser.add_argument(
'firewall_rule_id',
metavar='FIREWALL_RULE',
help=_('New rule to insert.'))
self.add_known_arguments(parser)
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
body = self.args2body(parsed_args)
_id = neutronv20.find_resourceid_by_name_or_id(neutron_client,
self.resource,
parsed_args.id)
self.call_api(neutron_client, _id, body)
print((_('Inserted firewall rule in firewall policy %(id)s') %
{'id': parsed_args.id}), file=self.app.stdout)
class FirewallPolicyRemoveRule(neutronv20.UpdateCommand):
"""Remove a rule from a given firewall policy."""
resource = 'firewall_policy'
def call_api(self, neutron_client, firewall_policy_id, body):
return neutron_client.firewall_policy_remove_rule(firewall_policy_id,
body)
def args2body(self, parsed_args):
_rule = ''
if parsed_args.firewall_rule_id:
_rule = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'firewall_rule',
parsed_args.firewall_rule_id)
body = {'firewall_rule_id': _rule}
return body
def get_parser(self, prog_name):
parser = super(FirewallPolicyRemoveRule, self).get_parser(prog_name)
parser.add_argument(
'firewall_rule_id',
metavar='FIREWALL_RULE',
help=_('ID or name of the firewall rule to be removed '
'from the policy.'))
self.add_known_arguments(parser)
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
body = self.args2body(parsed_args)
_id = neutronv20.find_resourceid_by_name_or_id(neutron_client,
self.resource,
parsed_args.id)
self.call_api(neutron_client, _id, body)
print((_('Removed firewall rule from firewall policy %(id)s') %
{'id': parsed_args.id}), file=self.app.stdout)

View File

@ -1,168 +0,0 @@
# Copyright 2013 Big Switch Networks
# 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 argparse
from neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronv20
def _add_common_args(parser, is_create=True):
"""If is_create is True, protocol and action become mandatory arguments.
CreateCommand = is_create : True
UpdateCommand = is_create : False
"""
parser.add_argument(
'--name',
help=_('Name for the firewall rule.'))
parser.add_argument(
'--description',
help=_('Description for the firewall rule.'))
parser.add_argument(
'--source-ip-address',
help=_('Source IP address or subnet.'))
parser.add_argument(
'--destination-ip-address',
help=_('Destination IP address or subnet.'))
parser.add_argument(
'--source-port',
help=_('Source port (integer in [1, 65535] or range in a:b).'))
parser.add_argument(
'--destination-port',
help=_('Destination port (integer in [1, 65535] or range in '
'a:b).'))
utils.add_boolean_argument(
parser, '--enabled', dest='enabled',
help=_('Whether to enable or disable this rule.'))
parser.add_argument(
'--protocol', choices=['tcp', 'udp', 'icmp', 'any'],
required=is_create,
type=utils.convert_to_lowercase,
help=_('Protocol for the firewall rule.'))
parser.add_argument(
'--action',
required=is_create,
type=utils.convert_to_lowercase,
choices=['allow', 'deny', 'reject'],
help=_('Action for the firewall rule.'))
def common_args2body(parsed_args):
body = {}
neutronv20.update_dict(parsed_args, body,
['name', 'description', 'shared', 'tenant_id',
'source_ip_address', 'destination_ip_address',
'source_port', 'destination_port', 'action',
'enabled', 'ip_version'])
protocol = parsed_args.protocol
if protocol:
if protocol == 'any':
protocol = None
body['protocol'] = protocol
return body
class ListFirewallRule(neutronv20.ListCommand):
"""List firewall rules that belong to a given tenant."""
resource = 'firewall_rule'
list_columns = ['id', 'name', 'firewall_policy_id', 'summary', 'enabled']
pagination_support = True
sorting_support = True
def extend_list(self, data, parsed_args):
for d in data:
val = []
if d.get('protocol'):
protocol = d['protocol'].upper()
else:
protocol = 'no-protocol'
val.append(protocol)
if 'source_ip_address' in d and 'source_port' in d:
src = 'source: ' + str(d['source_ip_address']).lower()
src = src + '(' + str(d['source_port']).lower() + ')'
else:
src = 'source: none specified'
val.append(src)
if 'destination_ip_address' in d and 'destination_port' in d:
dst = 'dest: ' + str(d['destination_ip_address']).lower()
dst = dst + '(' + str(d['destination_port']).lower() + ')'
else:
dst = 'dest: none specified'
val.append(dst)
if 'action' in d:
action = d['action']
else:
action = 'no-action'
val.append(action)
d['summary'] = ',\n '.join(val)
class ShowFirewallRule(neutronv20.ShowCommand):
"""Show information of a given firewall rule."""
resource = 'firewall_rule'
class CreateFirewallRule(neutronv20.CreateCommand):
"""Create a firewall rule."""
resource = 'firewall_rule'
def add_known_arguments(self, parser):
parser.add_argument(
'--shared',
action='store_true',
help=_('Set shared flag for the firewall rule.'),
default=argparse.SUPPRESS)
_add_common_args(parser)
parser.add_argument(
'--ip-version',
type=int, choices=[4, 6], default=4,
help=_('IP version for the firewall rule (default is 4).'))
def args2body(self, parsed_args):
return {self.resource: common_args2body(parsed_args)}
class UpdateFirewallRule(neutronv20.UpdateCommand):
"""Update a given firewall rule."""
resource = 'firewall_rule'
def add_known_arguments(self, parser):
utils.add_boolean_argument(
parser,
'--shared',
dest='shared',
help=_('Update the shared flag for the firewall rule.'),
default=argparse.SUPPRESS)
parser.add_argument(
'--ip-version',
type=int, choices=[4, 6],
help=_('Update IP version for the firewall rule.'))
_add_common_args(parser, is_create=False)
def args2body(self, parsed_args):
return {self.resource: common_args2body(parsed_args)}
class DeleteFirewallRule(neutronv20.DeleteCommand):
"""Delete a given firewall rule."""
resource = 'firewall_rule'

View File

@ -1,163 +0,0 @@
# Copyright 2013 Mirantis Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from __future__ import print_function
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
class ListHealthMonitor(neutronV20.ListCommand):
"""List health monitors that belong to a given tenant."""
resource = 'health_monitor'
list_columns = ['id', 'type', 'admin_state_up']
pagination_support = True
sorting_support = True
class ShowHealthMonitor(neutronV20.ShowCommand):
"""Show information of a given health monitor."""
resource = 'health_monitor'
allow_names = False
class CreateHealthMonitor(neutronV20.CreateCommand):
"""Create a health monitor."""
resource = 'health_monitor'
def add_known_arguments(self, parser):
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--expected-codes',
help=_('The list of HTTP status codes expected in '
'response from the member to declare it healthy. This '
'attribute can contain one value, '
'or a list of values separated by comma, '
'or a range of values (e.g. "200-299"). If this attribute '
'is not specified, it defaults to "200".'))
parser.add_argument(
'--http-method',
help=_('The HTTP method used for requests by the monitor of type '
'HTTP.'))
parser.add_argument(
'--url-path',
help=_('The HTTP path used in the HTTP request used by the monitor'
' to test a member health. This must be a string '
'beginning with a / (forward slash).'))
parser.add_argument(
'--delay',
required=True,
help=_('The time in milliseconds between sending probes to '
'members.'))
parser.add_argument(
'--max-retries',
required=True,
help=_('Number of permissible connection failures before changing '
'the member status to INACTIVE. [1..10]'))
parser.add_argument(
'--timeout',
required=True,
help=_('Maximum number of milliseconds for a monitor to wait for '
'a connection to be established before it times out. The '
'value must be less than the delay value.'))
parser.add_argument(
'--type',
required=True, choices=['PING', 'TCP', 'HTTP', 'HTTPS'],
help=_('One of the predefined health monitor types.'))
def args2body(self, parsed_args):
body = {'admin_state_up': parsed_args.admin_state,
'delay': parsed_args.delay,
'max_retries': parsed_args.max_retries,
'timeout': parsed_args.timeout,
'type': parsed_args.type}
neutronV20.update_dict(parsed_args, body,
['expected_codes', 'http_method', 'url_path',
'tenant_id'])
return {self.resource: body}
class UpdateHealthMonitor(neutronV20.UpdateCommand):
"""Update a given health monitor."""
resource = 'health_monitor'
allow_names = False
class DeleteHealthMonitor(neutronV20.DeleteCommand):
"""Delete a given health monitor."""
resource = 'health_monitor'
allow_names = False
class AssociateHealthMonitor(neutronV20.NeutronCommand):
"""Create a mapping between a health monitor and a pool."""
resource = 'health_monitor'
def get_parser(self, prog_name):
parser = super(AssociateHealthMonitor, self).get_parser(prog_name)
parser.add_argument(
'health_monitor_id', metavar='HEALTH_MONITOR_ID',
help=_('Health monitor to associate.'))
parser.add_argument(
'pool_id', metavar='POOL',
help=_('ID of the pool to be associated with the health monitor.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
body = {'health_monitor': {'id': parsed_args.health_monitor_id}}
pool_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'pool', parsed_args.pool_id)
neutron_client.associate_health_monitor(pool_id, body)
print((_('Associated health monitor '
'%s') % parsed_args.health_monitor_id),
file=self.app.stdout)
class DisassociateHealthMonitor(neutronV20.NeutronCommand):
"""Remove a mapping from a health monitor to a pool."""
resource = 'health_monitor'
def get_parser(self, prog_name):
parser = super(DisassociateHealthMonitor, self).get_parser(prog_name)
parser.add_argument(
'health_monitor_id', metavar='HEALTH_MONITOR_ID',
help=_('Health monitor to associate.'))
parser.add_argument(
'pool_id', metavar='POOL',
help=_('ID of the pool to be associated with the health monitor.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
pool_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'pool', parsed_args.pool_id)
neutron_client.disassociate_health_monitor(pool_id,
parsed_args
.health_monitor_id)
print((_('Disassociated health monitor '
'%s') % parsed_args.health_monitor_id),
file=self.app.stdout)

View File

@ -1,87 +0,0 @@
# Copyright 2013 Mirantis Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
class ListMember(neutronV20.ListCommand):
"""List members that belong to a given tenant."""
resource = 'member'
list_columns = [
'id', 'address', 'protocol_port', 'weight', 'admin_state_up', 'status'
]
pagination_support = True
sorting_support = True
class ShowMember(neutronV20.ShowCommand):
"""Show information of a given member."""
resource = 'member'
allow_names = False
class CreateMember(neutronV20.CreateCommand):
"""Create a member."""
resource = 'member'
def add_known_arguments(self, parser):
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--weight',
help=_('Weight of pool member in the pool (default:1, [0..256]).'))
parser.add_argument(
'--address',
required=True,
help=_('IP address of the pool member on the pool network.'))
parser.add_argument(
'--protocol-port',
required=True,
help=_('Port on which the pool member listens for requests or '
'connections.'))
parser.add_argument(
'pool_id', metavar='POOL',
help=_('ID or name of the pool this vip belongs to.'))
def args2body(self, parsed_args):
_pool_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'pool', parsed_args.pool_id)
body = {'pool_id': _pool_id,
'admin_state_up': parsed_args.admin_state}
neutronV20.update_dict(
parsed_args,
body,
['address', 'protocol_port', 'weight', 'tenant_id']
)
return {self.resource: body}
class UpdateMember(neutronV20.UpdateCommand):
"""Update a given member."""
resource = 'member'
class DeleteMember(neutronV20.DeleteCommand):
"""Delete a given member."""
resource = 'member'

View File

@ -1,124 +0,0 @@
# Copyright 2013 Mirantis Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import six
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
def _format_provider(pool):
return pool.get('provider') or 'N/A'
class ListPool(neutronV20.ListCommand):
"""List pools that belong to a given tenant."""
resource = 'pool'
list_columns = ['id', 'name', 'provider', 'lb_method', 'protocol',
'admin_state_up', 'status']
_formatters = {'provider': _format_provider}
pagination_support = True
sorting_support = True
class ShowPool(neutronV20.ShowCommand):
"""Show information of a given pool."""
resource = 'pool'
class CreatePool(neutronV20.CreateCommand):
"""Create a pool."""
resource = 'pool'
def add_known_arguments(self, parser):
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--description',
help=_('Description of the pool.'))
parser.add_argument(
'--lb-method',
required=True,
choices=['ROUND_ROBIN', 'LEAST_CONNECTIONS', 'SOURCE_IP'],
help=_('The algorithm used to distribute load between the members '
'of the pool.'))
parser.add_argument(
'--name',
required=True,
help=_('The name of the pool.'))
parser.add_argument(
'--protocol',
required=True,
choices=['HTTP', 'HTTPS', 'TCP'],
help=_('Protocol for balancing.'))
parser.add_argument(
'--subnet-id', metavar='SUBNET',
required=True,
help=_('The subnet on which the members of the pool will be '
'located.'))
parser.add_argument(
'--provider',
help=_('Provider name of the loadbalancer service.'))
def args2body(self, parsed_args):
_subnet_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'subnet', parsed_args.subnet_id)
body = {'admin_state_up': parsed_args.admin_state,
'subnet_id': _subnet_id}
neutronV20.update_dict(parsed_args, body,
['description', 'lb_method', 'name',
'protocol', 'tenant_id', 'provider'])
return {self.resource: body}
class UpdatePool(neutronV20.UpdateCommand):
"""Update a given pool."""
resource = 'pool'
class DeletePool(neutronV20.DeleteCommand):
"""Delete a given pool."""
resource = 'pool'
class RetrievePoolStats(neutronV20.ShowCommand):
"""Retrieve stats for a given pool."""
resource = 'pool'
def take_action(self, parsed_args):
neutron_client = self.get_client()
pool_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'pool', parsed_args.id)
params = {}
if parsed_args.fields:
params = {'fields': parsed_args.fields}
data = neutron_client.retrieve_pool_stats(pool_id, **params)
self.format_output_data(data)
stats = data['stats']
if 'stats' in data:
return zip(*sorted(six.iteritems(stats)))
else:
return None

View File

@ -1,143 +0,0 @@
# Copyright 2013 Mirantis Inc.
# Copyright 2014 Blue Box Group, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
def _add_common_args(parser, is_create=True):
parser.add_argument(
'--delay',
required=is_create,
help=_('The time in seconds between sending probes to members.'))
parser.add_argument(
'--name',
help=_('Name of the health monitor.'))
parser.add_argument(
'--timeout',
required=is_create,
help=_('Maximum number of seconds for a monitor to wait for a '
'connection to be established before it times out. The '
'value must be less than the delay value.'))
parser.add_argument(
'--http-method',
type=utils.convert_to_uppercase,
help=_('The HTTP method used for requests by the monitor of type '
'HTTP.'))
parser.add_argument(
'--url-path',
help=_('The HTTP path used in the HTTP request used by the monitor '
'to test a member health. This must be a string '
'beginning with a / (forward slash).'))
parser.add_argument(
'--max-retries',
required=is_create,
help=_('Number of permissible connection failures before changing '
'the member status to INACTIVE. [1..10].'))
parser.add_argument(
'--expected-codes',
help=_('The list of HTTP status codes expected in '
'response from the member to declare it healthy. This '
'attribute can contain one value, '
'or a list of values separated by comma, '
'or a range of values (e.g. "200-299"). If this attribute '
'is not specified, it defaults to "200".'))
def _parse_common_args(body, parsed_args):
neutronV20.update_dict(parsed_args, body,
['expected_codes', 'http_method', 'url_path',
'timeout', 'name', 'delay', 'max_retries'])
class ListHealthMonitor(neutronV20.ListCommand):
"""LBaaS v2 List healthmonitors that belong to a given tenant."""
resource = 'healthmonitor'
shadow_resource = 'lbaas_healthmonitor'
list_columns = ['id', 'name', 'type', 'admin_state_up']
pagination_support = True
sorting_support = True
class ShowHealthMonitor(neutronV20.ShowCommand):
"""LBaaS v2 Show information of a given healthmonitor."""
resource = 'healthmonitor'
shadow_resource = 'lbaas_healthmonitor'
class CreateHealthMonitor(neutronV20.CreateCommand):
"""LBaaS v2 Create a healthmonitor."""
resource = 'healthmonitor'
shadow_resource = 'lbaas_healthmonitor'
def add_known_arguments(self, parser):
_add_common_args(parser)
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--type',
required=True, choices=['PING', 'TCP', 'HTTP', 'HTTPS'],
help=_('One of the predefined health monitor types.'))
parser.add_argument(
'--pool', required=True,
help=_('ID or name of the pool that this healthmonitor will '
'monitor.'))
def args2body(self, parsed_args):
pool_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'pool', parsed_args.pool,
cmd_resource='lbaas_pool')
body = {'admin_state_up': parsed_args.admin_state,
'type': parsed_args.type,
'pool_id': pool_id}
neutronV20.update_dict(parsed_args, body,
['tenant_id'])
_parse_common_args(body, parsed_args)
return {self.resource: body}
class UpdateHealthMonitor(neutronV20.UpdateCommand):
"""LBaaS v2 Update a given healthmonitor."""
resource = 'healthmonitor'
shadow_resource = 'lbaas_healthmonitor'
def add_known_arguments(self, parser):
_add_common_args(parser, is_create=False)
utils.add_boolean_argument(
parser, '--admin-state-up',
help=_('Update the administrative state of '
'the health monitor (True meaning "Up").'))
def args2body(self, parsed_args):
body = {}
_parse_common_args(body, parsed_args)
neutronV20.update_dict(parsed_args, body,
['admin_state_up'])
return {self.resource: body}
class DeleteHealthMonitor(neutronV20.DeleteCommand):
"""LBaaS v2 Delete a given healthmonitor."""
resource = 'healthmonitor'
shadow_resource = 'lbaas_healthmonitor'

View File

@ -1,155 +0,0 @@
# Copyright 2016 Radware 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 neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
def _get_listener_id(client, listener_id_or_name):
return neutronV20.find_resourceid_by_name_or_id(
client, 'listener', listener_id_or_name)
def _get_pool_id(client, pool_id_or_name):
return neutronV20.find_resourceid_by_name_or_id(
client, 'pool', pool_id_or_name, cmd_resource='lbaas_pool')
def _add_common_args(parser, is_create=True):
parser.add_argument(
'--name',
help=_('Name of the policy.'))
parser.add_argument(
'--description',
help=_('Description of the policy.'))
parser.add_argument(
'--action',
required=is_create,
metavar='ACTION',
type=utils.convert_to_uppercase,
choices=['REJECT', 'REDIRECT_TO_POOL', 'REDIRECT_TO_URL'],
help=_('Action type of the policy.'))
parser.add_argument(
'--redirect-pool',
help=_('ID or name of the pool for REDIRECT_TO_POOL action type.'))
parser.add_argument(
'--redirect-url',
help=_('URL for REDIRECT_TO_URL action type. '
'This should be a valid URL string.'))
parser.add_argument(
'--position',
type=int,
help=_('L7 policy position in ordered policies list. '
'This must be an integer starting from 1. '
'Not specifying the position will place the policy '
'at the tail of existing policies list.'))
def _common_args2body(client, parsed_args, is_create=True):
if parsed_args.redirect_url:
if parsed_args.action != 'REDIRECT_TO_URL':
raise exceptions.CommandError(_('Action must be REDIRECT_TO_URL'))
if parsed_args.redirect_pool:
if parsed_args.action != 'REDIRECT_TO_POOL':
raise exceptions.CommandError(_('Action must be REDIRECT_TO_POOL'))
parsed_args.redirect_pool_id = _get_pool_id(
client, parsed_args.redirect_pool)
if (parsed_args.action == 'REDIRECT_TO_URL' and
not parsed_args.redirect_url):
raise exceptions.CommandError(_('Redirect URL must be specified'))
if (parsed_args.action == 'REDIRECT_TO_POOL' and
not parsed_args.redirect_pool):
raise exceptions.CommandError(_('Redirect pool must be specified'))
attributes = ['name', 'description',
'action', 'redirect_pool_id', 'redirect_url',
'position', 'admin_state_up']
if is_create:
parsed_args.listener_id = _get_listener_id(
client, parsed_args.listener)
attributes.extend(['listener_id', 'tenant_id'])
body = {}
neutronV20.update_dict(parsed_args, body, attributes)
return {'l7policy': body}
class ListL7Policy(neutronV20.ListCommand):
"""LBaaS v2 List L7 policies that belong to a given listener."""
resource = 'l7policy'
shadow_resource = 'lbaas_l7policy'
pagination_support = True
sorting_support = True
list_columns = [
'id', 'name', 'action', 'redirect_pool_id', 'redirect_url',
'position', 'admin_state_up', 'status'
]
class ShowL7Policy(neutronV20.ShowCommand):
"""LBaaS v2 Show information of a given L7 policy."""
resource = 'l7policy'
shadow_resource = 'lbaas_l7policy'
class CreateL7Policy(neutronV20.CreateCommand):
"""LBaaS v2 Create L7 policy."""
resource = 'l7policy'
shadow_resource = 'lbaas_l7policy'
def add_known_arguments(self, parser):
_add_common_args(parser)
parser.add_argument(
'--admin-state-down',
dest='admin_state_up',
action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--listener',
required=True,
metavar='LISTENER',
help=_('ID or name of the listener this policy belongs to.'))
def args2body(self, parsed_args):
return _common_args2body(self.get_client(), parsed_args)
class UpdateL7Policy(neutronV20.UpdateCommand):
"""LBaaS v2 Update a given L7 policy."""
resource = 'l7policy'
shadow_resource = 'lbaas_l7policy'
def add_known_arguments(self, parser):
_add_common_args(parser, is_create=False)
utils.add_boolean_argument(
parser, '--admin-state-up',
help=_('Specify the administrative state of the policy'
' (True meaning "Up").'))
def args2body(self, parsed_args):
return _common_args2body(self.get_client(), parsed_args, False)
class DeleteL7Policy(neutronV20.DeleteCommand):
"""LBaaS v2 Delete a given L7 policy."""
resource = 'l7policy'
shadow_resource = 'lbaas_l7policy'

View File

@ -1,148 +0,0 @@
# Copyright 2016 Radware 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 neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
def _get_policy_id(client, policy_id_or_name):
return neutronV20.find_resourceid_by_name_or_id(
client, 'l7policy', policy_id_or_name,
cmd_resource='lbaas_l7policy')
class LbaasL7RuleMixin(object):
def set_extra_attrs(self, parsed_args):
self.parent_id = _get_policy_id(self.get_client(),
parsed_args.l7policy)
def add_known_arguments(self, parser):
parser.add_argument(
'l7policy', metavar='L7POLICY',
help=_('ID or name of L7 policy this rule belongs to.'))
def _add_common_args(parser, is_create=True):
parser.add_argument(
'--type',
required=is_create,
type=utils.convert_to_uppercase,
choices=['HOST_NAME', 'PATH', 'FILE_TYPE', 'HEADER', 'COOKIE'],
help=_('Rule type.'))
parser.add_argument(
'--compare-type',
required=is_create,
type=utils.convert_to_uppercase,
choices=['REGEX', 'STARTS_WITH', 'ENDS_WITH',
'CONTAINS', 'EQUAL_TO'],
help=_('Rule compare type.'))
parser.add_argument(
'--invert-compare',
dest='invert',
action='store_true',
help=_('Invert the compare type.'))
parser.add_argument(
'--key',
help=_('Key to compare.'
' Relevant for HEADER and COOKIE types only.'))
parser.add_argument(
'--value',
required=is_create,
help=_('Value to compare.'))
def _common_args2body(client, parsed_args, is_create=True):
attributes = ['type', 'compare_type',
'invert', 'key', 'value', 'admin_state_up']
if is_create:
attributes.append('tenant_id')
body = {}
neutronV20.update_dict(parsed_args, body, attributes)
return {'rule': body}
class ListL7Rule(LbaasL7RuleMixin, neutronV20.ListCommand):
"""LBaaS v2 List L7 rules that belong to a given L7 policy."""
resource = 'rule'
shadow_resource = 'lbaas_l7rule'
pagination_support = True
sorting_support = True
list_columns = [
'id', 'type', 'compare_type', 'invert', 'key', 'value',
'admin_state_up', 'status'
]
def take_action(self, parsed_args):
self.parent_id = _get_policy_id(self.get_client(),
parsed_args.l7policy)
self.values_specs.append('--l7policy_id=%s' % self.parent_id)
return super(ListL7Rule, self).take_action(parsed_args)
class ShowL7Rule(LbaasL7RuleMixin, neutronV20.ShowCommand):
"""LBaaS v2 Show information of a given rule."""
resource = 'rule'
shadow_resource = 'lbaas_l7rule'
class CreateL7Rule(LbaasL7RuleMixin, neutronV20.CreateCommand):
"""LBaaS v2 Create L7 rule."""
resource = 'rule'
shadow_resource = 'lbaas_l7rule'
def add_known_arguments(self, parser):
super(CreateL7Rule, self).add_known_arguments(parser)
_add_common_args(parser)
parser.add_argument(
'--admin-state-down',
dest='admin_state_up',
action='store_false',
help=_('Set admin state up to false'))
def args2body(self, parsed_args):
return _common_args2body(self.get_client(), parsed_args)
class UpdateL7Rule(LbaasL7RuleMixin, neutronV20.UpdateCommand):
"""LBaaS v2 Update a given L7 rule."""
resource = 'rule'
shadow_resource = 'lbaas_l7rule'
def add_known_arguments(self, parser):
super(UpdateL7Rule, self).add_known_arguments(parser)
_add_common_args(parser, False)
utils.add_boolean_argument(
parser, '--admin-state-up',
help=_('Specify the administrative state of the rule'
' (True meaning "Up").'))
def args2body(self, parsed_args):
return _common_args2body(self.get_client(), parsed_args, False)
class DeleteL7Rule(LbaasL7RuleMixin, neutronV20.DeleteCommand):
"""LBaaS v2 Delete a given L7 rule."""
resource = 'rule'
shadow_resource = 'lbaas_l7rule'

View File

@ -1,168 +0,0 @@
# Copyright 2014 Blue Box Group, Inc.
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# 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 neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
def _get_loadbalancer_id(client, lb_id_or_name):
return neutronV20.find_resourceid_by_name_or_id(
client, 'loadbalancer', lb_id_or_name,
cmd_resource='lbaas_loadbalancer')
def _get_pool(client, pool_id_or_name):
return neutronV20.find_resource_by_name_or_id(
client, 'pool', pool_id_or_name, cmd_resource='lbaas_pool')
def _get_pool_id(client, pool_id_or_name):
return neutronV20.find_resourceid_by_name_or_id(
client, 'pool', pool_id_or_name, cmd_resource='lbaas_pool')
def _add_common_args(parser):
parser.add_argument(
'--description',
help=_('Description of the listener.'))
parser.add_argument(
'--connection-limit',
type=int,
help=_('The maximum number of connections per second allowed for '
'the vip. Positive integer or -1 for unlimited (default).'))
parser.add_argument(
'--default-pool',
help=_('Default pool for the listener.'))
def _parse_common_args(body, parsed_args, client):
neutronV20.update_dict(parsed_args, body,
['name', 'description', 'connection_limit'])
if parsed_args.default_pool:
default_pool_id = _get_pool_id(
client, parsed_args.default_pool)
body['default_pool_id'] = default_pool_id
class ListListener(neutronV20.ListCommand):
"""LBaaS v2 List listeners that belong to a given tenant."""
resource = 'listener'
list_columns = ['id', 'default_pool_id', 'name', 'protocol',
'protocol_port', 'admin_state_up', 'status']
pagination_support = True
sorting_support = True
class ShowListener(neutronV20.ShowCommand):
"""LBaaS v2 Show information of a given listener."""
resource = 'listener'
class CreateListener(neutronV20.CreateCommand):
"""LBaaS v2 Create a listener."""
resource = 'listener'
def add_known_arguments(self, parser):
_add_common_args(parser)
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--name',
help=_('The name of the listener. At least one of --default-pool '
'or --loadbalancer must be specified.'))
parser.add_argument(
'--default-tls-container-ref',
dest='default_tls_container_ref',
help=_('Default TLS container reference'
' to retrieve TLS information.'))
parser.add_argument(
'--sni-container-refs',
dest='sni_container_refs',
nargs='+',
help=_('List of TLS container references for SNI.'))
parser.add_argument(
'--loadbalancer',
metavar='LOADBALANCER',
help=_('ID or name of the load balancer.'))
parser.add_argument(
'--protocol',
required=True,
choices=['TCP', 'HTTP', 'HTTPS', 'TERMINATED_HTTPS'],
type=utils.convert_to_uppercase,
help=_('Protocol for the listener.'))
parser.add_argument(
'--protocol-port',
dest='protocol_port', required=True,
metavar='PORT',
help=_('Protocol port for the listener.'))
def args2body(self, parsed_args):
if not parsed_args.loadbalancer and not parsed_args.default_pool:
message = _('Either --default-pool or --loadbalancer must be '
'specified.')
raise exceptions.CommandError(message)
body = {
'protocol': parsed_args.protocol,
'protocol_port': parsed_args.protocol_port,
'admin_state_up': parsed_args.admin_state
}
if parsed_args.loadbalancer:
loadbalancer_id = _get_loadbalancer_id(
self.get_client(), parsed_args.loadbalancer)
body['loadbalancer_id'] = loadbalancer_id
neutronV20.update_dict(parsed_args, body,
['default_tls_container_ref',
'sni_container_refs', 'tenant_id'])
_parse_common_args(body, parsed_args, self.get_client())
return {self.resource: body}
class UpdateListener(neutronV20.UpdateCommand):
"""LBaaS v2 Update a given listener."""
resource = 'listener'
def add_known_arguments(self, parser):
_add_common_args(parser)
parser.add_argument(
'--name',
help=_('Name of the listener.'))
utils.add_boolean_argument(
parser, '--admin-state-up', dest='admin_state_up',
help=_('Specify the administrative state of the listener. '
'(True meaning "Up")'))
def args2body(self, parsed_args):
body = {}
neutronV20.update_dict(parsed_args, body,
['admin_state_up'])
_parse_common_args(body, parsed_args, self.get_client())
return {self.resource: body}
class DeleteListener(neutronV20.DeleteCommand):
"""LBaaS v2 Delete a given listener."""
resource = 'listener'

View File

@ -1,179 +0,0 @@
# Copyright 2014 Blue Box Group, Inc.
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# 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_serialization import jsonutils
from neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
def _add_common_args(parser):
parser.add_argument(
'--description',
help=_('Description of the load balancer.'))
parser.add_argument(
'--name', metavar='NAME',
help=_('Name of the load balancer.'))
def _parse_common_args(body, parsed_args):
neutronV20.update_dict(parsed_args, body,
['name', 'description'])
class ListLoadBalancer(neutronV20.ListCommand):
"""LBaaS v2 List loadbalancers that belong to a given tenant."""
resource = 'loadbalancer'
list_columns = ['id', 'name', 'vip_address',
'provisioning_status', 'provider']
pagination_support = True
sorting_support = True
class ShowLoadBalancer(neutronV20.ShowCommand):
"""LBaaS v2 Show information of a given loadbalancer."""
resource = 'loadbalancer'
class CreateLoadBalancer(neutronV20.CreateCommand):
"""LBaaS v2 Create a loadbalancer."""
resource = 'loadbalancer'
def add_known_arguments(self, parser):
_add_common_args(parser)
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--provider',
help=_('Provider name of the load balancer service.'))
parser.add_argument(
'--flavor',
help=_('ID or name of the flavor.'))
parser.add_argument(
'--vip-address',
help=_('VIP address for the load balancer.'))
parser.add_argument(
'vip_subnet', metavar='VIP_SUBNET',
help=_('Load balancer VIP subnet.'))
def args2body(self, parsed_args):
_subnet_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'subnet', parsed_args.vip_subnet)
body = {'vip_subnet_id': _subnet_id,
'admin_state_up': parsed_args.admin_state}
if parsed_args.flavor:
_flavor_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'flavor', parsed_args.flavor)
body['flavor_id'] = _flavor_id
neutronV20.update_dict(parsed_args, body,
['provider', 'vip_address', 'tenant_id'])
_parse_common_args(body, parsed_args)
return {self.resource: body}
class UpdateLoadBalancer(neutronV20.UpdateCommand):
"""LBaaS v2 Update a given loadbalancer."""
resource = 'loadbalancer'
def add_known_arguments(self, parser):
utils.add_boolean_argument(
parser, '--admin-state-up',
help=_('Update the administrative state of '
'the load balancer (True meaning "Up").'))
_add_common_args(parser)
def args2body(self, parsed_args):
body = {}
_parse_common_args(body, parsed_args)
neutronV20.update_dict(parsed_args, body,
['admin_state_up'])
return {self.resource: body}
class DeleteLoadBalancer(neutronV20.DeleteCommand):
"""LBaaS v2 Delete a given loadbalancer."""
resource = 'loadbalancer'
class RetrieveLoadBalancerStats(neutronV20.ShowCommand):
"""Retrieve stats for a given loadbalancer."""
resource = 'loadbalancer'
def take_action(self, parsed_args):
neutron_client = self.get_client()
neutron_client.format = parsed_args.request_format
loadbalancer_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'loadbalancer', parsed_args.id)
params = {}
if parsed_args.fields:
params = {'fields': parsed_args.fields}
data = neutron_client.retrieve_loadbalancer_stats(loadbalancer_id,
**params)
self.format_output_data(data)
stats = data['stats']
if 'stats' in data:
# To render the output table like:
# +--------------------+-------+
# | Field | Value |
# +--------------------+-------+
# | field1 | value1|
# | field2 | value2|
# | field3 | value3|
# | ... | ... |
# +--------------------+-------+
# it has two columns and the Filed column is alphabetical,
# here convert the data dict to the 1-1 vector format below:
# [(field1, field2, field3, ...), (value1, value2, value3, ...)]
return list(zip(*sorted(stats.items())))
class RetrieveLoadBalancerStatus(neutronV20.NeutronCommand):
"""Retrieve status for a given loadbalancer.
The only output is a formatted JSON tree, and the table format
does not support this type of data.
"""
resource = 'loadbalancer'
def get_parser(self, prog_name):
parser = super(RetrieveLoadBalancerStatus, self).get_parser(prog_name)
parser.add_argument(
self.resource, metavar=self.resource.upper(),
help=_('ID or name of %s to show.') % self.resource)
return parser
def take_action(self, parsed_args):
self.log.debug('run(%s)', parsed_args)
neutron_client = self.get_client()
lb_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, self.resource, parsed_args.loadbalancer)
params = {}
data = neutron_client.retrieve_loadbalancer_status(lb_id, **params)
res = data['statuses']
if 'statuses' in data:
print(jsonutils.dumps(res, indent=4))

View File

@ -1,160 +0,0 @@
# Copyright 2013 Mirantis Inc.
# Copyright 2014 Blue Box Group, Inc.
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# 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 argparse
from neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
def _get_pool_id(client, pool_id_or_name):
return neutronV20.find_resourceid_by_name_or_id(client, 'pool',
pool_id_or_name,
cmd_resource='lbaas_pool')
class LbaasMemberMixin(object):
def set_extra_attrs(self, parsed_args):
self.parent_id = _get_pool_id(self.get_client(), parsed_args.pool)
def add_known_arguments(self, parser):
parser.add_argument(
'pool', metavar='POOL',
help=_('ID or name of the pool that this member belongs to.'))
def _add_common_args(parser):
parser.add_argument(
'--name',
help=_('Name of the member.'))
parser.add_argument(
'--weight',
help=_('Weight of the member in the pool (default:1, [0..256]).'))
def _parse_common_args(body, parsed_args):
neutronV20.update_dict(parsed_args, body,
['weight', 'name'])
class ListMember(LbaasMemberMixin, neutronV20.ListCommand):
"""LBaaS v2 List members that belong to a given pool."""
resource = 'member'
shadow_resource = 'lbaas_member'
list_columns = [
'id', 'name', 'address', 'protocol_port', 'weight',
'subnet_id', 'admin_state_up', 'status'
]
pagination_support = True
sorting_support = True
def take_action(self, parsed_args):
self.parent_id = _get_pool_id(self.get_client(), parsed_args.pool)
self.values_specs.append('--pool_id=%s' % self.parent_id)
return super(ListMember, self).take_action(parsed_args)
class ShowMember(LbaasMemberMixin, neutronV20.ShowCommand):
"""LBaaS v2 Show information of a given member."""
resource = 'member'
shadow_resource = 'lbaas_member'
class CreateMember(neutronV20.CreateCommand):
"""LBaaS v2 Create a member."""
resource = 'member'
shadow_resource = 'lbaas_member'
def add_known_arguments(self, parser):
_add_common_args(parser)
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--subnet',
required=True,
help=_('Subnet ID or name for the member.'))
parser.add_argument(
'--address',
required=True,
help=_('IP address of the pool member in the pool.'))
parser.add_argument(
'--protocol-port',
required=True,
help=_('Port on which the pool member listens for requests or '
'connections.'))
parser.add_argument(
'pool', metavar='POOL',
help=_('ID or name of the pool that this member belongs to.'))
def args2body(self, parsed_args):
self.parent_id = _get_pool_id(self.get_client(), parsed_args.pool)
_subnet_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'subnet', parsed_args.subnet)
body = {'subnet_id': _subnet_id,
'admin_state_up': parsed_args.admin_state,
'protocol_port': parsed_args.protocol_port,
'address': parsed_args.address}
neutronV20.update_dict(parsed_args, body,
['subnet_id', 'tenant_id'])
_parse_common_args(body, parsed_args)
return {self.resource: body}
class UpdateMember(neutronV20.UpdateCommand):
"""LBaaS v2 Update a given member."""
resource = 'member'
shadow_resource = 'lbaas_member'
def add_known_arguments(self, parser):
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
default=argparse.SUPPRESS,
help=_('[DEPRECATED in Mitaka] Set admin state up to false.'))
parser.add_argument(
'pool', metavar='POOL',
help=_('ID or name of the pool that this member belongs to.'))
utils.add_boolean_argument(
parser, '--admin-state-up',
dest='admin_state',
help=_('Update the administrative state of '
'the member (True meaning "Up").'))
# ToDo(reedip): After Mitaka, remove admin-state-down
_add_common_args(parser)
def args2body(self, parsed_args):
self.parent_id = _get_pool_id(self.get_client(), parsed_args.pool)
body = {}
if hasattr(parsed_args, 'admin_state'):
body['admin_state_up'] = parsed_args.admin_state
_parse_common_args(body, parsed_args)
return {self.resource: body}
class DeleteMember(LbaasMemberMixin, neutronV20.DeleteCommand):
"""LBaaS v2 Delete a given member."""
resource = 'member'
shadow_resource = 'lbaas_member'

View File

@ -1,180 +0,0 @@
# Copyright 2013 Mirantis Inc.
# Copyright 2014 Blue Box Group, Inc.
# Copyright 2015 Hewlett-Packard Development Company, L.P.
# Copyright 2015 Blue Box, an IBM Company
# 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 neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
def _get_loadbalancer_id(client, lb_id_or_name):
return neutronV20.find_resourceid_by_name_or_id(
client, 'loadbalancer', lb_id_or_name,
cmd_resource='lbaas_loadbalancer')
def _get_listener(client, listener_id_or_name):
return neutronV20.find_resource_by_name_or_id(
client, 'listener', listener_id_or_name)
def _get_listener_id(client, listener_id_or_name):
return neutronV20.find_resourceid_by_name_or_id(
client, 'listener', listener_id_or_name)
def _add_common_args(parser):
parser.add_argument(
'--description',
help=_('Description of the pool.'))
parser.add_argument(
'--name', help=_('The name of the pool.'))
parser.add_argument(
'--lb-algorithm',
required=True,
type=utils.convert_to_uppercase,
choices=['ROUND_ROBIN', 'LEAST_CONNECTIONS', 'SOURCE_IP'],
help=_('The algorithm used to distribute load between the members '
'of the pool.'))
def _parse_common_args(parsed_args):
body = {}
neutronV20.update_dict(parsed_args,
body, ['description', 'lb_algorithm', 'name',
'session_persistence'])
return body
class ListPool(neutronV20.ListCommand):
"""LBaaS v2 List pools that belong to a given tenant."""
resource = 'pool'
shadow_resource = 'lbaas_pool'
list_columns = ['id', 'name', 'lb_method', 'protocol',
'admin_state_up']
pagination_support = True
sorting_support = True
class ShowPool(neutronV20.ShowCommand):
"""LBaaS v2 Show information of a given pool."""
resource = 'pool'
shadow_resource = 'lbaas_pool'
def cleanup_output_data(self, data):
if 'members' not in data['pool']:
return []
member_info = []
for member in data['pool']['members']:
member_info.append(member['id'])
data['pool']['members'] = member_info
class CreatePool(neutronV20.CreateCommand):
"""LBaaS v2 Create a pool."""
resource = 'pool'
shadow_resource = 'lbaas_pool'
def add_known_arguments(self, parser):
_add_common_args(parser)
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--listener',
help=_('Listener whose default-pool should be set to this pool. '
'At least one of --listener or --loadbalancer must be '
'specified.'))
parser.add_argument(
'--loadbalancer',
help=_('Loadbalancer with which this pool should be associated. '
'At least one of --listener or --loadbalancer must be '
'specified.'))
parser.add_argument(
'--protocol',
type=utils.convert_to_uppercase,
required=True,
choices=['HTTP', 'HTTPS', 'TCP'],
help=_('Protocol for balancing.'))
parser.add_argument(
'--session-persistence',
metavar='type=TYPE[,cookie_name=COOKIE_NAME]',
type=utils.str2dict_type(required_keys=['type'],
optional_keys=['cookie_name']),
help=_('The type of session persistence to use and associated '
'cookie name.'))
def args2body(self, parsed_args):
if not parsed_args.listener and not parsed_args.loadbalancer:
message = _('At least one of --listener or --loadbalancer must be '
'specified.')
raise exceptions.CommandError(message)
body = _parse_common_args(parsed_args)
if parsed_args.listener:
listener_id = _get_listener_id(
self.get_client(),
parsed_args.listener)
body['listener_id'] = listener_id
if parsed_args.loadbalancer:
loadbalancer_id = _get_loadbalancer_id(
self.get_client(),
parsed_args.loadbalancer)
body['loadbalancer_id'] = loadbalancer_id
body['admin_state_up'] = parsed_args.admin_state
neutronV20.update_dict(parsed_args, body,
['tenant_id', 'protocol'])
return {self.resource: body}
class UpdatePool(neutronV20.UpdateCommand):
"""LBaaS v2 Update a given pool."""
resource = 'pool'
shadow_resource = 'lbaas_pool'
def add_known_arguments(self, parser):
utils.add_boolean_argument(
parser, '--admin-state-up',
help=_('Update the administrative state of '
'the pool (True meaning "Up").'))
parser.add_argument(
'--session-persistence',
metavar='type=TYPE[,cookie_name=COOKIE_NAME]',
type=utils.str2dict_type(required_keys=['type'],
optional_keys=['cookie_name']),
help=_('The type of session persistence to use and associated '
'cookie name.'))
_add_common_args(parser)
def args2body(self, parsed_args):
body = _parse_common_args(parsed_args)
neutronV20.update_dict(parsed_args, body,
['admin_state_up'])
return {self.resource: body}
class DeletePool(neutronV20.DeleteCommand):
"""LBaaS v2 Delete a given pool."""
resource = 'pool'
shadow_resource = 'lbaas_pool'

View File

@ -1,104 +0,0 @@
# Copyright 2013 Mirantis Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
class ListVip(neutronV20.ListCommand):
"""List vips that belong to a given tenant."""
resource = 'vip'
list_columns = ['id', 'name', 'algorithm', 'address', 'protocol',
'admin_state_up', 'status']
pagination_support = True
sorting_support = True
class ShowVip(neutronV20.ShowCommand):
"""Show information of a given vip."""
resource = 'vip'
class CreateVip(neutronV20.CreateCommand):
"""Create a vip."""
resource = 'vip'
def add_known_arguments(self, parser):
parser.add_argument(
'pool_id', metavar='POOL',
help=_('ID or name of the pool to which this vip belongs.'))
parser.add_argument(
'--address',
help=_('IP address of the vip.'))
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--connection-limit',
help=_('The maximum number of connections per second allowed for '
'the vip. Valid values: a positive integer or -1 '
'for unlimited (default).'))
parser.add_argument(
'--description',
help=_('Description of the vip to be created.'))
parser.add_argument(
'--name',
required=True,
help=_('Name of the vip to be created.'))
parser.add_argument(
'--protocol-port',
required=True,
help=_('TCP port on which to listen for client traffic that is '
'associated with the vip address.'))
parser.add_argument(
'--protocol',
required=True, choices=['TCP', 'HTTP', 'HTTPS'],
help=_('Protocol for balancing.'))
parser.add_argument(
'--subnet-id', metavar='SUBNET',
required=True,
help=_('The subnet on which to allocate the vip address.'))
def args2body(self, parsed_args):
_pool_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'pool', parsed_args.pool_id)
_subnet_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'subnet', parsed_args.subnet_id)
body = {'pool_id': _pool_id,
'admin_state_up': parsed_args.admin_state,
'subnet_id': _subnet_id}
neutronV20.update_dict(parsed_args, body,
['address', 'connection_limit', 'description',
'name', 'protocol_port', 'protocol',
'tenant_id'])
return {self.resource: body}
class UpdateVip(neutronV20.UpdateCommand):
"""Update a given vip."""
resource = 'vip'
class DeleteVip(neutronV20.DeleteCommand):
"""Delete a given vip."""
resource = 'vip'

View File

@ -1,117 +0,0 @@
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# 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 neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronv20
class ListMeteringLabel(neutronv20.ListCommand):
"""List metering labels that belong to a given tenant."""
resource = 'metering_label'
list_columns = ['id', 'name', 'description', 'shared']
pagination_support = True
sorting_support = True
class ShowMeteringLabel(neutronv20.ShowCommand):
"""Show information of a given metering label."""
resource = 'metering_label'
allow_names = True
class CreateMeteringLabel(neutronv20.CreateCommand):
"""Create a metering label for a given tenant."""
resource = 'metering_label'
def add_known_arguments(self, parser):
parser.add_argument(
'name', metavar='NAME',
help=_('Name of the metering label to be created.'))
parser.add_argument(
'--description',
help=_('Description of the metering label to be created.'))
parser.add_argument(
'--shared',
action='store_true',
help=_('Set the label as shared.'))
def args2body(self, parsed_args):
body = {'name': parsed_args.name}
neutronv20.update_dict(parsed_args, body,
['tenant_id', 'description', 'shared'])
return {'metering_label': body}
class DeleteMeteringLabel(neutronv20.DeleteCommand):
"""Delete a given metering label."""
resource = 'metering_label'
allow_names = True
class ListMeteringLabelRule(neutronv20.ListCommand):
"""List metering labels that belong to a given label."""
resource = 'metering_label_rule'
list_columns = ['id', 'excluded', 'direction', 'remote_ip_prefix']
pagination_support = True
sorting_support = True
class ShowMeteringLabelRule(neutronv20.ShowCommand):
"""Show information of a given metering label rule."""
resource = 'metering_label_rule'
class CreateMeteringLabelRule(neutronv20.CreateCommand):
"""Create a metering label rule for a given label."""
resource = 'metering_label_rule'
def add_known_arguments(self, parser):
parser.add_argument(
'label_id', metavar='LABEL',
help=_('ID or name of the label.'))
parser.add_argument(
'remote_ip_prefix', metavar='REMOTE_IP_PREFIX',
help=_('CIDR to match on.'))
parser.add_argument(
'--direction',
default='ingress', choices=['ingress', 'egress'],
help=_('Direction of traffic, default: ingress.'))
parser.add_argument(
'--excluded',
action='store_true',
help=_('Exclude this CIDR from the label, default: not excluded.'))
def args2body(self, parsed_args):
neutron_client = self.get_client()
label_id = neutronv20.find_resourceid_by_name_or_id(
neutron_client, 'metering_label', parsed_args.label_id)
body = {'metering_label_id': label_id,
'remote_ip_prefix': parsed_args.remote_ip_prefix}
neutronv20.update_dict(parsed_args, body,
['direction', 'excluded'])
return {'metering_label_rule': body}
class DeleteMeteringLabelRule(neutronv20.DeleteCommand):
"""Delete a given metering label."""
resource = 'metering_label_rule'

View File

@ -1,232 +0,0 @@
# Copyright 2012 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.
#
import argparse
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.neutron.v2_0 import availability_zone
from neutronclient.neutron.v2_0 import dns
from neutronclient.neutron.v2_0.qos import policy as qos_policy
def _format_subnets(network):
try:
return '\n'.join([' '.join([s['id'], s.get('cidr', '')])
for s in network['subnets']])
except (TypeError, KeyError):
return ''
class ListNetwork(neutronV20.ListCommand):
"""List networks that belong to a given tenant."""
# Length of a query filter on subnet id
# id=<uuid>& (with len(uuid)=36)
subnet_id_filter_len = 40
resource = 'network'
_formatters = {'subnets': _format_subnets, }
list_columns = ['id', 'name', 'subnets']
pagination_support = True
sorting_support = True
filter_attrs = [
'tenant_id',
'name',
'admin_state_up',
{'name': 'status',
'help': _("Filter %s according to their operation status."
"(For example: ACTIVE, ERROR etc)"),
'boolean': False,
'argparse_kwargs': {'type': utils.convert_to_uppercase}},
{'name': 'shared',
'help': _('Filter and list the networks which are shared.'),
'boolean': True},
{'name': 'router:external',
'help': _('Filter and list the networks which are external.'),
'boolean': True},
{'name': 'tags',
'help': _("Filter and list %s which has all given tags. "
"Multiple tags can be set like --tags <tag[,tag...]>"),
'boolean': False,
'argparse_kwargs': {'metavar': 'TAG'}},
{'name': 'tags_any',
'help': _("Filter and list %s which has any given tags. "
"Multiple tags can be set like --tags-any <tag[,tag...]>"),
'boolean': False,
'argparse_kwargs': {'metavar': 'TAG'}},
{'name': 'not_tags',
'help': _("Filter and list %s which does not have all given tags. "
"Multiple tags can be set like --not-tags <tag[,tag...]>"),
'boolean': False,
'argparse_kwargs': {'metavar': 'TAG'}},
{'name': 'not_tags_any',
'help': _("Filter and list %s which does not have any given tags. "
"Multiple tags can be set like --not-tags-any "
"<tag[,tag...]>"),
'boolean': False,
'argparse_kwargs': {'metavar': 'TAG'}},
]
def extend_list(self, data, parsed_args):
"""Add subnet information to a network list."""
neutron_client = self.get_client()
search_opts = {'fields': ['id', 'cidr']}
if self.pagination_support:
page_size = parsed_args.page_size
if page_size:
search_opts.update({'limit': page_size})
subnet_ids = []
for n in data:
if 'subnets' in n:
subnet_ids.extend(n['subnets'])
def _get_subnet_list(sub_ids):
search_opts['id'] = sub_ids
return neutron_client.list_subnets(
**search_opts).get('subnets', [])
try:
subnets = _get_subnet_list(subnet_ids)
except exceptions.RequestURITooLong as uri_len_exc:
# The URI is too long because of too many subnet_id filters
# Use the excess attribute of the exception to know how many
# subnet_id filters can be inserted into a single request
subnet_count = len(subnet_ids)
max_size = ((self.subnet_id_filter_len * subnet_count) -
uri_len_exc.excess)
chunk_size = max_size // self.subnet_id_filter_len
subnets = []
for i in range(0, subnet_count, chunk_size):
subnets.extend(
_get_subnet_list(subnet_ids[i: i + chunk_size]))
subnet_dict = dict([(s['id'], s) for s in subnets])
for n in data:
if 'subnets' in n:
n['subnets'] = [(subnet_dict.get(s) or {"id": s})
for s in n['subnets']]
class ListExternalNetwork(ListNetwork):
"""List external networks that belong to a given tenant."""
pagination_support = True
sorting_support = True
def retrieve_list(self, parsed_args):
external = '--router:external=True'
if external not in self.values_specs:
self.values_specs.append('--router:external=True')
return super(ListExternalNetwork, self).retrieve_list(parsed_args)
class ShowNetwork(neutronV20.ShowCommand):
"""Show information of a given network."""
resource = 'network'
class CreateNetwork(neutronV20.CreateCommand, qos_policy.CreateQosPolicyMixin):
"""Create a network for a given tenant."""
resource = 'network'
def add_known_arguments(self, parser):
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--admin_state_down',
dest='admin_state', action='store_false',
help=argparse.SUPPRESS)
parser.add_argument(
'--shared',
action='store_true',
help=_('Set the network as shared.'),
default=argparse.SUPPRESS)
parser.add_argument(
'--provider:network_type',
metavar='<network_type>',
help=_('The physical mechanism by which the virtual network'
' is implemented.'))
parser.add_argument(
'--provider:physical_network',
metavar='<physical_network_name>',
help=_('Name of the physical network over which the virtual '
'network is implemented.'))
parser.add_argument(
'--provider:segmentation_id',
metavar='<segmentation_id>',
help=_('VLAN ID for VLAN networks or tunnel-id for GRE/VXLAN '
'networks.'))
utils.add_boolean_argument(
parser,
'--vlan-transparent',
default=argparse.SUPPRESS,
help=_('Create a VLAN transparent network.'))
parser.add_argument(
'name', metavar='NAME',
help=_('Name of the network to be created.'))
parser.add_argument(
'--description',
help=_('Description of network.'))
self.add_arguments_qos_policy(parser)
availability_zone.add_az_hint_argument(parser, self.resource)
dns.add_dns_argument_create(parser, self.resource, 'domain')
def args2body(self, parsed_args):
body = {'name': parsed_args.name,
'admin_state_up': parsed_args.admin_state}
neutronV20.update_dict(parsed_args, body,
['shared', 'tenant_id',
'vlan_transparent',
'provider:network_type',
'provider:physical_network',
'provider:segmentation_id',
'description'])
self.args2body_qos_policy(parsed_args, body)
availability_zone.args2body_az_hint(parsed_args, body)
dns.args2body_dns_create(parsed_args, body, 'domain')
return {'network': body}
class DeleteNetwork(neutronV20.DeleteCommand):
"""Delete a given network."""
resource = 'network'
class UpdateNetwork(neutronV20.UpdateCommand, qos_policy.UpdateQosPolicyMixin):
"""Update network's information."""
resource = 'network'
def add_known_arguments(self, parser):
self.add_arguments_qos_policy(parser)
dns.add_dns_argument_update(parser, self.resource, 'domain')
def args2body(self, parsed_args):
body = {}
self.args2body_qos_policy(parsed_args, body)
dns.args2body_dns_update(parsed_args, body, 'domain')
return {'network': body}

View File

@ -1,73 +0,0 @@
# 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 cliff import show
import six
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
class ListIpAvailability(neutronV20.ListCommand):
"""List IP usage of networks"""
resource = 'network_ip_availability'
resource_plural = 'network_ip_availabilities'
list_columns = ['network_id', 'network_name', 'total_ips', 'used_ips']
paginations_support = True
sorting_support = True
filter_attrs = [
{'name': 'ip_version',
'help': _('Returns IP availability for the network subnets '
'with a given IP version. Default: 4'),
'argparse_kwargs': {'type': int,
'choices': [4, 6],
'default': 4}
},
{'name': 'network_id',
'help': _('Returns IP availability for the network '
'matching a given network ID.')},
{'name': 'network_name',
'help': _('Returns IP availability for the network '
'matching a given name.')},
{'name': 'tenant_id',
'help': _('Returns IP availability for the networks '
'with a given tenant ID.')},
]
class ShowIpAvailability(neutronV20.NeutronCommand, show.ShowOne):
"""Show IP usage of specific network"""
resource = 'network_ip_availability'
def get_parser(self, prog_name):
parser = super(ShowIpAvailability, self).get_parser(prog_name)
parser.add_argument(
'network_id', metavar='NETWORK',
help=_('ID or name of network to look up.'))
return parser
def take_action(self, parsed_args):
self.log.debug('run(%s)', parsed_args)
neutron_client = self.get_client()
_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'network', parsed_args.network_id)
data = neutron_client.show_network_ip_availability(_id)
self.format_output_data(data)
resource = data[self.resource]
if self.resource in data:
return zip(*sorted(six.iteritems(resource)))
else:
return None

View File

@ -1,344 +0,0 @@
# Copyright 2012 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.
#
import argparse
from oslo_serialization import jsonutils
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.neutron.v2_0 import dns
from neutronclient.neutron.v2_0.qos import policy as qos_policy
def _format_fixed_ips(port):
try:
return '\n'.join([jsonutils.dumps(ip) for ip in port['fixed_ips']])
except (TypeError, KeyError):
return ''
def _format_fixed_ips_csv(port):
try:
return jsonutils.dumps(port['fixed_ips'])
except (TypeError, KeyError):
return ''
def _add_updatable_args(parser):
parser.add_argument(
'--name',
help=_('Name of this port.'))
parser.add_argument(
'--description',
help=_('Description of this port.'))
parser.add_argument(
'--fixed-ip', metavar='subnet_id=SUBNET,ip_address=IP_ADDR',
action='append',
type=utils.str2dict_type(optional_keys=['subnet_id', 'ip_address']),
help=_('Desired IP and/or subnet for this port: '
'subnet_id=<name_or_id>,ip_address=<ip>. '
'You can repeat this option.'))
parser.add_argument(
'--fixed_ip',
action='append',
help=argparse.SUPPRESS)
parser.add_argument(
'--device-id',
help=_('Device ID of this port.'))
parser.add_argument(
'--device_id',
help=argparse.SUPPRESS)
parser.add_argument(
'--device-owner',
help=_('Device owner of this port.'))
parser.add_argument(
'--device_owner',
help=argparse.SUPPRESS)
def _updatable_args2body(parsed_args, body, client):
neutronV20.update_dict(parsed_args, body,
['device_id', 'device_owner', 'name',
'description'])
ips = []
if parsed_args.fixed_ip:
for ip_spec in parsed_args.fixed_ip:
if 'subnet_id' in ip_spec:
subnet_name_id = ip_spec['subnet_id']
_subnet_id = neutronV20.find_resourceid_by_name_or_id(
client, 'subnet', subnet_name_id)
ip_spec['subnet_id'] = _subnet_id
ips.append(ip_spec)
if ips:
body['fixed_ips'] = ips
class ListPort(neutronV20.ListCommand):
"""List ports that belong to a given tenant."""
resource = 'port'
_formatters = {'fixed_ips': _format_fixed_ips, }
_formatters_csv = {'fixed_ips': _format_fixed_ips_csv, }
list_columns = ['id', 'name', 'mac_address', 'fixed_ips']
pagination_support = True
sorting_support = True
class ListRouterPort(neutronV20.ListCommand):
"""List ports that belong to a given tenant, with specified router."""
resource = 'port'
_formatters = {'fixed_ips': _format_fixed_ips, }
list_columns = ['id', 'name', 'mac_address', 'fixed_ips']
pagination_support = True
sorting_support = True
def get_parser(self, prog_name):
parser = super(ListRouterPort, self).get_parser(prog_name)
parser.add_argument(
'id', metavar='ROUTER',
help=_('ID or name of the router to look up.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'router', parsed_args.id)
self.values_specs.append('--device_id=%s' % _id)
return super(ListRouterPort, self).take_action(parsed_args)
class ShowPort(neutronV20.ShowCommand):
"""Show information of a given port."""
resource = 'port'
class UpdatePortSecGroupMixin(object):
def add_arguments_secgroup(self, parser):
group_sg = parser.add_mutually_exclusive_group()
group_sg.add_argument(
'--security-group', metavar='SECURITY_GROUP',
default=[], action='append', dest='security_groups',
help=_('Security group associated with the port. You can '
'repeat this option.'))
group_sg.add_argument(
'--no-security-groups',
action='store_true',
help=_('Associate no security groups with the port.'))
def _resolv_sgid(self, secgroup):
return neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'security_group', secgroup)
def args2body_secgroup(self, parsed_args, port):
if parsed_args.security_groups:
port['security_groups'] = [self._resolv_sgid(sg) for sg
in parsed_args.security_groups]
elif parsed_args.no_security_groups:
port['security_groups'] = []
class UpdateExtraDhcpOptMixin(object):
def add_arguments_extradhcpopt(self, parser):
group_sg = parser.add_mutually_exclusive_group()
group_sg.add_argument(
'--extra-dhcp-opt',
default=[],
action='append',
dest='extra_dhcp_opts',
type=utils.str2dict_type(
required_keys=['opt_name'],
optional_keys=['opt_value', 'ip_version']),
help=_('Extra dhcp options to be assigned to this port: '
'opt_name=<dhcp_option_name>,opt_value=<value>,'
'ip_version={4,6}. You can repeat this option.'))
def args2body_extradhcpopt(self, parsed_args, port):
ops = []
if parsed_args.extra_dhcp_opts:
# the extra_dhcp_opt params (opt_name & opt_value)
# must come in pairs, if there is a parm error
# both must be thrown out.
opt_ele = {}
edo_err_msg = _("Invalid --extra-dhcp-opt option, can only be: "
"opt_name=<dhcp_option_name>,opt_value=<value>,"
"ip_version={4,6}. "
"You can repeat this option.")
for opt in parsed_args.extra_dhcp_opts:
opt_ele.update(opt)
if ('opt_name' in opt_ele and
('opt_value' in opt_ele or 'ip_version' in opt_ele)):
if opt_ele.get('opt_value') == 'null':
opt_ele['opt_value'] = None
ops.append(opt_ele)
opt_ele = {}
else:
raise exceptions.CommandError(edo_err_msg)
if ops:
port['extra_dhcp_opts'] = ops
class UpdatePortAllowedAddressPair(object):
"""Update Port for allowed_address_pairs"""
def add_arguments_allowedaddresspairs(self, parser):
group_aap = parser.add_mutually_exclusive_group()
group_aap.add_argument(
'--allowed-address-pair',
metavar='ip_address=IP_ADDR[,mac_address=MAC_ADDR]',
default=[],
action='append',
dest='allowed_address_pairs',
type=utils.str2dict_type(
required_keys=['ip_address'],
optional_keys=['mac_address']),
help=_('Allowed address pair associated with the port. '
'You can repeat this option.'))
group_aap.add_argument(
'--no-allowed-address-pairs',
action='store_true',
help=_('Associate no allowed address pairs with the port.'))
def args2body_allowedaddresspairs(self, parsed_args, port):
if parsed_args.allowed_address_pairs:
port['allowed_address_pairs'] = parsed_args.allowed_address_pairs
elif parsed_args.no_allowed_address_pairs:
port['allowed_address_pairs'] = []
class CreatePort(neutronV20.CreateCommand, UpdatePortSecGroupMixin,
UpdateExtraDhcpOptMixin, qos_policy.CreateQosPolicyMixin,
UpdatePortAllowedAddressPair):
"""Create a port for a given tenant."""
resource = 'port'
def add_known_arguments(self, parser):
_add_updatable_args(parser)
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--admin_state_down',
dest='admin_state', action='store_false',
help=argparse.SUPPRESS)
parser.add_argument(
'--mac-address',
help=_('MAC address of this port.'))
parser.add_argument(
'--mac_address',
help=argparse.SUPPRESS)
parser.add_argument(
'--vnic-type',
metavar='<direct | direct-physical | macvtap '
'| normal | baremetal>',
choices=['direct', 'direct-physical', 'macvtap',
'normal', 'baremetal'],
help=_('VNIC type for this port.'))
parser.add_argument(
'--vnic_type',
choices=['direct', 'direct-physical', 'macvtap',
'normal', 'baremetal'],
help=argparse.SUPPRESS)
parser.add_argument(
'--binding-profile',
help=_('Custom data to be passed as binding:profile.'))
parser.add_argument(
'--binding_profile',
help=argparse.SUPPRESS)
self.add_arguments_secgroup(parser)
self.add_arguments_extradhcpopt(parser)
self.add_arguments_qos_policy(parser)
self.add_arguments_allowedaddresspairs(parser)
parser.add_argument(
'network_id', metavar='NETWORK',
help=_('ID or name of the network this port belongs to.'))
dns.add_dns_argument_create(parser, self.resource, 'name')
def args2body(self, parsed_args):
client = self.get_client()
_network_id = neutronV20.find_resourceid_by_name_or_id(
client, 'network', parsed_args.network_id)
body = {'admin_state_up': parsed_args.admin_state,
'network_id': _network_id, }
_updatable_args2body(parsed_args, body, client)
neutronV20.update_dict(parsed_args, body,
['mac_address', 'tenant_id'])
if parsed_args.vnic_type:
body['binding:vnic_type'] = parsed_args.vnic_type
if parsed_args.binding_profile:
body['binding:profile'] = jsonutils.loads(
parsed_args.binding_profile)
self.args2body_secgroup(parsed_args, body)
self.args2body_extradhcpopt(parsed_args, body)
self.args2body_qos_policy(parsed_args, body)
self.args2body_allowedaddresspairs(parsed_args, body)
dns.args2body_dns_create(parsed_args, body, 'name')
return {'port': body}
class DeletePort(neutronV20.DeleteCommand):
"""Delete a given port."""
resource = 'port'
class UpdatePort(neutronV20.UpdateCommand, UpdatePortSecGroupMixin,
UpdateExtraDhcpOptMixin, qos_policy.UpdateQosPolicyMixin,
UpdatePortAllowedAddressPair):
"""Update port's information."""
resource = 'port'
def add_known_arguments(self, parser):
_add_updatable_args(parser)
parser.add_argument(
'--admin-state-up',
choices=['True', 'False'],
help=_('Set admin state up for the port.'))
parser.add_argument(
'--admin_state_up',
choices=['True', 'False'],
help=argparse.SUPPRESS)
self.add_arguments_secgroup(parser)
self.add_arguments_extradhcpopt(parser)
self.add_arguments_qos_policy(parser)
self.add_arguments_allowedaddresspairs(parser)
dns.add_dns_argument_update(parser, self.resource, 'name')
def args2body(self, parsed_args):
body = {}
client = self.get_client()
_updatable_args2body(parsed_args, body, client)
if parsed_args.admin_state_up:
body['admin_state_up'] = parsed_args.admin_state_up
self.args2body_secgroup(parsed_args, body)
self.args2body_extradhcpopt(parsed_args, body)
self.args2body_qos_policy(parsed_args, body)
self.args2body_allowedaddresspairs(parsed_args, body)
dns.args2body_dns_update(parsed_args, body, 'name')
return {'port': body}

View File

@ -1,150 +0,0 @@
# Copyright 2016 Cisco Systems
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import sys
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
class Purge(neutronV20.NeutronCommand):
"""Delete all resources that belong to a given tenant."""
def _pluralize(self, string):
return string + 's'
def _get_resources(self, neutron_client, resource_types, tenant_id):
resources = []
for resource_type in resource_types:
resources.append([])
resource_type_plural = self._pluralize(resource_type)
opts = {'fields': ['id', 'tenant_id']}
if resource_type_plural == 'ports':
opts['fields'].append('device_id')
opts['fields'].append('device_owner')
function = getattr(neutron_client, 'list_%s' %
resource_type_plural)
if callable(function):
returned_resources = function(**opts).get(resource_type_plural,
[])
for resource in returned_resources:
if resource['tenant_id'] == tenant_id:
index = resource_types.index(resource_type)
resources[index].append(resource)
self.total_resources += 1
return resources
def _delete_resource(self, neutron_client, resource_type, resource):
resource_id = resource['id']
if resource_type == 'port':
router_interface_owners = ['network:router_interface',
'network:router_interface_distributed']
if resource.get('device_owner', '') in router_interface_owners:
body = {'port_id': resource_id}
neutron_client.remove_interface_router(resource['device_id'],
body)
return
function = getattr(neutron_client, 'delete_%s' % resource_type)
if callable(function):
function(resource_id)
def _purge_resources(self, neutron_client, resource_types,
tenant_resources):
deleted = {}
failed = {}
failures = False
for resources in tenant_resources:
index = tenant_resources.index(resources)
resource_type = resource_types[index]
failed[resource_type] = 0
deleted[resource_type] = 0
for resource in resources:
try:
self._delete_resource(neutron_client, resource_type,
resource)
deleted[resource_type] += 1
self.deleted_resources += 1
except Exception:
failures = True
failed[resource_type] += 1
self.total_resources -= 1
percent_complete = 100
if self.total_resources > 0:
percent_complete = (self.deleted_resources /
float(self.total_resources)) * 100
sys.stdout.write("\rPurging resources: %d%% complete." %
percent_complete)
sys.stdout.flush()
return (deleted, failed, failures)
def _build_message(self, deleted, failed, failures):
msg = ''
deleted_msg = []
for resource, value in deleted.items():
if value:
if not msg:
msg = 'Deleted'
if not value == 1:
resource = self._pluralize(resource)
deleted_msg.append(" %d %s" % (value, resource))
if deleted_msg:
msg += ','.join(deleted_msg)
failed_msg = []
if failures:
if msg:
msg += '. '
msg += 'The following resources could not be deleted:'
for resource, value in failed.items():
if value:
if not value == 1:
resource = self._pluralize(resource)
failed_msg.append(" %d %s" % (value, resource))
msg += ','.join(failed_msg)
if msg:
msg += '.'
else:
msg = _('Tenant has no supported resources.')
return msg
def get_parser(self, prog_name):
parser = super(Purge, self).get_parser(prog_name)
parser.add_argument(
'tenant', metavar='TENANT',
help=_('ID of Tenant owning the resources to be deleted.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
self.any_failures = False
# A list of the types of resources supported in the order in which
# they should be deleted.
resource_types = ['floatingip', 'port', 'router',
'network', 'security_group']
deleted = {}
failed = {}
self.total_resources = 0
self.deleted_resources = 0
resources = self._get_resources(neutron_client, resource_types,
parsed_args.tenant)
deleted, failed, failures = self._purge_resources(neutron_client,
resource_types,
resources)
print('\n%s' % self._build_message(deleted, failed, failures))

View File

@ -1,101 +0,0 @@
# Copyright 2015 Huawei Technologies India Pvt Ltd, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.neutron import v2_0 as neutronv20
from neutronclient.neutron.v2_0.qos import rule as qos_rule
BANDWIDTH_LIMIT_RULE_RESOURCE = 'bandwidth_limit_rule'
def add_bandwidth_limit_arguments(parser):
parser.add_argument(
'--max-kbps',
help=_('max bandwidth in kbps.'))
parser.add_argument(
'--max-burst-kbps',
help=_('max burst bandwidth in kbps.'))
def update_bandwidth_limit_args2body(parsed_args, body):
max_kbps = parsed_args.max_kbps
max_burst_kbps = parsed_args.max_burst_kbps
if not (max_kbps or max_burst_kbps):
raise exceptions.CommandError(_("Must provide max_kbps"
" or max_burst_kbps option."))
neutronv20.update_dict(parsed_args, body,
['max_kbps', 'max_burst_kbps', 'tenant_id'])
class CreateQoSBandwidthLimitRule(qos_rule.QosRuleMixin,
neutronv20.CreateCommand):
"""Create a qos bandwidth limit rule."""
resource = BANDWIDTH_LIMIT_RULE_RESOURCE
def add_known_arguments(self, parser):
super(CreateQoSBandwidthLimitRule, self).add_known_arguments(parser)
add_bandwidth_limit_arguments(parser)
def args2body(self, parsed_args):
body = {}
update_bandwidth_limit_args2body(parsed_args, body)
return {self.resource: body}
class ListQoSBandwidthLimitRules(qos_rule.QosRuleMixin,
neutronv20.ListCommand):
"""List all qos bandwidth limit rules belonging to the specified policy."""
resource = BANDWIDTH_LIMIT_RULE_RESOURCE
_formatters = {}
pagination_support = True
sorting_support = True
class ShowQoSBandwidthLimitRule(qos_rule.QosRuleMixin, neutronv20.ShowCommand):
"""Show information about the given qos bandwidth limit rule."""
resource = BANDWIDTH_LIMIT_RULE_RESOURCE
allow_names = False
class UpdateQoSBandwidthLimitRule(qos_rule.QosRuleMixin,
neutronv20.UpdateCommand):
"""Update the given qos bandwidth limit rule."""
resource = BANDWIDTH_LIMIT_RULE_RESOURCE
allow_names = False
def add_known_arguments(self, parser):
super(UpdateQoSBandwidthLimitRule, self).add_known_arguments(parser)
add_bandwidth_limit_arguments(parser)
def args2body(self, parsed_args):
body = {}
update_bandwidth_limit_args2body(parsed_args, body)
return {self.resource: body}
class DeleteQoSBandwidthLimitRule(qos_rule.QosRuleMixin,
neutronv20.DeleteCommand):
"""Delete a given qos bandwidth limit rule."""
resource = BANDWIDTH_LIMIT_RULE_RESOURCE
allow_names = False

View File

@ -1,112 +0,0 @@
# Copyright 2016 Comcast, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.neutron import v2_0 as neutronv20
from neutronclient.neutron.v2_0.qos import rule as qos_rule
DSCP_MARKING_RESOURCE = 'dscp_marking_rule'
# DSCP DETAILS
# 0 - none | 8 - cs1 | 10 - af11 | 12 - af12 | 14 - af13 |
# 16 - cs2 | 18 - af21 | 20 - af22 | 22 - af23 | 24 - cs3 |
# 26 - af31 | 28 - af32 | 30 - af33 | 32 - cs4 | 34 - af41 |
# 36 - af42 | 38 - af43 | 40 - cs5 | 46 - ef | 48 - cs6 |
# 56 - cs7
DSCP_VALID_MARKS = [0, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32,
34, 36, 38, 40, 46, 48, 56]
def add_dscp_marking_arguments(parser):
parser.add_argument(
'--dscp-mark',
required=True,
type=str,
help=_('DSCP mark: value can be 0, even numbers from 8-56, \
excluding 42, 44, 50, 52, and 54.'))
def update_dscp_args2body(parsed_args, body):
dscp_mark = parsed_args.dscp_mark
if int(dscp_mark) not in DSCP_VALID_MARKS:
raise exceptions.CommandError(_("DSCP mark: %s not supported. "
"Please note value can either be 0 "
"or any even number from 8-56 "
"excluding 42, 44, 50, 52 and "
"54.") % dscp_mark)
neutronv20.update_dict(parsed_args, body,
['dscp_mark'])
class CreateQoSDscpMarkingRule(qos_rule.QosRuleMixin,
neutronv20.CreateCommand):
"""Create a QoS DSCP marking rule."""
resource = DSCP_MARKING_RESOURCE
def add_known_arguments(self, parser):
super(CreateQoSDscpMarkingRule, self).add_known_arguments(parser)
add_dscp_marking_arguments(parser)
def args2body(self, parsed_args):
body = {}
update_dscp_args2body(parsed_args, body)
return {self.resource: body}
class ListQoSDscpMarkingRules(qos_rule.QosRuleMixin,
neutronv20.ListCommand):
"""List all QoS DSCP marking rules belonging to the specified policy."""
_formatters = {}
pagination_support = True
sorting_support = True
resource = DSCP_MARKING_RESOURCE
class ShowQoSDscpMarkingRule(qos_rule.QosRuleMixin,
neutronv20.ShowCommand):
"""Show information about the given qos dscp marking rule."""
resource = DSCP_MARKING_RESOURCE
allow_names = False
class UpdateQoSDscpMarkingRule(qos_rule.QosRuleMixin,
neutronv20.UpdateCommand):
"""Update the given QoS DSCP marking rule."""
allow_names = False
resource = DSCP_MARKING_RESOURCE
def add_known_arguments(self, parser):
super(UpdateQoSDscpMarkingRule, self).add_known_arguments(parser)
add_dscp_marking_arguments(parser)
def args2body(self, parsed_args):
body = {}
update_dscp_args2body(parsed_args, body)
return {self.resource: body}
class DeleteQoSDscpMarkingRule(qos_rule.QosRuleMixin,
neutronv20.DeleteCommand):
"""Delete a given qos dscp marking rule."""
allow_names = False
resource = DSCP_MARKING_RESOURCE

View File

@ -1,160 +0,0 @@
# Copyright 2015 Huawei Technologies India Pvt Ltd, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import os
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronv20
def get_qos_policy_id(client, policy_id_or_name):
_policy_id = neutronv20.find_resourceid_by_name_or_id(
client, 'policy', policy_id_or_name, cmd_resource='qos_policy')
return _policy_id
class CreateQosPolicyMixin(object):
def add_arguments_qos_policy(self, parser):
qos_policy_args = parser.add_mutually_exclusive_group()
qos_policy_args.add_argument(
'--qos-policy',
help=_('ID or name of the QoS policy that should'
'be attached to the resource.'))
return qos_policy_args
def args2body_qos_policy(self, parsed_args, resource):
if parsed_args.qos_policy:
_policy_id = get_qos_policy_id(self.get_client(),
parsed_args.qos_policy)
resource['qos_policy_id'] = _policy_id
class UpdateQosPolicyMixin(CreateQosPolicyMixin):
def add_arguments_qos_policy(self, parser):
qos_policy_args = (super(UpdateQosPolicyMixin, self).
add_arguments_qos_policy(parser))
qos_policy_args.add_argument(
'--no-qos-policy',
action='store_true',
help=_('Detach QoS policy from the resource.'))
return qos_policy_args
def args2body_qos_policy(self, parsed_args, resource):
super(UpdateQosPolicyMixin, self).args2body_qos_policy(parsed_args,
resource)
if parsed_args.no_qos_policy:
resource['qos_policy_id'] = None
class ListQoSPolicy(neutronv20.ListCommand):
"""List QoS policies that belong to a given tenant connection."""
resource = 'policy'
shadow_resource = 'qos_policy'
list_columns = ['id', 'name']
pagination_support = True
sorting_support = True
class ShowQoSPolicy(neutronv20.ShowCommand):
"""Show information of a given qos policy."""
resource = 'policy'
shadow_resource = 'qos_policy'
def format_output_data(self, data):
rules = []
for rule in data['policy'].get('rules', []):
rules.append("%s (type: %s)" % (rule['id'], rule['type']))
data['policy']['rules'] = os.linesep.join(rules)
super(ShowQoSPolicy, self).format_output_data(data)
class CreateQoSPolicy(neutronv20.CreateCommand):
"""Create a qos policy."""
resource = 'policy'
shadow_resource = 'qos_policy'
def add_known_arguments(self, parser):
parser.add_argument(
'name', metavar='NAME',
help=_('Name of the QoS policy to be created.'))
parser.add_argument(
'--description',
help=_('Description of the QoS policy to be created.'))
parser.add_argument(
'--shared',
action='store_true',
help=_('Accessible by other tenants. '
'Set shared to True (default is False).'))
def args2body(self, parsed_args):
body = {'name': parsed_args.name}
if parsed_args.description:
body['description'] = parsed_args.description
if parsed_args.shared:
body['shared'] = parsed_args.shared
if parsed_args.tenant_id:
body['tenant_id'] = parsed_args.tenant_id
return {self.resource: body}
class UpdateQoSPolicy(neutronv20.UpdateCommand):
"""Update a given qos policy."""
resource = 'policy'
shadow_resource = 'qos_policy'
def add_known_arguments(self, parser):
parser.add_argument(
'--name',
help=_('Name of the QoS policy.'))
parser.add_argument(
'--description',
help=_('Description of the QoS policy.'))
shared_group = parser.add_mutually_exclusive_group()
shared_group.add_argument(
'--shared',
action='store_true',
help=_('Accessible by other tenants. '
'Set shared to True (default is False).'))
shared_group.add_argument(
'--no-shared',
action='store_true',
help=_('Not accessible by other tenants. '
'Set shared to False.'))
def args2body(self, parsed_args):
body = {}
if parsed_args.name:
body['name'] = parsed_args.name
if parsed_args.description:
body['description'] = parsed_args.description
if parsed_args.shared:
body['shared'] = True
if parsed_args.no_shared:
body['shared'] = False
return {self.resource: body}
class DeleteQoSPolicy(neutronv20.DeleteCommand):
"""Delete a given qos policy."""
resource = 'policy'
shadow_resource = 'qos_policy'

View File

@ -1,63 +0,0 @@
# Copyright 2015 Huawei Technologies India Pvt Ltd, Inc.
# All Rights Reserved
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronv20
from neutronclient.neutron.v2_0.qos import policy as qos_policy
def add_policy_argument(parser):
parser.add_argument(
'policy', metavar='QOS_POLICY',
help=_('ID or name of the QoS policy.'))
def add_rule_argument(parser):
parser.add_argument(
'rule', metavar='QOS_RULE',
help=_('ID of the QoS rule.'))
def update_policy_args2body(parsed_args, body):
neutronv20.update_dict(parsed_args, body, ['policy'])
def update_rule_args2body(parsed_args, body):
neutronv20.update_dict(parsed_args, body, ['rule'])
class QosRuleMixin(object):
def add_known_arguments(self, parser):
add_policy_argument(parser)
def set_extra_attrs(self, parsed_args):
self.parent_id = qos_policy.get_qos_policy_id(self.get_client(),
parsed_args.policy)
def args2body(self, parsed_args):
body = {}
update_policy_args2body(parsed_args, body)
return {'qos_rule': body}
class ListQoSRuleTypes(neutronv20.ListCommand):
"""List available qos rule types."""
resource = 'rule_type'
shadow_resource = 'qos_rule_type'
pagination_support = True
sorting_support = True

View File

@ -1,243 +0,0 @@
# Copyright 2012 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.
#
from __future__ import print_function
import argparse
from cliff import lister
from cliff import show
from oslo_serialization import jsonutils
import six
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
def get_tenant_id(args, client):
return (args.pos_tenant_id or args.tenant_id or
client.get_quotas_tenant()['tenant']['tenant_id'])
class DeleteQuota(neutronV20.NeutronCommand):
"""Delete defined quotas of a given tenant."""
resource = 'quota'
def get_parser(self, prog_name):
parser = super(DeleteQuota, self).get_parser(prog_name)
parser.add_argument(
'--tenant-id', metavar='tenant-id',
help=_('The owner tenant ID.'))
parser.add_argument(
'--tenant_id',
help=argparse.SUPPRESS)
parser.add_argument(
'pos_tenant_id',
help=argparse.SUPPRESS, nargs='?')
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
tenant_id = get_tenant_id(parsed_args, neutron_client)
obj_deleter = getattr(neutron_client,
"delete_%s" % self.resource)
obj_deleter(tenant_id)
print((_('Deleted %(resource)s: %(tenant_id)s')
% {'tenant_id': tenant_id,
'resource': self.resource}),
file=self.app.stdout)
return
class ListQuota(neutronV20.NeutronCommand, lister.Lister):
"""List quotas of all tenants who have non-default quota values."""
resource = 'quota'
def get_parser(self, prog_name):
parser = super(ListQuota, self).get_parser(prog_name)
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
search_opts = {}
self.log.debug('search options: %s', search_opts)
obj_lister = getattr(neutron_client,
"list_%ss" % self.resource)
data = obj_lister(**search_opts)
info = []
collection = self.resource + "s"
if collection in data:
info = data[collection]
_columns = len(info) > 0 and sorted(info[0].keys()) or []
return (_columns, (utils.get_item_properties(s, _columns)
for s in info))
class ShowQuota(neutronV20.NeutronCommand, show.ShowOne):
"""Show quotas of a given tenant.
"""
resource = "quota"
def get_parser(self, prog_name):
parser = super(ShowQuota, self).get_parser(prog_name)
parser.add_argument(
'--tenant-id', metavar='tenant-id',
help=_('The owner tenant ID.'))
parser.add_argument(
'--tenant_id',
help=argparse.SUPPRESS)
# allow people to do neutron quota-show <tenant-id>.
# we use a different name for this because the default will
# override whatever is in the named arg otherwise.
parser.add_argument(
'pos_tenant_id',
help=argparse.SUPPRESS, nargs='?')
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
tenant_id = get_tenant_id(parsed_args, neutron_client)
params = {}
obj_shower = getattr(neutron_client,
"show_%s" % self.resource)
data = obj_shower(tenant_id, **params)
if self.resource in data:
for k, v in six.iteritems(data[self.resource]):
if isinstance(v, list):
value = ""
for _item in v:
if value:
value += "\n"
if isinstance(_item, dict):
value += jsonutils.dumps(_item)
else:
value += str(_item)
data[self.resource][k] = value
elif v is None:
data[self.resource][k] = ''
return zip(*sorted(six.iteritems(data[self.resource])))
else:
return None
class UpdateQuota(neutronV20.NeutronCommand, show.ShowOne):
"""Define tenant's quotas not to use defaults."""
resource = 'quota'
def get_parser(self, prog_name):
parser = super(UpdateQuota, self).get_parser(prog_name)
parser.add_argument(
'--tenant-id', metavar='tenant-id',
help=_('The owner tenant ID.'))
parser.add_argument(
'--tenant_id',
help=argparse.SUPPRESS)
parser.add_argument(
'--network', metavar='networks',
help=_('The limit of networks.'))
parser.add_argument(
'--subnet', metavar='subnets',
help=_('The limit of subnets.'))
parser.add_argument(
'--port', metavar='ports',
help=_('The limit of ports.'))
parser.add_argument(
'--router', metavar='routers',
help=_('The limit of routers.'))
parser.add_argument(
'--floatingip', metavar='floatingips',
help=_('The limit of floating IPs.'))
parser.add_argument(
'--security-group', metavar='security_groups',
help=_('The limit of security groups.'))
parser.add_argument(
'--security-group-rule', metavar='security_group_rules',
help=_('The limit of security groups rules.'))
parser.add_argument(
'--vip', metavar='vips',
help=_('The limit of vips.'))
parser.add_argument(
'--pool', metavar='pools',
help=_('The limit of pools.'))
parser.add_argument(
'--member', metavar='members',
help=_('The limit of pool members.'))
parser.add_argument(
'--health-monitor', metavar='health_monitors',
help=_('The limit of health monitors.'))
parser.add_argument(
'pos_tenant_id',
help=argparse.SUPPRESS, nargs='?')
return parser
def _validate_int(self, name, value):
try:
return_value = int(value)
except Exception:
message = (_('Quota limit for %(name)s must be an integer') %
{'name': name})
raise exceptions.NeutronClientException(message=message)
return return_value
def args2body(self, parsed_args):
quota = {}
for resource in ('network', 'subnet', 'port', 'router', 'floatingip',
'security_group', 'security_group_rule',
'vip', 'pool', 'member', 'health_monitor'):
if getattr(parsed_args, resource):
quota[resource] = self._validate_int(
resource,
getattr(parsed_args, resource))
return {self.resource: quota}
def take_action(self, parsed_args):
neutron_client = self.get_client()
_extra_values = neutronV20.parse_args_to_dict(self.values_specs)
neutronV20._merge_args(self, parsed_args, _extra_values,
self.values_specs)
body = self.args2body(parsed_args)
if self.resource in body:
body[self.resource].update(_extra_values)
else:
body[self.resource] = _extra_values
obj_updator = getattr(neutron_client,
"update_%s" % self.resource)
tenant_id = get_tenant_id(parsed_args, neutron_client)
data = obj_updator(tenant_id, body)
if self.resource in data:
for k, v in six.iteritems(data[self.resource]):
if isinstance(v, list):
value = ""
for _item in v:
if value:
value += "\n"
if isinstance(_item, dict):
value += jsonutils.dumps(_item)
else:
value += str(_item)
data[self.resource][k] = value
elif v is None:
data[self.resource][k] = ''
return zip(*sorted(six.iteritems(data[self.resource])))
else:
return None

View File

@ -1,115 +0,0 @@
# Copyright 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 neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronV20
# key=object_type: value={key=resource, value=cmd_resource}
RBAC_OBJECTS = {'network': {'network': 'network'},
'qos-policy': {'policy': 'qos_policy'}}
def _get_cmd_resource(obj_type):
resource = list(RBAC_OBJECTS[obj_type])[0]
cmd_resource = RBAC_OBJECTS[obj_type][resource]
return resource, cmd_resource
def get_rbac_obj_params(client, obj_type, obj_id_or_name):
resource, cmd_resource = _get_cmd_resource(obj_type)
obj_id = neutronV20.find_resourceid_by_name_or_id(
client=client, resource=resource, name_or_id=obj_id_or_name,
cmd_resource=cmd_resource)
return obj_id, cmd_resource
class ListRBACPolicy(neutronV20.ListCommand):
"""List RBAC policies that belong to a given tenant."""
resource = 'rbac_policy'
list_columns = ['id', 'object_type', 'object_id']
pagination_support = True
sorting_support = True
allow_names = False
class ShowRBACPolicy(neutronV20.ShowCommand):
"""Show information of a given RBAC policy."""
resource = 'rbac_policy'
allow_names = False
class CreateRBACPolicy(neutronV20.CreateCommand):
"""Create a RBAC policy for a given tenant."""
resource = 'rbac_policy'
def add_known_arguments(self, parser):
parser.add_argument(
'name',
metavar='RBAC_OBJECT',
help=_('ID or name of the RBAC object.'))
parser.add_argument(
'--type', choices=RBAC_OBJECTS.keys(),
required=True,
help=_('Type of the object that RBAC policy affects.'))
parser.add_argument(
'--target-tenant',
help=_('ID of the tenant to which the RBAC '
'policy will be enforced.'))
parser.add_argument(
'--action', choices=['access_as_external', 'access_as_shared'],
required=True,
help=_('Action for the RBAC policy.'))
def args2body(self, parsed_args):
neutron_client = self.get_client()
neutron_client.format = parsed_args.request_format
_object_id, _object_type = get_rbac_obj_params(neutron_client,
parsed_args.type,
parsed_args.name)
body = {
'object_id': _object_id,
'object_type': _object_type,
'target_tenant': parsed_args.target_tenant,
'action': parsed_args.action,
}
return {self.resource: body}
class UpdateRBACPolicy(neutronV20.UpdateCommand):
"""Update RBAC policy for given tenant."""
resource = 'rbac_policy'
allow_names = False
def add_known_arguments(self, parser):
parser.add_argument(
'--target-tenant',
help=_('ID of the tenant to which the RBAC '
'policy will be enforced.'))
def args2body(self, parsed_args):
body = {'target_tenant': parsed_args.target_tenant}
return {self.resource: body}
class DeleteRBACPolicy(neutronV20.DeleteCommand):
"""Delete a RBAC policy."""
resource = 'rbac_policy'
allow_names = False

View File

@ -1,287 +0,0 @@
# Copyright 2012 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.
#
from __future__ import print_function
import argparse
from oslo_serialization import jsonutils
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
from neutronclient.neutron.v2_0 import availability_zone
def _format_external_gateway_info(router):
try:
return jsonutils.dumps(router['external_gateway_info'])
except (TypeError, KeyError):
return ''
class ListRouter(neutronV20.ListCommand):
"""List routers that belong to a given tenant."""
resource = 'router'
_formatters = {'external_gateway_info': _format_external_gateway_info, }
list_columns = ['id', 'name', 'external_gateway_info', 'distributed', 'ha']
pagination_support = True
sorting_support = True
class ShowRouter(neutronV20.ShowCommand):
"""Show information of a given router."""
resource = 'router'
class CreateRouter(neutronV20.CreateCommand):
"""Create a router for a given tenant."""
resource = 'router'
_formatters = {'external_gateway_info': _format_external_gateway_info, }
def add_known_arguments(self, parser):
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--admin_state_down',
dest='admin_state', action='store_false',
help=argparse.SUPPRESS)
parser.add_argument(
'name', metavar='NAME',
help=_('Name of the router to be created.'))
parser.add_argument(
'--description',
help=_('Description of router.'))
utils.add_boolean_argument(
parser, '--distributed', dest='distributed',
help=_('Create a distributed router.'))
utils.add_boolean_argument(
parser, '--ha', dest='ha',
help=_('Create a highly available router.'))
availability_zone.add_az_hint_argument(parser, self.resource)
def args2body(self, parsed_args):
body = {'admin_state_up': parsed_args.admin_state}
neutronV20.update_dict(parsed_args, body,
['name', 'tenant_id', 'distributed', 'ha',
'description'])
availability_zone.args2body_az_hint(parsed_args, body)
return {self.resource: body}
class DeleteRouter(neutronV20.DeleteCommand):
"""Delete a given router."""
resource = 'router'
class UpdateRouter(neutronV20.UpdateCommand):
"""Update router's information."""
resource = 'router'
def add_known_arguments(self, parser):
parser.add_argument(
'--name',
help=_('Updated name of the router.'))
parser.add_argument(
'--description',
help=_('Description of router.'))
utils.add_boolean_argument(
parser, '--admin-state-up', dest='admin_state',
help=_('Specify the administrative state of the router '
'(True means "Up").'))
utils.add_boolean_argument(
parser, '--admin_state_up', dest='admin_state',
help=argparse.SUPPRESS)
utils.add_boolean_argument(
parser, '--distributed', dest='distributed',
help=_('True means this router should operate in '
'distributed mode.'))
routes_group = parser.add_mutually_exclusive_group()
routes_group.add_argument(
'--route', metavar='destination=CIDR,nexthop=IP_ADDR',
action='append', dest='routes',
type=utils.str2dict_type(required_keys=['destination', 'nexthop']),
help=_('Route to associate with the router.'
' You can repeat this option.'))
routes_group.add_argument(
'--no-routes',
action='store_true',
help=_('Remove routes associated with the router.'))
def args2body(self, parsed_args):
body = {}
if hasattr(parsed_args, 'admin_state'):
body['admin_state_up'] = parsed_args.admin_state
neutronV20.update_dict(parsed_args, body,
['name', 'distributed', 'description'])
if parsed_args.no_routes:
body['routes'] = None
elif parsed_args.routes:
body['routes'] = parsed_args.routes
return {self.resource: body}
class RouterInterfaceCommand(neutronV20.NeutronCommand):
"""Based class to Add/Remove router interface."""
resource = 'router'
def call_api(self, neutron_client, router_id, body):
raise NotImplementedError()
def success_message(self, router_id, portinfo):
raise NotImplementedError()
def get_parser(self, prog_name):
parser = super(RouterInterfaceCommand, self).get_parser(prog_name)
parser.add_argument(
'router', metavar='ROUTER',
help=_('ID or name of the router.'))
parser.add_argument(
'interface', metavar='INTERFACE',
help=_('The format is "SUBNET|subnet=SUBNET|port=PORT". '
'Either a subnet or port must be specified. '
'Both ID and name are accepted as SUBNET or PORT. '
'Note that "subnet=" can be omitted when specifying a '
'subnet.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
if '=' in parsed_args.interface:
resource, value = parsed_args.interface.split('=', 1)
if resource not in ['subnet', 'port']:
exceptions.CommandError(_('You must specify either subnet or '
'port for INTERFACE parameter.'))
else:
resource = 'subnet'
value = parsed_args.interface
_router_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, self.resource, parsed_args.router)
_interface_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, resource, value)
body = {'%s_id' % resource: _interface_id}
portinfo = self.call_api(neutron_client, _router_id, body)
print(self.success_message(parsed_args.router, portinfo),
file=self.app.stdout)
class AddInterfaceRouter(RouterInterfaceCommand):
"""Add an internal network interface to a router."""
def call_api(self, neutron_client, router_id, body):
return neutron_client.add_interface_router(router_id, body)
def success_message(self, router_id, portinfo):
return (_('Added interface %(port)s to router %(router)s.') %
{'router': router_id, 'port': portinfo['port_id']})
class RemoveInterfaceRouter(RouterInterfaceCommand):
"""Remove an internal network interface from a router."""
def call_api(self, neutron_client, router_id, body):
return neutron_client.remove_interface_router(router_id, body)
def success_message(self, router_id, portinfo):
# portinfo is not used since it is None for router-interface-delete.
return _('Removed interface from router %s.') % router_id
class SetGatewayRouter(neutronV20.NeutronCommand):
"""Set the external network gateway for a router."""
resource = 'router'
def get_parser(self, prog_name):
parser = super(SetGatewayRouter, self).get_parser(prog_name)
parser.add_argument(
'router', metavar='ROUTER',
help=_('ID or name of the router.'))
parser.add_argument(
'external_network', metavar='EXTERNAL-NETWORK',
help=_('ID or name of the external network for the gateway.'))
parser.add_argument(
'--disable-snat', action='store_true',
help=_('Disable source NAT on the router gateway.'))
parser.add_argument(
'--fixed-ip', metavar='subnet_id=SUBNET,ip_address=IP_ADDR',
action='append',
type=utils.str2dict_type(optional_keys=['subnet_id',
'ip_address']),
help=_('Desired IP and/or subnet on external network: '
'subnet_id=<name_or_id>,ip_address=<ip>. '
'You can specify both of subnet_id and ip_address or '
'specify one of them as well. '
'You can repeat this option.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_router_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, self.resource, parsed_args.router)
_ext_net_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'network', parsed_args.external_network)
router_dict = {'network_id': _ext_net_id}
if parsed_args.disable_snat:
router_dict['enable_snat'] = False
if parsed_args.fixed_ip:
ips = []
for ip_spec in parsed_args.fixed_ip:
subnet_name_id = ip_spec.get('subnet_id')
if subnet_name_id:
subnet_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, 'subnet', subnet_name_id)
ip_spec['subnet_id'] = subnet_id
ips.append(ip_spec)
router_dict['external_fixed_ips'] = ips
neutron_client.add_gateway_router(_router_id, router_dict)
print(_('Set gateway for router %s') % parsed_args.router,
file=self.app.stdout)
class RemoveGatewayRouter(neutronV20.NeutronCommand):
"""Remove an external network gateway from a router."""
resource = 'router'
def get_parser(self, prog_name):
parser = super(RemoveGatewayRouter, self).get_parser(prog_name)
parser.add_argument(
'router', metavar='ROUTER',
help=_('ID or name of the router.'))
return parser
def take_action(self, parsed_args):
neutron_client = self.get_client()
_router_id = neutronV20.find_resourceid_by_name_or_id(
neutron_client, self.resource, parsed_args.router)
neutron_client.remove_gateway_router(_router_id)
print(_('Removed gateway from router %s') % parsed_args.router,
file=self.app.stdout)

View File

@ -1,376 +0,0 @@
# Copyright 2012 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.
#
import argparse
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.neutron import v2_0 as neutronV20
def _get_remote(rule):
if rule['remote_ip_prefix']:
remote = '%s (CIDR)' % rule['remote_ip_prefix']
elif rule['remote_group_id']:
remote = '%s (group)' % rule['remote_group_id']
else:
remote = None
return remote
def _get_protocol_port(rule):
proto = rule['protocol']
port_min = rule['port_range_min']
port_max = rule['port_range_max']
if proto in ('tcp', 'udp'):
if (port_min and port_min == port_max):
protocol_port = '%s/%s' % (port_min, proto)
elif port_min:
protocol_port = '%s-%s/%s' % (port_min, port_max, proto)
else:
protocol_port = proto
elif proto == 'icmp':
icmp_opts = []
if port_min is not None:
icmp_opts.append('type:%s' % port_min)
if port_max is not None:
icmp_opts.append('code:%s' % port_max)
if icmp_opts:
protocol_port = 'icmp (%s)' % ', '.join(icmp_opts)
else:
protocol_port = 'icmp'
elif proto is not None:
# port_range_min/max are not recognized for protocol
# other than TCP, UDP and ICMP.
protocol_port = proto
else:
protocol_port = None
return protocol_port
def _format_sg_rule(rule):
formatted = []
for field in ['direction',
'ethertype',
('protocol_port', _get_protocol_port),
'remote_ip_prefix',
'remote_group_id']:
if isinstance(field, tuple):
field, get_method = field
data = get_method(rule)
else:
data = rule[field]
if not data:
continue
if field in ('remote_ip_prefix', 'remote_group_id'):
data = '%s: %s' % (field, data)
formatted.append(data)
return ', '.join(formatted)
def _format_sg_rules(secgroup):
try:
return '\n'.join(sorted([_format_sg_rule(rule) for rule
in secgroup['security_group_rules']]))
except Exception:
return ''
def generate_default_ethertype(protocol):
if protocol == 'icmpv6':
return 'IPv6'
return 'IPv4'
class ListSecurityGroup(neutronV20.ListCommand):
"""List security groups that belong to a given tenant."""
resource = 'security_group'
list_columns = ['id', 'name', 'security_group_rules']
_formatters = {'security_group_rules': _format_sg_rules}
pagination_support = True
sorting_support = True
class ShowSecurityGroup(neutronV20.ShowCommand):
"""Show information of a given security group."""
resource = 'security_group'
allow_names = True
json_indent = 5
class CreateSecurityGroup(neutronV20.CreateCommand):
"""Create a security group."""
resource = 'security_group'
def add_known_arguments(self, parser):
parser.add_argument(
'name', metavar='NAME',
help=_('Name of the security group to be created.'))
parser.add_argument(
'--description',
help=_('Description of the security group to be created.'))
def args2body(self, parsed_args):
body = {'name': parsed_args.name}
neutronV20.update_dict(parsed_args, body,
['description', 'tenant_id'])
return {'security_group': body}
class DeleteSecurityGroup(neutronV20.DeleteCommand):
"""Delete a given security group."""
resource = 'security_group'
allow_names = True
class UpdateSecurityGroup(neutronV20.UpdateCommand):
"""Update a given security group."""
resource = 'security_group'
def add_known_arguments(self, parser):
parser.add_argument(
'--name',
help=_('Updated name of the security group.'))
parser.add_argument(
'--description',
help=_('Updated description of the security group.'))
def args2body(self, parsed_args):
body = {}
neutronV20.update_dict(parsed_args, body,
['name', 'description'])
return {'security_group': body}
class ListSecurityGroupRule(neutronV20.ListCommand):
"""List security group rules that belong to a given tenant."""
resource = 'security_group_rule'
list_columns = ['id', 'security_group_id', 'direction',
'ethertype', 'port/protocol', 'remote']
# replace_rules: key is an attribute name in Neutron API and
# corresponding value is a display name shown by CLI.
replace_rules = {'security_group_id': 'security_group',
'remote_group_id': 'remote_group'}
digest_fields = {
# The entry 'protocol/port' is left deliberately for backwards
# compatibility.
'remote': {
'method': _get_remote,
'depends_on': ['remote_ip_prefix', 'remote_group_id']},
'port/protocol': {
'method': _get_protocol_port,
'depends_on': ['protocol', 'port_range_min', 'port_range_max']},
'protocol/port': {
'method': _get_protocol_port,
'depends_on': ['protocol', 'port_range_min', 'port_range_max']}}
pagination_support = True
sorting_support = True
def get_parser(self, prog_name):
parser = super(ListSecurityGroupRule, self).get_parser(prog_name)
parser.add_argument(
'--no-nameconv', action='store_true',
help=_('Do not convert security group ID to its name.'))
return parser
@staticmethod
def replace_columns(cols, rules, reverse=False):
if reverse:
rules = dict((rules[k], k) for k in rules.keys())
return [rules.get(col, col) for col in cols]
def get_required_fields(self, fields):
fields = self.replace_columns(fields, self.replace_rules, reverse=True)
for field, digest_fields in self.digest_fields.items():
if field in fields:
fields += digest_fields['depends_on']
fields.remove(field)
return fields
def retrieve_list(self, parsed_args):
parsed_args.fields = self.get_required_fields(parsed_args.fields)
return super(ListSecurityGroupRule, self).retrieve_list(parsed_args)
def _get_sg_name_dict(self, data, page_size, no_nameconv):
"""Get names of security groups referred in the retrieved rules.
:return: a dict from secgroup ID to secgroup name
"""
if no_nameconv:
return {}
neutron_client = self.get_client()
search_opts = {'fields': ['id', 'name']}
if self.pagination_support:
if page_size:
search_opts.update({'limit': page_size})
sec_group_ids = set()
for rule in data:
for key in self.replace_rules:
if rule.get(key):
sec_group_ids.add(rule[key])
sec_group_ids = list(sec_group_ids)
def _get_sec_group_list(sec_group_ids):
search_opts['id'] = sec_group_ids
return neutron_client.list_security_groups(
**search_opts).get('security_groups', [])
try:
secgroups = _get_sec_group_list(sec_group_ids)
except exceptions.RequestURITooLong as uri_len_exc:
# Length of a query filter on security group rule id
# id=<uuid>& (with len(uuid)=36)
sec_group_id_filter_len = 40
# The URI is too long because of too many sec_group_id filters
# Use the excess attribute of the exception to know how many
# sec_group_id filters can be inserted into a single request
sec_group_count = len(sec_group_ids)
max_size = ((sec_group_id_filter_len * sec_group_count) -
uri_len_exc.excess)
chunk_size = max_size // sec_group_id_filter_len
secgroups = []
for i in range(0, sec_group_count, chunk_size):
secgroups.extend(
_get_sec_group_list(sec_group_ids[i: i + chunk_size]))
return dict([(sg['id'], sg['name'])
for sg in secgroups if sg['name']])
@staticmethod
def _has_fields(rule, required_fields):
return all([key in rule for key in required_fields])
def extend_list(self, data, parsed_args):
sg_dict = self._get_sg_name_dict(data, parsed_args.page_size,
parsed_args.no_nameconv)
for rule in data:
# Replace security group UUID with its name.
for key in self.replace_rules:
if key in rule:
rule[key] = sg_dict.get(rule[key], rule[key])
for field, digest_rule in self.digest_fields.items():
if self._has_fields(rule, digest_rule['depends_on']):
rule[field] = digest_rule['method'](rule) or 'any'
def setup_columns(self, info, parsed_args):
# Translate the specified columns from the command line
# into field names used in "info".
parsed_args.columns = self.replace_columns(parsed_args.columns,
self.replace_rules,
reverse=True)
# NOTE(amotoki): 2nd element of the tuple returned by setup_columns()
# is a generator, so if you need to create a look using the generator
# object, you need to recreate a generator to show a list expectedly.
info = super(ListSecurityGroupRule, self).setup_columns(info,
parsed_args)
cols = info[0]
if not parsed_args.no_nameconv:
# Replace column names in the header line (in info[0])
cols = self.replace_columns(info[0], self.replace_rules)
parsed_args.columns = cols
return (cols, info[1])
class ShowSecurityGroupRule(neutronV20.ShowCommand):
"""Show information of a given security group rule."""
resource = 'security_group_rule'
allow_names = False
class CreateSecurityGroupRule(neutronV20.CreateCommand):
"""Create a security group rule."""
resource = 'security_group_rule'
def add_known_arguments(self, parser):
parser.add_argument(
'--description',
help=_('Description of security group rule.'))
parser.add_argument(
'security_group_id', metavar='SECURITY_GROUP',
help=_('ID or name of the security group to '
'which the rule is added.'))
parser.add_argument(
'--direction',
default='ingress', choices=['ingress', 'egress'],
help=_('Direction of traffic: ingress/egress.'))
parser.add_argument(
'--ethertype',
help=_('IPv4/IPv6'))
parser.add_argument(
'--protocol',
help=_('Protocol of packet. Allowed values are '
'[icmp, icmpv6, tcp, udp] and '
'integer representations [0-255].'))
parser.add_argument(
'--port-range-min',
help=_('Starting port range. For ICMP it is type.'))
parser.add_argument(
'--port_range_min',
help=argparse.SUPPRESS)
parser.add_argument(
'--port-range-max',
help=_('Ending port range. For ICMP it is code.'))
parser.add_argument(
'--port_range_max',
help=argparse.SUPPRESS)
parser.add_argument(
'--remote-ip-prefix',
help=_('CIDR to match on.'))
parser.add_argument(
'--remote_ip_prefix',
help=argparse.SUPPRESS)
parser.add_argument(
'--remote-group-id', metavar='REMOTE_GROUP',
help=_('ID or name of the remote security group '
'to which the rule is applied.'))
parser.add_argument(
'--remote_group_id',
help=argparse.SUPPRESS)
def args2body(self, parsed_args):
_security_group_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'security_group', parsed_args.security_group_id)
body = {'security_group_id': _security_group_id,
'direction': parsed_args.direction,
'ethertype': parsed_args.ethertype or
generate_default_ethertype(parsed_args.protocol)}
neutronV20.update_dict(parsed_args, body,
['protocol', 'port_range_min', 'port_range_max',
'remote_ip_prefix', 'tenant_id',
'description'])
if parsed_args.remote_group_id:
_remote_group_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'security_group',
parsed_args.remote_group_id)
body['remote_group_id'] = _remote_group_id
return {'security_group_rule': body}
class DeleteSecurityGroupRule(neutronV20.DeleteCommand):
"""Delete a given security group rule."""
resource = 'security_group_rule'
allow_names = False

View File

@ -1,27 +0,0 @@
# Copyright 2013 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.
#
from neutronclient.neutron import v2_0 as neutronV20
class ListServiceProvider(neutronV20.ListCommand):
"""List service providers."""
resource = 'service_provider'
list_columns = ['service_type', 'name', 'default']
_formatters = {}
pagination_support = True
sorting_support = True

View File

@ -1,274 +0,0 @@
# Copyright 2012 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.
#
import argparse
from oslo_serialization import jsonutils
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
def _format_allocation_pools(subnet):
try:
return '\n'.join([jsonutils.dumps(pool) for pool in
subnet['allocation_pools']])
except (TypeError, KeyError):
return ''
def _format_dns_nameservers(subnet):
try:
return '\n'.join([jsonutils.dumps(server) for server in
subnet['dns_nameservers']])
except (TypeError, KeyError):
return ''
def _format_host_routes(subnet):
try:
return '\n'.join([jsonutils.dumps(route) for route in
subnet['host_routes']])
except (TypeError, KeyError):
return ''
def add_updatable_arguments(parser):
parser.add_argument(
'--name',
help=_('Name of this subnet.'))
parser.add_argument(
'--description',
help=_('Description of this subnet.'))
gateway_sg = parser.add_mutually_exclusive_group()
gateway_sg.add_argument(
'--gateway', metavar='GATEWAY_IP',
help=_('Gateway IP of this subnet.'))
gateway_sg.add_argument(
'--no-gateway',
action='store_true',
help=_('Do not configure a gateway for this subnet.'))
parser.add_argument(
'--allocation-pool', metavar='start=IP_ADDR,end=IP_ADDR',
action='append', dest='allocation_pools',
type=utils.str2dict_type(required_keys=['start', 'end']),
help=_('Allocation pool IP addresses for this subnet '
'(This option can be repeated).'))
parser.add_argument(
'--allocation_pool',
action='append', dest='allocation_pools',
type=utils.str2dict_type(required_keys=['start', 'end']),
help=argparse.SUPPRESS)
parser.add_argument(
'--host-route', metavar='destination=CIDR,nexthop=IP_ADDR',
action='append', dest='host_routes',
type=utils.str2dict_type(required_keys=['destination', 'nexthop']),
help=_('Additional route (This option can be repeated).'))
parser.add_argument(
'--dns-nameserver', metavar='DNS_NAMESERVER',
action='append', dest='dns_nameservers',
help=_('DNS name server for this subnet '
'(This option can be repeated).'))
parser.add_argument(
'--disable-dhcp',
action='store_true',
help=_('Disable DHCP for this subnet.'))
parser.add_argument(
'--enable-dhcp',
action='store_true',
help=_('Enable DHCP for this subnet.'))
# NOTE(ihrachys): yes, that's awful, but should be left as-is for
# backwards compatibility for versions <=2.3.4 that passed the
# boolean values through to the server without any argument
# validation.
parser.add_argument(
'--enable-dhcp=True',
action='store_true',
dest='enable_dhcp',
help=argparse.SUPPRESS)
parser.add_argument(
'--enable-dhcp=False',
action='store_true',
dest='disable_dhcp',
help=argparse.SUPPRESS)
def updatable_args2body(parsed_args, body, for_create=True, ip_version=None):
if parsed_args.disable_dhcp and parsed_args.enable_dhcp:
raise exceptions.CommandError(_(
"You cannot enable and disable DHCP at the same time."))
neutronV20.update_dict(parsed_args, body,
['name', 'allocation_pools',
'host_routes', 'dns_nameservers',
'description'])
if parsed_args.no_gateway:
body['gateway_ip'] = None
elif parsed_args.gateway:
body['gateway_ip'] = parsed_args.gateway
if parsed_args.disable_dhcp:
body['enable_dhcp'] = False
if parsed_args.enable_dhcp:
body['enable_dhcp'] = True
if for_create and parsed_args.ipv6_ra_mode:
if ip_version == 4:
raise exceptions.CommandError(_("--ipv6-ra-mode is invalid "
"when --ip-version is 4"))
body['ipv6_ra_mode'] = parsed_args.ipv6_ra_mode
if for_create and parsed_args.ipv6_address_mode:
if ip_version == 4:
raise exceptions.CommandError(_("--ipv6-address-mode is "
"invalid when --ip-version "
"is 4"))
body['ipv6_address_mode'] = parsed_args.ipv6_address_mode
class ListSubnet(neutronV20.ListCommand):
"""List subnets that belong to a given tenant."""
resource = 'subnet'
_formatters = {'allocation_pools': _format_allocation_pools,
'dns_nameservers': _format_dns_nameservers,
'host_routes': _format_host_routes, }
list_columns = ['id', 'name', 'cidr', 'allocation_pools']
pagination_support = True
sorting_support = True
class ShowSubnet(neutronV20.ShowCommand):
"""Show information of a given subnet."""
resource = 'subnet'
class CreateSubnet(neutronV20.CreateCommand):
"""Create a subnet for a given tenant."""
resource = 'subnet'
def add_known_arguments(self, parser):
add_updatable_arguments(parser)
parser.add_argument(
'--ip-version',
type=int,
default=4, choices=[4, 6],
help=_('IP version to use, default is 4. '
'Note that when subnetpool is specified, '
'IP version is determined from the subnetpool '
'and this option is ignored.'))
parser.add_argument(
'--ip_version',
type=int,
choices=[4, 6],
help=argparse.SUPPRESS)
parser.add_argument(
'network_id', metavar='NETWORK',
help=_('Network ID or name this subnet belongs to.'))
parser.add_argument(
'cidr', nargs='?', metavar='CIDR',
help=_('CIDR of subnet to create.'))
parser.add_argument(
'--ipv6-ra-mode',
choices=['dhcpv6-stateful', 'dhcpv6-stateless', 'slaac'],
help=_('IPv6 RA (Router Advertisement) mode.'))
parser.add_argument(
'--ipv6-address-mode',
choices=['dhcpv6-stateful', 'dhcpv6-stateless', 'slaac'],
help=_('IPv6 address mode.'))
parser.add_argument(
'--subnetpool', metavar='SUBNETPOOL',
help=_('ID or name of subnetpool from which this subnet '
'will obtain a CIDR.'))
parser.add_argument(
'--use-default-subnetpool',
action='store_true',
help=_('Use default subnetpool for ip_version, if it exists.'))
parser.add_argument(
'--prefixlen', metavar='PREFIX_LENGTH',
help=_('Prefix length for subnet allocation from subnetpool.'))
parser.add_argument(
'--segment', metavar='SEGMENT',
help=_('ID of segment with which this subnet will be associated.'))
def args2body(self, parsed_args):
_network_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'network', parsed_args.network_id)
body = {'network_id': _network_id}
if parsed_args.prefixlen:
body['prefixlen'] = parsed_args.prefixlen
ip_version = parsed_args.ip_version
if parsed_args.use_default_subnetpool:
body['use_default_subnetpool'] = True
if parsed_args.segment:
body['segment_id'] = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'segment', parsed_args.segment)
if parsed_args.subnetpool:
if parsed_args.subnetpool == 'None':
_subnetpool_id = None
else:
_subnetpool = neutronV20.find_resource_by_name_or_id(
self.get_client(), 'subnetpool', parsed_args.subnetpool)
_subnetpool_id = _subnetpool['id']
# Now that we have the pool_id - let's just have a check on the
# ip version used in the pool
ip_version = _subnetpool['ip_version']
body['subnetpool_id'] = _subnetpool_id
# IP version needs to be set as IP version can be
# determined by subnetpool.
body['ip_version'] = ip_version
if parsed_args.cidr:
# With subnetpool, cidr is now optional for creating subnet.
cidr = parsed_args.cidr
body['cidr'] = cidr
unusable_cidr = '/32' if ip_version == 4 else '/128'
if cidr.endswith(unusable_cidr):
self.log.warning(_("An IPv%(ip)d subnet with a %(cidr)s CIDR "
"will have only one usable IP address so "
"the device attached to it will not have "
"any IP connectivity."),
{"ip": ip_version,
"cidr": unusable_cidr})
updatable_args2body(parsed_args, body, ip_version=ip_version)
if parsed_args.tenant_id:
body['tenant_id'] = parsed_args.tenant_id
return {'subnet': body}
class DeleteSubnet(neutronV20.DeleteCommand):
"""Delete a given subnet."""
resource = 'subnet'
class UpdateSubnet(neutronV20.UpdateCommand):
"""Update subnet's information."""
resource = 'subnet'
def add_known_arguments(self, parser):
add_updatable_arguments(parser)
def args2body(self, parsed_args):
body = {}
updatable_args2body(parsed_args, body, for_create=False)
return {'subnet': body}

View File

@ -1,153 +0,0 @@
# Copyright 2015 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.
#
from neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronV20
def _format_prefixes(subnetpool):
try:
return '\n'.join(pool for pool in subnetpool['prefixes'])
except (TypeError, KeyError):
return subnetpool['prefixes']
def add_updatable_arguments(parser, for_create=False):
parser.add_argument(
'--description',
help=_('Description of subnetpool.'))
parser.add_argument(
'--min-prefixlen', type=int,
help=_('Subnetpool minimum prefix length.'))
parser.add_argument(
'--max-prefixlen', type=int,
help=_('Subnetpool maximum prefix length.'))
parser.add_argument(
'--default-prefixlen', type=int,
help=_('Subnetpool default prefix length.'))
parser.add_argument(
'--pool-prefix',
action='append', dest='prefixes',
required=for_create,
help=_('Subnetpool prefixes (This option can be repeated).'))
utils.add_boolean_argument(
parser, '--is-default',
help=_('Specify whether this should be the default subnetpool '
'(True meaning default).'))
def updatable_args2body(parsed_args, body):
neutronV20.update_dict(parsed_args, body,
['name', 'prefixes', 'default_prefixlen',
'min_prefixlen', 'max_prefixlen', 'is_default',
'description'])
class ListSubnetPool(neutronV20.ListCommand):
"""List subnetpools that belong to a given tenant."""
_formatters = {'prefixes': _format_prefixes, }
resource = 'subnetpool'
list_columns = ['id', 'name', 'prefixes',
'default_prefixlen', 'address_scope_id', 'is_default']
pagination_support = True
sorting_support = True
class ShowSubnetPool(neutronV20.ShowCommand):
"""Show information of a given subnetpool."""
resource = 'subnetpool'
class CreateSubnetPool(neutronV20.CreateCommand):
"""Create a subnetpool for a given tenant."""
resource = 'subnetpool'
def add_known_arguments(self, parser):
add_updatable_arguments(parser, for_create=True)
parser.add_argument(
'--shared',
action='store_true',
help=_('Set the subnetpool as shared.'))
parser.add_argument(
'name',
metavar='NAME',
help=_('Name of the subnetpool to be created.'))
parser.add_argument(
'--address-scope',
metavar='ADDRSCOPE',
help=_('ID or name of the address scope with which the subnetpool '
'is associated. Prefixes must be unique across address '
'scopes.'))
def args2body(self, parsed_args):
body = {'prefixes': parsed_args.prefixes}
updatable_args2body(parsed_args, body)
if parsed_args.shared:
body['shared'] = True
# Parse and update for "address-scope" option
if parsed_args.address_scope:
_addrscope_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'address_scope',
parsed_args.address_scope)
body['address_scope_id'] = _addrscope_id
return {'subnetpool': body}
class DeleteSubnetPool(neutronV20.DeleteCommand):
"""Delete a given subnetpool."""
resource = 'subnetpool'
class UpdateSubnetPool(neutronV20.UpdateCommand):
"""Update subnetpool's information."""
resource = 'subnetpool'
def add_known_arguments(self, parser):
add_updatable_arguments(parser)
parser.add_argument('--name',
help=_('Updated name of the subnetpool.'))
addrscope_args = parser.add_mutually_exclusive_group()
addrscope_args.add_argument('--address-scope',
metavar='ADDRSCOPE',
help=_('ID or name of the address scope '
'with which the subnetpool is '
'associated. Prefixes must be '
'unique across address scopes.'))
addrscope_args.add_argument('--no-address-scope',
action='store_true',
help=_('Detach subnetpool from the '
'address scope.'))
def args2body(self, parsed_args):
body = {}
updatable_args2body(parsed_args, body)
# Parse and update for "address-scope" option/s
if parsed_args.no_address_scope:
body['address_scope_id'] = None
elif parsed_args.address_scope:
_addrscope_id = neutronV20.find_resourceid_by_name_or_id(
self.get_client(), 'address_scope',
parsed_args.address_scope)
body['address_scope_id'] = _addrscope_id
return {'subnetpool': body}

View File

@ -1,104 +0,0 @@
# 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 neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.neutron import v2_0 as neutronv20
# List of resources can be set tag
TAG_RESOURCES = ['network']
def _convert_resource_args(client, parsed_args):
resource_type = client.get_resource_plural(parsed_args.resource_type)
resource_id = neutronv20.find_resourceid_by_name_or_id(
client, parsed_args.resource_type, parsed_args.resource)
return resource_type, resource_id
def _add_common_arguments(parser):
parser.add_argument('--resource-type',
choices=TAG_RESOURCES,
dest='resource_type',
required=True,
help=_('Resource Type.'))
parser.add_argument('--resource',
required=True,
help=_('Resource name or ID.'))
class AddTag(neutronv20.NeutronCommand):
"""Add a tag into the resource."""
def get_parser(self, prog_name):
parser = super(AddTag, self).get_parser(prog_name)
_add_common_arguments(parser)
parser.add_argument('--tag',
required=True,
help=_('Tag to be added.'))
return parser
def take_action(self, parsed_args):
client = self.get_client()
resource_type, resource_id = _convert_resource_args(client,
parsed_args)
client.add_tag(resource_type, resource_id, parsed_args.tag)
class ReplaceTag(neutronv20.NeutronCommand):
"""Replace all tags on the resource."""
def get_parser(self, prog_name):
parser = super(ReplaceTag, self).get_parser(prog_name)
_add_common_arguments(parser)
parser.add_argument('--tag',
metavar='TAG',
action='append',
dest='tags',
required=True,
help=_('Tag (This option can be repeated).'))
return parser
def take_action(self, parsed_args):
client = self.get_client()
resource_type, resource_id = _convert_resource_args(client,
parsed_args)
body = {'tags': parsed_args.tags}
client.replace_tag(resource_type, resource_id, body)
class RemoveTag(neutronv20.NeutronCommand):
"""Remove a tag on the resource."""
def get_parser(self, prog_name):
parser = super(RemoveTag, self).get_parser(prog_name)
_add_common_arguments(parser)
tag_opt = parser.add_mutually_exclusive_group()
tag_opt.add_argument('--all',
action='store_true',
help=_('Remove all tags on the resource.'))
tag_opt.add_argument('--tag',
help=_('Tag to be removed.'))
return parser
def take_action(self, parsed_args):
if not parsed_args.all and not parsed_args.tag:
raise exceptions.CommandError(
_("--all or --tag must be specified"))
client = self.get_client()
resource_type, resource_id = _convert_resource_args(client,
parsed_args)
if parsed_args.all:
client.remove_tag_all(resource_type, resource_id)
else:
client.remove_tag(resource_type, resource_id, parsed_args.tag)

View File

@ -1,100 +0,0 @@
# (c) Copyright 2015 Cisco Systems, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronv20
def add_known_endpoint_group_arguments(parser, is_create=True):
parser.add_argument(
'--name',
help=_('Set a name for the endpoint group.'))
parser.add_argument(
'--description',
help=_('Set a description for the endpoint group.'))
if is_create:
parser.add_argument(
'--type',
required=is_create,
help=_('Type of endpoints in group (e.g. subnet, cidr, vlan).'))
parser.add_argument(
'--value',
action='append', dest='endpoints',
required=is_create,
help=_('Endpoint(s) for the group. Must all be of the same type.'))
class ListEndpointGroup(neutronv20.ListCommand):
"""List VPN endpoint groups that belong to a given tenant."""
resource = 'endpoint_group'
list_columns = ['id', 'name', 'type', 'endpoints']
_formatters = {}
pagination_support = True
sorting_support = True
class ShowEndpointGroup(neutronv20.ShowCommand):
"""Show a specific VPN endpoint group."""
resource = 'endpoint_group'
class CreateEndpointGroup(neutronv20.CreateCommand):
"""Create a VPN endpoint group."""
resource = 'endpoint_group'
def add_known_arguments(self, parser):
add_known_endpoint_group_arguments(parser)
def subnet_name2id(self, endpoint):
return neutronv20.find_resourceid_by_name_or_id(self.get_client(),
'subnet', endpoint)
def args2body(self, parsed_args):
if parsed_args.type == 'subnet':
endpoints = [self.subnet_name2id(ep)
for ep in parsed_args.endpoints]
else:
endpoints = parsed_args.endpoints
body = {'endpoints': endpoints}
neutronv20.update_dict(parsed_args, body,
['name', 'description',
'tenant_id', 'type'])
return {self.resource: body}
class UpdateEndpointGroup(neutronv20.UpdateCommand):
"""Update a given VPN endpoint group."""
resource = 'endpoint_group'
def add_known_arguments(self, parser):
add_known_endpoint_group_arguments(parser, is_create=False)
def args2body(self, parsed_args):
body = {}
neutronv20.update_dict(parsed_args, body,
['name', 'description'])
return {self.resource: body}
class DeleteEndpointGroup(neutronv20.DeleteCommand):
"""Delete a given VPN endpoint group."""
resource = 'endpoint_group'

View File

@ -1,119 +0,0 @@
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
# 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 neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronv20
from neutronclient.neutron.v2_0.vpn import utils as vpn_utils
class ListIKEPolicy(neutronv20.ListCommand):
"""List IKE policies that belong to a tenant."""
resource = 'ikepolicy'
list_columns = ['id', 'name', 'auth_algorithm',
'encryption_algorithm', 'ike_version', 'pfs']
_formatters = {}
pagination_support = True
sorting_support = True
class ShowIKEPolicy(neutronv20.ShowCommand):
"""Show information of a given IKE policy."""
resource = 'ikepolicy'
help_resource = 'IKE policy'
class CreateIKEPolicy(neutronv20.CreateCommand):
"""Create an IKE policy."""
resource = 'ikepolicy'
def add_known_arguments(self, parser):
parser.add_argument(
'--description',
help=_('Description of the IKE policy'))
parser.add_argument(
'--auth-algorithm',
default='sha1', choices=['sha1', 'sha256'],
help=_('Authentication algorithm in lowercase. '
'Default:sha1'))
parser.add_argument(
'--encryption-algorithm',
default='aes-128',
help=_('Encryption algorithm in lowercase, default:aes-128'))
parser.add_argument(
'--phase1-negotiation-mode',
default='main', choices=['main'],
help=_('IKE Phase1 negotiation mode in lowercase, default:main'))
parser.add_argument(
'--ike-version',
default='v1', choices=['v1', 'v2'],
help=_('IKE version in lowercase, default:v1'))
parser.add_argument(
'--pfs',
default='group5', choices=['group2', 'group5', 'group14'],
help=_('Perfect Forward Secrecy in lowercase, default:group5'))
parser.add_argument(
'--lifetime',
metavar="units=UNITS,value=VALUE",
type=utils.str2dict_type(optional_keys=['units', 'value']),
help=vpn_utils.lifetime_help("IKE"))
parser.add_argument(
'name', metavar='NAME',
help=_('Name of the IKE policy.'))
def args2body(self, parsed_args):
body = {}
neutronv20.update_dict(parsed_args, body,
['auth_algorithm', 'encryption_algorithm',
'phase1_negotiation_mode', 'ike_version',
'pfs', 'name', 'description', 'tenant_id'])
if parsed_args.lifetime:
vpn_utils.validate_lifetime_dict(parsed_args.lifetime)
body['lifetime'] = parsed_args.lifetime
return {'ikepolicy': body}
class UpdateIKEPolicy(neutronv20.UpdateCommand):
"""Update a given IKE policy."""
resource = 'ikepolicy'
help_resource = 'IKE policy'
def add_known_arguments(self, parser):
parser.add_argument(
'--lifetime',
metavar="units=UNITS,value=VALUE",
type=utils.str2dict_type(optional_keys=['units', 'value']),
help=vpn_utils.lifetime_help("IKE"))
def args2body(self, parsed_args):
body = {}
if parsed_args.lifetime:
vpn_utils.validate_lifetime_dict(parsed_args.lifetime)
body['lifetime'] = parsed_args.lifetime
return {'ikepolicy': body}
class DeleteIKEPolicy(neutronv20.DeleteCommand):
"""Delete a given IKE policy."""
resource = 'ikepolicy'
help_resource = 'IKE policy'

View File

@ -1,208 +0,0 @@
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
# 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_serialization import jsonutils
from neutronclient._i18n import _
from neutronclient.common import exceptions
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronv20
from neutronclient.neutron.v2_0.vpn import utils as vpn_utils
def _format_peer_cidrs(ipsec_site_connection):
try:
return '\n'.join([jsonutils.dumps(cidrs) for cidrs in
ipsec_site_connection['peer_cidrs']])
except (TypeError, KeyError):
return ''
class ListIPsecSiteConnection(neutronv20.ListCommand):
"""List IPsec site connections that belong to a given tenant."""
resource = 'ipsec_site_connection'
_formatters = {'peer_cidrs': _format_peer_cidrs}
list_columns = [
'id', 'name', 'peer_address', 'auth_mode', 'status']
pagination_support = True
sorting_support = True
class ShowIPsecSiteConnection(neutronv20.ShowCommand):
"""Show information of a given IPsec site connection."""
resource = 'ipsec_site_connection'
help_resource = 'IPsec site connection'
class IPsecSiteConnectionMixin(object):
def add_known_arguments(self, parser):
parser.add_argument(
'--dpd',
metavar="action=ACTION,interval=INTERVAL,timeout=TIMEOUT",
type=utils.str2dict_type(
optional_keys=['action', 'interval', 'timeout']),
help=vpn_utils.dpd_help("IPsec connection."))
parser.add_argument(
'--local-ep-group',
help=_('Local endpoint group ID/name with subnet(s) for '
'the IPsec connection.'))
parser.add_argument(
'--peer-ep-group',
help=_('Peer endpoint group ID/name with CIDR(s) for '
'the IPsec connection.'))
def args2body(self, parsed_args, body=None):
"""Add in conditional args and then return all conn info."""
if body is None:
body = {}
if parsed_args.dpd:
vpn_utils.validate_dpd_dict(parsed_args.dpd)
body['dpd'] = parsed_args.dpd
if parsed_args.local_ep_group:
_local_epg = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'endpoint_group',
parsed_args.local_ep_group)
body['local_ep_group_id'] = _local_epg
if parsed_args.peer_ep_group:
_peer_epg = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'endpoint_group',
parsed_args.peer_ep_group)
body['peer_ep_group_id'] = _peer_epg
return {self.resource: body}
class CreateIPsecSiteConnection(IPsecSiteConnectionMixin,
neutronv20.CreateCommand):
"""Create an IPsec site connection."""
resource = 'ipsec_site_connection'
def add_known_arguments(self, parser):
parser.add_argument(
'--admin-state-down',
default=True, action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--name',
help=_('Set a name for the connection.'))
parser.add_argument(
'--description',
help=_('Set a description for the connection.'))
parser.add_argument(
'--mtu',
default='1500',
help=_('MTU size for the connection, default:1500'))
parser.add_argument(
'--initiator',
default='bi-directional', choices=['bi-directional',
'response-only'],
help=_('Initiator state in lowercase, default:bi-directional'))
parser.add_argument(
'--vpnservice-id', metavar='VPNSERVICE',
required=True,
help=_('VPN service instance ID associated with this connection.'))
parser.add_argument(
'--ikepolicy-id', metavar='IKEPOLICY',
required=True,
help=_('IKE policy ID associated with this connection.'))
parser.add_argument(
'--ipsecpolicy-id', metavar='IPSECPOLICY',
required=True,
help=_('IPsec policy ID associated with this connection.'))
parser.add_argument(
'--peer-address',
required=True,
help=_('Peer gateway public IPv4/IPv6 address or FQDN.'))
parser.add_argument(
'--peer-id',
required=True,
help=_('Peer router identity for authentication. Can be '
'IPv4/IPv6 address, e-mail address, key id, or FQDN.'))
parser.add_argument(
'--peer-cidr',
action='append', dest='peer_cidrs',
help=_('[DEPRECATED in Mitaka] Remote subnet(s) in CIDR format. '
'Cannot be specified when using endpoint groups. Only '
'applicable, if subnet provided for VPN service.'))
parser.add_argument(
'--psk',
required=True,
help=_('Pre-shared key string.'))
super(CreateIPsecSiteConnection, self).add_known_arguments(parser)
def args2body(self, parsed_args):
_vpnservice_id = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'vpnservice',
parsed_args.vpnservice_id)
_ikepolicy_id = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'ikepolicy',
parsed_args.ikepolicy_id)
_ipsecpolicy_id = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'ipsecpolicy',
parsed_args.ipsecpolicy_id)
if int(parsed_args.mtu) < 68:
message = _("Invalid MTU value: MTU must be "
"greater than or equal to 68")
raise exceptions.CommandError(message)
if (bool(parsed_args.local_ep_group) !=
bool(parsed_args.peer_ep_group)):
message = _("You must specify both local and peer endpoint "
"groups.")
raise exceptions.CommandError(message)
if parsed_args.peer_cidrs and parsed_args.local_ep_group:
message = _("You cannot specify both endpoint groups and peer "
"CIDR(s).")
raise exceptions.CommandError(message)
if not parsed_args.peer_cidrs and not parsed_args.local_ep_group:
message = _("You must specify endpoint groups or peer CIDR(s).")
raise exceptions.CommandError(message)
body = {
'vpnservice_id': _vpnservice_id,
'ikepolicy_id': _ikepolicy_id,
'ipsecpolicy_id': _ipsecpolicy_id,
'admin_state_up': parsed_args.admin_state_down,
}
neutronv20.update_dict(parsed_args, body,
['peer_id', 'mtu', 'initiator', 'psk',
'peer_address'])
if parsed_args.name:
body['name'] = parsed_args.name
if parsed_args.description:
body['description'] = parsed_args.description
if parsed_args.tenant_id:
body['tenant_id'] = parsed_args.tenant_id
if parsed_args.peer_cidrs:
body['peer_cidrs'] = parsed_args.peer_cidrs
return super(CreateIPsecSiteConnection, self).args2body(parsed_args,
body)
class UpdateIPsecSiteConnection(IPsecSiteConnectionMixin,
neutronv20.UpdateCommand):
"""Update a given IPsec site connection."""
resource = 'ipsec_site_connection'
help_resource = 'IPsec site connection'
class DeleteIPsecSiteConnection(neutronv20.DeleteCommand):
"""Delete a given IPsec site connection."""
resource = 'ipsec_site_connection'
help_resource = 'IPsec site connection'

View File

@ -1,118 +0,0 @@
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
# 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 neutronclient._i18n import _
from neutronclient.common import utils
from neutronclient.neutron import v2_0 as neutronv20
from neutronclient.neutron.v2_0.vpn import utils as vpn_utils
class ListIPsecPolicy(neutronv20.ListCommand):
"""List IPsec policies that belong to a given tenant connection."""
resource = 'ipsecpolicy'
list_columns = ['id', 'name', 'auth_algorithm',
'encryption_algorithm', 'pfs']
_formatters = {}
pagination_support = True
sorting_support = True
class ShowIPsecPolicy(neutronv20.ShowCommand):
"""Show information of a given IPsec policy."""
resource = 'ipsecpolicy'
help_resource = 'IPsec policy'
class CreateIPsecPolicy(neutronv20.CreateCommand):
"""Create an IPsec policy."""
resource = 'ipsecpolicy'
def add_known_arguments(self, parser):
parser.add_argument(
'--description',
help=_('Description of the IPsec policy.'))
parser.add_argument(
'--transform-protocol',
default='esp', choices=['esp', 'ah', 'ah-esp'],
help=_('Transform protocol in lowercase, default:esp'))
parser.add_argument(
'--auth-algorithm',
default='sha1', choices=['sha1', 'sha256'],
help=_('Authentication algorithm in lowercase, default:sha1'))
parser.add_argument(
'--encryption-algorithm',
default='aes-128',
help=_('Encryption algorithm in lowercase, default:aes-128'))
parser.add_argument(
'--encapsulation-mode',
default='tunnel', choices=['tunnel', 'transport'],
help=_('Encapsulation mode in lowercase, default:tunnel'))
parser.add_argument(
'--pfs',
default='group5', choices=['group2', 'group5', 'group14'],
help=_('Perfect Forward Secrecy in lowercase, default:group5'))
parser.add_argument(
'--lifetime',
metavar="units=UNITS,value=VALUE",
type=utils.str2dict_type(optional_keys=['units', 'value']),
help=vpn_utils.lifetime_help("IPsec"))
parser.add_argument(
'name', metavar='NAME',
help=_('Name of the IPsec policy.'))
def args2body(self, parsed_args):
body = {}
neutronv20.update_dict(parsed_args, body,
['auth_algorithm', 'encryption_algorithm',
'encapsulation_mode', 'transform_protocol',
'pfs', 'name', 'description', 'tenant_id'])
if parsed_args.lifetime:
vpn_utils.validate_lifetime_dict(parsed_args.lifetime)
body['lifetime'] = parsed_args.lifetime
return {'ipsecpolicy': body}
class UpdateIPsecPolicy(neutronv20.UpdateCommand):
"""Update a given IPsec policy."""
resource = 'ipsecpolicy'
help_resource = 'IPsec policy'
def add_known_arguments(self, parser):
parser.add_argument(
'--lifetime',
metavar="units=UNITS,value=VALUE",
type=utils.str2dict_type(optional_keys=['units', 'value']),
help=vpn_utils.lifetime_help("IPsec"))
def args2body(self, parsed_args):
body = {}
if parsed_args.lifetime:
vpn_utils.validate_lifetime_dict(parsed_args.lifetime)
body['lifetime'] = parsed_args.lifetime
return {'ipsecpolicy': body}
class DeleteIPsecPolicy(neutronv20.DeleteCommand):
"""Delete a given IPsec policy."""
resource = 'ipsecpolicy'
help_resource = 'IPsec policy'

View File

@ -1,112 +0,0 @@
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
# 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.
#
"""VPN Utilities and helper functions."""
from neutronclient._i18n import _
from neutronclient.common import exceptions
dpd_supported_actions = ['hold', 'clear', 'restart',
'restart-by-peer', 'disabled']
dpd_supported_keys = ['action', 'interval', 'timeout']
lifetime_keys = ['units', 'value']
lifetime_units = ['seconds']
def validate_dpd_dict(dpd_dict):
for key, value in dpd_dict.items():
if key not in dpd_supported_keys:
message = _(
"DPD Dictionary KeyError: "
"Reason-Invalid DPD key : "
"'%(key)s' not in %(supported_key)s") % {
'key': key, 'supported_key': dpd_supported_keys}
raise exceptions.CommandError(message)
if key == 'action' and value not in dpd_supported_actions:
message = _(
"DPD Dictionary ValueError: "
"Reason-Invalid DPD action : "
"'%(key_value)s' not in %(supported_action)s") % {
'key_value': value,
'supported_action': dpd_supported_actions}
raise exceptions.CommandError(message)
if key in ('interval', 'timeout'):
try:
if int(value) <= 0:
raise ValueError()
except ValueError:
message = _(
"DPD Dictionary ValueError: "
"Reason-Invalid positive integer value: "
"'%(key)s' = %(value)s") % {
'key': key, 'value': value}
raise exceptions.CommandError(message)
else:
dpd_dict[key] = int(value)
return
def validate_lifetime_dict(lifetime_dict):
for key, value in lifetime_dict.items():
if key not in lifetime_keys:
message = _(
"Lifetime Dictionary KeyError: "
"Reason-Invalid unit key : "
"'%(key)s' not in %(supported_key)s") % {
'key': key, 'supported_key': lifetime_keys}
raise exceptions.CommandError(message)
if key == 'units' and value not in lifetime_units:
message = _(
"Lifetime Dictionary ValueError: "
"Reason-Invalid units : "
"'%(key_value)s' not in %(supported_units)s") % {
'key_value': key, 'supported_units': lifetime_units}
raise exceptions.CommandError(message)
if key == 'value':
try:
if int(value) < 60:
raise ValueError()
except ValueError:
message = _(
"Lifetime Dictionary ValueError: "
"Reason-Invalid value should be at least 60:"
"'%(key_value)s' = %(value)s") % {
'key_value': key, 'value': value}
raise exceptions.CommandError(message)
else:
lifetime_dict['value'] = int(value)
return
def lifetime_help(policy):
lifetime = _("%s lifetime attributes. "
"'units'-seconds, default:seconds. "
"'value'-non negative integer, default:3600.") % policy
return lifetime
def dpd_help(policy):
dpd = _(" %s Dead Peer Detection attributes."
" 'action'-hold,clear,disabled,restart,restart-by-peer."
" 'interval' and 'timeout' are non negative integers. "
" 'interval' should be less than 'timeout' value. "
" 'action', default:hold 'interval', default:30, "
" 'timeout', default:120.") % policy.capitalize()
return dpd

View File

@ -1,94 +0,0 @@
# (c) Copyright 2013 Hewlett-Packard Development Company, L.P.
# 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 neutronclient._i18n import _
from neutronclient.neutron import v2_0 as neutronv20
class ListVPNService(neutronv20.ListCommand):
"""List VPN service configurations that belong to a given tenant."""
resource = 'vpnservice'
list_columns = [
'id', 'name', 'router_id', 'status'
]
_formatters = {}
pagination_support = True
sorting_support = True
class ShowVPNService(neutronv20.ShowCommand):
"""Show information of a given VPN service."""
resource = 'vpnservice'
help_resource = 'VPN service'
class CreateVPNService(neutronv20.CreateCommand):
"""Create a VPN service."""
resource = 'vpnservice'
def add_known_arguments(self, parser):
parser.add_argument(
'--admin-state-down',
dest='admin_state', action='store_false',
help=_('Set admin state up to false.'))
parser.add_argument(
'--name',
help=_('Set a name for the VPN service.'))
parser.add_argument(
'--description',
help=_('Set a description for the VPN service.'))
parser.add_argument(
'router', metavar='ROUTER',
help=_('Router unique identifier for the VPN service.'))
parser.add_argument(
'subnet', nargs='?', metavar='SUBNET',
help=_('[DEPRECATED in Mitaka] Unique identifier for the local '
'private subnet.'))
def args2body(self, parsed_args):
if parsed_args.subnet:
_subnet_id = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'subnet', parsed_args.subnet)
else:
_subnet_id = None
_router_id = neutronv20.find_resourceid_by_name_or_id(
self.get_client(), 'router',
parsed_args.router)
body = {'subnet_id': _subnet_id,
'router_id': _router_id,
'admin_state_up': parsed_args.admin_state}
neutronv20.update_dict(parsed_args, body,
['name', 'description',
'tenant_id'])
return {self.resource: body}
class UpdateVPNService(neutronv20.UpdateCommand):
"""Update a given VPN service."""
resource = 'vpnservice'
help_resource = 'VPN service'
class DeleteVPNService(neutronv20.DeleteCommand):
"""Delete a given VPN service."""
resource = 'vpnservice'
help_resource = 'VPN service'

View File

@ -1,61 +0,0 @@
# 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 logging
# TODO(rtheis/amotoki): Add functional test infrastructure for OSC
# plugin commands.
# TODO(amotoki): Add and update document on OSC pluign.
from osc_lib import utils
LOG = logging.getLogger(__name__)
DEFAULT_API_VERSION = '2.0'
API_VERSION_OPTION = 'os_network_api_version'
# NOTE(rtheis): API_NAME must NOT be set to 'network' since
# 'network' is owned by OSC! The OSC 'network' client uses
# the OpenStack SDK.
API_NAME = 'neutronclient'
API_VERSIONS = {
'2.0': 'neutronclient.v2_0.client.Client',
'2': 'neutronclient.v2_0.client.Client',
}
def make_client(instance):
"""Returns an neutron client."""
neutron_client = utils.get_client_class(
API_NAME,
instance._api_version[API_NAME],
API_VERSIONS)
LOG.debug('Instantiating neutron client: %s', neutron_client)
# TODO(amotoki): Check the following arguments need to be passed
# to neutronclient class. Check keystoneauth code.
# - endpoint_type (do we need to specify it explicitly?)
# - auth (session object contains auth. Is it required?)
client = neutron_client(session=instance.session,
region_name=instance._region_name,
endpoint_type=instance._interface,
insecure=instance._insecure,
ca_cert=instance._cacert)
return client
def build_option_parser(parser):
"""Hook to add global options"""
# NOTE(amotoki): At now we register no option.
# OSC itself has an option for Network API version # and we refer to it.
return parser

Some files were not shown because too many files have changed in this diff Show More