Browse Source

Retire the Congress project

Recently the TC has worked on determining the criteria for when an
OpenStack project should be retired.  When there was not a PTL nominee
for the Congress project, that triggered the TC to review the project
health per [1], and the TC has determined [2] that development work on
the project has ceased.  This decision was announced in the
openstack-discuss mailing list in April 2020 [3].

This commit retires the repository per the process for governance
removal in the Victoria cycle as specified in the Mandatory Repository
Retirement resolution [4] and detailed in the infra manual [5].

Should interest in developing Congress as part of OpenStack revive,
please revert this commit to have the project rejoin the list of active
projects.

The community wishes to express our thanks and appreciation to all of
those who have contributed to the Congress project over the years.

[1] https://governance.openstack.org/tc/reference/dropping-projects.html
[2] http://eavesdrop.openstack.org/irclogs/%23openstack-tc/latest.log.html#t2020-04-20T15:36:59
[3] http://lists.openstack.org/pipermail/openstack-discuss/2020-April/014292.html
[4] https://governance.openstack.org/tc/resolutions/20190711-mandatory-repository-retirement.html
[5] https://docs.opendev.org/opendev/infra-manual/latest/drivers.html#retiring-a-project

Change-Id: I21c9ab9820f78cf76adf11c5f0591c60f76372a8
changes/33/721733/3
Nate Johnston 2 years ago
committed by Andreas Jaeger
parent
commit
bba805af02
  1. 7
      .coveragerc
  2. 66
      .gitignore
  3. 3
      .mailmap
  4. 3
      .stestr.conf
  5. 163
      .zuul.yaml
  6. 21
      CONTRIBUTING.rst
  7. 5
      HACKING.rst
  8. 175
      LICENSE
  9. 12
      Makefile
  10. 35
      README.rst
  11. 1
      antlr3runtime/Python/antlr3
  12. 1
      antlr3runtime/Python3/antlr3
  13. 1
      babel.cfg
  14. 38
      bin/congress-server
  15. 14
      bindep.txt
  16. 22
      congress/__init__.py
  17. 0
      congress/api/__init__.py
  18. 50
      congress/api/action_model.py
  19. 52
      congress/api/api_utils.py
  20. 107
      congress/api/application.py
  21. 43
      congress/api/base.py
  22. 165
      congress/api/datasource_model.py
  23. 123
      congress/api/error_codes.py
  24. 160
      congress/api/library_policy_model.py
  25. 254
      congress/api/policy_model.py
  26. 178
      congress/api/router.py
  27. 197
      congress/api/row_model.py
  28. 124
      congress/api/rule_model.py
  29. 67
      congress/api/schema_model.py
  30. 57
      congress/api/status_model.py
  31. 0
      congress/api/system/__init__.py
  32. 68
      congress/api/system/driver_model.py
  33. 151
      congress/api/table_model.py
  34. 146
      congress/api/versions.py
  35. 52
      congress/api/webhook_model.py
  36. 635
      congress/api/webservice.py
  37. 79
      congress/auth.py
  38. 0
      congress/cfg_validator/__init__.py
  39. 9
      congress/cfg_validator/agent/__init__.py
  40. 434
      congress/cfg_validator/agent/agent.py
  41. 136
      congress/cfg_validator/agent/generator.py
  42. 58
      congress/cfg_validator/agent/opts.py
  43. 89
      congress/cfg_validator/agent/rpc.py
  44. 242
      congress/cfg_validator/parsing.py
  45. 67
      congress/cfg_validator/utils.py
  46. 0
      congress/cmd/__init__.py
  47. 67
      congress/cmd/status.py
  48. 0
      congress/common/__init__.py
  49. 197
      congress/common/config.py
  50. 225
      congress/common/eventlet_server.py
  51. 17
      congress/common/policies/__init__.py
  52. 43
      congress/common/policies/base.py
  53. 140
      congress/common/policy.py
  54. 253
      congress/common/wsgi.py
  55. 149
      congress/context.py
  56. 298
      congress/data_types.py
  57. 353
      congress/datalog/Congress.g
  58. 2734
      congress/datalog/Python2/CongressLexer.py
  59. 2710
      congress/datalog/Python2/CongressParser.py
  60. 0
      congress/datalog/Python2/__init__.py
  61. 2750
      congress/datalog/Python3/CongressLexer.py
  62. 2726
      congress/datalog/Python3/CongressParser.py
  63. 0
      congress/datalog/Python3/__init__.py
  64. 11
      congress/datalog/README-Congress.g.txt
  65. 0
      congress/datalog/__init__.py
  66. 104
      congress/datalog/analysis.py
  67. 647
      congress/datalog/arithmetic_solvers.py
  68. 249
      congress/datalog/base.py
  69. 488
      congress/datalog/builtin.py
  70. 2352
      congress/datalog/compile.py
  71. 413
      congress/datalog/database.py
  72. 171
      congress/datalog/factset.py
  73. 621
      congress/datalog/materialized.py
  74. 406
      congress/datalog/nonrecursive.py
  75. 176
      congress/datalog/ruleset.py
  76. 642
      congress/datalog/topdown.py
  77. 526
      congress/datalog/unify.py
  78. 536
      congress/datalog/utility.py
  79. 0
      congress/datasources/__init__.py
  80. 109
      congress/datasources/aodh_driver.py
  81. 66
      congress/datasources/benchmark_driver.py
  82. 634
      congress/datasources/cfgvalidator_driver.py
  83. 180
      congress/datasources/cinder_driver.py
  84. 244
      congress/datasources/cloudfoundryv2_driver.py
  85. 21
      congress/datasources/constants.py
  86. 1734
      congress/datasources/datasource_driver.py
  87. 184
      congress/datasources/datasource_utils.py
  88. 106
      congress/datasources/doctor_driver.py
  89. 142
      congress/datasources/glancev2_driver.py
  90. 245
      congress/datasources/heatv1_driver.py
  91. 221
      congress/datasources/ironic_driver.py
  92. 0
      congress/datasources/json_ingester/__init__.py
  93. 178
      congress/datasources/json_ingester/exec_api.py
  94. 465
      congress/datasources/json_ingester/json_ingester.py
  95. 36
      congress/datasources/json_ingester/sql.py
  96. 136
      congress/datasources/keystone_driver.py
  97. 167
      congress/datasources/keystonev3_driver.py
  98. 204
      congress/datasources/mistral_driver.py
  99. 298
      congress/datasources/monasca_driver.py
  100. 150
      congress/datasources/murano_classes.py

