From 32c4560c3bee3130be252e8665e681e78d4cb949 Mon Sep 17 00:00:00 2001 From: Artur Basiak Date: Wed, 12 Jul 2017 08:36:47 +0200 Subject: [PATCH] Provide oslo.policies Add policies to the api based on oslo.policies. Small changes in documentation. Provide generator for sample policies file. Add policies for agent and admin. Story: 200112 Task: 4807 Depends-On: I76d737bf9d1216b041bc1a518cc2098f28e7da7b Change-Id: Idf5c4ec1b663ad9ed3ab25744bdf0b7f28cdb1a2 --- .gitignore | 1 + .testr.conf | 4 +- api-guide/source/conf.py | 259 ------------------ api-guide/source/index.rst | 35 --- .../__init__.py => api-ref/locale/.gitkeep | 0 api-ref/source/conf.py | 65 +---- api-ref/source/index.rst | 2 +- config-generator/README.md | 7 - config-generator/README.rst | 11 + .../{monasca-events-api.conf => config.conf} | 1 + config-generator/policy.conf | 3 + doc/api-samples/.gitkeep | 0 doc/source/.gitignore | 1 + doc/source/.gitkeep | 0 doc/source/_static/events-api.conf.sample | 114 -------- doc/source/admin/index.rst | 6 + doc/source/cli/index.rst | 3 + doc/source/code/modules.rst | 7 - doc/source/code/monasca_events_api.conf.rst | 8 - doc/source/code/monasca_events_api.rst | 35 --- doc/source/conf.py | 58 ++-- doc/source/configuration/index.rst | 3 + doc/source/contributor/.gitignore | 3 + doc/source/contributor/code.rst | 19 ++ doc/source/contributor/history.rst | 1 + doc/source/contributor/index.rst | 37 +++ doc/source/glossary.rst | 3 + doc/source/index.rst | 1 - doc/source/install/index.rst | 6 + doc/source/user/index.rst | 6 + etc/monasca/events-api-paste.ini | 31 +++ monasca_events_api/app/__init__.py | 0 monasca_events_api/app/core/__init__.py | 0 monasca_events_api/app/core/request.py | 41 +++ monasca_events_api/conf/__init__.py | 8 +- monasca_events_api/config.py | 12 +- monasca_events_api/policies/__init__.py | 58 ++++ monasca_events_api/policies/admin.py | 30 ++ monasca_events_api/policies/agent.py | 30 ++ monasca_events_api/policy.py | 148 ++++++++++ monasca_events_api/tests/__init__.py | 0 .../tests/functional/__init__.py | 0 monasca_events_api/tests/unit/__init__.py | 0 monasca_events_api/tests/unit/base.py | 95 +++++++ monasca_events_api/tests/unit/test_policy.py | 149 ++++++++++ monasca_events_api/tests/unit/test_request.py | 68 +++++ monasca_events_api/version.py | 2 +- .../notes/add_policies-24ddd2a505f3de6c.yaml | 9 + releasenotes/source/conf.py | 62 ++--- requirements.txt | 3 +- setup.cfg | 19 +- test-requirements.txt | 3 +- tox.ini | 33 +-- 53 files changed, 853 insertions(+), 647 deletions(-) delete mode 100644 api-guide/source/conf.py delete mode 100644 api-guide/source/index.rst rename monasca_events_api_tempest/__init__.py => api-ref/locale/.gitkeep (100%) delete mode 100644 config-generator/README.md create mode 100644 config-generator/README.rst rename config-generator/{monasca-events-api.conf => config.conf} (83%) create mode 100644 config-generator/policy.conf create mode 100644 doc/api-samples/.gitkeep create mode 100644 doc/source/.gitignore create mode 100644 doc/source/.gitkeep delete mode 100644 doc/source/_static/events-api.conf.sample create mode 100644 doc/source/admin/index.rst create mode 100644 doc/source/cli/index.rst delete mode 100644 doc/source/code/modules.rst delete mode 100644 doc/source/code/monasca_events_api.conf.rst delete mode 100644 doc/source/code/monasca_events_api.rst create mode 100644 doc/source/configuration/index.rst create mode 100644 doc/source/contributor/.gitignore create mode 100644 doc/source/contributor/code.rst create mode 100644 doc/source/contributor/history.rst create mode 100644 doc/source/contributor/index.rst create mode 100644 doc/source/glossary.rst create mode 100644 doc/source/install/index.rst create mode 100644 doc/source/user/index.rst create mode 100644 monasca_events_api/app/__init__.py create mode 100644 monasca_events_api/app/core/__init__.py create mode 100644 monasca_events_api/app/core/request.py create mode 100644 monasca_events_api/policies/__init__.py create mode 100644 monasca_events_api/policies/admin.py create mode 100644 monasca_events_api/policies/agent.py create mode 100644 monasca_events_api/policy.py create mode 100644 monasca_events_api/tests/__init__.py create mode 100644 monasca_events_api/tests/functional/__init__.py create mode 100644 monasca_events_api/tests/unit/__init__.py create mode 100644 monasca_events_api/tests/unit/base.py create mode 100644 monasca_events_api/tests/unit/test_policy.py create mode 100644 monasca_events_api/tests/unit/test_request.py create mode 100644 releasenotes/notes/add_policies-24ddd2a505f3de6c.yaml diff --git a/.gitignore b/.gitignore index a51428e..621937c 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ log/ *config*.yml db/config.yml .coverage.* +*.sample diff --git a/.testr.conf b/.testr.conf index 63601b8..7f33051 100644 --- a/.testr.conf +++ b/.testr.conf @@ -2,8 +2,8 @@ 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 monasca $LISTOPT $IDOPTION + ${PYTHON:-python} -m subunit.run discover $PWD $LISTOPT $IDOPTION test_id_option=--load-list $IDFILE test_list_option=--list -group_regex=monasca_events_api\.tests(?:\.|_)([^_]+) +group_regex=monasca_events_api\.tests\.unit(?:\.|_)([^_]+) diff --git a/api-guide/source/conf.py b/api-guide/source/conf.py deleted file mode 100644 index 60e6892..0000000 --- a/api-guide/source/conf.py +++ /dev/null @@ -1,259 +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. -# -# Key Manager API documentation build configuration file -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -needs_sphinx = '1.6' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'openstackdocstheme' -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -source_encoding = 'utf-8' - -# The master toctree document. -master_doc = 'index' - -# General details about project -repository_name = u'openstack/monasca-events-api' -project = u'Monasca Events API Guide' -bug_project = u'monasca-events-api' -bug_tag = u'api-guide' -copyright = u'2014, OpenStack Foundation' - -from monasca_events_api.version import version_info -version = version_info.version_string() -release = version_info.release_string() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# 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 - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# A shorter title for the navigation bar. Default is the same as html_title. -html_short_title = 'API Guide' - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = [] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'monascaeventsapi-api-guide' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'MonascaEventsApiAPI.tex', u'Key Manager API Documentation', - u'OpenStack Foundation', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'monascaeventsapiapi', u'Monasca Events API Documentation', - [u'OpenStack Foundation'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'MonascaEventsApiAPIGuide', u'Monasca Events API Guide', - u'OpenStack Foundation', 'APIGuide', - 'This guide teaches OpenStack Monasca Events service users concepts about ' - 'managing keys in an OpenStack cloud with the Monasca Events API.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - -# -- Options for Internationalization output ------------------------------ -locale_dirs = ['locale/'] - -# -- Options for PDF output -------------------------------------------------- - -pdf_documents = [ - ('index', u'MonascaEventsApiAPIGuide', u'Key Manager API Guide', u'OpenStack ' - 'contributors') -] diff --git a/api-guide/source/index.rst b/api-guide/source/index.rst deleted file mode 100644 index 1d7a4b2..0000000 --- a/api-guide/source/index.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. - Copyright 2017 Fujitsu LIMITED - - 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. - -================== -Monasca Events API -================== - -The monasca-events-api project has a RESTful HTTP service called the -Monasca Events API. To this API , services (agents) can send events collected -from OpenStack message bus. - -This guide covers the concepts in the Monasca Events API. -For a full reference listing, please see: -`Monasca Events API Reference `__. - -We welcome feedback, comments and bug reports at -`storyboard/monasca `__. - - -Contents -======== -.. toctree:: - :maxdepth: 2 diff --git a/monasca_events_api_tempest/__init__.py b/api-ref/locale/.gitkeep similarity index 100% rename from monasca_events_api_tempest/__init__.py rename to api-ref/locale/.gitkeep diff --git a/api-ref/source/conf.py b/api-ref/source/conf.py index e530c3e..887e125 100644 --- a/api-ref/source/conf.py +++ b/api-ref/source/conf.py @@ -16,6 +16,8 @@ # All configuration values have a default; values that are commented out # serve to show the default. +from monasca_events_api.version import version_info + # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -43,18 +45,13 @@ master_doc = 'index' # General details about project repository_name = u'openstack/monasca-events-api' -project = u'Monasca Events Ref Guide' -bug_project = u'monasca-events-api' -bug_tag = u'api-ref' -copyright = u'2014, OpenStack Foundation' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -from monasca_events_api.version import version_info -version = version_info.version_string() -release = version_info.release_string() +project = u'Monitoring Events API Reference' +version = version_info.canonical_version_string() +release = version_info.version_string_with_vcs() +bug_project = u'866' +bug_tag = u'' +copyright = u'2014-present, OpenStack Foundation' +author = u'OpenStack Foundation' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -173,8 +170,7 @@ html_use_index = True # html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'monascaeventsapi-api-ref' - +htmlhelp_basename = 'MonitoringEventsApiRefDoc' # -- Options for LaTeX output --------------------------------------------- @@ -193,8 +189,8 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'MonascaEventsApi.tex', u'Monasca Events API Documentation', - u'OpenStack Foundation', 'manual'), + (master_doc, 'MonitoringEventsApiRef.tex', u'Monitoring Events API Reference', + [author], 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -217,42 +213,5 @@ latex_documents = [ # If false, no module index is generated. # latex_domain_indices = True - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'monascaeventsapi', u'Monasca Events API Documentation', - [u'OpenStack Foundation'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'MonascaEventsAPI', u'Monasca Events API Documentation', - u'OpenStack Foundation', 'MonascaEventsAPI', 'Monasca Events API', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] diff --git a/api-ref/source/index.rst b/api-ref/source/index.rst index a43f782..e2ee1d3 100644 --- a/api-ref/source/index.rst +++ b/api-ref/source/index.rst @@ -1,7 +1,7 @@ :tocdepth: 2 .. - Copyright 2014-2017 Fujitsu LIMITED + Copyright 2017 Fujitsu LIMITED 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 diff --git a/config-generator/README.md b/config-generator/README.md deleted file mode 100644 index 92e0bb7..0000000 --- a/config-generator/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# config-generator - -To generate sample configuration execute - -```bash -tox -e genconfig -``` \ No newline at end of file diff --git a/config-generator/README.rst b/config-generator/README.rst new file mode 100644 index 0000000..b6c927a --- /dev/null +++ b/config-generator/README.rst @@ -0,0 +1,11 @@ +================ +config-generator +================ + +To generate sample configuration execute:: + + tox -e genconfig + +To generate the sample policies execute:: + + tox -e genpolicy \ No newline at end of file diff --git a/config-generator/monasca-events-api.conf b/config-generator/config.conf similarity index 83% rename from config-generator/monasca-events-api.conf rename to config-generator/config.conf index d85c8f7..2e4ff22 100644 --- a/config-generator/monasca-events-api.conf +++ b/config-generator/config.conf @@ -4,3 +4,4 @@ width = 80 format = ini namespace = events.api namespace = oslo.log +namespace = oslo.policy diff --git a/config-generator/policy.conf b/config-generator/policy.conf new file mode 100644 index 0000000..dc84303 --- /dev/null +++ b/config-generator/policy.conf @@ -0,0 +1,3 @@ +[DEFAULT] +output_file = etc/monasca/events-policy.yaml.sample +namespace = events.api \ No newline at end of file diff --git a/doc/api-samples/.gitkeep b/doc/api-samples/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/doc/source/.gitignore b/doc/source/.gitignore new file mode 100644 index 0000000..8edeff2 --- /dev/null +++ b/doc/source/.gitignore @@ -0,0 +1 @@ +_static/ diff --git a/doc/source/.gitkeep b/doc/source/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/doc/source/_static/events-api.conf.sample b/doc/source/_static/events-api.conf.sample deleted file mode 100644 index a937dd5..0000000 --- a/doc/source/_static/events-api.conf.sample +++ /dev/null @@ -1,114 +0,0 @@ -[DEFAULT] - -# -# From oslo.log -# - -# If set to true, the logging level will be set to DEBUG instead of -# the default INFO level. (boolean value) -# Note: This option can be changed without restarting. -#debug = false - -# The name of a logging configuration file. This file is appended to -# any existing logging configuration files. For details about logging -# configuration files, see the Python logging module documentation. -# Note that when logging configuration files are used then all logging -# configuration is set in the configuration file and other logging -# configuration options are ignored (for example, -# logging_context_format_string). (string value) -# Note: This option can be changed without restarting. -# Deprecated group/name - [DEFAULT]/log_config -#log_config_append = - -# Defines the format string for %%(asctime)s in log records. Default: -# %(default)s . This option is ignored if log_config_append is set. -# (string value) -#log_date_format = %Y-%m-%d %H:%M:%S - -# (Optional) Name of log file to send logging output to. If no default -# is set, logging will go to stderr as defined by use_stderr. This -# option is ignored if log_config_append is set. (string value) -# Deprecated group/name - [DEFAULT]/logfile -#log_file = - -# (Optional) The base directory used for relative log_file paths. -# This option is ignored if log_config_append is set. (string value) -# Deprecated group/name - [DEFAULT]/logdir -#log_dir = - -# Uses logging handler designed to watch file system. When log file is -# moved or removed this handler will open a new log file with -# specified path instantaneously. It makes sense only if log_file -# option is specified and Linux platform is used. This option is -# ignored if log_config_append is set. (boolean value) -#watch_log_file = false - -# Use syslog for logging. Existing syslog format is DEPRECATED and -# will be changed later to honor RFC5424. This option is ignored if -# log_config_append is set. (boolean value) -#use_syslog = false - -# Enable journald for logging. If running in a systemd environment you -# may wish to enable journal support. Doing so will use the journal -# native protocol which includes structured metadata in addition to -# log messages.This option is ignored if log_config_append is set. -# (boolean value) -#use_journal = false - -# Syslog facility to receive log lines. This option is ignored if -# log_config_append is set. (string value) -#syslog_log_facility = LOG_USER - -# Log output to standard error. This option is ignored if -# log_config_append is set. (boolean value) -#use_stderr = false - -# Format string to use for log messages with context. (string value) -#logging_context_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s - -# Format string to use for log messages when context is undefined. -# (string value) -#logging_default_format_string = %(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s - -# Additional data to append to log message when logging level for the -# message is DEBUG. (string value) -#logging_debug_format_suffix = %(funcName)s %(pathname)s:%(lineno)d - -# Prefix each line of exception output with this format. (string -# value) -#logging_exception_prefix = %(asctime)s.%(msecs)03d %(process)d ERROR %(name)s %(instance)s - -# Defines the format string for %(user_identity)s that is used in -# logging_context_format_string. (string value) -#logging_user_identity_format = %(user)s %(tenant)s %(domain)s %(user_domain)s %(project_domain)s - -# List of package logging levels in logger=LEVEL pairs. This option is -# ignored if log_config_append is set. (list value) -#default_log_levels = amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,oslo_messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN,websocket=WARN,requests.packages.urllib3.util.retry=WARN,urllib3.util.retry=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN,taskflow=WARN,keystoneauth=WARN,oslo.cache=INFO,dogpile.core.dogpile=INFO - -# Enables or disables publication of error events. (boolean value) -#publish_errors = false - -# The format for an instance that is passed with the log message. -# (string value) -#instance_format = "[instance: %(uuid)s] " - -# The format for an instance UUID that is passed with the log message. -# (string value) -#instance_uuid_format = "[instance: %(uuid)s] " - -# Interval, number of seconds, of log rate limiting. (integer value) -#rate_limit_interval = 0 - -# Maximum number of logged messages per rate_limit_interval. (integer -# value) -#rate_limit_burst = 0 - -# Log level name used by rate limiting: CRITICAL, ERROR, INFO, -# WARNING, DEBUG or empty string. Logs with level greater or equal to -# rate_limit_except_level are not filtered. An empty string means that -# all levels are filtered. (string value) -#rate_limit_except_level = CRITICAL - -# Enables or disables fatal status of deprecations. (boolean value) -#fatal_deprecations = false diff --git a/doc/source/admin/index.rst b/doc/source/admin/index.rst new file mode 100644 index 0000000..4b1b94a --- /dev/null +++ b/doc/source/admin/index.rst @@ -0,0 +1,6 @@ +==================== +Administration guide +==================== + +.. toctree:: + :maxdepth: 2 diff --git a/doc/source/cli/index.rst b/doc/source/cli/index.rst new file mode 100644 index 0000000..78d9f96 --- /dev/null +++ b/doc/source/cli/index.rst @@ -0,0 +1,3 @@ +====================== +Command Line Interface +====================== diff --git a/doc/source/code/modules.rst b/doc/source/code/modules.rst deleted file mode 100644 index 003a0cc..0000000 --- a/doc/source/code/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -monasca_events_api -================== - -.. toctree:: - :maxdepth: 4 - - monasca_events_api diff --git a/doc/source/code/monasca_events_api.conf.rst b/doc/source/code/monasca_events_api.conf.rst deleted file mode 100644 index b902d2c..0000000 --- a/doc/source/code/monasca_events_api.conf.rst +++ /dev/null @@ -1,8 +0,0 @@ -monasca\_events\_api\.conf package -================================== - -.. automodule:: monasca_events_api.conf - :members: - :undoc-members: - :show-inheritance: - diff --git a/doc/source/code/monasca_events_api.rst b/doc/source/code/monasca_events_api.rst deleted file mode 100644 index 3ee4e56..0000000 --- a/doc/source/code/monasca_events_api.rst +++ /dev/null @@ -1,35 +0,0 @@ -monasca\_events\_api package -============================ - -.. automodule:: monasca_events_api - :members: - :undoc-members: - :show-inheritance: - -Subpackages ------------ - -.. toctree:: - - monasca_events_api.conf - -Submodules ----------- - -monasca\_events\_api\.config module ------------------------------------ - -.. automodule:: monasca_events_api.config - :members: - :undoc-members: - :show-inheritance: - -monasca\_events\_api\.version module ------------------------------------- - -.. automodule:: monasca_events_api.version - :members: - :undoc-members: - :show-inheritance: - - diff --git a/doc/source/conf.py b/doc/source/conf.py index 4336cac..b5730c4 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# monasca-events-api documentation build configuration file, created by +# monasca-events-app documentation build configuration file, created by # sphinx-quickstart on Wed Nov 18 12:02:03 2015. # # This file is execfile()d with the current directory set to its @@ -19,7 +19,9 @@ from monasca_events_api.version import version_info sys.path = [ os.path.abspath('../..'), - os.path.abspath('../../bin') + os.path.abspath('../../bin'), + os.path.abspath('./'), + os.path.abspath('../') ] + sys.path # -- General configuration ------------------------------------------------ @@ -37,25 +39,30 @@ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'oslo_config.sphinxconfiggen', + 'oslo_policy.sphinxpolicygen', 'oslo_config.sphinxext', 'openstackdocstheme', ] # geeneral information about project repository_name = u'openstack/monasca-events-api' -project = u'Monasca Events Dev Docs' -version = version_info.version_string() -release = version_info.release_string() -bug_project = u'monasca-events-api' -bug_tag = u'doc' +project = u'monasca' +version = version_info.canonical_version_string() +release = version_info.version_string_with_vcs() +bug_project = u'866' +bug_tag = u'' copyright = u'2017-present, OpenStack Foundation' author = u'OpenStack Foundation' # sample config config_generator_config_file = [ - ('config-generator/monasca-events-api.conf', '_static/events-api') + ('config-generator/config.conf', '_static/events-api') ] +# sample policy file +policy_generator_config_file = 'config-generator/policy.conf' +sample_policy_basename = '_static/events-api' + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -194,7 +201,7 @@ html_use_modindex = True #html_search_scorer = 'scorer.js' # Output file base name for HTML help builder. -htmlhelp_basename = 'monasca-events-apidoc' +htmlhelp_basename = 'MonitoringEventsApiDoc' # -- Options for LaTeX output --------------------------------------------- @@ -216,8 +223,8 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'monasca-events-api.tex', u'monasca-events-api Documentation', - u'Openstack Foundation \\textless{}monasca@lists.launchpad.net\\textgreater{}', 'manual'), + (master_doc, 'MonitoringEventsApi.tex', u'Monasca Events Documentation', + [author], 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -246,37 +253,12 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'monasca-events-api', u'monasca-events-api Documentation', + (master_doc, 'monitoringeventsapi', u'Monasca Events Documentation', [author], 1) ] # If true, show URL addresses after external links. #man_show_urls = False - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'monasca-events-api', u'monasca-events-api Documentation', - author, 'monasca-events-api', 'Rest-API to collect events from your cloud.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - - # Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = {'https://doc.python.org/': None} +intersphinx_mapping = {'https://doc.python.org/': None} \ No newline at end of file diff --git a/doc/source/configuration/index.rst b/doc/source/configuration/index.rst new file mode 100644 index 0000000..e5cda69 --- /dev/null +++ b/doc/source/configuration/index.rst @@ -0,0 +1,3 @@ +============= +Configuration +============= diff --git a/doc/source/contributor/.gitignore b/doc/source/contributor/.gitignore new file mode 100644 index 0000000..13f025d --- /dev/null +++ b/doc/source/contributor/.gitignore @@ -0,0 +1,3 @@ +# codebase documentation is autogenerated +# do not track it +api/ diff --git a/doc/source/contributor/code.rst b/doc/source/contributor/code.rst new file mode 100644 index 0000000..bf2a21e --- /dev/null +++ b/doc/source/contributor/code.rst @@ -0,0 +1,19 @@ +.. _codedocs: + +====================== +Codebase documentation +====================== + +Following section contains codebase documentation generated with, a little +bit of assistance, `sphinx.ext.autodoc`_. + +.. _`sphinx.ext.autodoc`: http://www.sphinx-doc.org/en/stable/ext/autodoc.html + +Modules +======= + +.. toctree:: + :maxdepth: 2 + + api/autoindex.rst + diff --git a/doc/source/contributor/history.rst b/doc/source/contributor/history.rst new file mode 100644 index 0000000..f69be70 --- /dev/null +++ b/doc/source/contributor/history.rst @@ -0,0 +1 @@ +.. include:: ../../../ChangeLog diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst new file mode 100644 index 0000000..ab3bbb7 --- /dev/null +++ b/doc/source/contributor/index.rst @@ -0,0 +1,37 @@ +======================= +Contribution Guidelines +======================= + +In the Contributions Guide, you will find documented policies for +developing with monasca-events-api. This includes the processes we use for +blueprints and specs, bugs, contributor on boarding, core reviewer +memberships, and other procedural items. + +monasca-events-api, as with all OpenStack projects, is written with the +following design guidelines in mind: + +* **Component based architecture**: Quickly add new behaviors +* **Highly available**: Scale to very serious workloads +* **Fault tolerant**: Isolated processes avoid cascading failures +* **Recoverable**: Failures should be easy to diagnose, debug, and rectify +* **Open standards**: Be a reference implementation for a community-driven api + +This documentation is generated by the Sphinx toolkit and lives in the source +tree. Additional documentation on monasca-events-api and other components of +OpenStack can be found on the `OpenStack wiki `_. + +Developer reference +------------------- + +.. toctree:: + :maxdepth: 1 + + code + +Changelog +--------- + +.. toctree:: + :maxdepth: 1 + + history diff --git a/doc/source/glossary.rst b/doc/source/glossary.rst new file mode 100644 index 0000000..fa106d1 --- /dev/null +++ b/doc/source/glossary.rst @@ -0,0 +1,3 @@ +======== +Glossary +======== diff --git a/doc/source/index.rst b/doc/source/index.rst index 646ad8e..6c7f122 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -45,4 +45,3 @@ any specific prior release. :maxdepth: 1 glossary - diff --git a/doc/source/install/index.rst b/doc/source/install/index.rst new file mode 100644 index 0000000..eeb01df --- /dev/null +++ b/doc/source/install/index.rst @@ -0,0 +1,6 @@ +============ +Installation +============ + +.. toctree:: + :maxdepth: 2 diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst new file mode 100644 index 0000000..8da48ac --- /dev/null +++ b/doc/source/user/index.rst @@ -0,0 +1,6 @@ +========== +User guide +========== + +.. toctree:: + :maxdepth: 2 diff --git a/etc/monasca/events-api-paste.ini b/etc/monasca/events-api-paste.ini index e69de29..d72075f 100644 --- a/etc/monasca/events-api-paste.ini +++ b/etc/monasca/events-api-paste.ini @@ -0,0 +1,31 @@ +# Copyright 2017 FUJITSU LIMITED +# +# 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. + +[DEFAULT] +name = main + +[composite:main] +use = egg:Paste#urlmap +/: ea_version +/v1.0: ea_version_v1 + +[pipeline:ea_version_v1] +pipeline = request_id auth + + +[filter:request_id] +paste.filter_factory = oslo_middleware.request_id:RequestId.factory + +[filter:auth] +paste.filter_factory = keystonemiddleware.auth_token:filter_factory diff --git a/monasca_events_api/app/__init__.py b/monasca_events_api/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/monasca_events_api/app/core/__init__.py b/monasca_events_api/app/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/monasca_events_api/app/core/request.py b/monasca_events_api/app/core/request.py new file mode 100644 index 0000000..bc26d81 --- /dev/null +++ b/monasca_events_api/app/core/request.py @@ -0,0 +1,41 @@ +# Copyright 2017 FUJITSU LIMITED +# +# 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 falcon + +from oslo_context import context + +from monasca_events_api import policy + + +class Request(falcon.Request): + """Variation of falcon. Request with context. + + Following class enhances :py:class:`falcon.Request` with + :py:class:`context.RequestContext` + """ + + def __init__(self, env, options=None): + """Init an Request class.""" + super(Request, self).__init__(env, options) + self.is_admin = None + self.context = context.RequestContext.from_environ(self.env) + + if self.is_admin is None: + self.is_admin = policy.check_is_admin(self) + + def to_policy_values(self): + policy = self.context.to_policy_values() + policy['is_admin'] = self.is_admin + return policy diff --git a/monasca_events_api/conf/__init__.py b/monasca_events_api/conf/__init__.py index 4864338..82107e4 100644 --- a/monasca_events_api/conf/__init__.py +++ b/monasca_events_api/conf/__init__.py @@ -15,18 +15,16 @@ import os import pkgutil -from oslo_config import cfg from oslo_log import log from oslo_utils import importutils -CONF = cfg.CONF LOG = log.getLogger(__name__) def load_conf_modules(): """Load all modules that contain configuration. - Method iterates over modules of :py:module:`monasca_log_api.conf` + Method iterates over modules of :py:mod:`monasca_events_api.conf` and imports only those that contain following methods: - list_opts (required by oslo_config.genconfig) @@ -62,7 +60,7 @@ def _list_module_names(): return module_names -def register_opts(): +def register_opts(conf): """Register all conf modules opts. This method allows different modules to register @@ -70,7 +68,7 @@ def register_opts(): """ for mod in load_conf_modules(): - mod.register_opts(CONF) + mod.register_opts(conf) def list_opts(): diff --git a/monasca_events_api/config.py b/monasca_events_api/config.py index 8b6ac54..543d088 100644 --- a/monasca_events_api/config.py +++ b/monasca_events_api/config.py @@ -12,12 +12,14 @@ # License for the specific language governing permissions and limitations # under the License. +from oslo_config import cfg from oslo_log import log +from oslo_policy import opts as policy_opts from monasca_events_api import conf from monasca_events_api import version -CONF = conf.CONF +CONF = cfg.CONF LOG = log.getLogger(__name__) _CONF_LOADED = False @@ -39,15 +41,17 @@ def parse_args(): log.set_defaults() log.register_options(CONF) - CONF(prog='events-api', + CONF(args=[], + prog='events-app', project='monasca', version=version.version_str, description='RESTful API to collect events from cloud') log.setup(CONF, - product_name='monasca-events-api', + product_name='monasca-events-app', version=version.version_str) - conf.register_opts() + conf.register_opts(CONF) + policy_opts.set_defaults(CONF) _CONF_LOADED = True diff --git a/monasca_events_api/policies/__init__.py b/monasca_events_api/policies/__init__.py new file mode 100644 index 0000000..369ca44 --- /dev/null +++ b/monasca_events_api/policies/__init__.py @@ -0,0 +1,58 @@ +# Copyright 2017 FUJITSU LIMITED +# +# 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 pkgutil + +from oslo_log import log +from oslo_utils import importutils + +LOG = log.getLogger(__name__) +_BASE_MOD_PATH = 'monasca_events_api.policies.' + + +def load_policy_modules(): + """Load all modules that contain policies. + + Method iterates over modules of :py:mod:`monasca_events_api.policies` + and imports only those that contain following methods: + + - list_opts (required by oslo_config.genconfig) + - register_opts (required by :py:currentmodule:) + + """ + for modname in _list_module_names(): + mod = importutils.import_module(_BASE_MOD_PATH + modname) + if hasattr(mod, 'list_rules'): + yield mod + + +def _list_module_names(): + package_path = os.path.dirname(os.path.abspath(__file__)) + for _, modname, ispkg in pkgutil.iter_modules(path=[package_path]): + if not (modname == "opts" and ispkg): + yield modname + + +def list_rules(): + """List all policy modules rules. + + Goes through all policy modules and yields their rules + + """ + all_rules = [] + for mod in load_policy_modules(): + rules = mod.list_rules() + all_rules.extend(rules) + return all_rules diff --git a/monasca_events_api/policies/admin.py b/monasca_events_api/policies/admin.py new file mode 100644 index 0000000..32e81c9 --- /dev/null +++ b/monasca_events_api/policies/admin.py @@ -0,0 +1,30 @@ +# Copyright 2017 FUJITSU LIMITED +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_policy import policy + + +admin_rules = [ + policy.DocumentedRuleDefault( + name='admin_required', + check_str='role:admin or is_admin:1', + description='Admin role', + operations=[{'path': '/', 'method': 'POST'}] + ), +] + + +def list_rules(): + """List policy rules for admin access.""" + return admin_rules diff --git a/monasca_events_api/policies/agent.py b/monasca_events_api/policies/agent.py new file mode 100644 index 0000000..bc9ade8 --- /dev/null +++ b/monasca_events_api/policies/agent.py @@ -0,0 +1,30 @@ +# Copyright 2017 FUJITSU LIMITED +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from oslo_policy import policy + + +agent_policies = [ + policy.DocumentedRuleDefault( + name='events_api:agent_required', + check_str='role:monasca_events_agent', + description='Send events to api', + operations=[{'path': '/v1.0/events', 'method': 'POST'}] + ) +] + + +def list_rules(): + """List policies rules for agent access.""" + return agent_policies diff --git a/monasca_events_api/policy.py b/monasca_events_api/policy.py new file mode 100644 index 0000000..bbd2423 --- /dev/null +++ b/monasca_events_api/policy.py @@ -0,0 +1,148 @@ +# Copyright 2017 FUJITSU LIMITED +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import copy + +from oslo_config import cfg +from oslo_log import log +from oslo_policy import policy + +from monasca_events_api import policies + +CONF = cfg.CONF +LOG = log.getLogger(__name__) + +_ENFORCER = None +# oslo_policy will read the policy configuration file again when the file +# is changed in runtime so the old policy rules will be saved to +# saved_file_rules and used to compare with new rules to determine the +# rules whether were updated. +saved_file_rules = [] + + +def reset(): + """Reset Enforcer class.""" + global _ENFORCER + if _ENFORCER: + _ENFORCER.clear() + _ENFORCER = None + + +def init(policy_file=None, rules=None, default_rule=None, use_conf=True): + """Init an Enforcer class.""" + global _ENFORCER + global saved_file_rules + + if not _ENFORCER: + _ENFORCER = policy.Enforcer(CONF, + policy_file=policy_file, + rules=rules, + default_rule=default_rule, + use_conf=use_conf + ) + register_rules(_ENFORCER) + _ENFORCER.load_rules() + # Only the rules which are loaded from file may be changed + current_file_rules = _ENFORCER.file_rules + current_file_rules = _serialize_rules(current_file_rules) + + if saved_file_rules != current_file_rules: + saved_file_rules = copy.deepcopy(current_file_rules) + + +def _serialize_rules(rules): + """Serialize all the Rule object as string. + + New string is used to compare the rules list. + """ + result = [(rule_name, str(rule)) for rule_name, rule in rules.items()] + return sorted(result, key=lambda rule: rule[0]) + + +def register_rules(enforcer): + """Register default policy rules.""" + rules = policies.list_rules() + enforcer.register_defaults(rules) + + +def authorize(context, action, target, do_raise=True): + """Verify that the action is valid on the target in this context. + + :param context: monasca-events-api context + :param action: String representing the action to be checked. This + should be colon separated for clarity. + :param target: Dictionary representing the object of the action for + object creation. This should be a dictionary representing + the location of the object e.g. + ``{'project_id': 'context.project_id'}`` + :param do_raise: if True (the default), raises PolicyNotAuthorized, + if False returns False + :type context: object + :type action: str + :type target: dict + :type do_raise: bool + :return: returns a non-False value (not necessarily True) if authorized, + and the False if not authorized and do_raise if False + + :raises oslo_policy.policy.PolicyNotAuthorized: if verification fails + """ + init() + credentials = context.to_policy_values() + + try: + result = _ENFORCER.authorize(action, target, credentials, + do_raise=do_raise, action=action) + return result + except policy.PolicyNotRegistered: + LOG.exception('Policy not registered') + raise + except Exception: + LOG.debug('Policy check for %(action)s failed with credentials ' + '%(credentials)s', + {'action': action, 'credentials': credentials}) + raise + + +def check_is_admin(context): + """Check if roles contains 'admin' role according to policy settings.""" + init() + credentials = context.to_policy_values() + target = credentials + return _ENFORCER.authorize('admin_required', target, credentials) + + +def set_rules(rules, overwrite=True, use_conf=False): # pragma: no cover + """Set rules based on the provided dict of rules. + + Note: + Used in tests only. + + :param rules: New rules to use. It should be an instance of dict + :param overwrite: Whether to overwrite current rules or update them + with the new rules. + :param use_conf: Whether to reload rules from config file. + """ + init(use_conf=False) + _ENFORCER.set_rules(rules, overwrite, use_conf) + + +def get_rules(): # pragma: no cover + """Get policy rules. + + Note: + Used in tests only. + + """ + if _ENFORCER: + return _ENFORCER.rules diff --git a/monasca_events_api/tests/__init__.py b/monasca_events_api/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/monasca_events_api/tests/functional/__init__.py b/monasca_events_api/tests/functional/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/monasca_events_api/tests/unit/__init__.py b/monasca_events_api/tests/unit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/monasca_events_api/tests/unit/base.py b/monasca_events_api/tests/unit/base.py new file mode 100644 index 0000000..62e81ef --- /dev/null +++ b/monasca_events_api/tests/unit/base.py @@ -0,0 +1,95 @@ +# Copyright 2017 FUJITSU LIMITED +# +# 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 +from oslo_config import cfg +from oslo_config import fixture as config_fixture +from oslo_context import fixture as oc_fixture +from oslo_log.fixture import logging_error as log_fixture +from oslo_serialization import jsonutils +from oslotest import base + +from monasca_events_api import config +from monasca_events_api import policies +from monasca_events_api import policy + +CONF = cfg.CONF + + +class ConfigFixture(config_fixture.Config): + + def setUp(self): + super(ConfigFixture, self).setUp() + self.addCleanup(self._clean_config_loaded_flag) + config.parse_args() + + @staticmethod + def _clean_config_loaded_flag(): + config._CONF_LOADED = False + + +class BaseTestCase(base.BaseTestCase): + + def setUp(self): + super(BaseTestCase, self).setUp() + self.useFixture(fixtures.NestedTempfile()) + self.useFixture(fixtures.TempHomeDir()) + self.useFixture(log_fixture.get_logging_handle_error_fixture()) + self.useFixture(ConfigFixture(CONF)) + self.useFixture(oc_fixture.ClearRequestContext()) + self.useFixture(PolicyFixture()) + + @staticmethod + def conf_override(**kw): + """Override flag variables for a test.""" + group = kw.pop('group', None) + for k, v in kw.items(): + CONF.set_override(k, v, group) + + +class PolicyFixture(fixtures.Fixture): + """Override the policy with a completely new policy file. + + This overrides the policy with a completely fake and synthetic + policy file. + + """ + + def setUp(self): + super(PolicyFixture, self).setUp() + self._prepare_policy() + policy.reset() + policy.init() + self.addCleanup(policy.reset) + + def _prepare_policy(self): + policy_dir = self.useFixture(fixtures.TempDir()) + policy_file = os.path.join(policy_dir.path, 'policy.yaml') + + # load the fake_policy data and add the missing default rules. + policy_rules = jsonutils.loads('{}') + self.add_missing_default_rules(policy_rules) + with open(policy_file, 'w') as f: + jsonutils.dump(policy_rules, f) + + BaseTestCase.conf_override(policy_file=policy_file, + group='oslo_policy') + BaseTestCase.conf_override(policy_dirs=[], group='oslo_policy') + + def add_missing_default_rules(self, rules): + for rule in policies.list_rules(): + if rule.name not in rules: + rules[rule.name] = rule.check_str diff --git a/monasca_events_api/tests/unit/test_policy.py b/monasca_events_api/tests/unit/test_policy.py new file mode 100644 index 0000000..5c431a0 --- /dev/null +++ b/monasca_events_api/tests/unit/test_policy.py @@ -0,0 +1,149 @@ +# Copyright 2017 FUJITSU LIMITED +# +# 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 falcon import testing + +from oslo_context import context +from oslo_policy import policy as os_policy + +from monasca_events_api.app.core import request +from monasca_events_api import policy +from monasca_events_api.tests.unit import base + + +class TestPolicyFileCase(base.BaseTestCase): + def setUp(self): + super(TestPolicyFileCase, self).setUp() + self.context = context.RequestContext(user='fake', + tenant='fake', + is_admin=False) + self.target = {'tenant_id': 'fake'} + + def test_modified_policy_reloads(self): + tmp_file = \ + self.create_tempfiles(files=[('policies', '{}')], ext='.yaml')[0] + base.BaseTestCase.conf_override(policy_file=tmp_file, + group='oslo_policy') + + policy.reset() + policy.init() + + action = 'example:test' + rule = os_policy.RuleDefault(action, '') + policy._ENFORCER.register_defaults([rule]) + + with open(tmp_file, 'w') as policy_file: + policy_file.write('{"example:test": ""}') + policy.authorize(self.context, action, self.target) + + with open(tmp_file, 'w') as policy_file: + policy_file.write('{"example:test": "!"}') + policy._ENFORCER.load_rules(True) + self.assertRaises(os_policy.PolicyNotAuthorized, policy.authorize, + self.context, action, self.target) + + +class TestPolicyCase(base.BaseTestCase): + def setUp(self): + super(TestPolicyCase, self).setUp() + rules = [ + os_policy.RuleDefault("true", "@"), + os_policy.RuleDefault("example:allowed", "@"), + os_policy.RuleDefault("example:denied", "!"), + os_policy.RuleDefault("example:lowercase_admin", + "role:admin or role:sysadmin"), + os_policy.RuleDefault("example:uppercase_admin", + "role:ADMIN or role:sysadmin"), + ] + policy.reset() + policy.init() + policy._ENFORCER.register_defaults(rules) + + def test_authorize_nonexist_action_throws(self): + action = "example:noexist" + ctx = request.Request( + testing.create_environ( + path="/", + headers={ + "X_USER_ID": "fake", + "X_PROJECT_ID": "fake", + "X_ROLES": "member" + } + ) + ) + self.assertRaises(os_policy.PolicyNotRegistered, policy.authorize, + ctx, action, {}) + + def test_authorize_bad_action_throws(self): + action = "example:denied" + ctx = request.Request( + testing.create_environ( + path="/", + headers={ + "X_USER_ID": "fake", + "X_PROJECT_ID": "fake", + "X_ROLES": "member" + } + ) + ) + self.assertRaises(os_policy.PolicyNotAuthorized, policy.authorize, + ctx, action, {}) + + def test_authorize_bad_action_no_exception(self): + action = "example:denied" + ctx = request.Request( + testing.create_environ( + path="/", + headers={ + "X_USER_ID": "fake", + "X_PROJECT_ID": "fake", + "X_ROLES": "member" + } + ) + ) + result = policy.authorize(ctx, action, {}, False) + self.assertFalse(result) + + def test_authorize_good_action(self): + action = "example:allowed" + ctx = request.Request( + testing.create_environ( + path="/", + headers={ + "X_USER_ID": "fake", + "X_PROJECT_ID": "fake", + "X_ROLES": "member" + } + ) + ) + result = policy.authorize(ctx, action, False) + self.assertTrue(result) + + def test_ignore_case_role_check(self): + lowercase_action = "example:lowercase_admin" + uppercase_action = "example:uppercase_admin" + + admin_context = request.Request( + testing.create_environ( + path="/", + headers={ + "X_USER_ID": "admin", + "X_PROJECT_ID": "fake", + "X_ROLES": "AdMiN" + } + ) + ) + self.assertTrue(policy.authorize(admin_context, lowercase_action, + {})) + self.assertTrue(policy.authorize(admin_context, uppercase_action, + {})) diff --git a/monasca_events_api/tests/unit/test_request.py b/monasca_events_api/tests/unit/test_request.py new file mode 100644 index 0000000..2247903 --- /dev/null +++ b/monasca_events_api/tests/unit/test_request.py @@ -0,0 +1,68 @@ +# Copyright 2017 FUJITSU LIMITED +# +# 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 falcon import testing + +from monasca_events_api.app.core import request +from monasca_events_api.tests.unit import base + + +class TestRequest(base.BaseTestCase): + + def setUp(self): + super(TestRequest, self).setUp() + + def test_use_context_from_request(self): + req = request.Request( + testing.create_environ( + path='/', + headers={ + 'X_AUTH_TOKEN': '1111', + 'X_USER_ID': '2222', + 'X_PROJECT_ID': '3333', + 'X_ROLES': 'goku,vegeta' + } + ) + ) + self.assertEqual('1111', req.context.auth_token) + self.assertEqual('2222', req.context.user_id) + self.assertEqual('3333', req.context.project_id) + self.assertItemsEqual(['goku', 'vegeta'], req.context.roles) + + def test_check_is_admin_from_request(self): + req = request.Request( + testing.create_environ( + path='/', + headers={ + 'X_USER_ID': '2222', + 'X_PROJECT_ID': '3333', + 'X_ROLES': 'admin,burger' + } + ), + + ) + self.assertTrue(req.is_admin) + + def test_request_context_admin_uppercase(self): + req = request.Request( + testing.create_environ( + path='/', + headers={ + 'X_USER_ID': '1111', + 'X_PROJECT_ID': '2222', + 'X_ROLES': 'Admin,bob' + } + ) + ) + self.assertTrue(req.is_admin) diff --git a/monasca_events_api/version.py b/monasca_events_api/version.py index 9cb947d..4b03ab3 100644 --- a/monasca_events_api/version.py +++ b/monasca_events_api/version.py @@ -14,5 +14,5 @@ import pbr.version -version_info = pbr.version.VersionInfo('monasca-events-api') +version_info = pbr.version.VersionInfo('monasca-events-app') version_str = version_info.version_string() diff --git a/releasenotes/notes/add_policies-24ddd2a505f3de6c.yaml b/releasenotes/notes/add_policies-24ddd2a505f3de6c.yaml new file mode 100644 index 0000000..4436de4 --- /dev/null +++ b/releasenotes/notes/add_policies-24ddd2a505f3de6c.yaml @@ -0,0 +1,9 @@ +--- + +features: + - | + Initial implementation of oslo.policies. + +other: + - | + Add posibility to generate documentation with oslo-config-generator. diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py index 2648a2f..fb8df7b 100644 --- a/releasenotes/source/conf.py +++ b/releasenotes/source/conf.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from monasca_events_api.version import version_info + # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -38,18 +40,13 @@ master_doc = 'index' # General information about the project. repository_name = u'openstack/monasca-events-api' -project = u'Monasca Events Release Notes' -bug_project = u'monasca-events-api' -bug_tag = u'releasenotes' -copyright = u'2014, OpenStack Foundation' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -from monasca_events_api.version import version_info +project = u'Openstack Monitoring Release Notes' version = version_info.canonical_version_string() release = version_info.version_string_with_vcs() +bug_project = u'866' +bug_tag = u'' +copyright = u'2014-present, OpenStack Foundation' +author = u'OpenStack Foundation' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -172,8 +169,7 @@ html_last_updated_fmt = '%Y-%m-%d %H:%M' # html_file_suffix = None # Output file base name for HTML help builder. -htmlhelp_basename = 'MonascaEventsApiReleaseNotesdoc' - +htmlhelp_basename = 'MonitoringEventsApiReleaseNotesDoc' # -- Options for LaTeX output --------------------------------------------- @@ -191,11 +187,11 @@ latex_elements = { # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'MonascaEventsApiReleaseNotes.tex', - u'MonascaEventsApi Release Notes Documentation', u'OpenStack Foundation', - 'manual'), -] +latex_documents = [( + master_doc, 'MonitoringEventsApiReleaseNotes.tex', + u'Openstack Monitoring Events API Release Notes Documentation', [author], + 'manual' +)] # The name of an image file (relative to this directory) to place at the top of # the title page. @@ -223,36 +219,10 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'barbicanreleasenotes', u'MonascaEventsApi Release Notes Documentation', - [u'OpenStack Foundation'], 1) + (master_doc, 'monitoringeventsapireleasenotes', + u'Openstack Monitoring Events API Release Notes', [author], + 1) ] -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'MonascaEventsApiReleaseNotes', u'MonascaEventsApi Release Notes Documentation', - u'OpenStack Foundation', 'MonascaEventsApiReleaseNotes', - 'MonascaEventsApi Release Notes Documentation.', 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - # -- Options for Internationalization output ------------------------------ locale_dirs = ['locale/'] diff --git a/requirements.txt b/requirements.txt index 7b79e02..002f05e 100755 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,8 @@ oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0 oslo.context>=2.14.0 # Apache-2.0 oslo.middleware>=3.27.0 # Apache-2.0 oslo.log>=3.22.0 # Apache-2.0 -oslo.serialization>=1.10.0 # Apache-2.0 +oslo.policy>=1.23.0 # Apache-2.0 +oslo.serialization>=1.10.0,!=2.19.1 # Apache-2.0 oslo.utils>=3.20.0 # Apache-2.0 PasteDeploy>=1.5.0 # MIT eventlet!=0.18.3,!=0.20.1,<0.21.0,>=0.18.2 # MIT diff --git a/setup.cfg b/setup.cfg index d52317a..2a15c61 100755 --- a/setup.cfg +++ b/setup.cfg @@ -36,21 +36,25 @@ data_files = oslo.config.opts = events.api = monasca_events_api.conf:list_opts +oslo.policy.policies = + events.api = monasca_events_api.policies:list_rules + [build_sphinx] all_files = 1 build-dir = doc/build source-dir = doc/source - -[build_apiguide] -all_files = 1 -build-dir = api-guide/build -source-dir = api-guide/source +warning-is-error = 1 [build_apiref] all_files = 1 build-dir = api-ref/build source-dir = api-ref/source +[build_releasenotes] +all_files = 1 +build-dir = releasenotes/build +source-dir = releasenotes/source + [egg_info] tag_build = tag_date = 0 @@ -60,4 +64,7 @@ tag_svn_revision = 0 universal = 1 [pbr] -warnerrors = True +autodoc_index_modules = True +autodoc_exclude_modules = + monasca_events_api.tests.* +api_doc_dir = contributor/api \ No newline at end of file diff --git a/test-requirements.txt b/test-requirements.txt index 74f2d80..d636a02 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,7 +4,6 @@ # Install bounded pep8/pyflakes first, then let flake8 install hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 -flake8-docstrings==0.2.1.post1 # MIT flake8-import-order==0.12 # LGPLv3 bandit>=1.1.0 # Apache-2.0 bashate>=0.2 # Apache-2.0 @@ -21,4 +20,4 @@ doc8 # Apache-2.0 sphinx>=1.6.2 # BSD os-api-ref>=1.0.0 # Apache-2.0 reno!=2.3.1,>=1.8.0 # Apache-2.0 -openstackdocstheme>=1.11.0 # Apache-2.0 +openstackdocstheme>=1.16.0 # Apache-2.0 diff --git a/tox.ini b/tox.ini index 7253399..5d53fe9 100644 --- a/tox.ini +++ b/tox.ini @@ -6,14 +6,14 @@ skipsdist = True [testenv] usedevelop = True setenv = VIRTUAL_ENV={envdir} - OS_TEST_PATH=monasca_events_api/tests + OS_TEST_PATH=monasca_events_api/tests/unit CLIENT_NAME=monasca-events-api passenv = *_proxy *_PROXY whitelist_externals = bash find rm -install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} +install_command = {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?master} {opts} {packages} deps = -r{toxinidir}/test-requirements.txt commands = find ./ -type f -name '*.pyc' -delete @@ -46,7 +46,7 @@ commands = description = Allows to run unit-test with debug mode enabled commands = {[testenv]commands} - oslo_debug_helper -t {toxinidir}/monasca_events_api/tests {posargs} + oslo_debug_helper -t {env:OS_TEST_PATH} {posargs} [testenv:bashate] description = Validates (pep8-like) devstack plugins @@ -76,20 +76,12 @@ commands = {[testenv:checkniceness]commands} [testenv:docs] -description = Builds api-ref, api-guide, releasenotes and devdocs +description = Builds api-ref, releasenotes and devdocs commands = {[testenv:devdocs]commands} - {[testenv:api-guide]commands} {[testenv:api-ref]commands} {[testenv:releasenotes]commands} -[testenv:api-guide] -description = Called from CI scripts to test and publish the API Guide -commands = - rm -rf api-guide/build - {[testenv:checkjson]commands} - sphinx-build -W -b html -d api-guide/build/doctrees api-guide/source api-guide/build/html - [testenv:api-ref] description = Called from CI scripts to test and publish the API Ref commands = @@ -107,16 +99,9 @@ commands = description = Builds developer documentation commands = rm -rf doc/build - {[testenv:codedocs]commands} {[testenv:checkjson]commands} python setup.py build_sphinx -[testenv:codedocs] -description = Generates codebase documentation -commands = - rm -rf doc/source/code - sphinx-apidoc -o doc/source/code -fPM {toxinidir}/monasca_events_api --ext-todo - [testenv:checkniceness] description = Validates (pep-like) documentation skip_install = True @@ -124,7 +109,6 @@ usedevelop = False commands = doc8 --file-encoding utf-8 {toxinidir}/doc doc8 --file-encoding utf-8 {toxinidir}/api-ref - doc8 --file-encoding utf-8 {toxinidir}/api-guide doc8 --file-encoding utf-8 {toxinidir}/releasenotes [testenv:checkjson] @@ -139,13 +123,18 @@ commands = [testenv:genconfig] description = Generates sample documentation file for monasca-events-api -commands = oslo-config-generator --config-file=config-generator/monasca-events-api.conf +commands = oslo-config-generator --config-file=config-generator/config.conf + +[testenv:genpolicy] +description = Generates sample policy.yaml file for monasca-events-api +commands = oslopolicy-sample-generator --config-file=config-generator/policy.conf [testenv:venv] commands = {posargs} [flake8] -exclude = .git,.gitignore,.tox,dist,doc,api-ref,api-guide,releasenotes,documentation,*.egg,build +exclude = .git,.gitignore,.tox,dist,doc,api-ref,releasenotes,*.egg,build, + __pycache__ show-source = True enable-extensions = H203,H106 ignore = D100,D104