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: I7b546c64ae8c98626f5cbeb9e0c47f7c8d67cb74
This commit is contained in:
parent
6dc5844231
commit
9e2d943f2f
|
@ -1,7 +0,0 @@
|
|||
[run]
|
||||
branch = True
|
||||
source = congressclient
|
||||
omit = congressclient/tests/*
|
||||
|
||||
[report]
|
||||
ignore_errors = True
|
|
@ -1,57 +0,0 @@
|
|||
# Congress build/runtime artifacts
|
||||
subunit.log
|
||||
|
||||
*.py[cod]
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Packages
|
||||
*.egg
|
||||
*.egg-info
|
||||
dist
|
||||
build
|
||||
eggs
|
||||
parts
|
||||
bin
|
||||
var
|
||||
sdist
|
||||
develop-eggs
|
||||
.installed.cfg
|
||||
.eggs
|
||||
/lib
|
||||
/lib64
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
.coverage
|
||||
.tox
|
||||
nosetests.xml
|
||||
.testrepository
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
# Mr Developer
|
||||
.mr.developer.cfg
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
# Complexity
|
||||
output/*.html
|
||||
output/*/index.html
|
||||
|
||||
# Sphinx
|
||||
doc/build
|
||||
|
||||
# pbr generates these
|
||||
AUTHORS
|
||||
ChangeLog
|
||||
|
||||
# Editors
|
||||
*~
|
||||
.*.swp
|
||||
*.swo
|
||||
*.swn
|
|
@ -1,4 +0,0 @@
|
|||
[gerrit]
|
||||
host=review.openstack.org
|
||||
port=29418
|
||||
project=openstack/python-congressclient.git
|
3
.mailmap
3
.mailmap
|
@ -1,3 +0,0 @@
|
|||
# Format is:
|
||||
# <preferred e-mail> <other e-mail 1>
|
||||
# <preferred e-mail> <other e-mail 2>
|
|
@ -1,7 +0,0 @@
|
|||
[DEFAULT]
|
||||
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
|
||||
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
|
||||
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
|
||||
${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION
|
||||
test_id_option=--load-list $IDFILE
|
||||
test_list_option=--list
|
|
@ -1,16 +0,0 @@
|
|||
If you would like to contribute to the development of OpenStack,
|
||||
you must follow the steps in this page:
|
||||
|
||||
http://docs.openstack.org/infra/manual/developers.html
|
||||
|
||||
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-congressclient
|
|
@ -1,4 +0,0 @@
|
|||
python-congressclient Style Commandments
|
||||
===============================================
|
||||
|
||||
Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
|
175
LICENSE
175
LICENSE
|
@ -1,175 +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.
|
12
Makefile
12
Makefile
|
@ -1,12 +0,0 @@
|
|||
|
||||
TOPDIR=$(CURDIR)
|
||||
SRCDIR=$(TOPDIR)/congressclient
|
||||
|
||||
all: docs
|
||||
|
||||
clean: rm -Rf $(TOPDIR)/doc/html/*
|
||||
|
||||
docs: $(TOPDIR)/doc/source/*.rst
|
||||
sphinx-build -b html $(TOPDIR)/doc/source $(TOPDIR)/doc/html
|
||||
|
||||
|
61
NEWS
61
NEWS
|
@ -1,61 +0,0 @@
|
|||
1.0.4 - XXXX-XX-XX
|
||||
------------------
|
||||
- Add new CLI command to trigger a datasource to poll
|
||||
- congress datasource request-refresh Trigger a datasource to poll.
|
||||
|
||||
1.0.3 - 2015-03-30
|
||||
------------------
|
||||
|
||||
- Add new CLI commands to manage datasources/drivers
|
||||
- congress datasource create Create a datasource.
|
||||
- congress datasource delete Delete a datasource.
|
||||
- congress driver config show List driver tables.
|
||||
- congress driver list List drivers.
|
||||
- congress driver schema show List datasource tables.
|
||||
- All api commands now use uuids instead of names and the cli
|
||||
now looks up their ids when needed thou allows the user to still use
|
||||
the name for convenience.
|
||||
|
||||
|
||||
1.0.2 - 2015-01-15
|
||||
------------------
|
||||
- Add new CLI comment to create/delete policy
|
||||
- congress policy create Create a policy.
|
||||
- congress policy delete Delete a policy.
|
||||
- Restructure simulate API to pass query/sequence/action_policy in body instead of URI.
|
||||
|
||||
|
||||
1.0.1 - 2014-12-05
|
||||
------------------
|
||||
- Add missing CLI command
|
||||
- openstack congress policy rule show
|
||||
- python34 compatibility
|
||||
- New CLI command to simulate results of rule
|
||||
- openstack congress policy simulate Show the result of simulation.
|
||||
- Add new CLI command to check the status of a datasource
|
||||
- openstack congress datasource status list
|
||||
- Add new CLI for viewing schemas
|
||||
- openstack congress datasource table schema show Show schema for datasource table.
|
||||
- openstack congress datasource schema show Show schema for datasource.
|
||||
- Add CLI for creating/deleting policies
|
||||
- openstack congress policy create
|
||||
- openstack congress policy delete
|
||||
|
||||
|
||||
|
||||
1.0.0 - 2014-09-29
|
||||
------------------
|
||||
- First release
|
||||
- python-openstackclient integration
|
||||
- CLI
|
||||
- keystone catalog and auth
|
||||
- Support for the following CLI commands:
|
||||
- openstack congress datasource list List Datasources.
|
||||
- openstack congress datasource row list List datasource rows.
|
||||
- openstack congress datasource table list List datasource tables.
|
||||
- openstack congress policy list List Policy.
|
||||
- openstack congress policy row list List policy rows.
|
||||
- openstack congress policy rule create Create a policy rule.
|
||||
- openstack congress policy rule delete Delete a policy rule.
|
||||
- openstack congress policy rule list List policy rules.
|
||||
- openstack congress policy table list List policy tables.
|
|
@ -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.
|
97
README.rst
97
README.rst
|
@ -1,97 +0,0 @@
|
|||
========================
|
||||
Team and repository tags
|
||||
========================
|
||||
|
||||
.. image:: http://governance.openstack.org/badges/python-congressclient.svg
|
||||
:target: http://governance.openstack.org/reference/tags/index.html
|
||||
|
||||
.. Change things from this point on
|
||||
|
||||
===============================
|
||||
python-congressclient
|
||||
===============================
|
||||
|
||||
Client for Congress
|
||||
|
||||
* Free software: Apache license
|
||||
* Documentation: https://docs.openstack.org/python-congressclient/latest/
|
||||
* Source: http://git.openstack.org/cgit/openstack/python-congressclient
|
||||
* Bugs: http://bugs.launchpad.net/python-congressclient
|
||||
|
||||
|
||||
Client for Standalone Congress
|
||||
------------------------------
|
||||
Install the Congress CLI by cloning the repository and running the setup file.
|
||||
The master repository always contains the latest source code, so if you are
|
||||
installing and testing a specific branch of Congress, clone the matching branch
|
||||
of the python-congressclient.
|
||||
|
||||
To execute CLI commands to standalone Congress installed with noauth:
|
||||
|
||||
* Install python-openstackclient::
|
||||
|
||||
$ pip install python-openstackclient
|
||||
|
||||
* Clone master repository & install python-congressclient::
|
||||
|
||||
$ git clone https://github.com/openstack/python-congressclient.git
|
||||
$ cd python-congressclient
|
||||
$ python setup.py install
|
||||
|
||||
* (Optional) Clone a branch; for example, if you are using the Ocata version of OpenStack and Congress::
|
||||
|
||||
$ git clone -b stable/ocata https://github.com/openstack/python-congressclient.git
|
||||
$ cd python-congressclient
|
||||
$ python setup.py install
|
||||
|
||||
* Read the HTML documentation. Install python-sphinx and the oslosphinx extension if missing::
|
||||
|
||||
$ sudo pip install sphinx
|
||||
$ sudo pip install oslosphinx
|
||||
|
||||
Build the docs
|
||||
$ make docs
|
||||
|
||||
Open doc/html/index.html in a browser
|
||||
|
||||
* To execute CLI commands::
|
||||
|
||||
$ cd python-congressclient
|
||||
|
||||
For example:
|
||||
$ export CONGRESS_URL="http://127.0.0.1:1789"
|
||||
$ openstack --os-token foo --os-url $CONGRESS_URL
|
||||
(openstack) congress policy create test_policy
|
||||
+--------------+--------------------------------------+
|
||||
| Field | Value |
|
||||
+--------------+--------------------------------------+
|
||||
| abbreviation | test_ |
|
||||
| description | |
|
||||
| id | 8595f24a-7d74-45ee-8168-0b3e937b8419 |
|
||||
| kind | nonrecursive |
|
||||
| name | test_policy |
|
||||
| owner_id | user |
|
||||
+--------------+--------------------------------------+
|
||||
|
||||
(openstack) congress policy rule create test_policy "p(5)"
|
||||
+---------+--------------------------------------+
|
||||
| Field | Value |
|
||||
+---------+--------------------------------------+
|
||||
| comment | None |
|
||||
| id | 5ce7fb18-a227-447e-bec8-93e99c0052a5 |
|
||||
| name | None |
|
||||
| rule | p(5) |
|
||||
+---------+--------------------------------------+
|
||||
|
||||
(openstack) congress policy rule list test_policy
|
||||
// ID: 5ce7fb18-a227-447e-bec8-93e99c0052a5
|
||||
// Name: None
|
||||
p(5)
|
||||
|
||||
(openstack) exit
|
||||
$
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* TODO
|
|
@ -1,21 +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.
|
||||
|
||||
__all__ = ['__version__']
|
||||
|
||||
import pbr.version
|
||||
|
||||
version_info = pbr.version.VersionInfo('python-congressclient')
|
||||
try:
|
||||
__version__ = version_info.version_string()
|
||||
except AttributeError:
|
||||
__version__ = None
|
|
@ -1,67 +0,0 @@
|
|||
# Copyright 2013 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.
|
||||
#
|
||||
|
||||
"""argparse Custom Actions"""
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
class KeyValueAction(argparse.Action):
|
||||
"""A custom action to parse arguments as key=value pairs
|
||||
|
||||
Ensures that ``dest`` is a dict
|
||||
"""
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
# Make sure we have an empty dict rather than None
|
||||
if getattr(namespace, self.dest, None) is None:
|
||||
setattr(namespace, self.dest, {})
|
||||
|
||||
# Add value if an assignment else remove it
|
||||
if '=' in values:
|
||||
getattr(namespace, self.dest, {}).update([values.split('=', 1)])
|
||||
else:
|
||||
getattr(namespace, self.dest, {}).pop(values, None)
|
||||
|
||||
|
||||
class RangeAction(argparse.Action):
|
||||
"""A custom action to parse a single value or a range of values
|
||||
|
||||
Parses single integer values or a range of integer values delimited
|
||||
by a colon and returns a tuple of integers:
|
||||
'4' sets ``dest`` to (4, 4)
|
||||
'6:9' sets ``dest`` to (6, 9)
|
||||
"""
|
||||
|
||||
def __call__(self, parser, namespace, values, option_string=None):
|
||||
range = values.split(':')
|
||||
if len(range) == 0:
|
||||
# Nothing passed, return a zero default
|
||||
setattr(namespace, self.dest, (0, 0))
|
||||
elif len(range) == 1:
|
||||
# Only a single value is present
|
||||
setattr(namespace, self.dest, (int(range[0]), int(range[0])))
|
||||
elif len(range) == 2:
|
||||
# Range of two values
|
||||
if int(range[0]) <= int(range[1]):
|
||||
setattr(namespace, self.dest, (int(range[0]), int(range[1])))
|
||||
else:
|
||||
msg = ("Invalid range, %s is not less than %s" %
|
||||
(range[0], range[1]))
|
||||
raise argparse.ArgumentError(self, msg)
|
||||
else:
|
||||
# Too many values
|
||||
msg = "Invalid range, too many values"
|
||||
raise argparse.ArgumentError(self, msg)
|
|
@ -1,140 +0,0 @@
|
|||
# Copyright 2012-2013 OpenStack, LLC.
|
||||
#
|
||||
# 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 importlib
|
||||
import os
|
||||
|
||||
from congressclient import exceptions
|
||||
|
||||
|
||||
def env(*vars, **kwargs):
|
||||
"""Search for the first defined of possibly many env vars
|
||||
|
||||
Returns the first environment variable defined in vars, or
|
||||
returns the default defined in kwargs.
|
||||
"""
|
||||
for v in vars:
|
||||
value = os.environ.get(v, None)
|
||||
if value:
|
||||
return value
|
||||
return kwargs.get('default', '')
|
||||
|
||||
|
||||
def import_class(import_str):
|
||||
"""Returns a class from a string including module and class
|
||||
|
||||
:param import_str: a string representation of the class name
|
||||
:rtype: the requested class
|
||||
"""
|
||||
mod_str, _sep, class_str = import_str.rpartition('.')
|
||||
mod = importlib.import_module(mod_str)
|
||||
return getattr(mod, class_str)
|
||||
|
||||
|
||||
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 %s client version '%s'. must be one of: %s" % (
|
||||
(api_name, version, ', '.join(version_map.keys())))
|
||||
raise exceptions.UnsupportedVersion(msg)
|
||||
|
||||
return import_class(client_path)
|
||||
|
||||
|
||||
def format_long_dict_list(data):
|
||||
"""Return a formatted string.
|
||||
|
||||
:param data: a list of dicts
|
||||
:rtype: a string formatted to {a:b, c:d}, {e:f, g:h}
|
||||
"""
|
||||
newdata = [str({str(key): str(value) for key, value in d.iteritems()})
|
||||
for d in data]
|
||||
return ',\n'.join(newdata) + '\n'
|
||||
|
||||
|
||||
def format_dict(data):
|
||||
"""Return a formatted string.
|
||||
|
||||
:param data: a dict
|
||||
:rtype: a string formatted to {a:b, c:d}
|
||||
"""
|
||||
if not isinstance(data, dict):
|
||||
return str(data)
|
||||
return str({str(key): str(value) for key, value in data.items()})
|
||||
|
||||
|
||||
def format_list(data):
|
||||
"""Return a formatted strings
|
||||
|
||||
:param data: a list of strings
|
||||
:rtype: a string formatted to a,b,c
|
||||
"""
|
||||
|
||||
return ', '.join(data)
|
||||
|
||||
|
||||
def get_dict_properties(item, fields, mixed_case_fields=[], formatters={}):
|
||||
"""Return a tuple containing the item properties.
|
||||
|
||||
:param item: a single dict resource
|
||||
: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
|
||||
"""
|
||||
row = []
|
||||
for field in fields:
|
||||
if field in mixed_case_fields:
|
||||
field_name = field.replace(' ', '_')
|
||||
else:
|
||||
field_name = field.lower().replace(' ', '_')
|
||||
data = item[field_name] if field_name in item else ''
|
||||
if field in formatters:
|
||||
row.append(formatters[field](data))
|
||||
else:
|
||||
row.append(data)
|
||||
return tuple(row)
|
||||
|
||||
|
||||
def get_resource_id_from_name(name, results):
|
||||
# FIXME(arosen): move to common lib and add tests...
|
||||
name_match = None
|
||||
id_match = None
|
||||
double_name_match = False
|
||||
for result in results['results']:
|
||||
if result['id'] == name:
|
||||
id_match = result['id']
|
||||
if result['name'] == name:
|
||||
if name_match:
|
||||
double_name_match = True
|
||||
name_match = result['id']
|
||||
if not double_name_match and name_match:
|
||||
return name_match
|
||||
if double_name_match and not id_match:
|
||||
# NOTE(arosen): this should only occur is using congress
|
||||
# as admin and multiple tenants use the same datsource name.
|
||||
raise exceptions.Conflict(
|
||||
"Multiple resources have this name %s. Please specify id." % name)
|
||||
if id_match:
|
||||
return id_match
|
||||
|
||||
raise exceptions.NotFound("Resource %s not found" % name)
|
|
@ -1,464 +0,0 @@
|
|||
# Copyright 2010 Jacob Kaplan-Moss
|
||||
# Copyright 2011 Nebula, Inc.
|
||||
# Copyright 2013 Alessio Ababilov
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Exception definitions.
|
||||
"""
|
||||
|
||||
import inspect
|
||||
import sys
|
||||
|
||||
import six
|
||||
|
||||
from congressclient.i18n import _
|
||||
|
||||
|
||||
class ClientException(Exception):
|
||||
"""The base exception class for all exceptions this library raises."""
|
||||
pass
|
||||
|
||||
|
||||
class MissingArgs(ClientException):
|
||||
"""Supplied arguments are not sufficient for calling a function."""
|
||||
def __init__(self, missing):
|
||||
self.missing = missing
|
||||
msg = _("Missing arguments: %s") % ", ".join(missing)
|
||||
super(MissingArgs, self).__init__(msg)
|
||||
|
||||
|
||||
class ValidationError(ClientException):
|
||||
"""Error in validation on API client side."""
|
||||
pass
|
||||
|
||||
|
||||
class UnsupportedVersion(ClientException):
|
||||
"""User is trying to use an unsupported version of the API."""
|
||||
pass
|
||||
|
||||
|
||||
class CommandError(ClientException):
|
||||
"""Error in CLI tool."""
|
||||
pass
|
||||
|
||||
|
||||
class AuthorizationFailure(ClientException):
|
||||
"""Cannot authorize API client."""
|
||||
pass
|
||||
|
||||
|
||||
class ConnectionRefused(ClientException):
|
||||
"""Cannot connect to API service."""
|
||||
pass
|
||||
|
||||
|
||||
class AuthPluginOptionsMissing(AuthorizationFailure):
|
||||
"""Auth plugin misses some options."""
|
||||
def __init__(self, opt_names):
|
||||
super(AuthPluginOptionsMissing, self).__init__(
|
||||
_("Authentication failed. Missing options: %s") %
|
||||
", ".join(opt_names))
|
||||
self.opt_names = opt_names
|
||||
|
||||
|
||||
class AuthSystemNotFound(AuthorizationFailure):
|
||||
"""User has specified an AuthSystem that is not installed."""
|
||||
def __init__(self, auth_system):
|
||||
super(AuthSystemNotFound, self).__init__(
|
||||
_("AuthSystemNotFound: %s") % repr(auth_system))
|
||||
self.auth_system = auth_system
|
||||
|
||||
|
||||
class NoUniqueMatch(ClientException):
|
||||
"""Multiple entities found instead of one."""
|
||||
pass
|
||||
|
||||
|
||||
class EndpointException(ClientException):
|
||||
"""Something is rotten in Service Catalog."""
|
||||
pass
|
||||
|
||||
|
||||
class EndpointNotFound(EndpointException):
|
||||
"""Could not find requested endpoint in Service Catalog."""
|
||||
pass
|
||||
|
||||
|
||||
class AmbiguousEndpoints(EndpointException):
|
||||
"""Found more than one matching endpoint in Service Catalog."""
|
||||
def __init__(self, endpoints=None):
|
||||
super(AmbiguousEndpoints, self).__init__(
|
||||
_("AmbiguousEndpoints: %s") % repr(endpoints))
|
||||
self.endpoints = endpoints
|
||||
|
||||
|
||||
class HttpError(ClientException):
|
||||
"""The base exception class for all HTTP exceptions."""
|
||||
http_status = 0
|
||||
message = _("HTTP Error")
|
||||
|
||||
def __init__(self, message=None, details=None,
|
||||
response=None, request_id=None,
|
||||
url=None, method=None, http_status=None):
|
||||
self.http_status = http_status or self.http_status
|
||||
self.message = message or self.message
|
||||
self.details = details
|
||||
self.request_id = request_id
|
||||
self.response = response
|
||||
self.url = url
|
||||
self.method = method
|
||||
formatted_string = "%s (HTTP %s)" % (self.message, self.http_status)
|
||||
if request_id:
|
||||
formatted_string += " (Request-ID: %s)" % request_id
|
||||
super(HttpError, self).__init__(formatted_string)
|
||||
|
||||
|
||||
class HTTPRedirection(HttpError):
|
||||
"""HTTP Redirection."""
|
||||
message = _("HTTP Redirection")
|
||||
|
||||
|
||||
class HTTPClientError(HttpError):
|
||||
"""Client-side HTTP error.
|
||||
|
||||
Exception for cases in which the client seems to have erred.
|
||||
"""
|
||||
message = _("HTTP Client Error")
|
||||
|
||||
|
||||
class HttpServerError(HttpError):
|
||||
"""Server-side HTTP error.
|
||||
|
||||
Exception for cases in which the server is aware that it has
|
||||
erred or is incapable of performing the request.
|
||||
"""
|
||||
message = _("HTTP Server Error")
|
||||
|
||||
|
||||
class MultipleChoices(HTTPRedirection):
|
||||
"""HTTP 300 - Multiple Choices.
|
||||
|
||||
Indicates multiple options for the resource that the client may follow.
|
||||
"""
|
||||
|
||||
http_status = 300
|
||||
message = _("Multiple Choices")
|
||||
|
||||
|
||||
class BadRequest(HTTPClientError):
|
||||
"""HTTP 400 - Bad Request.
|
||||
|
||||
The request cannot be fulfilled due to bad syntax.
|
||||
"""
|
||||
http_status = 400
|
||||
message = _("Bad Request")
|
||||
|
||||
|
||||
class Unauthorized(HTTPClientError):
|
||||
"""HTTP 401 - Unauthorized.
|
||||
|
||||
Similar to 403 Forbidden, but specifically for use when authentication
|
||||
is required and has failed or has not yet been provided.
|
||||
"""
|
||||
http_status = 401
|
||||
message = _("Unauthorized")
|
||||
|
||||
|
||||
class PaymentRequired(HTTPClientError):
|
||||
"""HTTP 402 - Payment Required.
|
||||
|
||||
Reserved for future use.
|
||||
"""
|
||||
http_status = 402
|
||||
message = _("Payment Required")
|
||||
|
||||
|
||||
class Forbidden(HTTPClientError):
|
||||
"""HTTP 403 - Forbidden.
|
||||
|
||||
The request was a valid request, but the server is refusing to respond
|
||||
to it.
|
||||
"""
|
||||
http_status = 403
|
||||
message = _("Forbidden")
|
||||
|
||||
|
||||
class NotFound(HTTPClientError):
|
||||
"""HTTP 404 - Not Found.
|
||||
|
||||
The requested resource could not be found but may be available again
|
||||
in the future.
|
||||
"""
|
||||
http_status = 404
|
||||
message = _("Not Found")
|
||||
|
||||
|
||||
class MethodNotAllowed(HTTPClientError):
|
||||
"""HTTP 405 - Method Not Allowed.
|
||||
|
||||
A request was made of a resource using a request method not supported
|
||||
by that resource.
|
||||
"""
|
||||
http_status = 405
|
||||
message = _("Method Not Allowed")
|
||||
|
||||
|
||||
class NotAcceptable(HTTPClientError):
|
||||
"""HTTP 406 - Not Acceptable.
|
||||
|
||||
The requested resource is only capable of generating content not
|
||||
acceptable according to the Accept headers sent in the request.
|
||||
"""
|
||||
http_status = 406
|
||||
message = _("Not Acceptable")
|
||||
|
||||
|
||||
class ProxyAuthenticationRequired(HTTPClientError):
|
||||
"""HTTP 407 - Proxy Authentication Required.
|
||||
|
||||
The client must first authenticate itself with the proxy.
|
||||
"""
|
||||
http_status = 407
|
||||
message = _("Proxy Authentication Required")
|
||||
|
||||
|
||||
class RequestTimeout(HTTPClientError):
|
||||
"""HTTP 408 - Request Timeout.
|
||||
|
||||
The server timed out waiting for the request.
|
||||
"""
|
||||
http_status = 408
|
||||
message = _("Request Timeout")
|
||||
|
||||
|
||||
class Conflict(HTTPClientError):
|
||||
"""HTTP 409 - Conflict.
|
||||
|
||||
Indicates that the request could not be processed because of conflict
|
||||
in the request, such as an edit conflict.
|
||||
"""
|
||||
http_status = 409
|
||||
message = _("Conflict")
|
||||
|
||||
|
||||
class Gone(HTTPClientError):
|
||||
"""HTTP 410 - Gone.
|
||||
|
||||
Indicates that the resource requested is no longer available and will
|
||||
not be available again.
|
||||
"""
|
||||
http_status = 410
|
||||
message = _("Gone")
|
||||
|
||||
|
||||
class LengthRequired(HTTPClientError):
|
||||
"""HTTP 411 - Length Required.
|
||||
|
||||
The request did not specify the length of its content, which is
|
||||
required by the requested resource.
|
||||
"""
|
||||
http_status = 411
|
||||
message = _("Length Required")
|
||||
|
||||
|
||||
class PreconditionFailed(HTTPClientError):
|
||||
"""HTTP 412 - Precondition Failed.
|
||||
|
||||
The server does not meet one of the preconditions that the requester
|
||||
put on the request.
|
||||
"""
|
||||
http_status = 412
|
||||
message = _("Precondition Failed")
|
||||
|
||||
|
||||
class RequestEntityTooLarge(HTTPClientError):
|
||||
"""HTTP 413 - Request Entity Too Large.
|
||||
|
||||
The request is larger than the server is willing or able to process.
|
||||
"""
|
||||
http_status = 413
|
||||
message = _("Request Entity Too Large")
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
try:
|
||||
self.retry_after = int(kwargs.pop('retry_after'))
|
||||
except (KeyError, ValueError):
|
||||
self.retry_after = 0
|
||||
|
||||
super(RequestEntityTooLarge, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class RequestUriTooLong(HTTPClientError):
|
||||
"""HTTP 414 - Request-URI Too Long.
|
||||
|
||||
The URI provided was too long for the server to process.
|
||||
"""
|
||||
http_status = 414
|
||||
message = _("Request-URI Too Long")
|
||||
|
||||
|
||||
class UnsupportedMediaType(HTTPClientError):
|
||||
"""HTTP 415 - Unsupported Media Type.
|
||||
|
||||
The request entity has a media type which the server or resource does
|
||||
not support.
|
||||
"""
|
||||
http_status = 415
|
||||
message = _("Unsupported Media Type")
|
||||
|
||||
|
||||
class RequestedRangeNotSatisfiable(HTTPClientError):
|
||||
"""HTTP 416 - Requested Range Not Satisfiable.
|
||||
|
||||
The client has asked for a portion of the file, but the server cannot
|
||||
supply that portion.
|
||||
"""
|
||||
http_status = 416
|
||||
message = _("Requested Range Not Satisfiable")
|
||||
|
||||
|
||||
class ExpectationFailed(HTTPClientError):
|
||||
"""HTTP 417 - Expectation Failed.
|
||||
|
||||
The server cannot meet the requirements of the Expect request-header field.
|
||||
"""
|
||||
http_status = 417
|
||||
message = _("Expectation Failed")
|
||||
|
||||
|
||||
class UnprocessableEntity(HTTPClientError):
|
||||
"""HTTP 422 - Unprocessable Entity.
|
||||
|
||||
The request was well-formed but was unable to be followed due to semantic
|
||||
errors.
|
||||
"""
|
||||
http_status = 422
|
||||
message = _("Unprocessable Entity")
|
||||
|
||||
|
||||
class InternalServerError(HttpServerError):
|
||||
"""HTTP 500 - Internal Server Error.
|
||||
|
||||
A generic error message, given when no more specific message is suitable.
|
||||
"""
|
||||
http_status = 500
|
||||
message = _("Internal Server Error")
|
||||
|
||||
|
||||
# NotImplemented is a python keyword.
|
||||
class HttpNotImplemented(HttpServerError):
|
||||
"""HTTP 501 - Not Implemented.
|
||||
|
||||
The server either does not recognize the request method, or it lacks
|
||||
the ability to fulfill the request.
|
||||
"""
|
||||
http_status = 501
|
||||
message = _("Not Implemented")
|
||||
|
||||
|
||||
class BadGateway(HttpServerError):
|
||||
"""HTTP 502 - Bad Gateway.
|
||||
|
||||
The server was acting as a gateway or proxy and received an invalid
|
||||
response from the upstream server.
|
||||
"""
|
||||
http_status = 502
|
||||
message = _("Bad Gateway")
|
||||
|
||||
|
||||
class ServiceUnavailable(HttpServerError):
|
||||
"""HTTP 503 - Service Unavailable.
|
||||
|
||||
The server is currently unavailable.
|
||||
"""
|
||||
http_status = 503
|
||||
message = _("Service Unavailable")
|
||||
|
||||
|
||||
class GatewayTimeout(HttpServerError):
|
||||
"""HTTP 504 - Gateway Timeout.
|
||||
|
||||
The server was acting as a gateway or proxy and did not receive a timely
|
||||
response from the upstream server.
|
||||
"""
|
||||
http_status = 504
|
||||
message = _("Gateway Timeout")
|
||||
|
||||
|
||||
class HttpVersionNotSupported(HttpServerError):
|
||||
"""HTTP 505 - HttpVersion Not Supported.
|
||||
|
||||
The server does not support the HTTP protocol version used in the request.
|
||||
"""
|
||||
http_status = 505
|
||||
message = _("HTTP Version Not Supported")
|
||||
|
||||
|
||||
# _code_map contains all the classes that have http_status attribute.
|
||||
_code_map = dict(
|
||||
(getattr(obj, 'http_status', None), obj)
|
||||
for name, obj in six.iteritems(vars(sys.modules[__name__]))
|
||||
if inspect.isclass(obj) and getattr(obj, 'http_status', False)
|
||||
)
|
||||
|
||||
|
||||
def from_response(response, method, url):
|
||||
"""Returns an instance of :class:`HttpError` or subclass based on response.
|
||||
|
||||
:param response: instance of `requests.Response` class
|
||||
:param method: HTTP method used for request
|
||||
:param url: URL used for request
|
||||
"""
|
||||
|
||||
req_id = response.headers.get("x-openstack-request-id")
|
||||
# NOTE(hdd) true for older versions of nova and cinder
|
||||
if not req_id:
|
||||
req_id = response.headers.get("x-compute-request-id")
|
||||
kwargs = {
|
||||
"http_status": response.status_code,
|
||||
"response": response,
|
||||
"method": method,
|
||||
"url": url,
|
||||
"request_id": req_id,
|
||||
}
|
||||
if "retry-after" in response.headers:
|
||||
kwargs["retry_after"] = response.headers["retry-after"]
|
||||
|
||||
content_type = response.headers.get("Content-Type", "")
|
||||
if content_type.startswith("application/json"):
|
||||
try:
|
||||
body = response.json()
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
if isinstance(body, dict) and isinstance(body.get("error"), dict):
|
||||
error = body["error"]
|
||||
kwargs["message"] = error.get("message")
|
||||
kwargs["details"] = error.get("details")
|
||||
elif content_type.startswith("text/"):
|
||||
kwargs["details"] = response.text
|
||||
|
||||
try:
|
||||
cls = _code_map[response.status_code]
|
||||
except KeyError:
|
||||
if 500 <= response.status_code < 600:
|
||||
cls = HttpServerError
|
||||
elif 400 <= response.status_code < 500:
|
||||
cls = HTTPClientError
|
||||
else:
|
||||
cls = HttpError
|
||||
return cls(**kwargs)
|
|
@ -1,25 +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.
|
||||
|
||||
"""oslo_i18n integration module for novaclient.
|
||||
|
||||
See http://docs.openstack.org/developer/oslo.i18n/usage.html .
|
||||
|
||||
"""
|
||||
|
||||
import oslo_i18n
|
||||
|
||||
|
||||
_translators = oslo_i18n.TranslatorFactory(domain='congressclient')
|
||||
|
||||
# The primary translation function using the well-known name "_"
|
||||
_ = _translators.primary
|
|
@ -1,55 +0,0 @@
|
|||
# Copyright 2014 VMWare.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""OpenStackClient plugin for Governance service."""
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from congressclient.common import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_POLICY_API_VERSION = '1'
|
||||
API_VERSION_OPTION = 'os_policy_api_version'
|
||||
API_NAME = 'congressclient'
|
||||
API_VERSIONS = {
|
||||
'1': 'congressclient.v1.client.Client',
|
||||
}
|
||||
|
||||
|
||||
def make_client(instance):
|
||||
"""Returns a congress service client."""
|
||||
congress_client = utils.get_client_class(
|
||||
API_NAME,
|
||||
instance._api_version[API_NAME],
|
||||
API_VERSIONS)
|
||||
LOG.debug('instantiating congress client: %s', congress_client)
|
||||
return congress_client(session=instance.session,
|
||||
auth=None,
|
||||
interface='publicURL',
|
||||
service_type='policy',
|
||||
region_name=instance._region_name)
|
||||
|
||||
|
||||
def build_option_parser(parser):
|
||||
"""Hook to add global options."""
|
||||
parser.add_argument(
|
||||
'--os-policy-api-version',
|
||||
metavar='<policy-api-version>',
|
||||
default=utils.env(
|
||||
'OS_POLICY_API_VERSION',
|
||||
default=DEFAULT_POLICY_API_VERSION),
|
||||
help=('Policy API version, default=%s (Env: OS_POLICY_API_VERSION)' %
|
||||
DEFAULT_POLICY_API_VERSION))
|
||||
return parser
|
|
@ -1,39 +0,0 @@
|
|||
# Copyright 2015 Huawei.
|
||||
# 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.
|
||||
|
||||
"""List API versions implemenations"""
|
||||
|
||||
from cliff import lister
|
||||
from oslo_log import log as logging
|
||||
|
||||
from congressclient.common import utils
|
||||
|
||||
|
||||
class ListAPIVersions(lister.Lister):
|
||||
"""List API Versions."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ListAPIVersions')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
return super(ListAPIVersions, self).get_parser(prog_name)
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.congressclient
|
||||
data = client.list_api_versions()['versions']
|
||||
# sort API by id
|
||||
data.sort(key=lambda item: item.get('id'))
|
||||
columns = ['id', 'status', 'updated']
|
||||
return (columns,
|
||||
(utils.get_dict_properties(s, columns) for s in data))
|
|
@ -1,362 +0,0 @@
|
|||
# Copyright 2012-2013 OpenStack, LLC.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Datasource action implemenations"""
|
||||
|
||||
from cliff import command
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
import six
|
||||
|
||||
from congressclient.common import parseractions
|
||||
from congressclient.common import utils
|
||||
|
||||
|
||||
class ListDatasources(lister.Lister):
|
||||
"""List Datasources."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ListDatasources')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListDatasources, self).get_parser(prog_name)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.congressclient
|
||||
data = client.list_datasources()['results']
|
||||
# Type is always None, so disabling it for now.
|
||||
columns = ['id', 'name', 'enabled', 'driver', 'config']
|
||||
formatters = {'config': utils.format_dict}
|
||||
return (columns,
|
||||
(utils.get_dict_properties(s, columns,
|
||||
formatters=formatters)
|
||||
for s in data))
|
||||
|
||||
|
||||
class ListDatasourceTables(lister.Lister):
|
||||
"""List datasource tables."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ListDatasourceTables')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListDatasourceTables, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'datasource_name',
|
||||
metavar="<datasource>",
|
||||
help="Name or ID of the datasource")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
name_or_id = parsed_args.datasource_name
|
||||
data = client.list_datasource_tables(name_or_id)['results']
|
||||
columns = ['id']
|
||||
formatters = {'DatasourceTables': utils.format_list}
|
||||
return (columns,
|
||||
(utils.get_dict_properties(s, columns,
|
||||
formatters=formatters)
|
||||
for s in data))
|
||||
|
||||
|
||||
class ShowDatasourceStatus(show.ShowOne):
|
||||
"""List status for datasource."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ShowDatasourceStatus')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDatasourceStatus, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'datasource_name',
|
||||
metavar="<datasource>",
|
||||
help="Name or ID of the datasource")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
datasource_id = parsed_args.datasource_name
|
||||
data = client.list_datasource_status(datasource_id)
|
||||
return zip(*sorted(six.iteritems(data)))
|
||||
|
||||
|
||||
class ShowDatasourceActions(lister.Lister):
|
||||
"""List supported actions for datasource."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ShowDatasourceActions')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDatasourceActions, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'datasource_name',
|
||||
metavar="<datasource>",
|
||||
help="Name or ID of the datasource")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
|
||||
client = self.app.client_manager.congressclient
|
||||
datasource_id = parsed_args.datasource_name
|
||||
data = client.list_datasource_actions(datasource_id)
|
||||
formatters = {'args': utils.format_long_dict_list}
|
||||
newdata = [{'action': x['name'],
|
||||
'args': x['args'],
|
||||
'description': x['description']}
|
||||
for x in data['results']]
|
||||
columns = ['action', 'args', 'description']
|
||||
return (columns, (utils.get_dict_properties(s,
|
||||
columns,
|
||||
formatters=formatters)
|
||||
for s in newdata))
|
||||
|
||||
|
||||
class ShowDatasourceSchema(lister.Lister):
|
||||
"""Show schema for datasource."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ShowDatasourceSchema')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDatasourceSchema, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'datasource_name',
|
||||
metavar="<datasource>",
|
||||
help="Name or ID of the datasource")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
datasource_id = parsed_args.datasource_name
|
||||
data = client.show_datasource_schema(datasource_id)
|
||||
formatters = {'columns': utils.format_long_dict_list}
|
||||
newdata = [{'table': x['table_id'],
|
||||
'columns': x['columns']}
|
||||
for x in data['tables']]
|
||||
columns = ['table', 'columns']
|
||||
return (columns,
|
||||
(utils.get_dict_properties(s, columns,
|
||||
formatters=formatters)
|
||||
for s in newdata))
|
||||
|
||||
|
||||
class ShowDatasourceTableSchema(lister.Lister):
|
||||
"""Show schema for datasource table."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ShowDatasourceTableSchema')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDatasourceTableSchema, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'datasource_name',
|
||||
metavar="<datasource>",
|
||||
help="Name or ID of the datasource")
|
||||
parser.add_argument(
|
||||
'table_name',
|
||||
metavar="<table-name>",
|
||||
help="Name of the table")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
datasource_id = parsed_args.datasource_name
|
||||
data = client.show_datasource_table_schema(
|
||||
datasource_id,
|
||||
parsed_args.table_name)
|
||||
columns = ['name', 'description']
|
||||
return (columns,
|
||||
(utils.get_dict_properties(s, columns)
|
||||
for s in data['columns']))
|
||||
|
||||
|
||||
class ListDatasourceRows(lister.Lister):
|
||||
"""List datasource rows."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ListDatasourceRows')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListDatasourceRows, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'datasource_name',
|
||||
metavar="<datasource>",
|
||||
help="Name or ID of the datasource to show")
|
||||
parser.add_argument(
|
||||
'table',
|
||||
metavar="<table>",
|
||||
help="Table to get the datasource rows from")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
datasource_id = parsed_args.datasource_name
|
||||
results = client.list_datasource_rows(datasource_id,
|
||||
parsed_args.table)['results']
|
||||
if results:
|
||||
columns = client.show_datasource_table_schema(
|
||||
datasource_id, parsed_args.table)['columns']
|
||||
columns = [col['name'] for col in columns]
|
||||
else:
|
||||
columns = ['data'] # doesn't matter because the rows are empty
|
||||
return (columns, (x['data'] for x in results))
|
||||
|
||||
|
||||
class ShowDatasourceTable(show.ShowOne):
|
||||
"""Show Datasource Table properties."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ShowDatasourceTable')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDatasourceTable, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'datasource_name',
|
||||
metavar='<datasource>',
|
||||
help="Name or ID of datasource")
|
||||
parser.add_argument(
|
||||
'table_id',
|
||||
metavar='<table-id>',
|
||||
help="Table id")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
data = client.show_datasource_table(parsed_args.datasource_name,
|
||||
parsed_args.table_id)
|
||||
return zip(*sorted(six.iteritems(data)))
|
||||
|
||||
|
||||
class CreateDatasource(show.ShowOne):
|
||||
"""Create a datasource."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.CreateDatasource')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateDatasource, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'driver',
|
||||
metavar="<datasource-driver>",
|
||||
help="Selected datasource driver")
|
||||
parser.add_argument(
|
||||
'name',
|
||||
metavar="<datasource-name>",
|
||||
help="Name you want to call the datasource")
|
||||
parser.add_argument(
|
||||
'--description',
|
||||
metavar="<datasource-description>",
|
||||
help="Description of the datasource")
|
||||
|
||||
parser.add_argument(
|
||||
'--config',
|
||||
metavar="<key=value>",
|
||||
action=parseractions.KeyValueAction,
|
||||
help="config dictionary to pass in")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
body = {'name': parsed_args.name,
|
||||
'driver': parsed_args.driver,
|
||||
'config': parsed_args.config}
|
||||
if parsed_args.description:
|
||||
body['description'] = parsed_args.description
|
||||
results = client.create_datasource(body)
|
||||
return zip(*sorted(six.iteritems(results)))
|
||||
|
||||
|
||||
class DeleteDatasource(command.Command):
|
||||
"""Delete a datasource."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.DeleteDatasource')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteDatasource, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'datasource',
|
||||
metavar="<datasource>",
|
||||
help="Name or ID of the datasource to delete")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
try:
|
||||
datasource_id = parsed_args.datasource
|
||||
client.delete_datasource(datasource_id)
|
||||
except Exception:
|
||||
# for backwards compatibility with pre-Ocata congress server,
|
||||
# try old method of explicit conversion from name to UUID
|
||||
results = client.list_datasources()
|
||||
datasource_id = utils.get_resource_id_from_name(
|
||||
parsed_args.datasource, results)
|
||||
client.delete_datasource(datasource_id)
|
||||
|
||||
|
||||
class UpdateDatasourceRow(command.Command):
|
||||
"""Update rows to a datasource table."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.UpdateDatasourceRow')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UpdateDatasourceRow, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'datasource',
|
||||
metavar="<datasource>",
|
||||
help="Name or ID of the datasource to Update")
|
||||
parser.add_argument(
|
||||
'table',
|
||||
metavar="<table>",
|
||||
help="Name or ID of the table to Update")
|
||||
parser.add_argument(
|
||||
'rows',
|
||||
type=jsonutils.loads,
|
||||
metavar="<rows>",
|
||||
help=("List of Rows should be formmated json style."
|
||||
" ex. [[row1], [row2]]"))
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
body = parsed_args.rows
|
||||
client.update_datasource_rows(
|
||||
parsed_args.datasource, parsed_args.table, body)
|
||||
|
||||
|
||||
class DatasourceRequestRefresh(command.Command):
|
||||
"""Trigger a datasource to poll."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.DatasourceRequestRefresh')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DatasourceRequestRefresh, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'datasource',
|
||||
metavar="<datasource>",
|
||||
help="Name or ID of the datasource to poll")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
results = client.list_datasources()
|
||||
datasource_id = utils.get_resource_id_from_name(
|
||||
parsed_args.datasource, results)
|
||||
client.request_refresh(datasource_id, {})
|
|
@ -1,100 +0,0 @@
|
|||
# Copyright 2012-2013 OpenStack, LLC.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Driver action implemenations"""
|
||||
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from congressclient.common import utils
|
||||
|
||||
|
||||
class ListDrivers(lister.Lister):
|
||||
"""List drivers."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ListDrivers')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListDrivers, self).get_parser(prog_name)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.congressclient
|
||||
data = client.list_drivers()['results']
|
||||
columns = ['id', 'description']
|
||||
formatters = {'Drivers': utils.format_list}
|
||||
return (columns,
|
||||
(utils.get_dict_properties(s, columns,
|
||||
formatters=formatters)
|
||||
for s in data))
|
||||
|
||||
|
||||
class ShowDriverConfig(show.ShowOne):
|
||||
"""List driver tables."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ShowDriverConfig')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDriverConfig, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'driver',
|
||||
metavar="<datasource-driver>",
|
||||
help="Name of the datasource driver")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
data = client.show_driver(
|
||||
parsed_args.driver)
|
||||
# remove table schema info from displaying
|
||||
del data['tables']
|
||||
return zip(*sorted(six.iteritems(data)))
|
||||
columns = ['id']
|
||||
formatters = {'DriverTables': utils.format_list}
|
||||
return (columns,
|
||||
(utils.get_dict_properties(s, columns,
|
||||
formatters=formatters)
|
||||
for s in data))
|
||||
|
||||
|
||||
class ShowDriverSchema(lister.Lister):
|
||||
"""List datasource tables."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ShowDriverSchema')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowDriverSchema, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'driver',
|
||||
metavar="<datasource-driver>",
|
||||
help="Name of the datasource driver")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
data = client.show_driver(
|
||||
parsed_args.driver)
|
||||
formatters = {'columns': utils.format_long_dict_list}
|
||||
newdata = [{'table': x['table_id'],
|
||||
'columns': x['columns']}
|
||||
for x in data['tables']]
|
||||
columns = ['table', 'columns']
|
||||
return (columns,
|
||||
(utils.get_dict_properties(s, columns,
|
||||
formatters=formatters)
|
||||
for s in newdata))
|
|
@ -1,470 +0,0 @@
|
|||
# Copyright 2012-2013 OpenStack, LLC.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Policy action implemenations"""
|
||||
|
||||
import sys
|
||||
|
||||
from cliff import command
|
||||
from cliff import lister
|
||||
from cliff import show
|
||||
from keystoneauth1 import exceptions
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
import six
|
||||
import yaml
|
||||
|
||||
from congressclient.common import utils
|
||||
|
||||
|
||||
def _format_rule(rule):
|
||||
"""Break up rule string so it fits on screen."""
|
||||
|
||||
rule_split = jsonutils.dumps(rule).split(":-")
|
||||
formatted_string = rule_split[0] + ":-\n"
|
||||
for rule in rule_split[1].split("), "):
|
||||
formatted_string += rule + '\n'
|
||||
return formatted_string
|
||||
|
||||
|
||||
def get_rule_id_from_name(client, parsed_args):
|
||||
results = client.list_policy_rules(parsed_args.policy_name)['results']
|
||||
rule_id = None
|
||||
for result in results:
|
||||
if result.get('name') == parsed_args.rule_id:
|
||||
if rule_id is None:
|
||||
rule_id = result.get('id')
|
||||
else:
|
||||
raise exceptions.Conflict(
|
||||
"[Multiple rules with same name: %s]" %
|
||||
parsed_args.rule_id)
|
||||
if rule_id is None:
|
||||
raise exceptions.NotFound(
|
||||
"[No rule found with name: %s]" % parsed_args.rule_id)
|
||||
return rule_id
|
||||
|
||||
|
||||
class CreatePolicyRule(show.ShowOne):
|
||||
"""Create a policy rule."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.CreatePolicyRule')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreatePolicyRule, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy_name',
|
||||
metavar="<policy-name>",
|
||||
help="Name or identifier of the policy")
|
||||
parser.add_argument(
|
||||
'rule',
|
||||
metavar="<rule>",
|
||||
help="Policy rule")
|
||||
parser.add_argument(
|
||||
'--name', dest="rule_name",
|
||||
help="Name of the policy rule")
|
||||
parser.add_argument(
|
||||
'--comment', dest="comment",
|
||||
help="Comment about policy rule")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
body = {'rule': parsed_args.rule}
|
||||
if parsed_args.rule_name:
|
||||
body['name'] = parsed_args.rule_name
|
||||
if parsed_args.comment:
|
||||
body['comment'] = parsed_args.comment
|
||||
data = client.create_policy_rule(parsed_args.policy_name, body)
|
||||
return zip(*sorted(six.iteritems(data)))
|
||||
|
||||
|
||||
class DeletePolicyRule(command.Command):
|
||||
"""Delete a policy rule."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.DeletePolicyRule')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeletePolicyRule, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy_name',
|
||||
metavar="<policy-name>",
|
||||
help="Name of the policy to delete")
|
||||
parser.add_argument(
|
||||
'rule_id',
|
||||
metavar="<rule-id/rule-name>",
|
||||
help="ID/Name of the policy rule to delete")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
results = client.list_policy_rules(parsed_args.policy_name)
|
||||
rule_id = utils.get_resource_id_from_name(
|
||||
parsed_args.rule_id, results)
|
||||
client.delete_policy_rule(parsed_args.policy_name, rule_id)
|
||||
|
||||
|
||||
class ListPolicyRules(command.Command):
|
||||
"""List policy rules."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ListPolicyRules')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListPolicyRules, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy_name',
|
||||
metavar="<policy-name>",
|
||||
help="Name of the policy")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
results = client.list_policy_rules(parsed_args.policy_name)['results']
|
||||
for result in results:
|
||||
print("// ID: %s" % str(result['id']))
|
||||
print("// Name: %s" % str(result.get('name')))
|
||||
if result['comment'] != "None" and result['comment']:
|
||||
print("// %s" % str(result['comment']))
|
||||
print(result['rule'])
|
||||
print('')
|
||||
return 0
|
||||
|
||||
|
||||
class SimulatePolicy(command.Command):
|
||||
"""Show the result of simulation."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.SimulatePolicy')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(SimulatePolicy, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy',
|
||||
metavar="<policy>",
|
||||
help="Name of the policy")
|
||||
parser.add_argument(
|
||||
'query',
|
||||
metavar="<query>",
|
||||
help="String representing query (policy rule or literal)")
|
||||
parser.add_argument(
|
||||
'sequence',
|
||||
metavar="<sequence>",
|
||||
help="String representing sequence of updates/actions")
|
||||
parser.add_argument(
|
||||
'action_policy',
|
||||
metavar="<action_policy>",
|
||||
help="Name of the policy with actions",
|
||||
default=None)
|
||||
parser.add_argument(
|
||||
'--delta',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Return difference in query caused by update sequence")
|
||||
parser.add_argument(
|
||||
'--trace',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Include trace describing computation")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
args = {}
|
||||
args['query'] = parsed_args.query
|
||||
args['sequence'] = parsed_args.sequence
|
||||
if parsed_args.action_policy is not None:
|
||||
args['action_policy'] = parsed_args.action_policy
|
||||
if parsed_args.delta:
|
||||
args['delta'] = parsed_args.delta
|
||||
if parsed_args.trace:
|
||||
args['trace'] = parsed_args.trace
|
||||
|
||||
body = {'query': parsed_args.query,
|
||||
'sequence': parsed_args.sequence,
|
||||
'action_policy': parsed_args.action_policy}
|
||||
|
||||
results = client.execute_policy_action(
|
||||
policy_name=parsed_args.policy,
|
||||
action="simulate",
|
||||
trace=parsed_args.trace,
|
||||
delta=parsed_args.delta,
|
||||
body=body)
|
||||
for result in results['result']:
|
||||
print(result)
|
||||
if 'trace' in results:
|
||||
print(results['trace'])
|
||||
return 0
|
||||
|
||||
|
||||
class ListPolicyTables(lister.Lister):
|
||||
"""List policy tables."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ListPolicyTables')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListPolicyTables, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy_name',
|
||||
metavar="<policy-name>",
|
||||
help="Name of the policy")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
data = client.list_policy_tables(parsed_args.policy_name)['results']
|
||||
columns = ['id']
|
||||
formatters = {'PolicyTables': utils.format_list}
|
||||
return (columns,
|
||||
(utils.get_dict_properties(s, columns,
|
||||
formatters=formatters)
|
||||
for s in data))
|
||||
|
||||
|
||||
class ListPolicy(lister.Lister):
|
||||
"""List Policy."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ListPolicy')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListPolicy, self).get_parser(prog_name)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.congressclient
|
||||
data = client.list_policy()['results']
|
||||
columns = ['id', 'name', 'owner_id', 'kind', 'description']
|
||||
formatters = {'Policies': utils.format_list}
|
||||
return (columns,
|
||||
(utils.get_dict_properties(s, columns,
|
||||
formatters=formatters)
|
||||
for s in data))
|
||||
|
||||
|
||||
class CreatePolicy(show.ShowOne):
|
||||
"""Create a policy."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.CreatePolicy')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreatePolicy, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy_name',
|
||||
metavar="<policy_name>",
|
||||
help="Name of the policy")
|
||||
parser.add_argument(
|
||||
'--description',
|
||||
metavar="<description>",
|
||||
help="Policy description")
|
||||
parser.add_argument(
|
||||
'--abbreviation',
|
||||
metavar="<abbreviation>",
|
||||
help="Policy abbreviation (used in traces). The length of the "
|
||||
"string must be equal to or less than 5 characters. Defaults "
|
||||
"to the first five characters of policy_name if not set.")
|
||||
parser.add_argument(
|
||||
'--kind',
|
||||
metavar="<kind>",
|
||||
choices=['nonrecursive', 'database', 'action', 'materialized'],
|
||||
help="Kind of policy: "
|
||||
"{nonrecursive, database, action, materialized}")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
body = {'name': parsed_args.policy_name,
|
||||
'description': parsed_args.description,
|
||||
'abbreviation': parsed_args.abbreviation,
|
||||
'kind': parsed_args.kind}
|
||||
data = client.create_policy(body)
|
||||
return zip(*sorted(six.iteritems(data)))
|
||||
|
||||
|
||||
class CreatePolicyFromFile(show.ShowOne):
|
||||
"""Create a policy."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.CreatePolicy')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreatePolicyFromFile, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy_file_path',
|
||||
metavar="<policy_file_path>",
|
||||
help="Path to policy file")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
with open(parsed_args.policy_file_path, "r") as stream:
|
||||
policies = yaml.load_all(stream)
|
||||
try:
|
||||
body = next(policies)
|
||||
except StopIteration:
|
||||
raise Exception('No policy found in file.')
|
||||
try:
|
||||
body = next(policies)
|
||||
raise Exception(
|
||||
'More than one policy found in file. None imported.')
|
||||
except StopIteration:
|
||||
pass
|
||||
data = client.create_policy(body)
|
||||
|
||||
def rule_dict_to_string(rules):
|
||||
rule_str_list = [rule['rule'] for rule in rules]
|
||||
return "\n".join(rule_str_list)
|
||||
|
||||
data['rules'] = rule_dict_to_string(data['rules'])
|
||||
return zip(*sorted(six.iteritems(data)))
|
||||
|
||||
|
||||
class DeletePolicy(command.Command):
|
||||
"""Delete a policy."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.DeletePolicy')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeletePolicy, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy',
|
||||
metavar="<policy>",
|
||||
help="ID or name of the policy to delete")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
|
||||
client.delete_policy(parsed_args.policy)
|
||||
|
||||
|
||||
class ListPolicyRows(lister.Lister):
|
||||
"""List policy rows."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ListPolicyRows')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListPolicyRows, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy_name',
|
||||
metavar="<policy-name>",
|
||||
help="Name of the policy to show")
|
||||
parser.add_argument(
|
||||
'table',
|
||||
metavar="<table>",
|
||||
help="Table to get the policy rows from")
|
||||
parser.add_argument(
|
||||
'--trace',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Display explanation of result")
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
answer = client.list_policy_rows(parsed_args.policy_name,
|
||||
parsed_args.table,
|
||||
parsed_args.trace)
|
||||
|
||||
if 'trace' in answer:
|
||||
sys.stdout.write(answer['trace'] + '\n')
|
||||
results = answer['results']
|
||||
columns = []
|
||||
if results:
|
||||
columns = ['Col%s' % (i)
|
||||
for i in range(0, len(results[0]['data']))]
|
||||
self.log.debug("Columns: " + str(columns))
|
||||
return (columns, (x['data'] for x in results))
|
||||
|
||||
|
||||
class ShowPolicyRule(show.ShowOne):
|
||||
"""Show a policy rule."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ShowPolicyRule')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowPolicyRule, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy_name',
|
||||
metavar="<policy-name>",
|
||||
help="Name or identifier of the policy")
|
||||
parser.add_argument(
|
||||
'rule_id',
|
||||
metavar="<rule-id/rule-name>",
|
||||
help="Policy rule id or rule name")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
results = client.list_policy_rules(parsed_args.policy_name)
|
||||
rule_id = utils.get_resource_id_from_name(
|
||||
parsed_args.rule_id, results)
|
||||
data = client.show_policy_rule(parsed_args.policy_name, rule_id)
|
||||
return zip(*sorted(six.iteritems(data)))
|
||||
|
||||
|
||||
class ShowPolicyTable(show.ShowOne):
|
||||
"""Show policy table properties."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ShowPolicyTable')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowPolicyTable, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy_name',
|
||||
metavar='<policy-name>',
|
||||
help="Name of policy")
|
||||
parser.add_argument(
|
||||
'table_id',
|
||||
metavar='<table-id>',
|
||||
help="Table id")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
data = client.show_policy_table(parsed_args.policy_name,
|
||||
parsed_args.table_id)
|
||||
return zip(*sorted(six.iteritems(data)))
|
||||
|
||||
|
||||
class ShowPolicy(show.ShowOne):
|
||||
"""Show policy properties."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.ShowPolicy')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowPolicy, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'policy_name',
|
||||
metavar='<policy-name>',
|
||||
help="Name of policy")
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug('take_action(%s)' % parsed_args)
|
||||
client = self.app.client_manager.congressclient
|
||||
results = client.list_policy()
|
||||
policy_id = utils.get_resource_id_from_name(
|
||||
parsed_args.policy_name, results)
|
||||
data = client.show_policy(policy_id)
|
||||
return zip(*sorted(six.iteritems(data)))
|
|
@ -1,51 +0,0 @@
|
|||
# Copyright 2010-2011 OpenStack Foundation
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
|
||||
import fixtures
|
||||
import testtools
|
||||
|
||||
_TRUE_VALUES = ('True', 'true', '1', 'yes')
|
||||
|
||||
|
||||
class TestCase(testtools.TestCase):
|
||||
|
||||
"""Test case base class for all unit tests."""
|
||||
|
||||
def setUp(self):
|
||||
"""Run before each test method to initialize test environment."""
|
||||
|
||||
super(TestCase, self).setUp()
|
||||
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
|
||||
try:
|
||||
test_timeout = int(test_timeout)
|
||||
except ValueError:
|
||||
# If timeout value is invalid do not set a timeout.
|
||||
test_timeout = 0
|
||||
if test_timeout > 0:
|
||||
self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
|
||||
|
||||
self.useFixture(fixtures.NestedTempfile())
|
||||
self.useFixture(fixtures.TempHomeDir())
|
||||
|
||||
if os.environ.get('OS_STDOUT_CAPTURE') in _TRUE_VALUES:
|
||||
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
|
||||
if os.environ.get('OS_STDERR_CAPTURE') in _TRUE_VALUES:
|
||||
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
|
||||
|
||||
self.log_fixture = self.useFixture(fixtures.FakeLogger())
|
|
@ -1,53 +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 argparse
|
||||
|
||||
import mock
|
||||
|
||||
from congressclient.tests import utils
|
||||
|
||||
|
||||
class TestCongressBase(utils.TestCommand):
|
||||
def setUp(self):
|
||||
super(TestCongressBase, self).setUp()
|
||||
self.app = mock.Mock(name='app')
|
||||
self.app.client_manager = mock.Mock(name='client_manager')
|
||||
self.namespace = argparse.Namespace()
|
||||
|
||||
given_show_options = [
|
||||
'-f',
|
||||
'shell',
|
||||
'-c',
|
||||
'id',
|
||||
'--prefix',
|
||||
'TST',
|
||||
]
|
||||
then_show_options = [
|
||||
('formatter', 'shell'),
|
||||
('columns', ['id']),
|
||||
('prefix', 'TST'),
|
||||
]
|
||||
given_list_options = [
|
||||
'-f',
|
||||
'csv',
|
||||
'-c',
|
||||
'id',
|
||||
'--quote',
|
||||
'all',
|
||||
]
|
||||
then_list_options = [
|
||||
('formatter', 'csv'),
|
||||
('columns', ['id']),
|
||||
('quote_mode', 'all'),
|
||||
]
|
|
@ -1,81 +0,0 @@
|
|||
# Copyright 2013 Nebula 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.
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
import six
|
||||
|
||||
|
||||
AUTH_TOKEN = "foobar"
|
||||
AUTH_URL = "http://0.0.0.0"
|
||||
|
||||
|
||||
class FakeStdout(object):
|
||||
def __init__(self):
|
||||
self.content = []
|
||||
|
||||
def write(self, text):
|
||||
self.content.append(text)
|
||||
|
||||
def make_string(self):
|
||||
result = ''
|
||||
for line in self.content:
|
||||
result = result + line
|
||||
return result
|
||||
|
||||
|
||||
class FakeApp(object):
|
||||
def __init__(self, _stdout):
|
||||
self.stdout = _stdout
|
||||
self.client_manager = None
|
||||
self.stdin = sys.stdin
|
||||
self.stdout = _stdout or sys.stdout
|
||||
self.stderr = sys.stderr
|
||||
self.restapi = None
|
||||
|
||||
|
||||
class FakeClientManager(object):
|
||||
def __init__(self):
|
||||
self.compute = None
|
||||
self.identity = None
|
||||
self.image = None
|
||||
self.object = None
|
||||
self.volume = None
|
||||
self.network = None
|
||||
self.auth_ref = None
|
||||
|
||||
|
||||
class FakeModule(object):
|
||||
def __init__(self, name, version):
|
||||
self.name = name
|
||||
self.__version__ = version
|
||||
|
||||
|
||||
class FakeResource(object):
|
||||
def __init__(self, manager, info, loaded=False):
|
||||
self.manager = manager
|
||||
self._info = info
|
||||
self._add_details(info)
|
||||
self._loaded = loaded
|
||||
|
||||
def _add_details(self, info):
|
||||
for (k, v) in six.iteritems(info):
|
||||
setattr(self, k, v)
|
||||
|
||||
def __repr__(self):
|
||||
reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and
|
||||
k != 'manager')
|
||||
info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
|
||||
return "<%s %s>" % (self.__class__.__name__, info)
|
|
@ -1,93 +0,0 @@
|
|||
# Copyright 2012-2013 OpenStack Foundation
|
||||
# Copyright 2013 Nebula 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.
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import fixtures
|
||||
import testtools
|
||||
|
||||
from congressclient.tests import fakes
|
||||
|
||||
|
||||
class TestCase(testtools.TestCase):
|
||||
def setUp(self):
|
||||
testtools.TestCase.setUp(self)
|
||||
|
||||
if (os.environ.get("OS_STDOUT_CAPTURE") == "True" or
|
||||
os.environ.get("OS_STDOUT_CAPTURE") == "1"):
|
||||
stdout = self.useFixture(fixtures.StringStream("stdout")).stream
|
||||
self.useFixture(fixtures.MonkeyPatch("sys.stdout", stdout))
|
||||
|
||||
if (os.environ.get("OS_STDERR_CAPTURE") == "True" or
|
||||
os.environ.get("OS_STDERR_CAPTURE") == "1"):
|
||||
stderr = self.useFixture(fixtures.StringStream("stderr")).stream
|
||||
self.useFixture(fixtures.MonkeyPatch("sys.stderr", stderr))
|
||||
|
||||
def assertNotCalled(self, m, msg=None):
|
||||
"""Assert a function was not called."""
|
||||
|
||||
if m.called:
|
||||
if not msg:
|
||||
msg = 'method %s should not have been called' % m
|
||||
self.fail(msg)
|
||||
|
||||
# 2.6 doesn't have the assert dict equals so make sure that it exists
|
||||
if tuple(sys.version_info)[0:2] < (2, 7):
|
||||
|
||||
def assertIsInstance(self, obj, cls, msg=None):
|
||||
"""self.assertTrue(isinstance(obj, cls)), with a nicer message."""
|
||||
|
||||
if not isinstance(obj, cls):
|
||||
standardMsg = '%s is not an instance of %r' % (obj, cls)
|
||||
self.fail(self._formatMessage(msg, standardMsg))
|
||||
|
||||
def assertDictEqual(self, d1, d2, msg=None):
|
||||
# Simple version taken from 2.7
|
||||
self.assertIsInstance(d1, dict,
|
||||
'First argument is not a dictionary')
|
||||
self.assertIsInstance(d2, dict,
|
||||
'Second argument is not a dictionary')
|
||||
if d1 != d2:
|
||||
if msg:
|
||||
self.fail(msg)
|
||||
else:
|
||||
standardMsg = '%r != %r' % (d1, d2)
|
||||
self.fail(standardMsg)
|
||||
|
||||
|
||||
class TestCommand(TestCase):
|
||||
"""Test cliff command classes."""
|
||||
|
||||
def setUp(self):
|
||||
super(TestCommand, self).setUp()
|
||||
# Build up a fake app
|
||||
self.fake_stdout = fakes.FakeStdout()
|
||||
self.app = fakes.FakeApp(self.fake_stdout)
|
||||
self.app.client_manager = fakes.FakeClientManager()
|
||||
|
||||
def check_parser(self, cmd, args, verify_args):
|
||||
cmd_parser = cmd.get_parser('check_parser')
|
||||
try:
|
||||
parsed_args = cmd_parser.parse_args(args)
|
||||
except SystemExit:
|
||||
raise Exception("Argument parse failed")
|
||||
for av in verify_args:
|
||||
attr, value = av
|
||||
if attr:
|
||||
self.assertIn(attr, parsed_args)
|
||||
self.assertEqual(getattr(parsed_args, attr), value)
|
||||
return parsed_args
|
|
@ -1,65 +0,0 @@
|
|||
# Copyright 2015 Huawei.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from congressclient.osc.v1 import api_versions
|
||||
from congressclient.tests import common
|
||||
|
||||
|
||||
class TestAPIVersions(common.TestCongressBase):
|
||||
|
||||
def test_list_api_versions(self):
|
||||
fake_response = {
|
||||
"versions": [
|
||||
{
|
||||
"status": "CURRENT",
|
||||
"updated": "2015-08-12T17:42:13Z",
|
||||
"id": "v2",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://localhost:1789/v2/",
|
||||
"rel": "self"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"status": "SUPPORTED",
|
||||
"updated": "2013-08-12T17:42:13Z",
|
||||
"id": "v1",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://localhost:1789/v1/",
|
||||
"rel": "self"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
with mock.patch.object(self.app.client_manager.congressclient,
|
||||
'list_api_versions',
|
||||
return_value=fake_response) as lister:
|
||||
|
||||
cmd = api_versions.ListAPIVersions(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, [], [])
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_once_with()
|
||||
self.assertEqual(['id', 'status', 'updated'], result[0])
|
||||
self.assertEqual(('v1', 'SUPPORTED', '2013-08-12T17:42:13Z'),
|
||||
next(result[1]))
|
||||
self.assertEqual(('v2', 'CURRENT', '2015-08-12T17:42:13Z'),
|
||||
next(result[1]))
|
|
@ -1,387 +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 mock
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from congressclient.common import utils
|
||||
from congressclient.osc.v1 import datasource
|
||||
from congressclient.tests import common
|
||||
|
||||
|
||||
class TestListDatasources(common.TestCongressBase):
|
||||
def test_list_datasource(self):
|
||||
datasource_name = 'neutron'
|
||||
arglist = [
|
||||
]
|
||||
verifylist = [
|
||||
]
|
||||
response = {
|
||||
"results": [{"id": datasource_name,
|
||||
"name": "my_name",
|
||||
"enabled": "True",
|
||||
"driver": "driver1",
|
||||
"config": None}]
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_datasources = lister
|
||||
cmd = datasource.ListDatasources(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with()
|
||||
self.assertEqual(['id', 'name', 'enabled', 'driver', 'config'],
|
||||
result[0])
|
||||
for row in result[1]:
|
||||
self.assertEqual(datasource_name, row[0])
|
||||
self.assertEqual("my_name", row[1])
|
||||
self.assertEqual("True", row[2])
|
||||
self.assertEqual("driver1", row[3])
|
||||
self.assertEqual("None", row[4])
|
||||
|
||||
def test_list_datasource_output_not_unicode(self):
|
||||
# response json string is converted to dict by oslo jsonutils.loads(),
|
||||
# so the key and value in the dict should be unicode type.
|
||||
response = {
|
||||
u"results": [{u"id": u"neutron",
|
||||
u"name": u"my_name",
|
||||
u"enabled": True,
|
||||
u"driver": 'driver1',
|
||||
u"config": {
|
||||
u'username': u'admin',
|
||||
u'tenant_name': u'admin',
|
||||
u'poll_time': u'10',
|
||||
u'password': u'<hidden>',
|
||||
u'auth_url': u'http://127.0.0.1:5000/v2.0'
|
||||
}}]
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_datasources = lister
|
||||
cmd = datasource.ListDatasources(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, [], [])
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with()
|
||||
self.assertEqual(['id', 'name', 'enabled', 'driver', 'config'],
|
||||
result[0])
|
||||
# get 'config' column
|
||||
config = list(result[1])[0][-1]
|
||||
self.assertIn("'username': 'admin'", config)
|
||||
self.assertNotIn("u'username': u'admin'", config)
|
||||
|
||||
|
||||
class TestListDatasourceTables(common.TestCongressBase):
|
||||
def test_list_datasource_tables(self):
|
||||
datasource_name = 'neutron'
|
||||
arglist = [
|
||||
datasource_name
|
||||
]
|
||||
verifylist = [
|
||||
('datasource_name', datasource_name)
|
||||
]
|
||||
response = {
|
||||
"results": [{"id": "ports"},
|
||||
{"id": "networks"}]
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_datasource_tables = lister
|
||||
cmd = datasource.ListDatasourceTables(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
|
||||
result = cmd.take_action(parsed_args)
|
||||
lister.assert_called_with(datasource_name)
|
||||
self.assertEqual(['id'], result[0])
|
||||
|
||||
|
||||
class TestListDatasourceStatus(common.TestCongressBase):
|
||||
def test_list_datasource_status(self):
|
||||
datasource_name = 'neutron'
|
||||
arglist = [
|
||||
datasource_name
|
||||
]
|
||||
verifylist = [
|
||||
('datasource_name', datasource_name)
|
||||
]
|
||||
response = {'last_updated': "now",
|
||||
'last_error': "None"}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_datasource_status = lister
|
||||
cmd = datasource.ShowDatasourceStatus(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
|
||||
lister.assert_called_with(datasource_name)
|
||||
self.assertEqual([('last_error', 'last_updated'),
|
||||
('None', 'now')],
|
||||
result)
|
||||
|
||||
|
||||
class TestShowDatasourceActions(common.TestCongressBase):
|
||||
def test_show_datasource_actions(self):
|
||||
datasource_name = 'fake'
|
||||
arglist = [
|
||||
datasource_name
|
||||
]
|
||||
verifylist = [
|
||||
('datasource_name', datasource_name)
|
||||
]
|
||||
response = {
|
||||
"results":
|
||||
[{'name': 'execute',
|
||||
'args': [{"name": "name", "description": "None"},
|
||||
{"name": "status", "description": "None"},
|
||||
{"name": "id", "description": "None"}],
|
||||
'description': 'execute action'}]
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_datasource_actions = lister
|
||||
cmd = datasource.ShowDatasourceActions(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_once_with(datasource_name)
|
||||
self.assertEqual(['action', 'args', 'description'], result[0])
|
||||
|
||||
|
||||
class TestShowDatasourceSchema(common.TestCongressBase):
|
||||
def test_show_datasource_schema(self):
|
||||
datasource_name = 'neutron'
|
||||
arglist = [
|
||||
datasource_name
|
||||
]
|
||||
verifylist = [
|
||||
('datasource_name', datasource_name)
|
||||
]
|
||||
response = {
|
||||
"tables":
|
||||
[{'table_id': 'ports',
|
||||
'columns': [{"name": "name", "description": "None"},
|
||||
{"name": "status", "description": "None"},
|
||||
{"name": "id", "description": "None"}]},
|
||||
{'table_id': 'routers',
|
||||
'columns': [{"name": "name", "description": "None"},
|
||||
{"name": "floating_ip", "description": "None"},
|
||||
{"name": "id", "description": "None"}]}]
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.show_datasource_schema = lister
|
||||
cmd = datasource.ShowDatasourceSchema(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with(datasource_name)
|
||||
self.assertEqual(['table', 'columns'], result[0])
|
||||
|
||||
|
||||
class TestShowDatasourceTableSchema(common.TestCongressBase):
|
||||
def test_show_datasource_table_schema(self):
|
||||
datasource_name = 'neutron'
|
||||
table_name = 'ports'
|
||||
arglist = [
|
||||
datasource_name, table_name
|
||||
]
|
||||
verifylist = [
|
||||
('datasource_name', datasource_name),
|
||||
('table_name', table_name)
|
||||
]
|
||||
response = {
|
||||
'table_id': 'ports',
|
||||
'columns': [{"name": "name", "description": "None"},
|
||||
{"name": "status", "description": "None"},
|
||||
{"name": "id", "description": "None"}]
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
client = self.app.client_manager.congressclient
|
||||
client.show_datasource_table_schema = lister
|
||||
cmd = datasource.ShowDatasourceTableSchema(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with(datasource_name, table_name)
|
||||
self.assertEqual(['name', 'description'], result[0])
|
||||
|
||||
|
||||
class TestListDatasourceRows(common.TestCongressBase):
|
||||
|
||||
def test_list_datasource_row(self):
|
||||
datasource_name = 'neutron'
|
||||
table_name = 'ports'
|
||||
arglist = [
|
||||
datasource_name, table_name
|
||||
]
|
||||
verifylist = [
|
||||
('datasource_name', datasource_name),
|
||||
('table', table_name)
|
||||
]
|
||||
response = {
|
||||
"results": [{"data": ["69abc88b-c950-4625-801b-542e84381509",
|
||||
"default"]}]
|
||||
}
|
||||
schema_response = {
|
||||
'table_id': 'ports',
|
||||
'columns': [{"name": "ID", "description": "None"},
|
||||
{"name": "name", "description": "None"}]
|
||||
}
|
||||
|
||||
client = self.app.client_manager.congressclient
|
||||
lister = mock.Mock(return_value=response)
|
||||
client.list_datasource_rows = lister
|
||||
schema_lister = mock.Mock(return_value=schema_response)
|
||||
client.show_datasource_table_schema = schema_lister
|
||||
cmd = datasource.ListDatasourceRows(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with(datasource_name, table_name)
|
||||
self.assertEqual(['ID', 'name'], result[0])
|
||||
|
||||
|
||||
class TestShowDatasourceTable(common.TestCongressBase):
|
||||
def test_show_datasource_table(self):
|
||||
datasource_name = 'neutron'
|
||||
table_id = 'ports'
|
||||
arglist = [
|
||||
datasource_name, table_id
|
||||
]
|
||||
verifylist = [
|
||||
('datasource_name', datasource_name),
|
||||
('table_id', table_id)
|
||||
]
|
||||
response = {
|
||||
'id': 'ports',
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
client = self.app.client_manager.congressclient
|
||||
client.show_datasource_table = lister
|
||||
cmd = datasource.ShowDatasourceTable(self.app, self.namespace)
|
||||
expected_ret = [('id',), ('ports',)]
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
|
||||
self.assertEqual(expected_ret, result)
|
||||
|
||||
|
||||
class TestCreateDatasource(common.TestCongressBase):
|
||||
|
||||
def test_create_datasource(self):
|
||||
driver = 'neutronv2'
|
||||
name = 'arosen-neutronv2'
|
||||
response = {"description": '',
|
||||
"config": {"username": "admin",
|
||||
"tenant_name": "admin",
|
||||
"password": "password",
|
||||
"auth_url": "http://127.0.0.1:5000/v2.0"},
|
||||
"enabled": True,
|
||||
"owner": "user",
|
||||
"driver": "neutronv2",
|
||||
"type": None,
|
||||
"id": "b72f81a0-32b5-4bf4-a1f6-d69c09c42cec",
|
||||
"name": "arosen-neutronv2"}
|
||||
|
||||
arglist = [driver, name,
|
||||
"--config", "username=admin",
|
||||
"--config", "password=password",
|
||||
"--config", "auth_url=http://1.1.1.1/foo",
|
||||
"--config", "tenant_name=admin"]
|
||||
verifylist = [
|
||||
('driver', driver),
|
||||
('name', name),
|
||||
('config', {'username': 'admin', 'password': 'password',
|
||||
'auth_url': 'http://1.1.1.1/foo',
|
||||
'tenant_name': 'admin'}),
|
||||
]
|
||||
|
||||
mocker = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.create_datasource = mocker
|
||||
cmd = datasource.CreateDatasource(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
filtered = [('config', 'description',
|
||||
'driver', 'enabled', 'id', 'name',
|
||||
'owner', 'type'),
|
||||
(response['config'], response['description'],
|
||||
response['driver'], response['enabled'],
|
||||
response['id'], response['name'],
|
||||
response['owner'], response['type'])]
|
||||
self.assertEqual(filtered, result)
|
||||
|
||||
|
||||
class TestDeleteDatasourceDriver(common.TestCongressBase):
|
||||
|
||||
def test_delete_datasource(self):
|
||||
driver = 'neutronv2'
|
||||
|
||||
arglist = [driver]
|
||||
verifylist = [('datasource', driver), ]
|
||||
|
||||
mocker = mock.Mock(return_value=None)
|
||||
self.app.client_manager.congressclient.delete_datasource = mocker
|
||||
cmd = datasource.DeleteDatasource(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
mocker.assert_called_with(driver)
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
class TestUpdateDatasourceRow(common.TestCongressBase):
|
||||
|
||||
def test_update_datasource_row(self):
|
||||
driver = 'push'
|
||||
table_name = 'table'
|
||||
rows = [["data1", "data2"],
|
||||
["data3", "data4"]]
|
||||
|
||||
arglist = [driver, table_name, jsonutils.dumps(rows)]
|
||||
verifylist = [('datasource', driver),
|
||||
('table', table_name),
|
||||
('rows', rows)]
|
||||
|
||||
mocker = mock.Mock(return_value=None)
|
||||
self.app.client_manager.congressclient.update_datasource_rows = mocker
|
||||
self.app.client_manager.congressclient.list_datasources = mock.Mock()
|
||||
|
||||
cmd = datasource.UpdateDatasourceRow(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
with mock.patch.object(utils, 'get_resource_id_from_name',
|
||||
return_value="push"):
|
||||
cmd.take_action(parsed_args)
|
||||
mocker.assert_called_with(driver, table_name, rows)
|
||||
|
||||
|
||||
class TestDatasourceRequestRefresh(common.TestCongressBase):
|
||||
|
||||
def test_datasource_request_refresh(self):
|
||||
driver = 'neutronv2'
|
||||
|
||||
arglist = [driver]
|
||||
verifylist = [('datasource', driver), ]
|
||||
|
||||
mocker = mock.Mock(return_value=None)
|
||||
self.app.client_manager.congressclient.request_refresh = mocker
|
||||
self.app.client_manager.congressclient.list_datasources = mock.Mock()
|
||||
cmd = datasource.DatasourceRequestRefresh(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
with mock.patch.object(utils, "get_resource_id_from_name",
|
||||
return_value="id"):
|
||||
result = cmd.take_action(parsed_args)
|
||||
mocker.assert_called_with("id", {})
|
||||
self.assertIsNone(result)
|
|
@ -1,101 +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 mock
|
||||
|
||||
from congressclient.osc.v1 import driver
|
||||
from congressclient.tests import common
|
||||
|
||||
|
||||
class TestListDrivers(common.TestCongressBase):
|
||||
|
||||
def test_list_drivers(self):
|
||||
arglist = [
|
||||
]
|
||||
verifylist = [
|
||||
]
|
||||
response = {
|
||||
"results": [{"id": "neutronv2",
|
||||
"description": "this does blah.."}]
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_drivers = lister
|
||||
cmd = driver.ListDrivers(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with()
|
||||
self.assertEqual(['id', 'description'], result[0])
|
||||
|
||||
|
||||
class TestShowDriverSchema(common.TestCongressBase):
|
||||
|
||||
def test_show_driver_shema(self):
|
||||
arglist = [
|
||||
"neutronv2"
|
||||
]
|
||||
verifylist = [
|
||||
('driver', "neutronv2")
|
||||
]
|
||||
|
||||
response = {
|
||||
"tables":
|
||||
[{'table_id': 'ports',
|
||||
'columns': [{"name": "name", "description": "None"},
|
||||
{"name": "status", "description": "None"},
|
||||
{"name": "id", "description": "None"}]},
|
||||
{'table_id': 'routers',
|
||||
'columns': [{"name": "name", "description": "None"},
|
||||
{"name": "floating_ip", "description": "None"},
|
||||
{"name": "id", "description": "None"}]}]
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.show_driver = lister
|
||||
cmd = driver.ShowDriverSchema(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with("neutronv2")
|
||||
self.assertEqual(['table', 'columns'], result[0])
|
||||
|
||||
|
||||
class TestShowDriverConfig(common.TestCongressBase):
|
||||
|
||||
def test_show_driver_config(self):
|
||||
arglist = [
|
||||
"neutronv2"
|
||||
]
|
||||
verifylist = [
|
||||
('driver', "neutronv2")
|
||||
]
|
||||
|
||||
response = {
|
||||
"tables": [],
|
||||
'id': 'aabbcc',
|
||||
'description': 'foobar',
|
||||
'config': {'password': 'password'},
|
||||
}
|
||||
mocker = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.show_driver = mocker
|
||||
cmd = driver.ShowDriverConfig(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
|
||||
mocker.assert_called_with("neutronv2")
|
||||
filtered = [('config', 'description', 'id'),
|
||||
(response['config'], response['description'],
|
||||
response['id'])]
|
||||
self.assertEqual(filtered, result)
|
|
@ -1,474 +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 os
|
||||
|
||||
import mock
|
||||
|
||||
from congressclient.common import utils
|
||||
from congressclient.osc.v1 import policy
|
||||
from congressclient.tests import common
|
||||
|
||||
|
||||
class TestCreatePolicy(common.TestCongressBase):
|
||||
|
||||
def test_create_policy(self):
|
||||
policy_name = 'test1'
|
||||
policy_id = "e531f2b3-3d97-42c0-b3b5-b7b6ab532018"
|
||||
response = {"description": "",
|
||||
"id": policy_id,
|
||||
"name": policy_name,
|
||||
"kind": "nonrecursive",
|
||||
"owner": "system",
|
||||
"abbreviation": "test1"}
|
||||
|
||||
arglist = [policy_name]
|
||||
verifylist = [
|
||||
('policy_name', policy_name),
|
||||
]
|
||||
|
||||
mocker = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.create_policy = mocker
|
||||
cmd = policy.CreatePolicy(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
filtered = [('abbreviation', 'description', 'id', 'kind', 'name',
|
||||
'owner'),
|
||||
(policy_name, '', policy_id, 'nonrecursive',
|
||||
policy_name, 'system')]
|
||||
self.assertEqual(filtered, result)
|
||||
|
||||
|
||||
class TestCreatePolicyFromFile(common.TestCongressBase):
|
||||
|
||||
def test_create_policy(self):
|
||||
policy_path = os.path.dirname(
|
||||
os.path.abspath(__file__)) + '/test_policy_file.yaml'
|
||||
policy_id = "e531f2b3-3d97-42c0-b3b5-b7b6ab532018"
|
||||
response = {"description": "",
|
||||
"id": policy_id,
|
||||
"name": "test_policy",
|
||||
"kind": "nonrecursive",
|
||||
"owner": "system",
|
||||
"abbreviation": "abbr",
|
||||
"rules": [
|
||||
{'comment': 'test comment', 'name': 'test name',
|
||||
'rule': 'p(x) :- q(x)'},
|
||||
{'comment': 'test comment2', 'name': 'test name2',
|
||||
'rule': 'p(x) :- q2(x)'}]}
|
||||
|
||||
arglist = [policy_path]
|
||||
verifylist = [
|
||||
('policy_file_path', policy_path),
|
||||
]
|
||||
|
||||
mocker = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.create_policy = mocker
|
||||
cmd = policy.CreatePolicyFromFile(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
filtered = [('abbreviation', 'description', 'id', 'kind', 'name',
|
||||
'owner', 'rules'),
|
||||
('abbr', '', policy_id, 'nonrecursive',
|
||||
'test_policy', 'system',
|
||||
'p(x) :- q(x)\n'
|
||||
'p(x) :- q2(x)')]
|
||||
self.assertEqual(filtered, result)
|
||||
|
||||
|
||||
class TestShowPolicy(common.TestCongressBase):
|
||||
def test_show_policy(self):
|
||||
policy_id = "14f2897a-155a-4c9d-b3de-ef85c0a171d8"
|
||||
policy_name = "test1"
|
||||
arglist = [policy_id]
|
||||
verifylist = [
|
||||
('policy_name', policy_id),
|
||||
]
|
||||
response = {"description": "",
|
||||
"id": policy_id,
|
||||
"name": policy_name,
|
||||
"kind": "nonrecursive",
|
||||
"owner": "system",
|
||||
"abbreviation": "test1"}
|
||||
|
||||
mocker = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.show_policy = mocker
|
||||
self.app.client_manager.congressclient.list_policy = mock.Mock()
|
||||
cmd = policy.ShowPolicy(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
with mock.patch.object(utils, "get_resource_id_from_name",
|
||||
return_value="name"):
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
filtered = [('abbreviation', 'description', 'id', 'kind', 'name',
|
||||
'owner'),
|
||||
(policy_name, '', policy_id, 'nonrecursive',
|
||||
policy_name, 'system')]
|
||||
self.assertEqual(filtered, result)
|
||||
|
||||
|
||||
class TestDeletePolicy(common.TestCongressBase):
|
||||
def test_delete_policy(self):
|
||||
policy_id = 'e531f2b3-3d97-42c0-b3b5-b7b6ab532018'
|
||||
arglist = [
|
||||
policy_id
|
||||
]
|
||||
verifylist = [
|
||||
('policy', policy_id)
|
||||
]
|
||||
mocker = mock.Mock(return_value=None)
|
||||
self.app.client_manager.congressclient.delete_policy = mocker
|
||||
self.app.client_manager.congressclient.list_policy = mock.Mock()
|
||||
cmd = policy.DeletePolicy(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
with mock.patch.object(utils, "get_resource_id_from_name",
|
||||
return_value="id"):
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
mocker.assert_called_with(policy_id)
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
class TestCreatePolicyRule(common.TestCongressBase):
|
||||
|
||||
def test_create_policy_rule(self):
|
||||
policy_name = 'classification'
|
||||
rule = "p(x) :- q(x)"
|
||||
response = {"comment": "Comment",
|
||||
"id": "e531f2b3-3d97-42c0-b3b5-b7b6ab532018",
|
||||
"rule": rule}
|
||||
|
||||
arglist = [policy_name, rule]
|
||||
verifylist = [
|
||||
('policy_name', policy_name),
|
||||
('rule', rule),
|
||||
]
|
||||
|
||||
mocker = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.create_policy_rule = mocker
|
||||
cmd = policy.CreatePolicyRule(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
filtered = [('comment', 'id', 'rule'),
|
||||
('Comment', 'e531f2b3-3d97-42c0-b3b5-b7b6ab532018', rule)]
|
||||
self.assertEqual(filtered, result)
|
||||
|
||||
def test_create_policy_rule_with_name(self):
|
||||
policy_name = "classification"
|
||||
rule = "p(x) :- q(x)"
|
||||
rule_name = "classification_rule"
|
||||
response = {"comment": "None",
|
||||
"id": "e531f2b3-3d97-42c0-b3b5-b7b6ab532018",
|
||||
"rule": rule,
|
||||
"name": rule_name}
|
||||
|
||||
arglist = ["--name", rule_name, policy_name, rule]
|
||||
verifylist = [
|
||||
('policy_name', policy_name),
|
||||
('rule', rule),
|
||||
("rule_name", rule_name)
|
||||
]
|
||||
|
||||
mocker = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.create_policy_rule = mocker
|
||||
cmd = policy.CreatePolicyRule(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
filtered = [('comment', 'id', 'name', 'rule'),
|
||||
('None', 'e531f2b3-3d97-42c0-b3b5-b7b6ab532018', rule_name,
|
||||
rule)]
|
||||
self.assertEqual(filtered, result)
|
||||
|
||||
|
||||
class TestDeletePolicyRule(common.TestCongressBase):
|
||||
def test_delete_policy_rule(self):
|
||||
policy_name = 'classification'
|
||||
rule_id = 'e531f2b3-3d97-42c0-b3b5-b7b6ab532018'
|
||||
arglist = [
|
||||
policy_name, rule_id
|
||||
]
|
||||
verifylist = [
|
||||
('policy_name', policy_name),
|
||||
('rule_id', rule_id)
|
||||
]
|
||||
mocker = mock.Mock(return_value=None)
|
||||
self.app.client_manager.congressclient.delete_policy_rule = mocker
|
||||
self.app.client_manager.congressclient.list_policy_rules = mock.Mock()
|
||||
cmd = policy.DeletePolicyRule(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
with mock.patch.object(utils, "get_resource_id_from_name",
|
||||
return_value=rule_id):
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
mocker.assert_called_with(policy_name, rule_id)
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
class TestListPolicyRules(common.TestCongressBase):
|
||||
def test_list_policy_rules(self):
|
||||
policy_name = 'classification'
|
||||
rule_id = 'e531f2b3-3d97-42c0-b3b5-b7b6ab532018'
|
||||
arglist = [
|
||||
policy_name
|
||||
]
|
||||
verifylist = [
|
||||
('policy_name', policy_name)
|
||||
]
|
||||
response = {
|
||||
"results": [{"comment": "None",
|
||||
"id": rule_id,
|
||||
"rule": "security_group(port, security_group_name)"
|
||||
}]
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_policy_rules = lister
|
||||
cmd = policy.ListPolicyRules(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with(policy_name)
|
||||
|
||||
|
||||
class TestListPolicy(common.TestCongressBase):
|
||||
def test_list_policy_rules(self):
|
||||
policy_name = 'classification'
|
||||
policy_id = 'e531f2b3-3d97-42c0-b3b5-b7b6ab532018'
|
||||
arglist = [
|
||||
]
|
||||
verifylist = [
|
||||
]
|
||||
response = {
|
||||
"results": [{"id": policy_id,
|
||||
"owner_id": "system",
|
||||
"name": policy_name,
|
||||
"kind": "nonrecursive",
|
||||
"description": "my description"
|
||||
}]}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_policy = lister
|
||||
cmd = policy.ListPolicy(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with()
|
||||
self.assertEqual(['id', 'name', 'owner_id', 'kind', 'description'],
|
||||
result[0])
|
||||
|
||||
|
||||
class TestListPolicyTables(common.TestCongressBase):
|
||||
def test_list_policy_tables(self):
|
||||
policy_name = 'classification'
|
||||
arglist = [
|
||||
policy_name
|
||||
]
|
||||
verifylist = [
|
||||
('policy_name', policy_name)
|
||||
]
|
||||
response = {
|
||||
"results": [{"id": "ports"},
|
||||
{"id": "virtual_machines"}]
|
||||
}
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_policy_tables = lister
|
||||
cmd = policy.ListPolicyTables(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
result = cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with(policy_name)
|
||||
self.assertEqual(['id'], result[0])
|
||||
|
||||
|
||||
class TestListPolicyRows(common.TestCongressBase):
|
||||
|
||||
def test_list_policy_rules(self):
|
||||
policy_name = 'classification'
|
||||
table_name = 'port_security_group'
|
||||
arglist = [
|
||||
policy_name, table_name
|
||||
]
|
||||
verifylist = [
|
||||
('policy_name', policy_name),
|
||||
('table', table_name)
|
||||
]
|
||||
response = {"results":
|
||||
[{"data": ["69abc88b-c950-4625-801b-542e84381509",
|
||||
"default"]}]}
|
||||
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_policy_rows = lister
|
||||
cmd = policy.ListPolicyRows(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with(policy_name, table_name, False)
|
||||
|
||||
def test_list_policy_rules_trace(self):
|
||||
policy_name = 'classification'
|
||||
table_name = 'p'
|
||||
arglist = [
|
||||
policy_name, table_name, "--trace"
|
||||
]
|
||||
verifylist = [
|
||||
('policy_name', policy_name),
|
||||
('table', table_name)
|
||||
]
|
||||
response = {"results":
|
||||
[{"data": ["69abc88b-c950-4625-801b-542e84381509",
|
||||
"default"]}],
|
||||
"trace": "Call p(x, y)\n "
|
||||
"Exit p('69abc88b-c950-4625-801b-542e84381509', "
|
||||
"'default')\n"}
|
||||
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.list_policy_rows = lister
|
||||
cmd = policy.ListPolicyRows(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
cmd.take_action(parsed_args)
|
||||
|
||||
lister.assert_called_with(policy_name, table_name, True)
|
||||
|
||||
|
||||
class TestSimulatePolicy(common.TestCongressBase):
|
||||
|
||||
def test_simulate_policy(self):
|
||||
policy_name = 'classification'
|
||||
action_name = 'action'
|
||||
sequence = 'q(1)'
|
||||
query = 'error(x)'
|
||||
arglist = [
|
||||
policy_name, query, sequence, action_name
|
||||
]
|
||||
verifylist = [
|
||||
('policy', policy_name),
|
||||
('action_policy', action_name),
|
||||
('sequence', sequence),
|
||||
('query', query),
|
||||
('delta', False)
|
||||
]
|
||||
response = {'result': ['error(1)', 'error(2)']}
|
||||
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.execute_policy_action = lister
|
||||
cmd = policy.SimulatePolicy(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
cmd.take_action(parsed_args)
|
||||
|
||||
body = {'action_policy': action_name,
|
||||
'sequence': sequence,
|
||||
'query': query}
|
||||
lister.assert_called_with(policy_name=policy_name,
|
||||
action='simulate',
|
||||
trace=False,
|
||||
delta=False,
|
||||
body=body)
|
||||
|
||||
def test_simulate_policy_delta(self):
|
||||
policy_name = 'classification'
|
||||
action_name = 'action'
|
||||
sequence = 'q(1)'
|
||||
query = 'error(x)'
|
||||
arglist = [
|
||||
policy_name, query, sequence, action_name, "--delta"
|
||||
]
|
||||
verifylist = [
|
||||
('policy', policy_name),
|
||||
('action_policy', action_name),
|
||||
('sequence', sequence),
|
||||
('query', query),
|
||||
('delta', True)
|
||||
]
|
||||
response = {'result': ['error(1)', 'error(2)']}
|
||||
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.execute_policy_action = lister
|
||||
cmd = policy.SimulatePolicy(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
cmd.take_action(parsed_args)
|
||||
|
||||
body = {'action_policy': action_name,
|
||||
'sequence': sequence,
|
||||
'query': query}
|
||||
lister.assert_called_with(policy_name=policy_name,
|
||||
action='simulate',
|
||||
trace=False,
|
||||
delta=True,
|
||||
body=body)
|
||||
|
||||
def test_simulate_policy_trace(self):
|
||||
policy_name = 'classification'
|
||||
action_name = 'action'
|
||||
sequence = 'q(1)'
|
||||
query = 'error(x)'
|
||||
arglist = [
|
||||
policy_name, query, sequence, action_name, "--trace"
|
||||
]
|
||||
verifylist = [
|
||||
('policy', policy_name),
|
||||
('action_policy', action_name),
|
||||
('sequence', sequence),
|
||||
('query', query),
|
||||
('trace', True)
|
||||
]
|
||||
response = {'result': ['error(1)', 'error(2)'], 'trace': 'Call'}
|
||||
|
||||
lister = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.execute_policy_action = lister
|
||||
cmd = policy.SimulatePolicy(self.app, self.namespace)
|
||||
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
cmd.take_action(parsed_args)
|
||||
|
||||
body = {'action_policy': action_name,
|
||||
'sequence': sequence,
|
||||
'query': query}
|
||||
lister.assert_called_with(policy_name=policy_name,
|
||||
action='simulate',
|
||||
trace=True,
|
||||
delta=False,
|
||||
body=body)
|
||||
|
||||
|
||||
class TestGet(common.TestCongressBase):
|
||||
|
||||
def test_create_policy_rule(self):
|
||||
policy_name = 'classification'
|
||||
rule = "p(x) :- q(x)"
|
||||
id = "e531f2b3-3d97-42c0-b3b5-b7b6ab532018"
|
||||
response = {"comment": "None",
|
||||
"id": id,
|
||||
"rule": rule}
|
||||
|
||||
arglist = [policy_name, id]
|
||||
verifylist = [
|
||||
('policy_name', policy_name),
|
||||
('rule_id', id),
|
||||
]
|
||||
|
||||
mocker = mock.Mock(return_value=response)
|
||||
self.app.client_manager.congressclient.show_policy_rule = mocker
|
||||
self.app.client_manager.congressclient.list_policy_rules = mock.Mock()
|
||||
cmd = policy.ShowPolicyRule(self.app, self.namespace)
|
||||
parsed_args = self.check_parser(cmd, arglist, verifylist)
|
||||
with mock.patch.object(utils, "get_resource_id_from_name",
|
||||
return_value="id"):
|
||||
result = list(cmd.take_action(parsed_args))
|
||||
filtered = [('comment', 'id', 'rule'),
|
||||
('None', id, rule)]
|
||||
self.assertEqual(filtered, result)
|
|
@ -1,17 +0,0 @@
|
|||
---
|
||||
name: PauseBadFlavors
|
||||
description: "Pause any server using a flavor that is not permitted"
|
||||
rules:
|
||||
-
|
||||
comment: "User should customize this. Permitted flavors."
|
||||
rule: permitted_flavor('m1.tiny')
|
||||
-
|
||||
comment: "User should customize this. Permitted flavors."
|
||||
rule: permitted_flavor('m1.large')
|
||||
-
|
||||
rule: >
|
||||
server_with_bad_flavor(id) :- nova:servers(id=id,flavor_id=flavor_id),
|
||||
nova:flavors(id=flavor_id, name=flavor), not permitted_flavor(flavor)
|
||||
-
|
||||
comment: "Remediation: Pause any VM that shows up in the server_with_bad_flavor table"
|
||||
rule: "execute[nova:servers.pause(id)] :- server_with_bad_flavor(id), nova:servers(id,status='ACTIVE')"
|
|
@ -1,242 +0,0 @@
|
|||
# Copyright 2014 VMWare.
|
||||
#
|
||||
# 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 keystoneauth1 import adapter
|
||||
|
||||
|
||||
class Client(object):
|
||||
"""Client for the Congress v1 API.
|
||||
|
||||
Example
|
||||
::
|
||||
|
||||
from keystoneauth1.identity import v2
|
||||
from keystoneauth1 import session
|
||||
from congressclient.v1 import client
|
||||
auth = v2.Password(auth_url=AUTH_URL, username=USERNAME,
|
||||
password=PASSWORD, tenant_name=TENANT_NAME)
|
||||
sess = session.Session(auth=auth)
|
||||
congress = client.Client(session=sess,
|
||||
auth=None,
|
||||
interface='publicURL',
|
||||
service_type='policy',
|
||||
region_name='RegionOne')
|
||||
congress.create_policy_rule(..)
|
||||
|
||||
"""
|
||||
policy_path = '/v1/policies/%s'
|
||||
policy_rules = '/v1/policies/%s/rules'
|
||||
policy_rules_path = '/v1/policies/%s/rules/%s'
|
||||
policy_tables = '/v1/policies/%s/tables'
|
||||
policy_table_path = '/v1/policies/%s/tables/%s'
|
||||
policy_rows = '/v1/policies/%s/tables/%s/rows'
|
||||
policy_rows_trace = '/v1/policies/%s/tables/%s/rows?trace=True'
|
||||
policies = '/v1/policies'
|
||||
policy_action = '/v1/policies/%s?%s'
|
||||
library_policy_path = '/v1/librarypolicies/%s'
|
||||
library_policies = '/v1/librarypolicies'
|
||||
datasources = '/v1/data-sources'
|
||||
datasource_path = '/v1/data-sources/%s'
|
||||
datasource_tables = '/v1/data-sources/%s/tables'
|
||||
datasource_table_path = '/v1/data-sources/%s/tables/%s'
|
||||
datasource_status = '/v1/data-sources/%s/status'
|
||||
datasource_actions = '/v1/data-sources/%s/actions'
|
||||
datasource_schema = '/v1/data-sources/%s/schema'
|
||||
datasource_table_schema = '/v1/data-sources/%s/tables/%s/spec'
|
||||
datasource_rows = '/v1/data-sources/%s/tables/%s/rows'
|
||||
driver = '/v1/system/drivers'
|
||||
driver_path = '/v1/system/drivers/%s'
|
||||
policy_api_versions = '/'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(Client, self).__init__()
|
||||
|
||||
kwargs.setdefault('user_agent', 'python-congressclient')
|
||||
self.httpclient = adapter.LegacyJsonAdapter(**kwargs)
|
||||
|
||||
def create_policy(self, body):
|
||||
resp, body = self.httpclient.post(
|
||||
self.policies, body=body)
|
||||
return body
|
||||
|
||||
def delete_policy(self, policy):
|
||||
resp, body = self.httpclient.delete(
|
||||
self.policy_path % policy)
|
||||
return body
|
||||
|
||||
def show_policy(self, policy):
|
||||
resp, body = self.httpclient.get(
|
||||
self.policy_path % policy)
|
||||
return body
|
||||
|
||||
def create_library_policy(self, body):
|
||||
resp, body = self.httpclient.post(
|
||||
self.library_policies, body=body)
|
||||
return body
|
||||
|
||||
def delete_library_policy(self, policy):
|
||||
resp, body = self.httpclient.delete(
|
||||
self.library_policy_path % policy)
|
||||
return body
|
||||
|
||||
def show_library_policy(self, policy):
|
||||
resp, body = self.httpclient.get(
|
||||
self.library_policy_path % policy)
|
||||
return body
|
||||
|
||||
def create_policy_rule(self, policy_name, body=None):
|
||||
resp, body = self.httpclient.post(
|
||||
self.policy_rules % policy_name, body=body)
|
||||
return body
|
||||
|
||||
def delete_policy_rule(self, policy_name, rule_id):
|
||||
resp, body = self.httpclient.delete(
|
||||
self.policy_rules_path % (policy_name, rule_id))
|
||||
return body
|
||||
|
||||
def show_policy_rule(self, policy_name, rule_id):
|
||||
resp, body = self.httpclient.get(
|
||||
self.policy_rules_path % (policy_name, rule_id))
|
||||
return body
|
||||
|
||||
def list_policy_rows(self, policy_name, table, trace=None):
|
||||
if trace:
|
||||
query = self.policy_rows_trace
|
||||
else:
|
||||
query = self.policy_rows
|
||||
resp, body = self.httpclient.get(query % (policy_name, table))
|
||||
return body
|
||||
|
||||
def list_policy_rules(self, policy_name):
|
||||
resp, body = self.httpclient.get(self.policy_rules % (policy_name))
|
||||
return body
|
||||
|
||||
def list_policy(self):
|
||||
resp, body = self.httpclient.get(self.policies)
|
||||
return body
|
||||
|
||||
def list_library_policy(self):
|
||||
resp, body = self.httpclient.get(self.library_policies)
|
||||
return body
|
||||
|
||||
def list_policy_tables(self, policy_name):
|
||||
resp, body = self.httpclient.get(self.policy_tables % (policy_name))
|
||||
return body
|
||||
|
||||
def execute_policy_action(self, policy_name, action, trace, delta, body):
|
||||
uri = "?action=%s&trace=%s&delta=%s" % (action, trace, delta)
|
||||
resp, body = self.httpclient.post(
|
||||
(self.policy_path % policy_name) + str(uri), body=body)
|
||||
return body
|
||||
|
||||
def show_policy_table(self, policy_name, table_id):
|
||||
resp, body = self.httpclient.get(self.policy_table_path %
|
||||
(policy_name, table_id))
|
||||
return body
|
||||
|
||||
def list_datasources(self):
|
||||
resp, body = self.httpclient.get(self.datasources)
|
||||
return body
|
||||
|
||||
def show_datasource(self, datasource_name):
|
||||
"""Get a single datasource
|
||||
|
||||
Intended for use by Horizon. Not available in CLI
|
||||
"""
|
||||
resp, body = self.httpclient.get(self.datasource_path %
|
||||
(datasource_name))
|
||||
return body
|
||||
|
||||
def list_datasource_tables(self, datasource_name):
|
||||
resp, body = self.httpclient.get(self.datasource_tables %
|
||||
(datasource_name))
|
||||
return body
|
||||
|
||||
def list_datasource_rows(self, datasource_name, table_name):
|
||||
resp, body = self.httpclient.get(self.datasource_rows %
|
||||
(datasource_name, table_name))
|
||||
return body
|
||||
|
||||
def update_datasource_rows(self, datasource_name, table_name, body=None):
|
||||
"""Update rows in a table of a datasource.
|
||||
|
||||
Args:
|
||||
datasource_name: Name or id of the datasource
|
||||
table_name: Table name for updating
|
||||
body: Rows for update.
|
||||
"""
|
||||
resp, body = self.httpclient.put(self.datasource_rows %
|
||||
(datasource_name, table_name),
|
||||
body=body)
|
||||
return body
|
||||
|
||||
def list_datasource_status(self, datasource_name):
|
||||
resp, body = self.httpclient.get(self.datasource_status %
|
||||
datasource_name)
|
||||
return body
|
||||
|
||||
def list_datasource_actions(self, datasource_name):
|
||||
resp, body = self.httpclient.get(self.datasource_actions %
|
||||
datasource_name)
|
||||
return body
|
||||
|
||||
def show_datasource_schema(self, datasource_name):
|
||||
resp, body = self.httpclient.get(self.datasource_schema %
|
||||
datasource_name)
|
||||
return body
|
||||
|
||||
def show_datasource_table_schema(self, datasource_name, table_name):
|
||||
resp, body = self.httpclient.get(self.datasource_table_schema %
|
||||
(datasource_name, table_name))
|
||||
return body
|
||||
|
||||
def show_datasource_table(self, datasource_name, table_id):
|
||||
resp, body = self.httpclient.get(self.datasource_table_path %
|
||||
(datasource_name, table_id))
|
||||
return body
|
||||
|
||||
def create_datasource(self, body=None):
|
||||
resp, body = self.httpclient.post(
|
||||
self.datasources, body=body)
|
||||
return body
|
||||
|
||||
def delete_datasource(self, datasource):
|
||||
resp, body = self.httpclient.delete(
|
||||
self.datasource_path % datasource)
|
||||
return body
|
||||
|
||||
def execute_datasource_action(self, service_name, action, body):
|
||||
uri = "?action=%s" % (action)
|
||||
resp, body = self.httpclient.post(
|
||||
(self.datasource_path % service_name) + str(uri), body=body)
|
||||
return body
|
||||
|
||||
def list_drivers(self):
|
||||
resp, body = self.httpclient.get(self.driver)
|
||||
return body
|
||||
|
||||
def show_driver(self, driver):
|
||||
resp, body = self.httpclient.get(self.driver_path %
|
||||
(driver))
|
||||
return body
|
||||
|
||||
def request_refresh(self, driver, body=None):
|
||||
resp, body = self.httpclient.post(self.datasource_path %
|
||||
(driver) + "?action=request-refresh",
|
||||
body=body)
|
||||
return body
|
||||
|
||||
def list_api_versions(self):
|
||||
resp, body = self.httpclient.get(self.policy_api_versions)
|
||||
return body
|
|
@ -1,86 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
# -- General configuration ----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
#'sphinx.ext.intersphinx',
|
||||
'openstackdocstheme'
|
||||
]
|
||||
|
||||
# openstackdocstheme options
|
||||
repository_name = 'openstack/python-congressclient'
|
||||
bug_project = 'python-congressclient'
|
||||
bug_tag = ''
|
||||
|
||||
# Must set this variable to include year, month, day, hours, and minutes.
|
||||
html_last_updated_fmt = '%Y-%m-%d %H:%M'
|
||||
|
||||
# autodoc generation is a bit aggressive and a nuisance when doing heavy
|
||||
# text edit cycles.
|
||||
# execute "export SPHINX_DEBUG=1" in your terminal to disable
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'python-congressclient'
|
||||
copyright = u'2013, OpenStack Foundation'
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
add_module_names = True
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
# html_theme_path = ["."]
|
||||
html_theme = 'openstackdocs'
|
||||
# html_static_path = ['static']
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = '%sdoc' % project
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
modindex_common_prefix = ['congressclient.']
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass
|
||||
# [howto/manual]).
|
||||
latex_documents = [
|
||||
('index',
|
||||
'%s.tex' % project,
|
||||
u'%s Documentation' % project,
|
||||
u'OpenStack Foundation', 'manual'),
|
||||
]
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
#intersphinx_mapping = {'http://docs.python.org/': None}
|
|
@ -1,4 +0,0 @@
|
|||
============
|
||||
Contributing
|
||||
============
|
||||
.. include:: ../../../CONTRIBUTING.rst
|
|
@ -1,29 +0,0 @@
|
|||
.. python-congressclient documentation master file, created by
|
||||
sphinx-quickstart on Tue Jul 9 22:26:36 2013.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to python-congressclient's documentation!
|
||||
========================================================
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
user/readme
|
||||
install/index
|
||||
user/index
|
||||
contributor/index
|
||||
reference/index
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
||||
|
||||
.. # Below are items we don't want to show doc consumers but need to be
|
||||
# included to avoid sphinx warning/error.
|
||||
# api/autoindex hidden because the information is already in modindex above
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
reference/api/autoindex
|
|
@ -1,12 +0,0 @@
|
|||
============
|
||||
Installation
|
||||
============
|
||||
|
||||
At the command line::
|
||||
|
||||
$ pip install python-congressclient
|
||||
|
||||
Or, if you have virtualenvwrapper installed::
|
||||
|
||||
$ mkvirtualenv python-congressclient
|
||||
$ pip install python-congressclient
|
|
@ -1,5 +0,0 @@
|
|||
==========
|
||||
References
|
||||
==========
|
||||
|
||||
* :ref:`modindex`
|
|
@ -1,7 +0,0 @@
|
|||
=====
|
||||
Usage
|
||||
=====
|
||||
|
||||
To use python-congressclient in a project::
|
||||
|
||||
import congressclient
|
|
@ -1,5 +0,0 @@
|
|||
##########
|
||||
README
|
||||
##########
|
||||
|
||||
.. include:: ../../../README.rst
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
features:
|
||||
- Now supports 'datasource row update' for those
|
||||
datasource drivers that allow you to push data
|
||||
into them over HTTP.
|
||||
issues:
|
||||
- The 'datasource row update' command sometimes returns
|
||||
unfriendly error messages.
|
|
@ -1,11 +0,0 @@
|
|||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||
Babel!=2.4.0,>=2.3.4 # BSD
|
||||
cliff>=2.8.0 # Apache-2.0
|
||||
keystoneauth1>=3.0.1 # Apache-2.0
|
||||
oslo.i18n!=3.15.2,>=2.1.0 # Apache-2.0
|
||||
oslo.log>=3.22.0 # Apache-2.0
|
||||
oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0
|
||||
six>=1.9.0 # MIT
|
86
setup.cfg
86
setup.cfg
|
@ -1,86 +0,0 @@
|
|||
[metadata]
|
||||
name = python-congressclient
|
||||
summary = Client for Congress
|
||||
description-file =
|
||||
README.rst
|
||||
author = OpenStack
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
home-page = http://git.openstack.org/cgit/openstack/python-congressclient
|
||||
classifier =
|
||||
Environment :: OpenStack
|
||||
Intended Audience :: Information Technology
|
||||
Intended Audience :: System Administrators
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
||||
Programming Language :: Python
|
||||
Programming Language :: Python :: 2
|
||||
Programming Language :: Python :: 2.7
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.5
|
||||
|
||||
[files]
|
||||
packages =
|
||||
congressclient
|
||||
|
||||
[entry_points]
|
||||
openstack.cli.extension =
|
||||
congressclient = congressclient.osc.osc_plugin
|
||||
|
||||
openstack.congressclient.v1 =
|
||||
congress_policy_create = congressclient.osc.v1.policy:CreatePolicy
|
||||
congress_policy_create-from-file = congressclient.osc.v1.policy:CreatePolicyFromFile
|
||||
congress_policy_delete = congressclient.osc.v1.policy:DeletePolicy
|
||||
congress_policy_show = congressclient.osc.v1.policy:ShowPolicy
|
||||
congress_policy_rule_create = congressclient.osc.v1.policy:CreatePolicyRule
|
||||
congress_policy_rule_delete = congressclient.osc.v1.policy:DeletePolicyRule
|
||||
congress_policy_rule_show = congressclient.osc.v1.policy:ShowPolicyRule
|
||||
congress_policy_rule_list = congressclient.osc.v1.policy:ListPolicyRules
|
||||
congress_policy_list = congressclient.osc.v1.policy:ListPolicy
|
||||
congress_policy_row_list = congressclient.osc.v1.policy:ListPolicyRows
|
||||
congress_policy_table_list = congressclient.osc.v1.policy:ListPolicyTables
|
||||
congress_policy_simulate = congressclient.osc.v1.policy:SimulatePolicy
|
||||
congress_datasource_list = congressclient.osc.v1.datasource:ListDatasources
|
||||
congress_datasource_create = congressclient.osc.v1.datasource:CreateDatasource
|
||||
congress_datasource_delete = congressclient.osc.v1.datasource:DeleteDatasource
|
||||
congress_datasource_request-refresh = congressclient.osc.v1.datasource:DatasourceRequestRefresh
|
||||
congress_datasource_table_list = congressclient.osc.v1.datasource:ListDatasourceTables
|
||||
congress_datasource_row_list = congressclient.osc.v1.datasource:ListDatasourceRows
|
||||
congress_datasource_row_update = congressclient.osc.v1.datasource:UpdateDatasourceRow
|
||||
congress_datasource_status_show = congressclient.osc.v1.datasource:ShowDatasourceStatus
|
||||
congress_datasource_actions_show= congressclient.osc.v1.datasource:ShowDatasourceActions
|
||||
congress_datasource_schema_show = congressclient.osc.v1.datasource:ShowDatasourceSchema
|
||||
congress_datasource_table_schema_show = congressclient.osc.v1.datasource:ShowDatasourceTableSchema
|
||||
congress_policy_table_show = congressclient.osc.v1.policy:ShowPolicyTable
|
||||
congress_datasource_table_show = congressclient.osc.v1.datasource:ShowDatasourceTable
|
||||
congress_driver_config_show = congressclient.osc.v1.driver:ShowDriverConfig
|
||||
congress_driver_schema_show = congressclient.osc.v1.driver:ShowDriverSchema
|
||||
congress_driver_list = congressclient.osc.v1.driver:ListDrivers
|
||||
congress_version_list = congressclient.osc.v1.api_versions:ListAPIVersions
|
||||
|
||||
[pbr]
|
||||
autodoc_index_modules = True
|
||||
api_doc_dir = reference/api
|
||||
warnerrors = True
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
build-dir = doc/build
|
||||
all_files = 1
|
||||
warning-is-error = 1
|
||||
|
||||
[upload_sphinx]
|
||||
upload-dir = doc/build/html
|
||||
|
||||
[compile_catalog]
|
||||
directory = congressclient/locale
|
||||
domain = python-congressclient
|
||||
|
||||
[update_catalog]
|
||||
domain = python-congressclient
|
||||
output_dir = congressclient/locale
|
||||
input_file = congressclient/locale/python-congressclient.pot
|
||||
|
||||
[extract_messages]
|
||||
keywords = _ gettext ngettext l_ lazy_gettext
|
||||
mapping_file = babel.cfg
|
||||
output_file = congressclient/locale/python-congressclient.pot
|
29
setup.py
29
setup.py
|
@ -1,29 +0,0 @@
|
|||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
import setuptools
|
||||
|
||||
# In python < 2.7.4, a lazy loading of package `pbr` will break
|
||||
# setuptools if some other modules registered functions in `atexit`.
|
||||
# solution from: http://bugs.python.org/issue15881#msg170215
|
||||
try:
|
||||
import multiprocessing # noqa
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr>=2.0.0'],
|
||||
pbr=True)
|
|
@ -1,8 +0,0 @@
|
|||
+----------------------------------+--------------------+---------+
|
||||
| id | name | enabled |
|
||||
+----------------------------------+--------------------+---------+
|
||||
| 8918ef508b3a48a1ad963cec1d7bec18 | admin | True |
|
||||
| e41ef6f35dab448699a5ca69eff60692 | demo | True |
|
||||
| c01bea38e55d44d3a87bb018b050338c | invisible_to_admin | True |
|
||||
| 3a1208bc143a4ed589288057ea8e0735 | service | True |
|
||||
+----------------------------------+--------------------+---------+
|
|
@ -1,13 +0,0 @@
|
|||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
|
||||
|
||||
coverage!=4.4,>=4.0 # Apache-2.0
|
||||
fixtures>=3.0.0 # Apache-2.0/BSD
|
||||
python-subunit>=0.0.18 # Apache-2.0/BSD
|
||||
sphinx>=1.6.2 # BSD
|
||||
openstackdocstheme>=1.11.0 # Apache-2.0
|
||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||
testtools>=1.4.0 # MIT
|
||||
mock>=2.0 # BSD
|
|
@ -1,30 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Client constraint file contains this client version pin that is in conflict
|
||||
# with installing the client from source. We should remove the version pin in
|
||||
# the constraints file before applying it for from-source installation.
|
||||
|
||||
CONSTRAINTS_FILE="$1"
|
||||
shift 1
|
||||
|
||||
set -e
|
||||
|
||||
# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get
|
||||
# published to logs.openstack.org for easy debugging.
|
||||
localfile="$VIRTUAL_ENV/log/upper-constraints.txt"
|
||||
|
||||
if [[ "$CONSTRAINTS_FILE" != http* ]]; then
|
||||
CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE"
|
||||
fi
|
||||
# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep
|
||||
curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile"
|
||||
|
||||
pip install -c"$localfile" openstack-requirements
|
||||
|
||||
# This is the main purpose of the script: Allow local installation of
|
||||
# the current repo. It is listed in constraints file and thus any
|
||||
# install will be constrained and we need to unconstrain it.
|
||||
edit-constraints "$localfile" -- "$CLIENT_NAME"
|
||||
|
||||
pip install -c"$localfile" -U "$@"
|
||||
exit $?
|
38
tox.ini
38
tox.ini
|
@ -1,38 +0,0 @@
|
|||
[tox]
|
||||
minversion = 2.0
|
||||
envlist = py35,py27,pep8
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
|
||||
whitelist_externals = find
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
BRANCH_NAME=master
|
||||
CLIENT_NAME=python-congressclient
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
commands =
|
||||
find . -type f -name "*.pyc" -delete
|
||||
python setup.py testr --slowest --testr-args='{posargs}'
|
||||
|
||||
[testenv:pep8]
|
||||
commands = flake8
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
||||
|
||||
[testenv:cover]
|
||||
commands = python setup.py testr --coverage --testr-args='{posargs}'
|
||||
|
||||
[testenv:docs]
|
||||
commands = python setup.py build_sphinx
|
||||
|
||||
[hacking]
|
||||
import_exceptions = congressclient.i18n
|
||||
|
||||
[flake8]
|
||||
show-source = True
|
||||
builtins = _
|
||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
|
Loading…
Reference in New Issue