7
.coveragerc

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

66
.gitignore

@ -1,66 +0,0 @@
# Congress build/runtime artifacts
Congress.tokens
subunit.log
congress/tests/policy_engines/snapshot/test
congress/tests/policy/snapshot/test
/doc/html
*.py[cod]
# C extensions
*.so
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
/lib
/lib64
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
.stestr/
.venv
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Complexity
output/*.html
output/*/index.html
# Sphinx
doc/build
doc/source/_static/
doc/source/api/
# pbr generates these
AUTHORS
ChangeLog
# Editors
*~
.*.sw?
# IDEs
.idea
# Files generated by tests
congress/tests/etc/keys

3
.mailmap

@ -1,3 +0,0 @@
# Format is:
# <preferred e-mail> <other e-mail 1>
# <preferred e-mail> <other e-mail 2>

3
.stestr.conf

@ -1,3 +0,0 @@
[DEFAULT]
test_path=./congress/tests
top_dir=./

163
.zuul.yaml

@ -1,163 +0,0 @@
- job:
name: congress-tempest-base
parent: devstack-tempest
description: |
Congress devstack tempest tests job
irrelevant-files: &base_irrelevant_files
- ^.*\.rst$
- ^doc/.*$
- ^congress/tests/.*$
- ^releasenotes/.*$
required-projects: &base_required_projects
- name: openstack/devstack-gate
- name: openstack/aodh
- name: openstack/python-aodhclient
- name: openstack/congress
- name: openstack/congress-dashboard
- name: openstack/congress-tempest-plugin
- name: openstack/python-congressclient
- name: openstack/murano
- name: openstack/murano-dashboard
- name: openstack/python-muranoclient
- name: openstack/mistral
- name: openstack/python-mistralclient
- name: openstack/heat
- name: openstack/python-heatclient
- name: openstack/monasca-agent
- name: openstack/monasca-api
- name: openstack/monasca-common
- name: openstack/monasca-grafana-datasource
- name: openstack/monasca-notification
- name: openstack/monasca-persister
- name: openstack/monasca-statsd
- name: openstack/monasca-thresh
- name: openstack/monasca-ui
- name: openstack/python-monascaclient
timeout: 6000
vars: &base_vars
devstack_plugins:
congress: https://opendev.org/openstack/congress
heat: https://opendev.org/openstack/heat
neutron: https://opendev.org/openstack/neutron
devstack_services:
tempest: true
neutron-qos: true
horizon: false
tempest_concurrency: 1
tox_envlist: all
tempest_test_regex: congress_tempest_plugin.*
devstack_localrc:
LIBS_FROM_GIT: python-congressclient
SERVICE_TIMEOUT: 120 # default too short for this job
TEMPEST_PLUGINS: '"/opt/stack/congress-tempest-plugin"'
CONGRESS_MULTIPROCESS_DEPLOYMENT: true
CONGRESS_EXPOSE_ENCRYPTION_KEY_FOR_TEST: true
ENABLE_CONGRESS_Z3: true
USE_Z3_RELEASE: 4.7.1
USE_PYTHON3: True
- job:
name: congress-tempest-ipv6-only
parent: devstack-tempest-ipv6
description: |
Congress devstack tempest tests job for IPv6-only deployment
irrelevant-files: *base_irrelevant_files
required-projects: *base_required_projects
timeout: 6000
vars:
<<: *base_vars
tempest_test_regex: '(^congress_tempest_plugin.*)(\[.*\bsmoke\b.*\])'
- job:
name: congress-tempest-py3
parent: congress-tempest-base
vars:
devstack_plugins:
murano: https://opendev.org/openstack/murano
devstack_localrc:
USE_PYTHON3: true
- job:
name: congress-tempest-replicated
parent: congress-tempest-base
voting: false
vars:
devstack_plugins:
murano: https://opendev.org/openstack/murano
devstack_localrc:
CONGRESS_REPLICATED: true
- job:
name: congress-tempest-replicated-mysql
parent: congress-tempest-replicated
vars:
database: mysql
- job:
name: congress-tempest-replicated-postgresql
parent: congress-tempest-replicated
voting: false
vars:
devstack_services:
mysql: false
postgresql: true
- job:
name: congress-tempest-py3-mysql
parent: congress-tempest-py3
vars:
database: mysql
- job:
name: congress-tempest-py3-JsonIngester
parent: congress-tempest-base
voting: false
vars:
devstack_localrc:
ENABLE_CONGRESS_JSON: true
- job:
name: congress-tempest-py3-postgresql
parent: congress-tempest-base
voting: false
vars:
devstack_services:
mysql: false
postgresql: true
- project:
templates:
- check-requirements
- openstack-cover-jobs
- openstack-lower-constraints-jobs
- openstack-python3-ussuri-jobs
- release-notes-jobs-python3
- publish-openstack-docs-pti
- periodic-stable-jobs
check:
jobs:
- congress-tempest-py3-mysql
- congress-tempest-replicated-postgresql
- congress-tempest-py3-JsonIngester
- congress-tempest-ipv6-only
# Note: the above jobs most likely provides sufficient coverage
# - congress-tempest-py2-postgresql
# - congress-tempest-py3-postgresql
# - congress-tempest-replicated-mysql
# TripleO jobs that deploy Congress.
# Note we don't use a project-template here, so it's easier
# to disable voting on one specific job if things go wrong.
# tripleo-ci-centos-7-scenario001-multinode-oooq will only
# run on stable/pike while the -container will run in Queens
# and beyond.
# If you need any support to debug these jobs in case of
# failures, please reach us on #tripleo IRC channel.
# temporarily disable tripleO check until faster single-node job is available
# - tripleo-ci-centos-7-scenario007-multinode-oooq-container:
# voting: false
gate:
queue: congress
jobs:
- congress-tempest-py3-mysql
- congress-tempest-ipv6-only

21
CONTRIBUTING.rst

@ -1,21 +0,0 @@
============
Contributing
============
The Congress wiki page is the authoritative starting point.
https://wiki.openstack.org/wiki/Congress
If you would like to contribute to the development of any OpenStack
project including Congress,
you must follow the steps in this page:
https://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:
https://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/congress

5
HACKING.rst

@ -1,5 +0,0 @@
===========================
Congress style commandments
===========================
Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/

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

@ -1,12 +0,0 @@
TOPDIR=$(CURDIR)
SRCDIR=$(TOPDIR)/congress
all: docs
clean:
find . -name '*.pyc' -exec rm -f {} \;
rm -Rf $(TOPDIR)/doc/html/*
docs: $(TOPDIR)/doc/source/*.rst
sphinx-build -b html $(TOPDIR)/doc/source $(TOPDIR)/doc/html

35
README.rst

@ -2,32 +2,13 @@
Welcome to Congress
===================
Congress is an open policy framework for the cloud. With Congress, a
cloud operator can declare, monitor, enforce, and audit "policy" in a
heterogeneous cloud environment. Congress gets inputs from a cloud's
various cloud services; for example in OpenStack, Congress fetches
information about VMs from Nova, and network state from Neutron, etc.
Congress then feeds input data from those services into its policy engine
where Congress verifies that the cloud's actual state abides by the cloud
operator's policies. Congress is designed to work with **any policy** and
**any cloud service**.
This project is no longer maintained.
* Free software: Apache license
* Documentation: https://docs.openstack.org/congress/latest/
* Wiki: https://wiki.openstack.org/wiki/Congress
* Source: https://github.com/openstack/Congress
* Bugs: https://bugs.launchpad.net/congress
* Blueprints: https://blueprints.launchpad.net/congress
* Release notes: https://docs.openstack.org/releasenotes/congress
* Admin guide: https://docs.openstack.org/congress/latest/admin/index.html
* Contributing: https://docs.openstack.org/congress/latest/contributor/index.html
* REST Client:https://opendev.org/openstack/python-congressclient
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".
.. image:: https://governance.openstack.org/tc/badges/congress.svg
:target: https://governance.openstack.org/tc/reference/tags/index.html
Installing Congress
===================
Please refer to the
`installation guide <https://docs.openstack.org/congress/latest/install/>`_
For any further questions, please email
openstack-discuss@lists.openstack.org or join #openstack-dev on
Freenode.

1
antlr3runtime/Python/antlr3

@ -1 +0,0 @@
../../thirdparty/antlr3-antlr-3.5/runtime/Python/antlr3/

1
antlr3runtime/Python3/antlr3

@ -1 +0,0 @@
../../thirdparty/antlr3-antlr-3.5/runtime/Python3/antlr3/

1
babel.cfg

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

38
bin/congress-server

@ -1,38 +0,0 @@
#!/usr/bin/env python
# Copyright (c) 2013 VMware, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
import os
import sys
# If ../congress/__init__.py exists, add ../ to Python search path, so that
# it will override what happens to be installed in /usr/(local/)lib/python...
possible_topdir = os.path.normpath(os.path.join(os.path.abspath(__file__),
os.pardir,
os.pardir))
if os.path.exists(os.path.join(possible_topdir,
'congress',
'__init__.py')):
sys.path.insert(0, possible_topdir)
# set command line config options
from congress.common import config
config.init(sys.argv[1:])
from congress.server import congress_server
if __name__ == '__main__':
congress_server.main()

14
bindep.txt

@ -1,14 +0,0 @@
python-all-dev
python3-all-dev
libvirt-dev
libxml2-dev
libxslt1-dev
# libmysqlclient-dev
libpq-dev [platform:dpkg]
libsqlite3-dev
libffi-dev
# mysql-client
# mysql-server
# postgresql
# postgresql-client
rabbitmq-server

22
congress/__init__.py

@ -1,22 +0,0 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
import gettext
import pbr.version
gettext.install('congress')
__version__ = pbr.version.VersionInfo(
'openstack-congress').version_string()

0
congress/api/__init__.py

50
congress/api/action_model.py

@ -1,50 +0,0 @@
# Copyright (c) 2015 Intel, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from congress.api import api_utils
from congress.api import base
from congress.api import webservice
from congress import exception
class ActionsModel(base.APIModel):
"""Model for handling API requests about Actions."""
# Note(dse2): blocking function
def get_items(self, params, context=None):
"""Retrieve items from this model.
:param: params: A dict-like object containing parameters
from the request query string and body.
:param: context: Key-values providing frame of reference of request
:returns: A dict containing at least a 'actions' key whose value is a
list of items in this model.
"""
# Note: blocking call
caller, source_id = api_utils.get_id_from_context(context)
try:
rpc_args = {'source_id': source_id}
# Note(dse2): blocking call
return self.invoke_rpc(caller, 'get_actions', rpc_args)
except exception.CongressException as e:
raise webservice.DataModelException(
exception.NotFound.code, str(e),
http_status_code=exception.NotFound.code)

52
congress/api/api_utils.py

@ -1,52 +0,0 @@
# Copyright (c) 2015 NTT All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from oslo_log import log as logging
from congress.api import base
from congress.api import webservice
from congress.db import datasources as db_datasources
LOG = logging.getLogger(__name__)
def create_table_dict(tablename, schema):
cols = [{'name': x['name'], 'description': x['desc']}
if isinstance(x, dict)
else {'name': x, 'description': 'None'}
for x in schema[tablename]]
return {'table_id': tablename,
'columns': cols}
# Note(thread-safety): blocking function
def get_id_from_context(context):
if 'ds_id' in context:
# Note(thread-safety): blocking call
ds_name = db_datasources.get_datasource_name(context.get('ds_id'))
return ds_name, context.get('ds_id')
elif 'policy_id' in context:
return base.ENGINE_SERVICE_ID, context.get('policy_id')
else:
msg = "Internal error: context %s should have included " % str(context)
"either ds_id or policy_id"
try: # Py3: ensure LOG.exception is inside except
raise webservice.DataModelException('404', msg)
except webservice.DataModelException:
LOG.exception(msg)
raise

107
congress/api/application.py

@ -1,107 +0,0 @@
# Copyright (c) 2014 VMware, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
import traceback
from oslo_log import log as logging
import webob
import webob.dec
from congress.api import webservice
from congress.dse2 import data_service
LOG = logging.getLogger(__name__)
API_SERVICE_NAME = '__api'
class ApiApplication(object):
"""An API web application that binds REST resources to a wsgi server.
This indirection between the wsgi server and REST resources facilitates
binding the same resource tree to multiple endpoints (e.g. HTTP/HTTPS).
"""
def __init__(self, resource_mgr):
self.resource_mgr = resource_mgr
@webob.dec.wsgify(RequestClass=webob.Request)
def __call__(self, request):
try:
handler = self.resource_mgr.get_handler(request)
if handler:
msg = _("Handling request '%(meth)s %(path)s' with %(hndlr)s")
LOG.info(msg, {"meth": request.method, "path": request.path,
"hndlr": handler})
# TODO(pballand): validation
response = handler.handle_request(request)
else:
response = webservice.NOT_FOUND_RESPONSE
except webservice.DataModelException as e:
# Error raised based on invalid user input
LOG.exception("ApiApplication: found DataModelException")
response = e.rest_response()
except Exception as e:
# Unexpected error raised by API framework or data model
msg = _("Exception caught for request: %s")
LOG.error(msg, request)
LOG.error(traceback.format_exc())
response = webservice.INTERNAL_ERROR_RESPONSE
return response
class ResourceManager(data_service.DataService):
"""A container for REST API resources.
This container is meant to be called from one or more wsgi servers/ports.
Attributes:
handlers: An array of API resource handlers for registered resources.
"""
def __init__(self):
self.handlers = []
super(ResourceManager, self).__init__(API_SERVICE_NAME)
def register_handler(self, handler, search_index=None):
"""Register a new resource handler.
:param: handler: The resource handler to register.
:param: search_index: Priority of resource handler to resolve cases
where a request matches multiple handlers.
"""
if search_index is not None:
self.handlers.insert(search_index, handler)
else:
self.handlers.append(handler)
msg = _("Registered API handler: %s")
LOG.info(msg, handler)
def get_handler(self, request):
"""Find a handler for a REST request.
:param: request: A webob request object.
:returns: A handler instance or None.
"""
for h in self.handlers:
if h.handles_request(request):
return h
return None

43
congress/api/base.py

@ -1,43 +0,0 @@
# Copyright (c) 2016 NEC Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
""" Base class for all API models."""
from __future__ import absolute_import
from oslo_config import cfg
ENGINE_SERVICE_ID = '__engine'
LIBRARY_SERVICE_ID = '__library'
DS_MANAGER_SERVICE_ID = '_ds_manager'
JSON_DS_SERVICE_PREFIX = '__json__'
class APIModel(object):
"""Base Class for handling API requests."""
def __init__(self, name, bus=None):
self.name = name
self.dse_long_timeout = cfg.CONF.dse.long_timeout
self.action_retry_timeout = cfg.CONF.dse.execute_action_retry_timeout
self.bus = bus
# Note(thread-safety): blocking function
def invoke_rpc(self, caller, name, kwargs, timeout=None):
local = (caller is ENGINE_SERVICE_ID and
self.bus.node.service_object(
ENGINE_SERVICE_ID) is not None)
return self.bus.rpc(
caller, name, kwargs, timeout=timeout, local=local)

165
congress/api/datasource_model.py

@ -1,165 +0,0 @@
# Copyright (c) 2014 VMware, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from oslo_log import log as logging
from oslo_serialization import jsonutils as json
from congress.api import api_utils
from congress.api import base
from congress.api import error_codes
from congress.api import webservice
from congress import exception
LOG = logging.getLogger(__name__)
class DatasourceModel(base.APIModel):
"""Model for handling API requests about Datasources."""
# Note(thread-safety): blocking function
def get_items(self, params, context=None):
"""Get items in model.
:param: params: A dict-like object containing parameters
from the request query string and body.
:param: context: Key-values providing frame of reference of request
:returns: A dict containing at least a 'results' key whose value is
a list of items in the model. Additional keys set in the
dict will also be rendered for the user.
"""
# Note(thread-safety): blocking call
results = self.bus.get_datasources(filter_secret=True)
# Check that running datasources match the datasources in the
# database since this is going to tell the client about those
# datasources, and the running datasources should match the
# datasources we show the client.
return {"results": results}
def get_item(self, id_, params, context=None):
"""Get datasource corresponding to id\_ in model."""
try:
datasource = self.bus.get_datasource(id_)
return datasource
except exception.DatasourceNotFound as e:
LOG.debug("Datasource '%s' not found", id_)
raise webservice.DataModelException(e.code, str(e),
http_status_code=e.code)
# Note(thread-safety): blocking function
def add_item(self, item, params, id_=None, context=None):
"""Add item to model.
:param: item: The item to add to the model
:param: id\_: The ID of the item, or None if an ID should be generated
:param: context: Key-values providing frame of reference of request
:returns: Tuple of (ID, newly_created_item)
:raises KeyError: ID already exists.
"""
obj = None
try:
# Note(thread-safety): blocking call
obj = self.invoke_rpc(base.DS_MANAGER_SERVICE_ID,
'add_datasource',
{'items': item},
timeout=self.dse_long_timeout)
# Let PE synchronizer take care of creating the policy.
except (exception.BadConfig,
exception.DatasourceNameInUse,
exception.DriverNotFound,
exception.DatasourceCreationError) as e:
LOG.debug(_("Datasource creation failed."))
raise webservice.DataModelException(
e.code, webservice.original_msg(e), http_status_code=e.code)
except exception.RpcTargetNotFound as e:
LOG.debug("Datasource creation failed.")
LOG.warning(webservice.original_msg(e))
raise webservice.DataModelException(
e.code, webservice.original_msg(e), http_status_code=503)
return (obj['id'], obj)
# Note(thread-safety): blocking function
def delete_item(self, id_, params, context=None):
ds_id = context.get('ds_id')
try:
# Note(thread-safety): blocking call
datasource = self.bus.get_datasource(ds_id)
# FIXME(thread-safety):
# by the time greenthread resumes, the
# returned datasource name could refer to a totally different
# datasource, causing the rest of this code to unintentionally
# delete a different datasource
# Fix: check UUID of datasource before operating.
# Abort if mismatch
self.invoke_rpc(base.DS_MANAGER_SERVICE_ID,
'delete_datasource',
{'datasource': datasource},
timeout=self.dse_long_timeout)
# Let PE synchronizer takes care of deleting policy
except (exception.DatasourceNotFound,
exception.DanglingReference) as e:
LOG.debug("Datasource deletion failed.")
raise webservice.DataModelException(e.code, str(e))
except exception.RpcTargetNotFound as e:
LOG.debug("Datasource deletion failed.")
LOG.warning(webservice.original_msg(e))
raise webservice.DataModelException(
e.code, webservice.original_msg(e), http_status_code=503)
# Note(thread-safety): blocking function
def request_refresh_action(self, params, context=None, request=None):
caller, source_id = api_utils.get_id_from_context(context)
try:
args = {'source_id': source_id}
# Note(thread-safety): blocking call
self.invoke_rpc(caller, 'request_refresh', args)
except exception.CongressException as e:
LOG.debug(e)
raise webservice.DataModelException.create(e)
# Note(thread-safety): blocking function
def execute_action(self, params, context=None, request=None):
"Execute the action."
service = context.get('ds_id')
body = json.loads(request.body)
action = body.get('name')
action_args = body.get('args', {})
if (not isinstance(action_args, dict)):
(num, desc) = error_codes.get('execute_action_args_syntax')
raise webservice.DataModelException(num, desc)
try:
args = {'service_name': service, 'action': action,
'action_args': action_args}
# TODO(ekcs): perhaps keep execution synchronous when explicitly
# called via API
# Note(thread-safety): blocking call
self.invoke_rpc(base.ENGINE_SERVICE_ID, 'execute_action', args)
except exception.PolicyException as e:
(num, desc) = error_codes.get('execute_error')
raise webservice.DataModelException(num, desc + "::" + str(e))
return {}

123
congress/api/error_codes.py

@ -1,123 +0,0 @@
# Copyright (c) 2014 VMware, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
try:
# For Python 3
import http.client as httplib
except ImportError:
import httplib
# TODO(thinrichs): move this out of api directory. Could go into
# the exceptions.py file. The HTTP error codes may make these errors
# look like they are only useful for the API, but actually they are
# just encoding the classification of the error using http codes.
# To make this more explicit, we could have 2 dictionaries where
# one maps an error name (readable for programmers) to an error number
# and another dictionary that maps an error name/number to the HTTP
# classification. But then it would be easy for a programmer when
# adding a new error to forget one or the other.
# name of unknown error
UNKNOWN = 'unknown'
# dict mapping error name to (<error id>, <description>, <http error code>)
errors = {}
errors[UNKNOWN] = (
1000, "Unknown error", httplib.BAD_REQUEST)
errors['add_item_id'] = (
1001, "Add item does not support user-chosen ID", httplib.BAD_REQUEST)
errors['rule_syntax'] = (
1002, "Syntax error for rule", httplib.BAD_REQUEST)
errors['multiple_rules'] = (
1003, "Received string representing more than 1 rule", httplib.BAD_REQUEST)
errors['incomplete_simulate_args'] = (
1004, "Simulate requires parameters: query, sequence, action_policy",
httplib.BAD_REQUEST)
errors['simulate_without_policy'] = (
1005, "Simulate must be told which policy evaluate the query on",
httplib.BAD_REQUEST)
errors['sequence_syntax'] = (
1006, "Syntax error in sequence", httplib.BAD_REQUEST)
errors['simulate_error'] = (
1007, "Error in simulate procedure", httplib.INTERNAL_SERVER_ERROR)
errors['rule_already_exists'] = (
1008, "Rule already exists", httplib.CONFLICT)
errors['schema_get_item_id'] = (
1009, "Get item for schema does not support user-chosen ID",
httplib.BAD_REQUEST)
errors['policy_name_must_be_provided'] = (
1010, "A name must be provided when creating a policy",
httplib.BAD_REQUEST)
errors['no_policy_update_owner'] = (
1012, "The policy owner_id cannot be updated",
httplib.BAD_REQUEST)
errors['no_policy_update_kind'] = (
1013, "The policy kind cannot be updated",
httplib.BAD_REQUEST)
errors['failed_to_create_policy'] = (
1014, "A new policy could not be created",
httplib.INTERNAL_SERVER_ERROR)
errors['policy_id_must_not_be_provided'] = (
1015, "An ID may not be provided when creating a policy",
httplib.BAD_REQUEST)
errors['execute_error'] = (
1016, "Error in execution procedure", httplib.INTERNAL_SERVER_ERROR)
errors['service_action_syntax'] = (
1017, "Incorrect action syntax. Requires: <service>:<action>",
httplib.BAD_REQUEST)
errors['execute_action_args_syntax'] = (
1018, "Incorrect argument syntax. "
"Requires: {'positional': [<args>], 'named': {<key>:<value>,}}",
httplib.BAD_REQUEST)
errors['rule_not_permitted'] = (
1019, "Rules not permitted on non persisted policies.",
httplib.BAD_REQUEST)
errors['policy_not_exist'] = (
1020, "The specified policy does not exist.", httplib.NOT_FOUND)
errors['policy_rule_insertion_failure'] = (
1021, "The policy rule could not be inserted.", httplib.BAD_REQUEST)
errors['policy_abbreviation_error'] = (
1022, "The policy abbreviation must be a string and the length of the "
"string must be equal to or less than 5 characters.",
httplib.BAD_REQUEST)
def get(name):
if name not in errors:
name = UNKNOWN
return errors[name][:2]
def get_num(name):
if name not in errors:
name = UNKNOWN
return errors[name][0]
def get_desc(name):
if name not in errors:
name = UNKNOWN
return errors[name][1]
def get_http(name):
if name not in errors:
name = UNKNOWN
return errors[name][2]

160
congress/api/library_policy_model.py

@ -1,160 +0,0 @@
# Copyright (c) 2017 VMware, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from oslo_log import log as logging
from congress.api import base
from congress.api import error_codes
from congress.api import webservice
from congress import exception
LOG = logging.getLogger(__name__)
class LibraryPolicyModel(base.APIModel):
"""Model for handling API requests about Library Policies."""
# Note(thread-safety): blocking function
def get_items(self, params, context=None):
"""Get items in model.
:param: params: A dict-like object containing parameters
from the request query string and body.
The name parameter filters results by name policy name.
:param: context: Key-values providing frame of reference of request
:returns: A dict containing at least a 'results' key whose value is
a list of items in the model. Additional keys set in the
dict will also be rendered for the user.
"""
include_rules = True
if params.get('include_rules', 'true').lower() == 'false':
include_rules = False
try:
# Note: name is included as a filtering parameter in get_items
# rather than a key in get_item because the API does not commit to
# library policy name being unique.
if 'name' in params:
# Note(thread-safety): blocking call
try:
policy = self.invoke_rpc(
base.LIBRARY_SERVICE_ID, 'get_policy_by_name',
{'name': params['name'],
'include_rules': include_rules})
return {"results": [policy]}
except KeyError: # not found
return {"results": []}
else:
# Note(thread-safety): blocking call
return {"results": self.invoke_rpc(
base.LIBRARY_SERVICE_ID,
'get_policies', {'include_rules': include_rules})}
except exception.CongressException as e:
raise webservice.DataModelException.create(e)
# Note(thread-safety): blocking function
def get_item(self, id_, params, context=None):
"""Retrieve item with id from model.
:param: id\_: The id of the item to retrieve
:param: params: A dict-like object containing parameters
from the request query string and body.
:param: context: Key-values providing frame of reference of request
:returns: The matching item or None if no item with id exists.
"""
try:
# Note(thread-safety): blocking call
include_rules = True
if params.get('include_rules', 'true').lower() == 'false':
include_rules = False
return self.invoke_rpc(base.LIBRARY_SERVICE_ID,
'get_policy',
{'id_': id_,
'include_rules': include_rules})
except exception.CongressException as e:
raise webservice.DataModelException.create(e)
# Note(thread-safety): blocking function
def add_item(self, item, params, id_=None, context=None):
"""Add item to model.
:param: item: The item to add to the model
:param: params: A dict-like object containing parameters
from the request query string and body.
:param: id\_: The unique name of the item
:param: context: Key-values providing frame of reference of request
:returns: Tuple of (ID, newly_created_item)
:raises KeyError: ID already exists.
:raises DataModelException: Addition cannot be performed.
"""
if id_ is not None:
(num, desc) = error_codes.get('policy_id_must_not_be_provided')
raise webservice.DataModelException(num, desc)
try:
# Note(thread-safety): blocking call
policy_metadata = self.invoke_rpc(
base.LIBRARY_SERVICE_ID, 'create_policy',
{'policy_dict': item})
except exception.CongressException as e:
raise webservice.DataModelException.create(e)
return (policy_metadata['id'], policy_metadata)
# Note(thread-safety): blocking function
def delete_item(self, id_, params, context=None):
"""Remove item from model.
:param: id\_: The unique name of the item to be removed
:param: params:
:param: context: Key-values providing frame of reference of request
:returns: The removed item.
:raises KeyError: Item with specified id\_ not present.
"""
# Note(thread-safety): blocking call
return self.invoke_rpc(base.LIBRARY_SERVICE_ID,
'delete_policy',
{'id_': id_})
def replace_item(self, id_, item, params, context=None):
"""Replace item with id\_ with new data.
:param: id\_: The ID of the item to be replaced
:param: item: The new item
:param: params: A dict-like object containing parameters
from the request query string and body.
:param: context: Key-values providing frame of reference of request
:returns: The new item after replacement.
:raises KeyError: Item with specified id\_ not present.
"""
# Note(thread-safety): blocking call
try:
return self.invoke_rpc(base.LIBRARY_SERVICE_ID,
'replace_policy',
{'id_': id_,
'policy_dict': item})
except exception.CongressException as e:
raise webservice.DataModelException.create(e)

254
congress/api/policy_model.py

@ -1,254 +0,0 @@
# Copyright (c) 2014 VMware, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
import re
from oslo_serialization import jsonutils as json
import six
from congress.api import base
from congress.api import error_codes
from congress.api import webservice
from congress import exception
from congress.library_service import library_service
class PolicyModel(base.APIModel):
"""Model for handling API requests about Policies."""
# Note(thread-safety): blocking function
def get_items(self, params, context=None):
"""Get items in model.
:param: params: A dict-like object containing parameters
from the request query string and body.
:param: context: Key-values providing frame of reference of request
:returns: A dict containing at least a 'results' key whose value is
a list of items in the model. Additional keys set in the
dict will also be rendered for the user.
"""
try:
# Note(thread-safety): blocking call
return {"results": self.invoke_rpc(base.ENGINE_SERVICE_ID,
'persistent_get_policies',
{})}
except exception.CongressException as e:
raise webservice.DataModelException.create(e)
# Note(thread-safety): blocking function
def get_item(self, id_, params, context=None):
"""Retrieve item with id id\_ from model.
:param: id\_: The ID of the item to retrieve
:param: params: A dict-like object containing parameters
from the request query string and body.
:param: context: Key-values providing frame of reference of request
:returns: The matching item or None if id\_ does not exist.
"""
try:
# Note(thread-safety): blocking call
return self.invoke_rpc(base.ENGINE_SERVICE_ID,
'persistent_get_policy',
{'id_': id_})
except exception.CongressException as e:
raise webservice.DataModelException.create(e)
# Note(thread-safety): blocking function
def add_item(self, item, params, id_=None, context=None):
"""Add item to model.
:param: item: The item to add to the model
:param: params: A dict-like object containing parameters
from the request query string and body.
:param: id\_: The ID of the item, or None if an ID should be generated
:param: context: Key-values providing frame of reference of request
:returns: Tuple of (ID, newly_created_item)
:raises KeyError: ID already exists.
:raises DataModelException: Addition cannot be performed.
:raises BadRequest: library_policy parameter and request body both
present
"""
if id_ is not None:
(num, desc) = error_codes.get('policy_id_must_not_be_provided')
raise webservice.DataModelException(num, desc)
# case 1: parameter gives library policy UUID
if 'library_policy' in params:
if item:
raise exception.BadRequest(
'Policy creation request with `library_policy` parameter '
'must not have non-empty body.')
try:
# Note(thread-safety): blocking call
library_policy_object = self.invoke_rpc(
base.LIBRARY_SERVICE_ID,
'get_policy', {'id_': params['library_policy']})
policy_metadata = self.invoke_rpc(
base.ENGINE_SERVICE_ID,
'persistent_create_policy_with_rules',
{'policy_rules_obj': library_policy_object},
timeout=self.dse_long_timeout)
except exception.CongressException as e:
raise webservice.DataModelException.create(e)
return (policy_metadata['id'], policy_metadata)
# case 2: item contains rules
if 'rules' in item:
self._check_create_policy_item(item)
try:
library_service.validate_policy_item(item)
# Note(thread-safety): blocking call
policy_metadata = self.invoke_rpc(
base.ENGINE_SERVICE_ID,
'persistent_create_policy_with_rules',
{'policy_rules_obj': item}, timeout=self.dse_long_timeout)
except exception.CongressException as e:
raise webservice.DataModelException.create(e)
return (policy_metadata['id'], policy_metadata)
# case 3: item does not contain rules
self._check_create_policy_item(item)
name = item['name']
try:
# Note(thread-safety): blocking call
policy_metadata = self.invoke_rpc(
base.ENGINE_SERVICE_ID, 'persistent_create_policy',
{'name': name,
'abbr': item.get('abbreviation'),
'kind': item.get('kind'),
'desc': item.get('description')})
except exception.CongressException as e:
raise webservice.DataModelException.create(e)
return (policy_metadata['id'], policy_metadata)
def _check_create_policy_item(self, item):
if 'name' not in item:
(num, desc) = error_codes.get('policy_name_must_be_provided')
raise webservice.DataModelException(num, desc)
abbr = item.get('abbreviation')
if abbr:
# the length of abbreviation column is 5 chars in policy DB table,
# check it in API layer and raise exception if it's too long.
if not isinstance(abbr, six.string_types) or len(abbr) > 5:
(num, desc) = error_codes.get('policy_abbreviation_error')
raise webservice.DataModelException(num, desc)
# Note(thread-safety): blocking function
def delete_item(self, id_, params, context=None):
"""Remove item from model.
:param: id\_: The ID or name of the item to be removed
:param: params:
:param: context: Key-values providing frame of reference of request
:returns: The removed item.
:raises KeyError: Item with specified id\_ not present.
"""
# Note(thread-safety): blocking call
return self.invoke_rpc(base.ENGINE_SERVICE_ID,
'persistent_delete_policy',
{'name_or_id': id_},
timeout=self.dse_long_timeout)
def _get_boolean_param(self, key, params):
if key not in params:
return False
value = params[key]
return value.lower() == "true" or value == "1"
# Note: It's confusing to figure out how this method is called.
# It is called via user supplied string in the `action` method of
# api/webservice.py:ElementHandler
# Note(thread-safety): blocking function
def simulate_action(self, params, context=None, request=None):
"""Simulate the effects of executing a sequence of updates.
:returns: the result of a query.
"""
# grab string arguments
theory = context.get('policy_id') or params.get('policy')
if theory is None:
(num, desc) = error_codes.get('simulate_without_policy')
raise webservice.DataModelException(num, desc)
body = json.loads(request.body)
query = body.get('query')
sequence = body.get('sequence')
actions = body.get('action_policy')
delta = self._get_boolean_param('delta', params)
trace = self._get_boolean_param('trace', params)
if query is None or sequence is None or actions is None:
(num, desc) = error_codes.get('incomplete_simulate_args')
raise webservice.DataModelException(num, desc)
try:
args = {'query': query, 'theory': theory, 'sequence': sequence,
'action_theory': actions, 'delta': delta,
'trace': trace, 'as_list': True}
# Note(thread-safety): blocking call
result = self.invoke_rpc(base.ENGINE_SERVICE_ID, 'simulate',
args, timeout=self.dse_long_timeout)
except exception.PolicyException as e:
(num, desc) = error_codes.get('simulate_error')
raise webservice.DataModelException(num, desc + "::" + str(e))
# always return dict
if trace:
return {'result': result[0],
'trace': result[1]}
return {'result': result}
# Note(thread-safety): blocking function
def execute_action(self, params, context=None, request=None):
"""Execute the action."""
body = json.loads(request.body)
# e.g. name = 'nova:disconnectNetwork'
items = re.split(':', body.get('name'))
if len(items) != 2:
(num, desc) = error_codes.get('service_action_syntax')
raise webservice.DataModelException(num, desc)
service</